]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sparc64: chip handler IRQ cookie checking
authorDave Kleikamp <dave.kleikamp@oracle.com>
Wed, 21 May 2014 18:33:21 +0000 (13:33 -0500)
committerDave Kleikamp <dave.kleikamp@oracle.com>
Mon, 18 Apr 2016 16:42:46 +0000 (11:42 -0500)
original patch by Bob Picco

Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
Cc: Bob Picco <bob.picco@oracle.com>
arch/sparc/kernel/irq_64.c

index 4033c23bdfa6cc76a9ef4b34ad671da39b6b5077..135ace35b8f36a91688c67f74d0b5c264b7e0443 100644 (file)
@@ -251,6 +251,38 @@ out:
        return 0;
 }
 
+/* This bitmap is for early boot chip handler IRQ cookie checking.
+ * It is required by kexec because the cookies already exist.
+ * Legacy devhandle|devino IRQ isn't sufficient to discriminate an
+ * IRQ because it could be shared and transformed this way by DT
+ * swizzle handling.
+ * So for kexec we'll detect with a bitmap first. Should the bit be
+ * set, then the cookie has already been created by the current kernel.
+ * The bitmap is limited to a devhandle|devino maximum NR_COOKIE_BITS.
+ */
+#define NR_COOKIE_BITS (1UL << 16UL)
+DECLARE_BITMAP(cookie_bitmap, NR_COOKIE_BITS);
+
+static int test_cookie(unsigned int devhandle, unsigned int devino)
+{
+       int nr = (int) (devhandle | devino);
+
+       if (nr >= NR_COOKIE_BITS) {
+               pr_debug("test_cookie: exceeded bitmap size (%d).\n", nr);
+               return 0;
+       }
+       return test_bit(nr, cookie_bitmap);
+}
+
+static void set_cookie(unsigned int devhandle, unsigned int devino)
+{
+       int nr = (int) (devhandle | devino);
+
+       if (nr >= NR_COOKIE_BITS)
+               return;
+       set_bit(nr, cookie_bitmap);
+}
+
 static unsigned int cookie_exists(u32 devhandle, unsigned int devino)
 {
        unsigned long hv_err, cookie;
@@ -264,6 +296,8 @@ static unsigned int cookie_exists(u32 devhandle, unsigned int devino)
        }
 
        if (cookie & ((1UL << 63UL))) {
+               if (!test_cookie(devhandle, devino))
+                       goto out;
                cookie = ~cookie;
                bucket = (struct ino_bucket *) __va(cookie);
                irq = bucket->__irq;
@@ -685,6 +719,8 @@ static unsigned long cookie_assign(unsigned int irq, u32 devhandle,
        hv_error = sun4v_vintr_set_cookie(devhandle, devino, cookie);
        if (hv_error)
                pr_err("HV vintr set cookie failed = %ld\n", hv_error);
+       else
+               set_cookie(devhandle, devino);
 
        return hv_error;
 }