aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/sgi-gru/grufault.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/sgi-gru/grufault.c')
-rw-r--r--drivers/misc/sgi-gru/grufault.c89
1 files changed, 85 insertions, 4 deletions
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
index 7d757e9c42f0..a1b3a1d66af5 100644
--- a/drivers/misc/sgi-gru/grufault.c
+++ b/drivers/misc/sgi-gru/grufault.c
@@ -290,6 +290,61 @@ upm:
290 290
291 291
292/* 292/*
293 * Flush a CBE from cache. The CBE is clean in the cache. Dirty the
294 * CBE cacheline so that the line will be written back to home agent.
295 * Otherwise the line may be silently dropped. This has no impact
296 * except on performance.
297 */
298static void gru_flush_cache_cbe(struct gru_control_block_extended *cbe)
299{
300 if (unlikely(cbe)) {
301 cbe->cbrexecstatus = 0; /* make CL dirty */
302 gru_flush_cache(cbe);
303 }
304}
305
306/*
307 * Preload the TLB with entries that may be required. Currently, preloading
308 * is implemented only for BCOPY. Preload <tlb_preload_count> pages OR to
309 * the end of the bcopy tranfer, whichever is smaller.
310 */
311static void gru_preload_tlb(struct gru_state *gru,
312 struct gru_thread_state *gts, int atomic,
313 unsigned long fault_vaddr, int asid, int write,
314 unsigned char tlb_preload_count,
315 struct gru_tlb_fault_handle *tfh,
316 struct gru_control_block_extended *cbe)
317{
318 unsigned long vaddr = 0, gpa;
319 int ret, pageshift;
320
321 if (cbe->opccpy != OP_BCOPY)
322 return;
323
324 if (fault_vaddr == cbe->cbe_baddr0)
325 vaddr = fault_vaddr + GRU_CACHE_LINE_BYTES * cbe->cbe_src_cl - 1;
326 else if (fault_vaddr == cbe->cbe_baddr1)
327 vaddr = fault_vaddr + (1 << cbe->xtypecpy) * cbe->cbe_nelemcur - 1;
328
329 fault_vaddr &= PAGE_MASK;
330 vaddr &= PAGE_MASK;
331 vaddr = min(vaddr, fault_vaddr + tlb_preload_count * PAGE_SIZE);
332
333 while (vaddr > fault_vaddr) {
334 ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift);
335 if (ret || tfh_write_only(tfh, gpa, GAA_RAM, vaddr, asid, write,
336 GRU_PAGESIZE(pageshift)))
337 return;
338 gru_dbg(grudev,
339 "%s: gid %d, gts 0x%p, tfh 0x%p, vaddr 0x%lx, asid 0x%x, rw %d, ps %d, gpa 0x%lx\n",
340 atomic ? "atomic" : "non-atomic", gru->gs_gid, gts, tfh,
341 vaddr, asid, write, pageshift, gpa);
342 vaddr -= PAGE_SIZE;
343 STAT(tlb_preload_page);
344 }
345}
346
347/*
293 * Drop a TLB entry into the GRU. The fault is described by info in an TFH. 348 * Drop a TLB entry into the GRU. The fault is described by info in an TFH.
294 * Input: 349 * Input:
295 * cb Address of user CBR. Null if not running in user context 350 * cb Address of user CBR. Null if not running in user context
@@ -303,6 +358,8 @@ static int gru_try_dropin(struct gru_thread_state *gts,
303 struct gru_tlb_fault_handle *tfh, 358 struct gru_tlb_fault_handle *tfh,
304 struct gru_instruction_bits *cbk) 359 struct gru_instruction_bits *cbk)
305{ 360{
361 struct gru_control_block_extended *cbe = NULL;
362 unsigned char tlb_preload_count = gts->ts_tlb_preload_count;
306 int pageshift = 0, asid, write, ret, atomic = !cbk, indexway; 363 int pageshift = 0, asid, write, ret, atomic = !cbk, indexway;
307 unsigned long gpa = 0, vaddr = 0; 364 unsigned long gpa = 0, vaddr = 0;
308 365
@@ -314,6 +371,14 @@ static int gru_try_dropin(struct gru_thread_state *gts,
314 */ 371 */
315 372
316 /* 373 /*
374 * Prefetch the CBE if doing TLB preloading
375 */
376 if (unlikely(tlb_preload_count)) {
377 cbe = gru_tfh_to_cbe(tfh);
378 prefetchw(cbe);
379 }
380
381 /*
317 * Error if TFH state is IDLE or FMM mode & the user issuing a UPM call. 382 * Error if TFH state is IDLE or FMM mode & the user issuing a UPM call.
318 * Might be a hardware race OR a stupid user. Ignore FMM because FMM 383 * Might be a hardware race OR a stupid user. Ignore FMM because FMM
319 * is a transient state. 384 * is a transient state.
@@ -359,6 +424,12 @@ static int gru_try_dropin(struct gru_thread_state *gts,
359 goto failupm; 424 goto failupm;
360 } 425 }
361 } 426 }
427
428 if (unlikely(cbe) && pageshift == PAGE_SHIFT) {
429 gru_preload_tlb(gts->ts_gru, gts, atomic, vaddr, asid, write, tlb_preload_count, tfh, cbe);
430 gru_flush_cache_cbe(cbe);
431 }
432
362 gru_cb_set_istatus_active(cbk); 433 gru_cb_set_istatus_active(cbk);
363 tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write, 434 tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write,
364 GRU_PAGESIZE(pageshift)); 435 GRU_PAGESIZE(pageshift));
@@ -378,11 +449,13 @@ failnoasid:
378 tfh_user_polling_mode(tfh); 449 tfh_user_polling_mode(tfh);
379 else 450 else
380 gru_flush_cache(tfh); 451 gru_flush_cache(tfh);
452 gru_flush_cache_cbe(cbe);
381 return -EAGAIN; 453 return -EAGAIN;
382 454
383failupm: 455failupm:
384 /* Atomic failure switch CBR to UPM */ 456 /* Atomic failure switch CBR to UPM */
385 tfh_user_polling_mode(tfh); 457 tfh_user_polling_mode(tfh);
458 gru_flush_cache_cbe(cbe);
386 STAT(tlb_dropin_fail_upm); 459 STAT(tlb_dropin_fail_upm);
387 gru_dbg(grudev, "FAILED upm tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); 460 gru_dbg(grudev, "FAILED upm tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr);
388 return 1; 461 return 1;
@@ -390,6 +463,7 @@ failupm:
390failfmm: 463failfmm:
391 /* FMM state on UPM call */ 464 /* FMM state on UPM call */
392 gru_flush_cache(tfh); 465 gru_flush_cache(tfh);
466 gru_flush_cache_cbe(cbe);
393 STAT(tlb_dropin_fail_fmm); 467 STAT(tlb_dropin_fail_fmm);
394 gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state); 468 gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state);
395 return 0; 469 return 0;
@@ -397,6 +471,7 @@ failfmm:
397failnoexception: 471failnoexception:
398 /* TFH status did not show exception pending */ 472 /* TFH status did not show exception pending */
399 gru_flush_cache(tfh); 473 gru_flush_cache(tfh);
474 gru_flush_cache_cbe(cbe);
400 if (cbk) 475 if (cbk)
401 gru_flush_cache(cbk); 476 gru_flush_cache(cbk);
402 STAT(tlb_dropin_fail_no_exception); 477 STAT(tlb_dropin_fail_no_exception);
@@ -407,6 +482,7 @@ failnoexception:
407failidle: 482failidle:
408 /* TFH state was idle - no miss pending */ 483 /* TFH state was idle - no miss pending */
409 gru_flush_cache(tfh); 484 gru_flush_cache(tfh);
485 gru_flush_cache_cbe(cbe);
410 if (cbk) 486 if (cbk)
411 gru_flush_cache(cbk); 487 gru_flush_cache(cbk);
412 STAT(tlb_dropin_fail_idle); 488 STAT(tlb_dropin_fail_idle);
@@ -416,6 +492,7 @@ failidle:
416failinval: 492failinval:
417 /* All errors (atomic & non-atomic) switch CBR to EXCEPTION state */ 493 /* All errors (atomic & non-atomic) switch CBR to EXCEPTION state */
418 tfh_exception(tfh); 494 tfh_exception(tfh);
495 gru_flush_cache_cbe(cbe);
419 STAT(tlb_dropin_fail_invalid); 496 STAT(tlb_dropin_fail_invalid);
420 gru_dbg(grudev, "FAILED inval tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); 497 gru_dbg(grudev, "FAILED inval tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr);
421 return -EFAULT; 498 return -EFAULT;
@@ -426,6 +503,7 @@ failactive:
426 tfh_user_polling_mode(tfh); 503 tfh_user_polling_mode(tfh);
427 else 504 else
428 gru_flush_cache(tfh); 505 gru_flush_cache(tfh);
506 gru_flush_cache_cbe(cbe);
429 STAT(tlb_dropin_fail_range_active); 507 STAT(tlb_dropin_fail_range_active);
430 gru_dbg(grudev, "FAILED range active: tfh 0x%p, vaddr 0x%lx\n", 508 gru_dbg(grudev, "FAILED range active: tfh 0x%p, vaddr 0x%lx\n",
431 tfh, vaddr); 509 tfh, vaddr);
@@ -627,7 +705,7 @@ int gru_get_exception_detail(unsigned long arg)
627 excdet.exceptdet1 = cbe->idef3upd; 705 excdet.exceptdet1 = cbe->idef3upd;
628 excdet.cbrstate = cbe->cbrstate; 706 excdet.cbrstate = cbe->cbrstate;
629 excdet.cbrexecstatus = cbe->cbrexecstatus; 707 excdet.cbrexecstatus = cbe->cbrexecstatus;
630 gru_flush_cache(cbe); 708 gru_flush_cache_cbe(cbe);
631 ret = 0; 709 ret = 0;
632 } else { 710 } else {
633 ret = -EAGAIN; 711 ret = -EAGAIN;
@@ -770,9 +848,12 @@ int gru_set_context_option(unsigned long arg)
770 return -EFAULT; 848 return -EFAULT;
771 gru_dbg(grudev, "op %d, gseg 0x%lx, value1 0x%lx\n", req.op, req.gseg, req.val1); 849 gru_dbg(grudev, "op %d, gseg 0x%lx, value1 0x%lx\n", req.op, req.gseg, req.val1);
772 850
773 gts = gru_alloc_locked_gts(req.gseg); 851 gts = gru_find_lock_gts(req.gseg);
774 if (IS_ERR(gts)) 852 if (!gts) {
775 return PTR_ERR(gts); 853 gts = gru_alloc_locked_gts(req.gseg);
854 if (IS_ERR(gts))
855 return PTR_ERR(gts);
856 }
776 857
777 switch (req.op) { 858 switch (req.op) {
778 case sco_blade_chiplet: 859 case sco_blade_chiplet: