gru: fix cache coherency issues with instruction retry
authorJack Steiner <steiner@sgi.com>
Wed, 17 Jun 2009 23:28:28 +0000 (16:28 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 18 Jun 2009 20:04:02 +0000 (13:04 -0700)
Fix two problems related to GRU instruction failures.  Cache coherency is
not maintained for CBEs except when loading or unloading contexts.  When
reading a CBE to extract error information, the CBE must first be flushed
from the cache.

The function that reads kerrnel CBEs was reading the wrong CBE.

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/grufault.c
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-gru/grukservices.c
drivers/misc/sgi-gru/grutables.h

index a489807613f8246ed9ebf0880959200421972442..6d0681236db5ea4bae4e1b8e0da7822d512f93c3 100644 (file)
@@ -614,7 +614,7 @@ int gru_get_exception_detail(unsigned long arg)
        } else if (gts->ts_gru) {
                cbrnum = thread_cbr_number(gts, ucbnum);
                cbe = get_cbe_by_index(gts->ts_gru, cbrnum);
-               prefetchw(cbe);/* Harmless on hardware, required for emulator */
+               gru_flush_cache(cbe);   /* CBE not coherent */
                excdet.opc = cbe->opccpy;
                excdet.exopc = cbe->exopccpy;
                excdet.ecause = cbe->ecause;
@@ -622,6 +622,7 @@ int gru_get_exception_detail(unsigned long arg)
                excdet.exceptdet1 = cbe->idef3upd;
                excdet.cbrstate = cbe->cbrstate;
                excdet.cbrexecstatus = cbe->cbrexecstatus;
+               gru_flush_cache(cbe);
                ret = 0;
        } else {
                ret = -EAGAIN;
index 796ac704795e82383f4dd1543607a0b911e45e27..bfc88d1b2a5bcae8c738537ad3ce78cd865ea73b 100644 (file)
@@ -46,6 +46,7 @@
 
 struct gru_blade_state *gru_base[GRU_MAX_BLADES] __read_mostly;
 unsigned long gru_start_paddr __read_mostly;
+void *gru_start_vaddr __read_mostly;
 unsigned long gru_end_paddr __read_mostly;
 unsigned int gru_max_gids __read_mostly;
 struct gru_stats_s gru_stats;
@@ -376,7 +377,6 @@ static int __init gru_init(void)
 {
        int ret, irq, chip;
        char id[10];
-       void *gru_start_vaddr;
 
        if (!is_uv_system())
                return 0;
index ba6fcd963f3054cc917f92ebf45f87db54b465bd..7586b89fd0d3a82ecb0554bf7c0130f710fa8ab9 100644 (file)
@@ -98,6 +98,9 @@
 #define ASYNC_HAN_TO_BID(h)    ((h) - 1)
 #define ASYNC_BID_TO_HAN(b)    ((b) + 1)
 #define ASYNC_HAN_TO_BS(h)     gru_base[ASYNC_HAN_TO_BID(h)]
+#define KCB_TO_GID(cb)         ((cb - gru_start_vaddr) /               \
+                                       (GRU_SIZE * GRU_CHIPLETS_PER_BLADE))
+#define KCB_TO_BS(cb)          gru_base[KCB_TO_GID(cb)]
 
 #define GRU_NUM_KERNEL_CBR     1
 #define GRU_NUM_KERNEL_DSR_BYTES 256
@@ -354,14 +357,19 @@ int gru_get_cb_exception_detail(void *cb,
                struct control_block_extended_exc_detail *excdet)
 {
        struct gru_control_block_extended *cbe;
+       struct gru_blade_state *bs;
+       int cbrnum;
 
-       cbe = get_cbe(GRUBASE(cb), get_cb_number(cb));
-       prefetchw(cbe); /* Harmless on hardware, required for emulator */
+       bs = KCB_TO_BS(cb);
+       cbrnum = thread_cbr_number(bs->bs_kgts, get_cb_number(cb));
+       cbe = get_cbe(GRUBASE(cb), cbrnum);
+       gru_flush_cache(cbe);   /* CBE not coherent */
        excdet->opc = cbe->opccpy;
        excdet->exopc = cbe->exopccpy;
        excdet->ecause = cbe->ecause;
        excdet->exceptdet0 = cbe->idef1upd;
        excdet->exceptdet1 = cbe->idef3upd;
+       gru_flush_cache(cbe);
        return 0;
 }
 
index 246c63883ebf92b58147164ab2d838adac9ad0fe..665704683ab8c7f3ff5631a1df6066d217d1fc79 100644 (file)
 extern struct gru_stats_s gru_stats;
 extern struct gru_blade_state *gru_base[];
 extern unsigned long gru_start_paddr, gru_end_paddr;
+extern void *gru_start_vaddr;
 extern unsigned int gru_max_gids;
 
 #define GRU_MAX_BLADES         MAX_NUMNODES