gru: update gru kernel self tests
authorJack Steiner <steiner@sgi.com>
Wed, 17 Jun 2009 23:28:26 +0000 (16:28 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 18 Jun 2009 20:04:02 +0000 (13:04 -0700)
Change the kernel self tests that can be optionally executed on GRU
initialization.  This is primarily for testing.

Eliminate the BUG statements on failure and return bad status.  Add ioctl
interface to execute the tests on demand.

Signed-off-by: Jack Steiner <steiner@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-gru/grukservices.c
drivers/misc/sgi-gru/grulib.h
drivers/misc/sgi-gru/grutables.h

index b1567ce868e9d5f289acf664ff2f28bbfdd42de4..796ac704795e82383f4dd1543607a0b911e45e27 100644 (file)
@@ -250,6 +250,9 @@ static long gru_file_unlocked_ioctl(struct file *file, unsigned int req,
        case GRU_USER_CALL_OS:
                err = gru_handle_user_call_os(arg);
                break;
+       case GRU_KTEST:
+               err = gru_ktest(arg);
+               break;
        case GRU_GET_CONFIG_INFO:
                err = gru_get_config_info(arg);
                break;
index 9dff33cb72e3ff7d6e53292c1a15d516f4562e90..7d7952b27e039f20115e4823fe7c02ff345e6062 100644 (file)
@@ -846,13 +846,14 @@ EXPORT_SYMBOL_GPL(gru_copy_gpa);
 /* ------------------- KERNEL QUICKTESTS RUN AT STARTUP ----------------*/
 /*     Temp - will delete after we gain confidence in the GRU          */
 
-int quicktest(void)
+static int quicktest0(unsigned long arg)
 {
        unsigned long word0;
        unsigned long word1;
        void *cb;
        void *dsr;
        unsigned long *p;
+       int ret = -EIO;
 
        if (gru_get_cpu_resources(GRU_CACHE_LINE_BYTES, &cb, &dsr))
                return MQE_BUG_NO_RESOURCES;
@@ -861,26 +862,148 @@ int quicktest(void)
        word1 = 0;
 
        gru_vload(cb, uv_gpa(&word0), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA);
-       if (gru_wait(cb) != CBS_IDLE)
-               BUG();
+       if (gru_wait(cb) != CBS_IDLE) {
+               printk(KERN_DEBUG "GRU quicktest0: CBR failure 1\n");
+               goto done;
+       }
 
-       if (*p != MAGIC)
-               BUG();
+       if (*p != MAGIC) {
+               printk(KERN_DEBUG "GRU: quicktest0 bad magic 0x%lx\n", *p);
+               goto done;
+       }
        gru_vstore(cb, uv_gpa(&word1), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA);
-       if (gru_wait(cb) != CBS_IDLE)
-               BUG();
-       gru_free_cpu_resources(cb, dsr);
+       if (gru_wait(cb) != CBS_IDLE) {
+               printk(KERN_DEBUG "GRU quicktest0: CBR failure 2\n");
+               goto done;
+       }
 
        if (word0 != word1 || word1 != MAGIC) {
-               printk
-                   ("GRU quicktest err: found 0x%lx, expected 0x%lx\n",
+               printk(KERN_DEBUG
+                      "GRU quicktest0 err: found 0x%lx, expected 0x%lx\n",
                     word1, MAGIC);
-               BUG();          /* ZZZ should not be fatal */
+               goto done;
        }
+       ret = 0;
 
-       return 0;
+done:
+       gru_free_cpu_resources(cb, dsr);
+       return ret;
 }
 
+#define ALIGNUP(p, q)  ((void *)(((unsigned long)(p) + (q) - 1) & ~(q - 1)))
+
+static int quicktest1(unsigned long arg)
+{
+       struct gru_message_queue_desc mqd;
+       void *p, *mq;
+       unsigned long *dw;
+       int i, ret = -EIO;
+       char mes[GRU_CACHE_LINE_BYTES], *m;
+
+       /* Need  1K cacheline aligned that does not cross page boundary */
+       p = kmalloc(4096, 0);
+       mq = ALIGNUP(p, 1024);
+       memset(mes, 0xee, sizeof(mes));
+       dw = mq;
+
+       gru_create_message_queue(&mqd, mq, 8 * GRU_CACHE_LINE_BYTES, 0, 0, 0);
+       for (i = 0; i < 6; i++) {
+               mes[8] = i;
+               do {
+                       ret = gru_send_message_gpa(&mqd, mes, sizeof(mes));
+               } while (ret == MQE_CONGESTION);
+               if (ret)
+                       break;
+       }
+       if (ret != MQE_QUEUE_FULL || i != 4)
+               goto done;
+
+       for (i = 0; i < 6; i++) {
+               m = gru_get_next_message(&mqd);
+               if (!m || m[8] != i)
+                       break;
+               gru_free_message(&mqd, m);
+       }
+       ret = (i == 4) ? 0 : -EIO;
+
+done:
+       kfree(p);
+       return ret;
+}
+
+static int quicktest2(unsigned long arg)
+{
+       static DECLARE_COMPLETION(cmp);
+       unsigned long han;
+       int blade_id = 0;
+       int numcb = 4;
+       int ret = 0;
+       unsigned long *buf;
+       void *cb0, *cb;
+       int i, k, istatus, bytes;
+
+       bytes = numcb * 4 * 8;
+       buf = kmalloc(bytes, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = -EBUSY;
+       han = gru_reserve_async_resources(blade_id, numcb, 0, &cmp);
+       if (!han)
+               goto done;
+
+       gru_lock_async_resource(han, &cb0, NULL);
+       memset(buf, 0xee, bytes);
+       for (i = 0; i < numcb; i++)
+               gru_vset(cb0 + i * GRU_HANDLE_STRIDE, uv_gpa(&buf[i * 4]), 0,
+                               XTYPE_DW, 4, 1, IMA_INTERRUPT);
+
+       ret = 0;
+       for (k = 0; k < numcb; k++) {
+               gru_wait_async_cbr(han);
+               for (i = 0; i < numcb; i++) {
+                       cb = cb0 + i * GRU_HANDLE_STRIDE;
+                       istatus = gru_check_status(cb);
+                       if (istatus == CBS_ACTIVE)
+                               continue;
+                       if (istatus == CBS_EXCEPTION)
+                               ret = -EFAULT;
+                       else if (buf[i] || buf[i + 1] || buf[i + 2] ||
+                                       buf[i + 3])
+                               ret = -EIO;
+               }
+       }
+       BUG_ON(cmp.done);
+
+       gru_unlock_async_resource(han);
+       gru_release_async_resources(han);
+done:
+       kfree(buf);
+       return ret;
+}
+
+/*
+ * Debugging only. User hook for various kernel tests
+ * of driver & gru.
+ */
+int gru_ktest(unsigned long arg)
+{
+       int ret = -EINVAL;
+
+       switch (arg & 0xff) {
+       case 0:
+               ret = quicktest0(arg);
+               break;
+       case 1:
+               ret = quicktest1(arg);
+               break;
+       case 2:
+               ret = quicktest2(arg);
+               break;
+       }
+       return ret;
+
+}
 
 int gru_kservices_init(struct gru_state *gru)
 {
@@ -891,9 +1014,6 @@ int gru_kservices_init(struct gru_state *gru)
                return 0;
 
        init_rwsem(&bs->bs_kgts_sema);
-
-       if (gru_options & GRU_QUICKLOOK)
-               quicktest();
        return 0;
 }
 
index 6ab872665e7f958af4c22fda544acfadfb839319..87586551d16f87d9d5a3edb69123a585c5c894a4 100644 (file)
@@ -56,6 +56,9 @@
 /* Get some config options (primarily for tests & emulator) */
 #define GRU_GET_CONFIG_INFO            _IOWR(GRU_IOCTL_NUM, 51, void *)
 
+/* Various kernel self-tests */
+#define GRU_KTEST                      _IOWR(GRU_IOCTL_NUM, 52, void *)
+
 #define CONTEXT_WINDOW_BYTES(th)        (GRU_GSEG_PAGESIZE * (th))
 #define THREAD_POINTER(p, th)          (p + GRU_GSEG_PAGESIZE * (th))
 
index ca81800146ffc048bd3b123c4d81f76f53910be4..6dfb3e69411f360f9db441c4d5c347b71ff42bfd 100644 (file)
@@ -258,7 +258,6 @@ extern struct mcs_op_statistic mcs_op_statistics[mcsop_last];
 
 #define OPT_DPRINT     1
 #define OPT_STATS      2
-#define GRU_QUICKLOOK  4
 
 
 #define IRQ_GRU                        110     /* Starting IRQ number for interrupts */
@@ -662,6 +661,7 @@ extern int gru_fault(struct vm_area_struct *, struct vm_fault *vmf);
 extern struct gru_mm_struct *gru_register_mmu_notifier(void);
 extern void gru_drop_mmu_notifier(struct gru_mm_struct *gms);
 
+extern int gru_ktest(unsigned long arg);
 extern void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start,
                                        unsigned long len);