diff options
Diffstat (limited to 'drivers/misc/sgi-gru/grumain.c')
-rw-r--r-- | drivers/misc/sgi-gru/grumain.c | 84 |
1 files changed, 49 insertions, 35 deletions
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index 3d2fc216bae5..ec3f7a17d221 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c | |||
@@ -76,10 +76,9 @@ int gru_cpu_fault_map_id(void) | |||
76 | /* Hit the asid limit. Start over */ | 76 | /* Hit the asid limit. Start over */ |
77 | static int gru_wrap_asid(struct gru_state *gru) | 77 | static int gru_wrap_asid(struct gru_state *gru) |
78 | { | 78 | { |
79 | gru_dbg(grudev, "gru %p\n", gru); | 79 | gru_dbg(grudev, "gid %d\n", gru->gs_gid); |
80 | STAT(asid_wrap); | 80 | STAT(asid_wrap); |
81 | gru->gs_asid_gen++; | 81 | gru->gs_asid_gen++; |
82 | gru_flush_all_tlb(gru); | ||
83 | return MIN_ASID; | 82 | return MIN_ASID; |
84 | } | 83 | } |
85 | 84 | ||
@@ -88,19 +87,21 @@ static int gru_reset_asid_limit(struct gru_state *gru, int asid) | |||
88 | { | 87 | { |
89 | int i, gid, inuse_asid, limit; | 88 | int i, gid, inuse_asid, limit; |
90 | 89 | ||
91 | gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); | 90 | gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid); |
92 | STAT(asid_next); | 91 | STAT(asid_next); |
93 | limit = MAX_ASID; | 92 | limit = MAX_ASID; |
94 | if (asid >= limit) | 93 | if (asid >= limit) |
95 | asid = gru_wrap_asid(gru); | 94 | asid = gru_wrap_asid(gru); |
95 | gru_flush_all_tlb(gru); | ||
96 | gid = gru->gs_gid; | 96 | gid = gru->gs_gid; |
97 | again: | 97 | again: |
98 | for (i = 0; i < GRU_NUM_CCH; i++) { | 98 | for (i = 0; i < GRU_NUM_CCH; i++) { |
99 | if (!gru->gs_gts[i]) | 99 | if (!gru->gs_gts[i]) |
100 | continue; | 100 | continue; |
101 | inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid; | 101 | inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid; |
102 | gru_dbg(grudev, "gru %p, inuse_asid 0x%x, cxtnum %d, gts %p\n", | 102 | gru_dbg(grudev, "gid %d, gts %p, gms %p, inuse 0x%x, cxt %d\n", |
103 | gru, inuse_asid, i, gru->gs_gts[i]); | 103 | gru->gs_gid, gru->gs_gts[i], gru->gs_gts[i]->ts_gms, |
104 | inuse_asid, i); | ||
104 | if (inuse_asid == asid) { | 105 | if (inuse_asid == asid) { |
105 | asid += ASID_INC; | 106 | asid += ASID_INC; |
106 | if (asid >= limit) { | 107 | if (asid >= limit) { |
@@ -120,8 +121,8 @@ again: | |||
120 | } | 121 | } |
121 | gru->gs_asid_limit = limit; | 122 | gru->gs_asid_limit = limit; |
122 | gru->gs_asid = asid; | 123 | gru->gs_asid = asid; |
123 | gru_dbg(grudev, "gru %p, new asid 0x%x, new_limit 0x%x\n", gru, asid, | 124 | gru_dbg(grudev, "gid %d, new asid 0x%x, new_limit 0x%x\n", gru->gs_gid, |
124 | limit); | 125 | asid, limit); |
125 | return asid; | 126 | return asid; |
126 | } | 127 | } |
127 | 128 | ||
@@ -130,14 +131,12 @@ static int gru_assign_asid(struct gru_state *gru) | |||
130 | { | 131 | { |
131 | int asid; | 132 | int asid; |
132 | 133 | ||
133 | spin_lock(&gru->gs_asid_lock); | ||
134 | gru->gs_asid += ASID_INC; | 134 | gru->gs_asid += ASID_INC; |
135 | asid = gru->gs_asid; | 135 | asid = gru->gs_asid; |
136 | if (asid >= gru->gs_asid_limit) | 136 | if (asid >= gru->gs_asid_limit) |
137 | asid = gru_reset_asid_limit(gru, asid); | 137 | asid = gru_reset_asid_limit(gru, asid); |
138 | spin_unlock(&gru->gs_asid_lock); | ||
139 | 138 | ||
140 | gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); | 139 | gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid); |
141 | return asid; | 140 | return asid; |
142 | } | 141 | } |
143 | 142 | ||
@@ -215,17 +214,20 @@ static int check_gru_resources(struct gru_state *gru, int cbr_au_count, | |||
215 | * TLB manangment requires tracking all GRU chiplets that have loaded a GSEG | 214 | * TLB manangment requires tracking all GRU chiplets that have loaded a GSEG |
216 | * context. | 215 | * context. |
217 | */ | 216 | */ |
218 | static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms, | 217 | static int gru_load_mm_tracker(struct gru_state *gru, |
219 | int ctxnum) | 218 | struct gru_thread_state *gts) |
220 | { | 219 | { |
220 | struct gru_mm_struct *gms = gts->ts_gms; | ||
221 | struct gru_mm_tracker *asids = &gms->ms_asids[gru->gs_gid]; | 221 | struct gru_mm_tracker *asids = &gms->ms_asids[gru->gs_gid]; |
222 | unsigned short ctxbitmap = (1 << ctxnum); | 222 | unsigned short ctxbitmap = (1 << gts->ts_ctxnum); |
223 | int asid; | 223 | int asid; |
224 | 224 | ||
225 | spin_lock(&gms->ms_asid_lock); | 225 | spin_lock(&gms->ms_asid_lock); |
226 | asid = asids->mt_asid; | 226 | asid = asids->mt_asid; |
227 | 227 | ||
228 | if (asid == 0 || asids->mt_asid_gen != gru->gs_asid_gen) { | 228 | spin_lock(&gru->gs_asid_lock); |
229 | if (asid == 0 || (asids->mt_ctxbitmap == 0 && asids->mt_asid_gen != | ||
230 | gru->gs_asid_gen)) { | ||
229 | asid = gru_assign_asid(gru); | 231 | asid = gru_assign_asid(gru); |
230 | asids->mt_asid = asid; | 232 | asids->mt_asid = asid; |
231 | asids->mt_asid_gen = gru->gs_asid_gen; | 233 | asids->mt_asid_gen = gru->gs_asid_gen; |
@@ -233,6 +235,7 @@ static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms, | |||
233 | } else { | 235 | } else { |
234 | STAT(asid_reuse); | 236 | STAT(asid_reuse); |
235 | } | 237 | } |
238 | spin_unlock(&gru->gs_asid_lock); | ||
236 | 239 | ||
237 | BUG_ON(asids->mt_ctxbitmap & ctxbitmap); | 240 | BUG_ON(asids->mt_ctxbitmap & ctxbitmap); |
238 | asids->mt_ctxbitmap |= ctxbitmap; | 241 | asids->mt_ctxbitmap |= ctxbitmap; |
@@ -241,24 +244,28 @@ static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms, | |||
241 | spin_unlock(&gms->ms_asid_lock); | 244 | spin_unlock(&gms->ms_asid_lock); |
242 | 245 | ||
243 | gru_dbg(grudev, | 246 | gru_dbg(grudev, |
244 | "gru %x, gms %p, ctxnum 0x%d, asid 0x%x, asidmap 0x%lx\n", | 247 | "gid %d, gts %p, gms %p, ctxnum %d, asid 0x%x, asidmap 0x%lx\n", |
245 | gru->gs_gid, gms, ctxnum, asid, gms->ms_asidmap[0]); | 248 | gru->gs_gid, gts, gms, gts->ts_ctxnum, asid, |
249 | gms->ms_asidmap[0]); | ||
246 | return asid; | 250 | return asid; |
247 | } | 251 | } |
248 | 252 | ||
249 | static void gru_unload_mm_tracker(struct gru_state *gru, | 253 | static void gru_unload_mm_tracker(struct gru_state *gru, |
250 | struct gru_mm_struct *gms, int ctxnum) | 254 | struct gru_thread_state *gts) |
251 | { | 255 | { |
256 | struct gru_mm_struct *gms = gts->ts_gms; | ||
252 | struct gru_mm_tracker *asids; | 257 | struct gru_mm_tracker *asids; |
253 | unsigned short ctxbitmap; | 258 | unsigned short ctxbitmap; |
254 | 259 | ||
255 | asids = &gms->ms_asids[gru->gs_gid]; | 260 | asids = &gms->ms_asids[gru->gs_gid]; |
256 | ctxbitmap = (1 << ctxnum); | 261 | ctxbitmap = (1 << gts->ts_ctxnum); |
257 | spin_lock(&gms->ms_asid_lock); | 262 | spin_lock(&gms->ms_asid_lock); |
263 | spin_lock(&gru->gs_asid_lock); | ||
258 | BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap); | 264 | BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap); |
259 | asids->mt_ctxbitmap ^= ctxbitmap; | 265 | asids->mt_ctxbitmap ^= ctxbitmap; |
260 | gru_dbg(grudev, "gru %x, gms %p, ctxnum 0x%d, asidmap 0x%lx\n", | 266 | gru_dbg(grudev, "gid %d, gts %p, gms %p, ctxnum 0x%d, asidmap 0x%lx\n", |
261 | gru->gs_gid, gms, ctxnum, gms->ms_asidmap[0]); | 267 | gru->gs_gid, gts, gms, gts->ts_ctxnum, gms->ms_asidmap[0]); |
268 | spin_unlock(&gru->gs_asid_lock); | ||
262 | spin_unlock(&gms->ms_asid_lock); | 269 | spin_unlock(&gms->ms_asid_lock); |
263 | } | 270 | } |
264 | 271 | ||
@@ -319,6 +326,7 @@ static struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | |||
319 | gts->ts_vma = vma; | 326 | gts->ts_vma = vma; |
320 | gts->ts_tlb_int_select = -1; | 327 | gts->ts_tlb_int_select = -1; |
321 | gts->ts_gms = gru_register_mmu_notifier(); | 328 | gts->ts_gms = gru_register_mmu_notifier(); |
329 | gts->ts_sizeavail = GRU_SIZEAVAIL(PAGE_SHIFT); | ||
322 | if (!gts->ts_gms) | 330 | if (!gts->ts_gms) |
323 | goto err; | 331 | goto err; |
324 | 332 | ||
@@ -399,7 +407,7 @@ static void gru_free_gru_context(struct gru_thread_state *gts) | |||
399 | struct gru_state *gru; | 407 | struct gru_state *gru; |
400 | 408 | ||
401 | gru = gts->ts_gru; | 409 | gru = gts->ts_gru; |
402 | gru_dbg(grudev, "gts %p, gru %p\n", gts, gru); | 410 | gru_dbg(grudev, "gts %p, gid %d\n", gts, gru->gs_gid); |
403 | 411 | ||
404 | spin_lock(&gru->gs_lock); | 412 | spin_lock(&gru->gs_lock); |
405 | gru->gs_gts[gts->ts_ctxnum] = NULL; | 413 | gru->gs_gts[gts->ts_ctxnum] = NULL; |
@@ -408,6 +416,7 @@ static void gru_free_gru_context(struct gru_thread_state *gts) | |||
408 | __clear_bit(gts->ts_ctxnum, &gru->gs_context_map); | 416 | __clear_bit(gts->ts_ctxnum, &gru->gs_context_map); |
409 | gts->ts_ctxnum = NULLCTX; | 417 | gts->ts_ctxnum = NULLCTX; |
410 | gts->ts_gru = NULL; | 418 | gts->ts_gru = NULL; |
419 | gts->ts_blade = -1; | ||
411 | spin_unlock(&gru->gs_lock); | 420 | spin_unlock(&gru->gs_lock); |
412 | 421 | ||
413 | gts_drop(gts); | 422 | gts_drop(gts); |
@@ -432,8 +441,8 @@ static inline long gru_copy_handle(void *d, void *s) | |||
432 | return GRU_HANDLE_BYTES; | 441 | return GRU_HANDLE_BYTES; |
433 | } | 442 | } |
434 | 443 | ||
435 | static void gru_prefetch_context(void *gseg, void *cb, void *cbe, unsigned long cbrmap, | 444 | static void gru_prefetch_context(void *gseg, void *cb, void *cbe, |
436 | unsigned long length) | 445 | unsigned long cbrmap, unsigned long length) |
437 | { | 446 | { |
438 | int i, scr; | 447 | int i, scr; |
439 | 448 | ||
@@ -500,12 +509,12 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate) | |||
500 | zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); | 509 | zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); |
501 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); | 510 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); |
502 | 511 | ||
512 | gru_dbg(grudev, "gts %p\n", gts); | ||
503 | lock_cch_handle(cch); | 513 | lock_cch_handle(cch); |
504 | if (cch_interrupt_sync(cch)) | 514 | if (cch_interrupt_sync(cch)) |
505 | BUG(); | 515 | BUG(); |
506 | gru_dbg(grudev, "gts %p\n", gts); | ||
507 | 516 | ||
508 | gru_unload_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); | 517 | gru_unload_mm_tracker(gru, gts); |
509 | if (savestate) | 518 | if (savestate) |
510 | gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, | 519 | gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, |
511 | ctxnum, gts->ts_cbr_map, | 520 | ctxnum, gts->ts_cbr_map, |
@@ -534,7 +543,7 @@ static void gru_load_context(struct gru_thread_state *gts) | |||
534 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); | 543 | cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); |
535 | 544 | ||
536 | lock_cch_handle(cch); | 545 | lock_cch_handle(cch); |
537 | asid = gru_load_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); | 546 | asid = gru_load_mm_tracker(gru, gts); |
538 | cch->tfm_fault_bit_enable = | 547 | cch->tfm_fault_bit_enable = |
539 | (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL | 548 | (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL |
540 | || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); | 549 | || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); |
@@ -544,7 +553,8 @@ static void gru_load_context(struct gru_thread_state *gts) | |||
544 | cch->tlb_int_select = gts->ts_tlb_int_select; | 553 | cch->tlb_int_select = gts->ts_tlb_int_select; |
545 | } | 554 | } |
546 | cch->tfm_done_bit_enable = 0; | 555 | cch->tfm_done_bit_enable = 0; |
547 | err = cch_allocate(cch, asid, gts->ts_cbr_map, gts->ts_dsr_map); | 556 | err = cch_allocate(cch, asid, gts->ts_sizeavail, gts->ts_cbr_map, |
557 | gts->ts_dsr_map); | ||
548 | if (err) { | 558 | if (err) { |
549 | gru_dbg(grudev, | 559 | gru_dbg(grudev, |
550 | "err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n", | 560 | "err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n", |
@@ -565,11 +575,12 @@ static void gru_load_context(struct gru_thread_state *gts) | |||
565 | /* | 575 | /* |
566 | * Update fields in an active CCH: | 576 | * Update fields in an active CCH: |
567 | * - retarget interrupts on local blade | 577 | * - retarget interrupts on local blade |
578 | * - update sizeavail mask | ||
568 | * - force a delayed context unload by clearing the CCH asids. This | 579 | * - force a delayed context unload by clearing the CCH asids. This |
569 | * forces TLB misses for new GRU instructions. The context is unloaded | 580 | * forces TLB misses for new GRU instructions. The context is unloaded |
570 | * when the next TLB miss occurs. | 581 | * when the next TLB miss occurs. |
571 | */ | 582 | */ |
572 | static int gru_update_cch(struct gru_thread_state *gts, int int_select) | 583 | int gru_update_cch(struct gru_thread_state *gts, int force_unload) |
573 | { | 584 | { |
574 | struct gru_context_configuration_handle *cch; | 585 | struct gru_context_configuration_handle *cch; |
575 | struct gru_state *gru = gts->ts_gru; | 586 | struct gru_state *gru = gts->ts_gru; |
@@ -583,9 +594,11 @@ static int gru_update_cch(struct gru_thread_state *gts, int int_select) | |||
583 | goto exit; | 594 | goto exit; |
584 | if (cch_interrupt(cch)) | 595 | if (cch_interrupt(cch)) |
585 | BUG(); | 596 | BUG(); |
586 | if (int_select >= 0) { | 597 | if (!force_unload) { |
587 | gts->ts_tlb_int_select = int_select; | 598 | for (i = 0; i < 8; i++) |
588 | cch->tlb_int_select = int_select; | 599 | cch->sizeavail[i] = gts->ts_sizeavail; |
600 | gts->ts_tlb_int_select = gru_cpu_fault_map_id(); | ||
601 | cch->tlb_int_select = gru_cpu_fault_map_id(); | ||
589 | } else { | 602 | } else { |
590 | for (i = 0; i < 8; i++) | 603 | for (i = 0; i < 8; i++) |
591 | cch->asid[i] = 0; | 604 | cch->asid[i] = 0; |
@@ -617,7 +630,7 @@ static int gru_retarget_intr(struct gru_thread_state *gts) | |||
617 | 630 | ||
618 | gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select, | 631 | gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select, |
619 | gru_cpu_fault_map_id()); | 632 | gru_cpu_fault_map_id()); |
620 | return gru_update_cch(gts, gru_cpu_fault_map_id()); | 633 | return gru_update_cch(gts, 0); |
621 | } | 634 | } |
622 | 635 | ||
623 | 636 | ||
@@ -688,7 +701,7 @@ static void gru_steal_context(struct gru_thread_state *gts) | |||
688 | STAT(steal_context_failed); | 701 | STAT(steal_context_failed); |
689 | } | 702 | } |
690 | gru_dbg(grudev, | 703 | gru_dbg(grudev, |
691 | "stole gru %x, ctxnum %d from gts %p. Need cb %d, ds %d;" | 704 | "stole gid %d, ctxnum %d from gts %p. Need cb %d, ds %d;" |
692 | " avail cb %ld, ds %ld\n", | 705 | " avail cb %ld, ds %ld\n", |
693 | gru->gs_gid, ctxnum, ngts, cbr, dsr, hweight64(gru->gs_cbr_map), | 706 | gru->gs_gid, ctxnum, ngts, cbr, dsr, hweight64(gru->gs_cbr_map), |
694 | hweight64(gru->gs_dsr_map)); | 707 | hweight64(gru->gs_dsr_map)); |
@@ -727,6 +740,7 @@ again: | |||
727 | } | 740 | } |
728 | reserve_gru_resources(gru, gts); | 741 | reserve_gru_resources(gru, gts); |
729 | gts->ts_gru = gru; | 742 | gts->ts_gru = gru; |
743 | gts->ts_blade = gru->gs_blade_id; | ||
730 | gts->ts_ctxnum = | 744 | gts->ts_ctxnum = |
731 | find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH); | 745 | find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH); |
732 | BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH); | 746 | BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH); |
@@ -737,7 +751,7 @@ again: | |||
737 | 751 | ||
738 | STAT(assign_context); | 752 | STAT(assign_context); |
739 | gru_dbg(grudev, | 753 | gru_dbg(grudev, |
740 | "gseg %p, gts %p, gru %x, ctx %d, cbr %d, dsr %d\n", | 754 | "gseg %p, gts %p, gid %d, ctx %d, cbr %d, dsr %d\n", |
741 | gseg_virtual_address(gts->ts_gru, gts->ts_ctxnum), gts, | 755 | gseg_virtual_address(gts->ts_gru, gts->ts_ctxnum), gts, |
742 | gts->ts_gru->gs_gid, gts->ts_ctxnum, | 756 | gts->ts_gru->gs_gid, gts->ts_ctxnum, |
743 | gts->ts_cbr_au_count, gts->ts_dsr_au_count); | 757 | gts->ts_cbr_au_count, gts->ts_dsr_au_count); |
@@ -773,8 +787,8 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
773 | return VM_FAULT_SIGBUS; | 787 | return VM_FAULT_SIGBUS; |
774 | 788 | ||
775 | again: | 789 | again: |
776 | preempt_disable(); | ||
777 | mutex_lock(>s->ts_ctxlock); | 790 | mutex_lock(>s->ts_ctxlock); |
791 | preempt_disable(); | ||
778 | if (gts->ts_gru) { | 792 | if (gts->ts_gru) { |
779 | if (gts->ts_gru->gs_blade_id != uv_numa_blade_id()) { | 793 | if (gts->ts_gru->gs_blade_id != uv_numa_blade_id()) { |
780 | STAT(migrated_nopfn_unload); | 794 | STAT(migrated_nopfn_unload); |