diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/misc/sgi-gru/grufault.c | 49 |
1 files changed, 20 insertions, 29 deletions
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 2605edfbaebe..a9f0cf483005 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c | |||
@@ -122,22 +122,11 @@ static void gru_unlock_gts(struct gru_thread_state *gts) | |||
122 | * is necessary to prevent the user from seeing a stale cb.istatus that will | 122 | * is necessary to prevent the user from seeing a stale cb.istatus that will |
123 | * change as soon as the TFH restart is complete. Races may cause an | 123 | * change as soon as the TFH restart is complete. Races may cause an |
124 | * occasional failure to clear the cb.istatus, but that is ok. | 124 | * occasional failure to clear the cb.istatus, but that is ok. |
125 | * | ||
126 | * If the cb address is not valid (should not happen, but...), nothing | ||
127 | * bad will happen.. The get_user()/put_user() will fail but there | ||
128 | * are no bad side-effects. | ||
129 | */ | 125 | */ |
130 | static void gru_cb_set_istatus_active(unsigned long __user *cb) | 126 | static void gru_cb_set_istatus_active(struct gru_instruction_bits *cbk) |
131 | { | 127 | { |
132 | union { | 128 | if (cbk) { |
133 | struct gru_instruction_bits bits; | 129 | cbk->istatus = CBS_ACTIVE; |
134 | unsigned long dw; | ||
135 | } u; | ||
136 | |||
137 | if (cb) { | ||
138 | get_user(u.dw, cb); | ||
139 | u.bits.istatus = CBS_ACTIVE; | ||
140 | put_user(u.dw, cb); | ||
141 | } | 130 | } |
142 | } | 131 | } |
143 | 132 | ||
@@ -322,9 +311,9 @@ upm: | |||
322 | */ | 311 | */ |
323 | static int gru_try_dropin(struct gru_thread_state *gts, | 312 | static int gru_try_dropin(struct gru_thread_state *gts, |
324 | struct gru_tlb_fault_handle *tfh, | 313 | struct gru_tlb_fault_handle *tfh, |
325 | unsigned long __user *cb) | 314 | struct gru_instruction_bits *cbk) |
326 | { | 315 | { |
327 | int pageshift = 0, asid, write, ret, atomic = !cb; | 316 | int pageshift = 0, asid, write, ret, atomic = !cbk; |
328 | unsigned long gpa = 0, vaddr = 0; | 317 | unsigned long gpa = 0, vaddr = 0; |
329 | 318 | ||
330 | /* | 319 | /* |
@@ -347,7 +336,7 @@ static int gru_try_dropin(struct gru_thread_state *gts, | |||
347 | } | 336 | } |
348 | if (tfh->state == TFHSTATE_IDLE) | 337 | if (tfh->state == TFHSTATE_IDLE) |
349 | goto failidle; | 338 | goto failidle; |
350 | if (tfh->state == TFHSTATE_MISS_FMM && cb) | 339 | if (tfh->state == TFHSTATE_MISS_FMM && cbk) |
351 | goto failfmm; | 340 | goto failfmm; |
352 | 341 | ||
353 | write = (tfh->cause & TFHCAUSE_TLB_MOD) != 0; | 342 | write = (tfh->cause & TFHCAUSE_TLB_MOD) != 0; |
@@ -378,7 +367,7 @@ static int gru_try_dropin(struct gru_thread_state *gts, | |||
378 | goto failupm; | 367 | goto failupm; |
379 | } | 368 | } |
380 | } | 369 | } |
381 | gru_cb_set_istatus_active(cb); | 370 | gru_cb_set_istatus_active(cbk); |
382 | tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write, | 371 | tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write, |
383 | GRU_PAGESIZE(pageshift)); | 372 | GRU_PAGESIZE(pageshift)); |
384 | STAT(tlb_dropin); | 373 | STAT(tlb_dropin); |
@@ -392,7 +381,7 @@ failnoasid: | |||
392 | /* No asid (delayed unload). */ | 381 | /* No asid (delayed unload). */ |
393 | STAT(tlb_dropin_fail_no_asid); | 382 | STAT(tlb_dropin_fail_no_asid); |
394 | gru_dbg(grudev, "FAILED no_asid tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); | 383 | gru_dbg(grudev, "FAILED no_asid tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); |
395 | if (!cb) | 384 | if (!cbk) |
396 | tfh_user_polling_mode(tfh); | 385 | tfh_user_polling_mode(tfh); |
397 | else | 386 | else |
398 | gru_flush_cache(tfh); | 387 | gru_flush_cache(tfh); |
@@ -415,17 +404,18 @@ failfmm: | |||
415 | failnoexception: | 404 | failnoexception: |
416 | /* TFH status did not show exception pending */ | 405 | /* TFH status did not show exception pending */ |
417 | gru_flush_cache(tfh); | 406 | gru_flush_cache(tfh); |
418 | if (cb) | 407 | if (cbk) |
419 | gru_flush_cache(cb); | 408 | gru_flush_cache(cbk); |
420 | STAT(tlb_dropin_fail_no_exception); | 409 | STAT(tlb_dropin_fail_no_exception); |
421 | gru_dbg(grudev, "FAILED non-exception tfh: 0x%p, status %d, state %d\n", tfh, tfh->status, tfh->state); | 410 | gru_dbg(grudev, "FAILED non-exception tfh: 0x%p, status %d, state %d\n", |
411 | tfh, tfh->status, tfh->state); | ||
422 | return 0; | 412 | return 0; |
423 | 413 | ||
424 | failidle: | 414 | failidle: |
425 | /* TFH state was idle - no miss pending */ | 415 | /* TFH state was idle - no miss pending */ |
426 | gru_flush_cache(tfh); | 416 | gru_flush_cache(tfh); |
427 | if (cb) | 417 | if (cbk) |
428 | gru_flush_cache(cb); | 418 | gru_flush_cache(cbk); |
429 | STAT(tlb_dropin_fail_idle); | 419 | STAT(tlb_dropin_fail_idle); |
430 | gru_dbg(grudev, "FAILED idle tfh: 0x%p, state %d\n", tfh, tfh->state); | 420 | gru_dbg(grudev, "FAILED idle tfh: 0x%p, state %d\n", tfh, tfh->state); |
431 | return 0; | 421 | return 0; |
@@ -439,7 +429,7 @@ failinval: | |||
439 | 429 | ||
440 | failactive: | 430 | failactive: |
441 | /* Range invalidate active. Switch to UPM iff atomic */ | 431 | /* Range invalidate active. Switch to UPM iff atomic */ |
442 | if (!cb) | 432 | if (!cbk) |
443 | tfh_user_polling_mode(tfh); | 433 | tfh_user_polling_mode(tfh); |
444 | else | 434 | else |
445 | gru_flush_cache(tfh); | 435 | gru_flush_cache(tfh); |
@@ -512,7 +502,7 @@ irqreturn_t gru_intr(int irq, void *dev_id) | |||
512 | 502 | ||
513 | static int gru_user_dropin(struct gru_thread_state *gts, | 503 | static int gru_user_dropin(struct gru_thread_state *gts, |
514 | struct gru_tlb_fault_handle *tfh, | 504 | struct gru_tlb_fault_handle *tfh, |
515 | unsigned long __user *cb) | 505 | void *cb) |
516 | { | 506 | { |
517 | struct gru_mm_struct *gms = gts->ts_gms; | 507 | struct gru_mm_struct *gms = gts->ts_gms; |
518 | int ret; | 508 | int ret; |
@@ -538,7 +528,7 @@ int gru_handle_user_call_os(unsigned long cb) | |||
538 | { | 528 | { |
539 | struct gru_tlb_fault_handle *tfh; | 529 | struct gru_tlb_fault_handle *tfh; |
540 | struct gru_thread_state *gts; | 530 | struct gru_thread_state *gts; |
541 | unsigned long __user *cbp; | 531 | void *cbk; |
542 | int ucbnum, cbrnum, ret = -EINVAL; | 532 | int ucbnum, cbrnum, ret = -EINVAL; |
543 | 533 | ||
544 | STAT(call_os); | 534 | STAT(call_os); |
@@ -548,7 +538,6 @@ int gru_handle_user_call_os(unsigned long cb) | |||
548 | ucbnum = get_cb_number((void *)cb); | 538 | ucbnum = get_cb_number((void *)cb); |
549 | if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB) | 539 | if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB) |
550 | return -EINVAL; | 540 | return -EINVAL; |
551 | cbp = (unsigned long *)cb; | ||
552 | 541 | ||
553 | gts = gru_find_lock_gts(cb); | 542 | gts = gru_find_lock_gts(cb); |
554 | if (!gts) | 543 | if (!gts) |
@@ -583,7 +572,9 @@ int gru_handle_user_call_os(unsigned long cb) | |||
583 | gru_unload_context(gts, 1); | 572 | gru_unload_context(gts, 1); |
584 | } else if (gts->ts_gru) { | 573 | } else if (gts->ts_gru) { |
585 | tfh = get_tfh_by_index(gts->ts_gru, cbrnum); | 574 | tfh = get_tfh_by_index(gts->ts_gru, cbrnum); |
586 | ret = gru_user_dropin(gts, tfh, cbp); | 575 | cbk = get_gseg_base_address_cb(gts->ts_gru->gs_gru_base_vaddr, |
576 | gts->ts_ctxnum, ucbnum); | ||
577 | ret = gru_user_dropin(gts, tfh, cbk); | ||
587 | } | 578 | } |
588 | exit: | 579 | exit: |
589 | gru_unlock_gts(gts); | 580 | gru_unlock_gts(gts); |