diff options
author | Jack Steiner <steiner@sgi.com> | 2009-12-15 19:48:11 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 10:20:15 -0500 |
commit | 67bf04a5c2574e9495f660f418f6df776821d578 (patch) | |
tree | ff28ab4983b007136da88786c8966ea1598841a0 /drivers/misc | |
parent | e006043a4d2da52bba9fd9cb7e5a22e2951ff69b (diff) |
gru: fix prefetch and speculation bugs
Fix several bugs related to prefetch, ordering & speculation:
- GRU cch_allocate() instruction causes cacheable memory
to be created. Add a barriers to prevent speculation
from prefetching data before it exists.
- Add memory barriers before cache-flush instructions to ensure
that previously stored data is included in the line flushed to memory.
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>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/sgi-gru/gru_instructions.h | 1 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grufault.c | 2 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/gruhandles.c | 22 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grukservices.c | 10 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grumain.c | 9 |
5 files changed, 38 insertions, 6 deletions
diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h index e033b6ce4a3f..32f358d9f429 100644 --- a/drivers/misc/sgi-gru/gru_instructions.h +++ b/drivers/misc/sgi-gru/gru_instructions.h | |||
@@ -325,6 +325,7 @@ static inline void gru_flush_cache(void *p) | |||
325 | static inline void gru_start_instruction(struct gru_instruction *ins, int op32) | 325 | static inline void gru_start_instruction(struct gru_instruction *ins, int op32) |
326 | { | 326 | { |
327 | gru_ordered_store_int(ins, op32); | 327 | gru_ordered_store_int(ins, op32); |
328 | mb(); | ||
328 | gru_flush_cache(ins); | 329 | gru_flush_cache(ins); |
329 | } | 330 | } |
330 | 331 | ||
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 7466234450f3..d3cacd696b38 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c | |||
@@ -333,6 +333,7 @@ static int gru_try_dropin(struct gru_thread_state *gts, | |||
333 | */ | 333 | */ |
334 | if (tfh->status != TFHSTATUS_EXCEPTION) { | 334 | if (tfh->status != TFHSTATUS_EXCEPTION) { |
335 | gru_flush_cache(tfh); | 335 | gru_flush_cache(tfh); |
336 | sync_core(); | ||
336 | if (tfh->status != TFHSTATUS_EXCEPTION) | 337 | if (tfh->status != TFHSTATUS_EXCEPTION) |
337 | goto failnoexception; | 338 | goto failnoexception; |
338 | STAT(tfh_stale_on_fault); | 339 | STAT(tfh_stale_on_fault); |
@@ -599,6 +600,7 @@ int gru_get_exception_detail(unsigned long arg) | |||
599 | cbrnum = thread_cbr_number(gts, ucbnum); | 600 | cbrnum = thread_cbr_number(gts, ucbnum); |
600 | cbe = get_cbe_by_index(gts->ts_gru, cbrnum); | 601 | cbe = get_cbe_by_index(gts->ts_gru, cbrnum); |
601 | gru_flush_cache(cbe); /* CBE not coherent */ | 602 | gru_flush_cache(cbe); /* CBE not coherent */ |
603 | sync_core(); /* make sure we are have current data */ | ||
602 | excdet.opc = cbe->opccpy; | 604 | excdet.opc = cbe->opccpy; |
603 | excdet.exopc = cbe->exopccpy; | 605 | excdet.exopc = cbe->exopccpy; |
604 | excdet.ecause = cbe->ecause; | 606 | excdet.ecause = cbe->ecause; |
diff --git a/drivers/misc/sgi-gru/gruhandles.c b/drivers/misc/sgi-gru/gruhandles.c index 806419a6b44c..f1117a7637a2 100644 --- a/drivers/misc/sgi-gru/gruhandles.c +++ b/drivers/misc/sgi-gru/gruhandles.c | |||
@@ -91,9 +91,18 @@ static int wait_instruction_complete(void *h, enum mcs_op opc) | |||
91 | 91 | ||
92 | int cch_allocate(struct gru_context_configuration_handle *cch) | 92 | int cch_allocate(struct gru_context_configuration_handle *cch) |
93 | { | 93 | { |
94 | int ret; | ||
95 | |||
94 | cch->opc = CCHOP_ALLOCATE; | 96 | cch->opc = CCHOP_ALLOCATE; |
95 | start_instruction(cch); | 97 | start_instruction(cch); |
96 | return wait_instruction_complete(cch, cchop_allocate); | 98 | ret = wait_instruction_complete(cch, cchop_allocate); |
99 | |||
100 | /* | ||
101 | * Stop speculation into the GSEG being mapped by the previous ALLOCATE. | ||
102 | * The GSEG memory does not exist until the ALLOCATE completes. | ||
103 | */ | ||
104 | sync_core(); | ||
105 | return ret; | ||
97 | } | 106 | } |
98 | 107 | ||
99 | int cch_start(struct gru_context_configuration_handle *cch) | 108 | int cch_start(struct gru_context_configuration_handle *cch) |
@@ -112,9 +121,18 @@ int cch_interrupt(struct gru_context_configuration_handle *cch) | |||
112 | 121 | ||
113 | int cch_deallocate(struct gru_context_configuration_handle *cch) | 122 | int cch_deallocate(struct gru_context_configuration_handle *cch) |
114 | { | 123 | { |
124 | int ret; | ||
125 | |||
115 | cch->opc = CCHOP_DEALLOCATE; | 126 | cch->opc = CCHOP_DEALLOCATE; |
116 | start_instruction(cch); | 127 | start_instruction(cch); |
117 | return wait_instruction_complete(cch, cchop_deallocate); | 128 | ret = wait_instruction_complete(cch, cchop_deallocate); |
129 | |||
130 | /* | ||
131 | * Stop speculation into the GSEG being unmapped by the previous | ||
132 | * DEALLOCATE. | ||
133 | */ | ||
134 | sync_core(); | ||
135 | return ret; | ||
118 | } | 136 | } |
119 | 137 | ||
120 | int cch_interrupt_sync(struct gru_context_configuration_handle | 138 | int cch_interrupt_sync(struct gru_context_configuration_handle |
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index 24ec109e61cc..8c81aca0463a 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c | |||
@@ -395,6 +395,7 @@ int gru_get_cb_exception_detail(void *cb, | |||
395 | cbrnum = thread_cbr_number(bs->bs_kgts, get_cb_number(cb)); | 395 | cbrnum = thread_cbr_number(bs->bs_kgts, get_cb_number(cb)); |
396 | cbe = get_cbe(GRUBASE(cb), cbrnum); | 396 | cbe = get_cbe(GRUBASE(cb), cbrnum); |
397 | gru_flush_cache(cbe); /* CBE not coherent */ | 397 | gru_flush_cache(cbe); /* CBE not coherent */ |
398 | sync_core(); | ||
398 | excdet->opc = cbe->opccpy; | 399 | excdet->opc = cbe->opccpy; |
399 | excdet->exopc = cbe->exopccpy; | 400 | excdet->exopc = cbe->exopccpy; |
400 | excdet->ecause = cbe->ecause; | 401 | excdet->ecause = cbe->ecause; |
@@ -461,9 +462,10 @@ int gru_check_status_proc(void *cb) | |||
461 | int ret; | 462 | int ret; |
462 | 463 | ||
463 | ret = gen->istatus; | 464 | ret = gen->istatus; |
464 | if (ret != CBS_EXCEPTION) | 465 | if (ret == CBS_EXCEPTION) |
465 | return ret; | 466 | ret = gru_retry_exception(cb); |
466 | return gru_retry_exception(cb); | 467 | rmb(); |
468 | return ret; | ||
467 | 469 | ||
468 | } | 470 | } |
469 | 471 | ||
@@ -475,7 +477,7 @@ int gru_wait_proc(void *cb) | |||
475 | ret = gru_wait_idle_or_exception(gen); | 477 | ret = gru_wait_idle_or_exception(gen); |
476 | if (ret == CBS_EXCEPTION) | 478 | if (ret == CBS_EXCEPTION) |
477 | ret = gru_retry_exception(cb); | 479 | ret = gru_retry_exception(cb); |
478 | 480 | rmb(); | |
479 | return ret; | 481 | return ret; |
480 | } | 482 | } |
481 | 483 | ||
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index 944028871884..a383271d3912 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c | |||
@@ -499,6 +499,9 @@ static void gru_load_context_data(void *save, void *grubase, int ctxnum, | |||
499 | memset(cbe + i * GRU_HANDLE_STRIDE, 0, | 499 | memset(cbe + i * GRU_HANDLE_STRIDE, 0, |
500 | GRU_CACHE_LINE_BYTES); | 500 | GRU_CACHE_LINE_BYTES); |
501 | } | 501 | } |
502 | /* Flush CBE to hide race in context restart */ | ||
503 | mb(); | ||
504 | gru_flush_cache(cbe + i * GRU_HANDLE_STRIDE); | ||
502 | cb += GRU_HANDLE_STRIDE; | 505 | cb += GRU_HANDLE_STRIDE; |
503 | } | 506 | } |
504 | 507 | ||
@@ -519,6 +522,12 @@ static void gru_unload_context_data(void *save, void *grubase, int ctxnum, | |||
519 | cb = gseg + GRU_CB_BASE; | 522 | cb = gseg + GRU_CB_BASE; |
520 | cbe = grubase + GRU_CBE_BASE; | 523 | cbe = grubase + GRU_CBE_BASE; |
521 | length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; | 524 | length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; |
525 | |||
526 | /* CBEs may not be coherent. Flush them from cache */ | ||
527 | for_each_cbr_in_allocation_map(i, &cbrmap, scr) | ||
528 | gru_flush_cache(cbe + i * GRU_HANDLE_STRIDE); | ||
529 | mb(); /* Let the CL flush complete */ | ||
530 | |||
522 | gru_prefetch_context(gseg, cb, cbe, cbrmap, length); | 531 | gru_prefetch_context(gseg, cb, cbe, cbrmap, length); |
523 | 532 | ||
524 | for_each_cbr_in_allocation_map(i, &cbrmap, scr) { | 533 | for_each_cbr_in_allocation_map(i, &cbrmap, scr) { |