1*9a0deeccSJack Steiner /* 2*9a0deeccSJack Steiner * SN Platform GRU Driver 3*9a0deeccSJack Steiner * 4*9a0deeccSJack Steiner * DRIVER TABLE MANAGER + GRU CONTEXT LOAD/UNLOAD 5*9a0deeccSJack Steiner * 6*9a0deeccSJack Steiner * This file is subject to the terms and conditions of the GNU General Public 7*9a0deeccSJack Steiner * License. See the file "COPYING" in the main directory of this archive 8*9a0deeccSJack Steiner * for more details. 9*9a0deeccSJack Steiner * 10*9a0deeccSJack Steiner * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. 11*9a0deeccSJack Steiner */ 12*9a0deeccSJack Steiner 13*9a0deeccSJack Steiner #include <linux/kernel.h> 14*9a0deeccSJack Steiner #include <linux/slab.h> 15*9a0deeccSJack Steiner #include <linux/mm.h> 16*9a0deeccSJack Steiner #include <linux/spinlock.h> 17*9a0deeccSJack Steiner #include <linux/sched.h> 18*9a0deeccSJack Steiner #include <linux/device.h> 19*9a0deeccSJack Steiner #include <linux/list.h> 20*9a0deeccSJack Steiner #include <asm/uv/uv_hub.h> 21*9a0deeccSJack Steiner #include "gru.h" 22*9a0deeccSJack Steiner #include "grutables.h" 23*9a0deeccSJack Steiner #include "gruhandles.h" 24*9a0deeccSJack Steiner 25*9a0deeccSJack Steiner unsigned long options __read_mostly; 26*9a0deeccSJack Steiner 27*9a0deeccSJack Steiner static struct device_driver gru_driver = { 28*9a0deeccSJack Steiner .name = "gru" 29*9a0deeccSJack Steiner }; 30*9a0deeccSJack Steiner 31*9a0deeccSJack Steiner static struct device gru_device = { 32*9a0deeccSJack Steiner .bus_id = {0}, 33*9a0deeccSJack Steiner .driver = &gru_driver, 34*9a0deeccSJack Steiner }; 35*9a0deeccSJack Steiner 36*9a0deeccSJack Steiner struct device *grudev = &gru_device; 37*9a0deeccSJack Steiner 38*9a0deeccSJack Steiner /* 39*9a0deeccSJack Steiner * Select a gru fault map to be used by the current cpu. Note that 40*9a0deeccSJack Steiner * multiple cpus may be using the same map. 41*9a0deeccSJack Steiner * ZZZ should "shift" be used?? Depends on HT cpu numbering 42*9a0deeccSJack Steiner * ZZZ should be inline but did not work on emulator 43*9a0deeccSJack Steiner */ 44*9a0deeccSJack Steiner int gru_cpu_fault_map_id(void) 45*9a0deeccSJack Steiner { 46*9a0deeccSJack Steiner return uv_blade_processor_id() % GRU_NUM_TFM; 47*9a0deeccSJack Steiner } 48*9a0deeccSJack Steiner 49*9a0deeccSJack Steiner /*--------- ASID Management ------------------------------------------- 50*9a0deeccSJack Steiner * 51*9a0deeccSJack Steiner * Initially, assign asids sequentially from MIN_ASID .. MAX_ASID. 52*9a0deeccSJack Steiner * Once MAX is reached, flush the TLB & start over. However, 53*9a0deeccSJack Steiner * some asids may still be in use. There won't be many (percentage wise) still 54*9a0deeccSJack Steiner * in use. Search active contexts & determine the value of the first 55*9a0deeccSJack Steiner * asid in use ("x"s below). Set "limit" to this value. 56*9a0deeccSJack Steiner * This defines a block of assignable asids. 57*9a0deeccSJack Steiner * 58*9a0deeccSJack Steiner * When "limit" is reached, search forward from limit+1 and determine the 59*9a0deeccSJack Steiner * next block of assignable asids. 60*9a0deeccSJack Steiner * 61*9a0deeccSJack Steiner * Repeat until MAX_ASID is reached, then start over again. 62*9a0deeccSJack Steiner * 63*9a0deeccSJack Steiner * Each time MAX_ASID is reached, increment the asid generation. Since 64*9a0deeccSJack Steiner * the search for in-use asids only checks contexts with GRUs currently 65*9a0deeccSJack Steiner * assigned, asids in some contexts will be missed. Prior to loading 66*9a0deeccSJack Steiner * a context, the asid generation of the GTS asid is rechecked. If it 67*9a0deeccSJack Steiner * doesn't match the current generation, a new asid will be assigned. 68*9a0deeccSJack Steiner * 69*9a0deeccSJack Steiner * 0---------------x------------x---------------------x----| 70*9a0deeccSJack Steiner * ^-next ^-limit ^-MAX_ASID 71*9a0deeccSJack Steiner * 72*9a0deeccSJack Steiner * All asid manipulation & context loading/unloading is protected by the 73*9a0deeccSJack Steiner * gs_lock. 74*9a0deeccSJack Steiner */ 75*9a0deeccSJack Steiner 76*9a0deeccSJack Steiner /* Hit the asid limit. Start over */ 77*9a0deeccSJack Steiner static int gru_wrap_asid(struct gru_state *gru) 78*9a0deeccSJack Steiner { 79*9a0deeccSJack Steiner gru_dbg(grudev, "gru %p\n", gru); 80*9a0deeccSJack Steiner STAT(asid_wrap); 81*9a0deeccSJack Steiner gru->gs_asid_gen++; 82*9a0deeccSJack Steiner gru_flush_all_tlb(gru); 83*9a0deeccSJack Steiner return MIN_ASID; 84*9a0deeccSJack Steiner } 85*9a0deeccSJack Steiner 86*9a0deeccSJack Steiner /* Find the next chunk of unused asids */ 87*9a0deeccSJack Steiner static int gru_reset_asid_limit(struct gru_state *gru, int asid) 88*9a0deeccSJack Steiner { 89*9a0deeccSJack Steiner int i, gid, inuse_asid, limit; 90*9a0deeccSJack Steiner 91*9a0deeccSJack Steiner gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); 92*9a0deeccSJack Steiner STAT(asid_next); 93*9a0deeccSJack Steiner limit = MAX_ASID; 94*9a0deeccSJack Steiner if (asid >= limit) 95*9a0deeccSJack Steiner asid = gru_wrap_asid(gru); 96*9a0deeccSJack Steiner gid = gru->gs_gid; 97*9a0deeccSJack Steiner again: 98*9a0deeccSJack Steiner for (i = 0; i < GRU_NUM_CCH; i++) { 99*9a0deeccSJack Steiner if (!gru->gs_gts[i]) 100*9a0deeccSJack Steiner continue; 101*9a0deeccSJack Steiner inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid; 102*9a0deeccSJack Steiner gru_dbg(grudev, "gru %p, inuse_asid 0x%x, cxtnum %d, gts %p\n", 103*9a0deeccSJack Steiner gru, inuse_asid, i, gru->gs_gts[i]); 104*9a0deeccSJack Steiner if (inuse_asid == asid) { 105*9a0deeccSJack Steiner asid += ASID_INC; 106*9a0deeccSJack Steiner if (asid >= limit) { 107*9a0deeccSJack Steiner /* 108*9a0deeccSJack Steiner * empty range: reset the range limit and 109*9a0deeccSJack Steiner * start over 110*9a0deeccSJack Steiner */ 111*9a0deeccSJack Steiner limit = MAX_ASID; 112*9a0deeccSJack Steiner if (asid >= MAX_ASID) 113*9a0deeccSJack Steiner asid = gru_wrap_asid(gru); 114*9a0deeccSJack Steiner goto again; 115*9a0deeccSJack Steiner } 116*9a0deeccSJack Steiner } 117*9a0deeccSJack Steiner 118*9a0deeccSJack Steiner if ((inuse_asid > asid) && (inuse_asid < limit)) 119*9a0deeccSJack Steiner limit = inuse_asid; 120*9a0deeccSJack Steiner } 121*9a0deeccSJack Steiner gru->gs_asid_limit = limit; 122*9a0deeccSJack Steiner gru->gs_asid = asid; 123*9a0deeccSJack Steiner gru_dbg(grudev, "gru %p, new asid 0x%x, new_limit 0x%x\n", gru, asid, 124*9a0deeccSJack Steiner limit); 125*9a0deeccSJack Steiner return asid; 126*9a0deeccSJack Steiner } 127*9a0deeccSJack Steiner 128*9a0deeccSJack Steiner /* Assign a new ASID to a thread context. */ 129*9a0deeccSJack Steiner static int gru_assign_asid(struct gru_state *gru) 130*9a0deeccSJack Steiner { 131*9a0deeccSJack Steiner int asid; 132*9a0deeccSJack Steiner 133*9a0deeccSJack Steiner spin_lock(&gru->gs_asid_lock); 134*9a0deeccSJack Steiner gru->gs_asid += ASID_INC; 135*9a0deeccSJack Steiner asid = gru->gs_asid; 136*9a0deeccSJack Steiner if (asid >= gru->gs_asid_limit) 137*9a0deeccSJack Steiner asid = gru_reset_asid_limit(gru, asid); 138*9a0deeccSJack Steiner spin_unlock(&gru->gs_asid_lock); 139*9a0deeccSJack Steiner 140*9a0deeccSJack Steiner gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); 141*9a0deeccSJack Steiner return asid; 142*9a0deeccSJack Steiner } 143*9a0deeccSJack Steiner 144*9a0deeccSJack Steiner /* 145*9a0deeccSJack Steiner * Clear n bits in a word. Return a word indicating the bits that were cleared. 146*9a0deeccSJack Steiner * Optionally, build an array of chars that contain the bit numbers allocated. 147*9a0deeccSJack Steiner */ 148*9a0deeccSJack Steiner static unsigned long reserve_resources(unsigned long *p, int n, int mmax, 149*9a0deeccSJack Steiner char *idx) 150*9a0deeccSJack Steiner { 151*9a0deeccSJack Steiner unsigned long bits = 0; 152*9a0deeccSJack Steiner int i; 153*9a0deeccSJack Steiner 154*9a0deeccSJack Steiner do { 155*9a0deeccSJack Steiner i = find_first_bit(p, mmax); 156*9a0deeccSJack Steiner if (i == mmax) 157*9a0deeccSJack Steiner BUG(); 158*9a0deeccSJack Steiner __clear_bit(i, p); 159*9a0deeccSJack Steiner __set_bit(i, &bits); 160*9a0deeccSJack Steiner if (idx) 161*9a0deeccSJack Steiner *idx++ = i; 162*9a0deeccSJack Steiner } while (--n); 163*9a0deeccSJack Steiner return bits; 164*9a0deeccSJack Steiner } 165*9a0deeccSJack Steiner 166*9a0deeccSJack Steiner unsigned long reserve_gru_cb_resources(struct gru_state *gru, int cbr_au_count, 167*9a0deeccSJack Steiner char *cbmap) 168*9a0deeccSJack Steiner { 169*9a0deeccSJack Steiner return reserve_resources(&gru->gs_cbr_map, cbr_au_count, GRU_CBR_AU, 170*9a0deeccSJack Steiner cbmap); 171*9a0deeccSJack Steiner } 172*9a0deeccSJack Steiner 173*9a0deeccSJack Steiner unsigned long reserve_gru_ds_resources(struct gru_state *gru, int dsr_au_count, 174*9a0deeccSJack Steiner char *dsmap) 175*9a0deeccSJack Steiner { 176*9a0deeccSJack Steiner return reserve_resources(&gru->gs_dsr_map, dsr_au_count, GRU_DSR_AU, 177*9a0deeccSJack Steiner dsmap); 178*9a0deeccSJack Steiner } 179*9a0deeccSJack Steiner 180*9a0deeccSJack Steiner static void reserve_gru_resources(struct gru_state *gru, 181*9a0deeccSJack Steiner struct gru_thread_state *gts) 182*9a0deeccSJack Steiner { 183*9a0deeccSJack Steiner gru->gs_active_contexts++; 184*9a0deeccSJack Steiner gts->ts_cbr_map = 185*9a0deeccSJack Steiner reserve_gru_cb_resources(gru, gts->ts_cbr_au_count, 186*9a0deeccSJack Steiner gts->ts_cbr_idx); 187*9a0deeccSJack Steiner gts->ts_dsr_map = 188*9a0deeccSJack Steiner reserve_gru_ds_resources(gru, gts->ts_dsr_au_count, NULL); 189*9a0deeccSJack Steiner } 190*9a0deeccSJack Steiner 191*9a0deeccSJack Steiner static void free_gru_resources(struct gru_state *gru, 192*9a0deeccSJack Steiner struct gru_thread_state *gts) 193*9a0deeccSJack Steiner { 194*9a0deeccSJack Steiner gru->gs_active_contexts--; 195*9a0deeccSJack Steiner gru->gs_cbr_map |= gts->ts_cbr_map; 196*9a0deeccSJack Steiner gru->gs_dsr_map |= gts->ts_dsr_map; 197*9a0deeccSJack Steiner } 198*9a0deeccSJack Steiner 199*9a0deeccSJack Steiner /* 200*9a0deeccSJack Steiner * Check if a GRU has sufficient free resources to satisfy an allocation 201*9a0deeccSJack Steiner * request. Note: GRU locks may or may not be held when this is called. If 202*9a0deeccSJack Steiner * not held, recheck after acquiring the appropriate locks. 203*9a0deeccSJack Steiner * 204*9a0deeccSJack Steiner * Returns 1 if sufficient resources, 0 if not 205*9a0deeccSJack Steiner */ 206*9a0deeccSJack Steiner static int check_gru_resources(struct gru_state *gru, int cbr_au_count, 207*9a0deeccSJack Steiner int dsr_au_count, int max_active_contexts) 208*9a0deeccSJack Steiner { 209*9a0deeccSJack Steiner return hweight64(gru->gs_cbr_map) >= cbr_au_count 210*9a0deeccSJack Steiner && hweight64(gru->gs_dsr_map) >= dsr_au_count 211*9a0deeccSJack Steiner && gru->gs_active_contexts < max_active_contexts; 212*9a0deeccSJack Steiner } 213*9a0deeccSJack Steiner 214*9a0deeccSJack Steiner /* 215*9a0deeccSJack Steiner * TLB manangment requires tracking all GRU chiplets that have loaded a GSEG 216*9a0deeccSJack Steiner * context. 217*9a0deeccSJack Steiner */ 218*9a0deeccSJack Steiner static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms, 219*9a0deeccSJack Steiner int ctxnum) 220*9a0deeccSJack Steiner { 221*9a0deeccSJack Steiner struct gru_mm_tracker *asids = &gms->ms_asids[gru->gs_gid]; 222*9a0deeccSJack Steiner unsigned short ctxbitmap = (1 << ctxnum); 223*9a0deeccSJack Steiner int asid; 224*9a0deeccSJack Steiner 225*9a0deeccSJack Steiner spin_lock(&gms->ms_asid_lock); 226*9a0deeccSJack Steiner asid = asids->mt_asid; 227*9a0deeccSJack Steiner 228*9a0deeccSJack Steiner if (asid == 0 || asids->mt_asid_gen != gru->gs_asid_gen) { 229*9a0deeccSJack Steiner asid = gru_assign_asid(gru); 230*9a0deeccSJack Steiner asids->mt_asid = asid; 231*9a0deeccSJack Steiner asids->mt_asid_gen = gru->gs_asid_gen; 232*9a0deeccSJack Steiner STAT(asid_new); 233*9a0deeccSJack Steiner } else { 234*9a0deeccSJack Steiner STAT(asid_reuse); 235*9a0deeccSJack Steiner } 236*9a0deeccSJack Steiner 237*9a0deeccSJack Steiner BUG_ON(asids->mt_ctxbitmap & ctxbitmap); 238*9a0deeccSJack Steiner asids->mt_ctxbitmap |= ctxbitmap; 239*9a0deeccSJack Steiner if (!test_bit(gru->gs_gid, gms->ms_asidmap)) 240*9a0deeccSJack Steiner __set_bit(gru->gs_gid, gms->ms_asidmap); 241*9a0deeccSJack Steiner spin_unlock(&gms->ms_asid_lock); 242*9a0deeccSJack Steiner 243*9a0deeccSJack Steiner gru_dbg(grudev, 244*9a0deeccSJack Steiner "gru %x, gms %p, ctxnum 0x%d, asid 0x%x, asidmap 0x%lx\n", 245*9a0deeccSJack Steiner gru->gs_gid, gms, ctxnum, asid, gms->ms_asidmap[0]); 246*9a0deeccSJack Steiner return asid; 247*9a0deeccSJack Steiner } 248*9a0deeccSJack Steiner 249*9a0deeccSJack Steiner static void gru_unload_mm_tracker(struct gru_state *gru, 250*9a0deeccSJack Steiner struct gru_mm_struct *gms, int ctxnum) 251*9a0deeccSJack Steiner { 252*9a0deeccSJack Steiner struct gru_mm_tracker *asids; 253*9a0deeccSJack Steiner unsigned short ctxbitmap; 254*9a0deeccSJack Steiner 255*9a0deeccSJack Steiner asids = &gms->ms_asids[gru->gs_gid]; 256*9a0deeccSJack Steiner ctxbitmap = (1 << ctxnum); 257*9a0deeccSJack Steiner spin_lock(&gms->ms_asid_lock); 258*9a0deeccSJack Steiner BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap); 259*9a0deeccSJack Steiner asids->mt_ctxbitmap ^= ctxbitmap; 260*9a0deeccSJack Steiner gru_dbg(grudev, "gru %x, gms %p, ctxnum 0x%d, asidmap 0x%lx\n", 261*9a0deeccSJack Steiner gru->gs_gid, gms, ctxnum, gms->ms_asidmap[0]); 262*9a0deeccSJack Steiner spin_unlock(&gms->ms_asid_lock); 263*9a0deeccSJack Steiner } 264*9a0deeccSJack Steiner 265*9a0deeccSJack Steiner /* 266*9a0deeccSJack Steiner * Decrement the reference count on a GTS structure. Free the structure 267*9a0deeccSJack Steiner * if the reference count goes to zero. 268*9a0deeccSJack Steiner */ 269*9a0deeccSJack Steiner void gts_drop(struct gru_thread_state *gts) 270*9a0deeccSJack Steiner { 271*9a0deeccSJack Steiner if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { 272*9a0deeccSJack Steiner gru_drop_mmu_notifier(gts->ts_gms); 273*9a0deeccSJack Steiner kfree(gts); 274*9a0deeccSJack Steiner STAT(gts_free); 275*9a0deeccSJack Steiner } 276*9a0deeccSJack Steiner } 277*9a0deeccSJack Steiner 278*9a0deeccSJack Steiner /* 279*9a0deeccSJack Steiner * Locate the GTS structure for the current thread. 280*9a0deeccSJack Steiner */ 281*9a0deeccSJack Steiner static struct gru_thread_state *gru_find_current_gts_nolock(struct gru_vma_data 282*9a0deeccSJack Steiner *vdata, int tsid) 283*9a0deeccSJack Steiner { 284*9a0deeccSJack Steiner struct gru_thread_state *gts; 285*9a0deeccSJack Steiner 286*9a0deeccSJack Steiner list_for_each_entry(gts, &vdata->vd_head, ts_next) 287*9a0deeccSJack Steiner if (gts->ts_tsid == tsid) 288*9a0deeccSJack Steiner return gts; 289*9a0deeccSJack Steiner return NULL; 290*9a0deeccSJack Steiner } 291*9a0deeccSJack Steiner 292*9a0deeccSJack Steiner /* 293*9a0deeccSJack Steiner * Allocate a thread state structure. 294*9a0deeccSJack Steiner */ 295*9a0deeccSJack Steiner static struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, 296*9a0deeccSJack Steiner struct gru_vma_data *vdata, 297*9a0deeccSJack Steiner int tsid) 298*9a0deeccSJack Steiner { 299*9a0deeccSJack Steiner struct gru_thread_state *gts; 300*9a0deeccSJack Steiner int bytes; 301*9a0deeccSJack Steiner 302*9a0deeccSJack Steiner bytes = DSR_BYTES(vdata->vd_dsr_au_count) + 303*9a0deeccSJack Steiner CBR_BYTES(vdata->vd_cbr_au_count); 304*9a0deeccSJack Steiner bytes += sizeof(struct gru_thread_state); 305*9a0deeccSJack Steiner gts = kzalloc(bytes, GFP_KERNEL); 306*9a0deeccSJack Steiner if (!gts) 307*9a0deeccSJack Steiner return NULL; 308*9a0deeccSJack Steiner 309*9a0deeccSJack Steiner STAT(gts_alloc); 310*9a0deeccSJack Steiner atomic_set(>s->ts_refcnt, 1); 311*9a0deeccSJack Steiner mutex_init(>s->ts_ctxlock); 312*9a0deeccSJack Steiner gts->ts_cbr_au_count = vdata->vd_cbr_au_count; 313*9a0deeccSJack Steiner gts->ts_dsr_au_count = vdata->vd_dsr_au_count; 314*9a0deeccSJack Steiner gts->ts_user_options = vdata->vd_user_options; 315*9a0deeccSJack Steiner gts->ts_tsid = tsid; 316*9a0deeccSJack Steiner gts->ts_user_options = vdata->vd_user_options; 317*9a0deeccSJack Steiner gts->ts_ctxnum = NULLCTX; 318*9a0deeccSJack Steiner gts->ts_mm = current->mm; 319*9a0deeccSJack Steiner gts->ts_vma = vma; 320*9a0deeccSJack Steiner gts->ts_tlb_int_select = -1; 321*9a0deeccSJack Steiner gts->ts_gms = gru_register_mmu_notifier(); 322*9a0deeccSJack Steiner if (!gts->ts_gms) 323*9a0deeccSJack Steiner goto err; 324*9a0deeccSJack Steiner 325*9a0deeccSJack Steiner gru_dbg(grudev, "alloc vdata %p, new gts %p\n", vdata, gts); 326*9a0deeccSJack Steiner return gts; 327*9a0deeccSJack Steiner 328*9a0deeccSJack Steiner err: 329*9a0deeccSJack Steiner gts_drop(gts); 330*9a0deeccSJack Steiner return NULL; 331*9a0deeccSJack Steiner } 332*9a0deeccSJack Steiner 333*9a0deeccSJack Steiner /* 334*9a0deeccSJack Steiner * Allocate a vma private data structure. 335*9a0deeccSJack Steiner */ 336*9a0deeccSJack Steiner struct gru_vma_data *gru_alloc_vma_data(struct vm_area_struct *vma, int tsid) 337*9a0deeccSJack Steiner { 338*9a0deeccSJack Steiner struct gru_vma_data *vdata = NULL; 339*9a0deeccSJack Steiner 340*9a0deeccSJack Steiner vdata = kmalloc(sizeof(*vdata), GFP_KERNEL); 341*9a0deeccSJack Steiner if (!vdata) 342*9a0deeccSJack Steiner return NULL; 343*9a0deeccSJack Steiner 344*9a0deeccSJack Steiner INIT_LIST_HEAD(&vdata->vd_head); 345*9a0deeccSJack Steiner spin_lock_init(&vdata->vd_lock); 346*9a0deeccSJack Steiner gru_dbg(grudev, "alloc vdata %p\n", vdata); 347*9a0deeccSJack Steiner return vdata; 348*9a0deeccSJack Steiner } 349*9a0deeccSJack Steiner 350*9a0deeccSJack Steiner /* 351*9a0deeccSJack Steiner * Find the thread state structure for the current thread. 352*9a0deeccSJack Steiner */ 353*9a0deeccSJack Steiner struct gru_thread_state *gru_find_thread_state(struct vm_area_struct *vma, 354*9a0deeccSJack Steiner int tsid) 355*9a0deeccSJack Steiner { 356*9a0deeccSJack Steiner struct gru_vma_data *vdata = vma->vm_private_data; 357*9a0deeccSJack Steiner struct gru_thread_state *gts; 358*9a0deeccSJack Steiner 359*9a0deeccSJack Steiner spin_lock(&vdata->vd_lock); 360*9a0deeccSJack Steiner gts = gru_find_current_gts_nolock(vdata, tsid); 361*9a0deeccSJack Steiner spin_unlock(&vdata->vd_lock); 362*9a0deeccSJack Steiner gru_dbg(grudev, "vma %p, gts %p\n", vma, gts); 363*9a0deeccSJack Steiner return gts; 364*9a0deeccSJack Steiner } 365*9a0deeccSJack Steiner 366*9a0deeccSJack Steiner /* 367*9a0deeccSJack Steiner * Allocate a new thread state for a GSEG. Note that races may allow 368*9a0deeccSJack Steiner * another thread to race to create a gts. 369*9a0deeccSJack Steiner */ 370*9a0deeccSJack Steiner struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, 371*9a0deeccSJack Steiner int tsid) 372*9a0deeccSJack Steiner { 373*9a0deeccSJack Steiner struct gru_vma_data *vdata = vma->vm_private_data; 374*9a0deeccSJack Steiner struct gru_thread_state *gts, *ngts; 375*9a0deeccSJack Steiner 376*9a0deeccSJack Steiner gts = gru_alloc_gts(vma, vdata, tsid); 377*9a0deeccSJack Steiner if (!gts) 378*9a0deeccSJack Steiner return NULL; 379*9a0deeccSJack Steiner 380*9a0deeccSJack Steiner spin_lock(&vdata->vd_lock); 381*9a0deeccSJack Steiner ngts = gru_find_current_gts_nolock(vdata, tsid); 382*9a0deeccSJack Steiner if (ngts) { 383*9a0deeccSJack Steiner gts_drop(gts); 384*9a0deeccSJack Steiner gts = ngts; 385*9a0deeccSJack Steiner STAT(gts_double_allocate); 386*9a0deeccSJack Steiner } else { 387*9a0deeccSJack Steiner list_add(>s->ts_next, &vdata->vd_head); 388*9a0deeccSJack Steiner } 389*9a0deeccSJack Steiner spin_unlock(&vdata->vd_lock); 390*9a0deeccSJack Steiner gru_dbg(grudev, "vma %p, gts %p\n", vma, gts); 391*9a0deeccSJack Steiner return gts; 392*9a0deeccSJack Steiner } 393*9a0deeccSJack Steiner 394*9a0deeccSJack Steiner /* 395*9a0deeccSJack Steiner * Free the GRU context assigned to the thread state. 396*9a0deeccSJack Steiner */ 397*9a0deeccSJack Steiner static void gru_free_gru_context(struct gru_thread_state *gts) 398*9a0deeccSJack Steiner { 399*9a0deeccSJack Steiner struct gru_state *gru; 400*9a0deeccSJack Steiner 401*9a0deeccSJack Steiner gru = gts->ts_gru; 402*9a0deeccSJack Steiner gru_dbg(grudev, "gts %p, gru %p\n", gts, gru); 403*9a0deeccSJack Steiner 404*9a0deeccSJack Steiner spin_lock(&gru->gs_lock); 405*9a0deeccSJack Steiner gru->gs_gts[gts->ts_ctxnum] = NULL; 406*9a0deeccSJack Steiner free_gru_resources(gru, gts); 407*9a0deeccSJack Steiner BUG_ON(test_bit(gts->ts_ctxnum, &gru->gs_context_map) == 0); 408*9a0deeccSJack Steiner __clear_bit(gts->ts_ctxnum, &gru->gs_context_map); 409*9a0deeccSJack Steiner gts->ts_ctxnum = NULLCTX; 410*9a0deeccSJack Steiner gts->ts_gru = NULL; 411*9a0deeccSJack Steiner spin_unlock(&gru->gs_lock); 412*9a0deeccSJack Steiner 413*9a0deeccSJack Steiner gts_drop(gts); 414*9a0deeccSJack Steiner STAT(free_context); 415*9a0deeccSJack Steiner } 416*9a0deeccSJack Steiner 417*9a0deeccSJack Steiner /* 418*9a0deeccSJack Steiner * Prefetching cachelines help hardware performance. 419*9a0deeccSJack Steiner */ 420*9a0deeccSJack Steiner static void prefetch_data(void *p, int num, int stride) 421*9a0deeccSJack Steiner { 422*9a0deeccSJack Steiner while (num-- > 0) { 423*9a0deeccSJack Steiner prefetchw(p); 424*9a0deeccSJack Steiner p += stride; 425*9a0deeccSJack Steiner } 426*9a0deeccSJack Steiner } 427*9a0deeccSJack Steiner 428*9a0deeccSJack Steiner static inline long gru_copy_handle(void *d, void *s) 429*9a0deeccSJack Steiner { 430*9a0deeccSJack Steiner memcpy(d, s, GRU_HANDLE_BYTES); 431*9a0deeccSJack Steiner return GRU_HANDLE_BYTES; 432*9a0deeccSJack Steiner } 433*9a0deeccSJack Steiner 434*9a0deeccSJack Steiner /* rewrite in assembly & use lots of prefetch */ 435*9a0deeccSJack Steiner static void gru_load_context_data(void *save, void *grubase, int ctxnum, 436*9a0deeccSJack Steiner unsigned long cbrmap, unsigned long dsrmap) 437*9a0deeccSJack Steiner { 438*9a0deeccSJack Steiner void *gseg, *cb, *cbe; 439*9a0deeccSJack Steiner unsigned long length; 440*9a0deeccSJack Steiner int i, scr; 441*9a0deeccSJack Steiner 442*9a0deeccSJack Steiner gseg = grubase + ctxnum * GRU_GSEG_STRIDE; 443*9a0deeccSJack Steiner length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; 444*9a0deeccSJack Steiner prefetch_data(gseg + GRU_DS_BASE, length / GRU_CACHE_LINE_BYTES, 445*9a0deeccSJack Steiner GRU_CACHE_LINE_BYTES); 446*9a0deeccSJack Steiner 447*9a0deeccSJack Steiner cb = gseg + GRU_CB_BASE; 448*9a0deeccSJack Steiner cbe = grubase + GRU_CBE_BASE; 449*9a0deeccSJack Steiner for_each_cbr_in_allocation_map(i, &cbrmap, scr) { 450*9a0deeccSJack Steiner prefetch_data(cb, 1, GRU_CACHE_LINE_BYTES); 451*9a0deeccSJack Steiner prefetch_data(cbe + i * GRU_HANDLE_STRIDE, 1, 452*9a0deeccSJack Steiner GRU_CACHE_LINE_BYTES); 453*9a0deeccSJack Steiner cb += GRU_HANDLE_STRIDE; 454*9a0deeccSJack Steiner } 455*9a0deeccSJack Steiner 456*9a0deeccSJack Steiner cb = gseg + GRU_CB_BASE; 457*9a0deeccSJack Steiner for_each_cbr_in_allocation_map(i, &cbrmap, scr) { 458*9a0deeccSJack Steiner save += gru_copy_handle(cb, save); 459*9a0deeccSJack Steiner save += gru_copy_handle(cbe + i * GRU_HANDLE_STRIDE, save); 460*9a0deeccSJack Steiner cb += GRU_HANDLE_STRIDE; 461*9a0deeccSJack Steiner } 462*9a0deeccSJack Steiner 463*9a0deeccSJack Steiner memcpy(gseg + GRU_DS_BASE, save, length); 464*9a0deeccSJack Steiner } 465*9a0deeccSJack Steiner 466*9a0deeccSJack Steiner static void gru_unload_context_data(void *save, void *grubase, int ctxnum, 467*9a0deeccSJack Steiner unsigned long cbrmap, unsigned long dsrmap) 468*9a0deeccSJack Steiner { 469*9a0deeccSJack Steiner void *gseg, *cb, *cbe; 470*9a0deeccSJack Steiner unsigned long length; 471*9a0deeccSJack Steiner int i, scr; 472*9a0deeccSJack Steiner 473*9a0deeccSJack Steiner gseg = grubase + ctxnum * GRU_GSEG_STRIDE; 474*9a0deeccSJack Steiner 475*9a0deeccSJack Steiner cb = gseg + GRU_CB_BASE; 476*9a0deeccSJack Steiner cbe = grubase + GRU_CBE_BASE; 477*9a0deeccSJack Steiner for_each_cbr_in_allocation_map(i, &cbrmap, scr) { 478*9a0deeccSJack Steiner save += gru_copy_handle(save, cb); 479*9a0deeccSJack Steiner save += gru_copy_handle(save, cbe + i * GRU_HANDLE_STRIDE); 480*9a0deeccSJack Steiner cb += GRU_HANDLE_STRIDE; 481*9a0deeccSJack Steiner } 482*9a0deeccSJack Steiner length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; 483*9a0deeccSJack Steiner memcpy(save, gseg + GRU_DS_BASE, length); 484*9a0deeccSJack Steiner } 485*9a0deeccSJack Steiner 486*9a0deeccSJack Steiner void gru_unload_context(struct gru_thread_state *gts, int savestate) 487*9a0deeccSJack Steiner { 488*9a0deeccSJack Steiner struct gru_state *gru = gts->ts_gru; 489*9a0deeccSJack Steiner struct gru_context_configuration_handle *cch; 490*9a0deeccSJack Steiner int ctxnum = gts->ts_ctxnum; 491*9a0deeccSJack Steiner 492*9a0deeccSJack Steiner zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); 493*9a0deeccSJack Steiner cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); 494*9a0deeccSJack Steiner 495*9a0deeccSJack Steiner lock_cch_handle(cch); 496*9a0deeccSJack Steiner if (cch_interrupt_sync(cch)) 497*9a0deeccSJack Steiner BUG(); 498*9a0deeccSJack Steiner gru_dbg(grudev, "gts %p\n", gts); 499*9a0deeccSJack Steiner 500*9a0deeccSJack Steiner gru_unload_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); 501*9a0deeccSJack Steiner if (savestate) 502*9a0deeccSJack Steiner gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, 503*9a0deeccSJack Steiner ctxnum, gts->ts_cbr_map, 504*9a0deeccSJack Steiner gts->ts_dsr_map); 505*9a0deeccSJack Steiner 506*9a0deeccSJack Steiner if (cch_deallocate(cch)) 507*9a0deeccSJack Steiner BUG(); 508*9a0deeccSJack Steiner gts->ts_force_unload = 0; /* ts_force_unload locked by CCH lock */ 509*9a0deeccSJack Steiner unlock_cch_handle(cch); 510*9a0deeccSJack Steiner 511*9a0deeccSJack Steiner gru_free_gru_context(gts); 512*9a0deeccSJack Steiner STAT(unload_context); 513*9a0deeccSJack Steiner } 514*9a0deeccSJack Steiner 515*9a0deeccSJack Steiner /* 516*9a0deeccSJack Steiner * Load a GRU context by copying it from the thread data structure in memory 517*9a0deeccSJack Steiner * to the GRU. 518*9a0deeccSJack Steiner */ 519*9a0deeccSJack Steiner static void gru_load_context(struct gru_thread_state *gts) 520*9a0deeccSJack Steiner { 521*9a0deeccSJack Steiner struct gru_state *gru = gts->ts_gru; 522*9a0deeccSJack Steiner struct gru_context_configuration_handle *cch; 523*9a0deeccSJack Steiner int err, asid, ctxnum = gts->ts_ctxnum; 524*9a0deeccSJack Steiner 525*9a0deeccSJack Steiner gru_dbg(grudev, "gts %p\n", gts); 526*9a0deeccSJack Steiner cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); 527*9a0deeccSJack Steiner 528*9a0deeccSJack Steiner lock_cch_handle(cch); 529*9a0deeccSJack Steiner asid = gru_load_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); 530*9a0deeccSJack Steiner cch->tfm_fault_bit_enable = 531*9a0deeccSJack Steiner (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL 532*9a0deeccSJack Steiner || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); 533*9a0deeccSJack Steiner cch->tlb_int_enable = (gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); 534*9a0deeccSJack Steiner if (cch->tlb_int_enable) { 535*9a0deeccSJack Steiner gts->ts_tlb_int_select = gru_cpu_fault_map_id(); 536*9a0deeccSJack Steiner cch->tlb_int_select = gts->ts_tlb_int_select; 537*9a0deeccSJack Steiner } 538*9a0deeccSJack Steiner cch->tfm_done_bit_enable = 0; 539*9a0deeccSJack Steiner err = cch_allocate(cch, asid, gts->ts_cbr_map, gts->ts_dsr_map); 540*9a0deeccSJack Steiner if (err) { 541*9a0deeccSJack Steiner gru_dbg(grudev, 542*9a0deeccSJack Steiner "err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n", 543*9a0deeccSJack Steiner err, cch, gts, gts->ts_cbr_map, gts->ts_dsr_map); 544*9a0deeccSJack Steiner BUG(); 545*9a0deeccSJack Steiner } 546*9a0deeccSJack Steiner 547*9a0deeccSJack Steiner gru_load_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, ctxnum, 548*9a0deeccSJack Steiner gts->ts_cbr_map, gts->ts_dsr_map); 549*9a0deeccSJack Steiner 550*9a0deeccSJack Steiner if (cch_start(cch)) 551*9a0deeccSJack Steiner BUG(); 552*9a0deeccSJack Steiner unlock_cch_handle(cch); 553*9a0deeccSJack Steiner 554*9a0deeccSJack Steiner STAT(load_context); 555*9a0deeccSJack Steiner } 556*9a0deeccSJack Steiner 557*9a0deeccSJack Steiner /* 558*9a0deeccSJack Steiner * Update fields in an active CCH: 559*9a0deeccSJack Steiner * - retarget interrupts on local blade 560*9a0deeccSJack Steiner * - force a delayed context unload by clearing the CCH asids. This 561*9a0deeccSJack Steiner * forces TLB misses for new GRU instructions. The context is unloaded 562*9a0deeccSJack Steiner * when the next TLB miss occurs. 563*9a0deeccSJack Steiner */ 564*9a0deeccSJack Steiner static int gru_update_cch(struct gru_thread_state *gts, int int_select) 565*9a0deeccSJack Steiner { 566*9a0deeccSJack Steiner struct gru_context_configuration_handle *cch; 567*9a0deeccSJack Steiner struct gru_state *gru = gts->ts_gru; 568*9a0deeccSJack Steiner int i, ctxnum = gts->ts_ctxnum, ret = 0; 569*9a0deeccSJack Steiner 570*9a0deeccSJack Steiner cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); 571*9a0deeccSJack Steiner 572*9a0deeccSJack Steiner lock_cch_handle(cch); 573*9a0deeccSJack Steiner if (cch->state == CCHSTATE_ACTIVE) { 574*9a0deeccSJack Steiner if (gru->gs_gts[gts->ts_ctxnum] != gts) 575*9a0deeccSJack Steiner goto exit; 576*9a0deeccSJack Steiner if (cch_interrupt(cch)) 577*9a0deeccSJack Steiner BUG(); 578*9a0deeccSJack Steiner if (int_select >= 0) { 579*9a0deeccSJack Steiner gts->ts_tlb_int_select = int_select; 580*9a0deeccSJack Steiner cch->tlb_int_select = int_select; 581*9a0deeccSJack Steiner } else { 582*9a0deeccSJack Steiner for (i = 0; i < 8; i++) 583*9a0deeccSJack Steiner cch->asid[i] = 0; 584*9a0deeccSJack Steiner cch->tfm_fault_bit_enable = 0; 585*9a0deeccSJack Steiner cch->tlb_int_enable = 0; 586*9a0deeccSJack Steiner gts->ts_force_unload = 1; 587*9a0deeccSJack Steiner } 588*9a0deeccSJack Steiner if (cch_start(cch)) 589*9a0deeccSJack Steiner BUG(); 590*9a0deeccSJack Steiner ret = 1; 591*9a0deeccSJack Steiner } 592*9a0deeccSJack Steiner exit: 593*9a0deeccSJack Steiner unlock_cch_handle(cch); 594*9a0deeccSJack Steiner return ret; 595*9a0deeccSJack Steiner } 596*9a0deeccSJack Steiner 597*9a0deeccSJack Steiner /* 598*9a0deeccSJack Steiner * Update CCH tlb interrupt select. Required when all the following is true: 599*9a0deeccSJack Steiner * - task's GRU context is loaded into a GRU 600*9a0deeccSJack Steiner * - task is using interrupt notification for TLB faults 601*9a0deeccSJack Steiner * - task has migrated to a different cpu on the same blade where 602*9a0deeccSJack Steiner * it was previously running. 603*9a0deeccSJack Steiner */ 604*9a0deeccSJack Steiner static int gru_retarget_intr(struct gru_thread_state *gts) 605*9a0deeccSJack Steiner { 606*9a0deeccSJack Steiner if (gts->ts_tlb_int_select < 0 607*9a0deeccSJack Steiner || gts->ts_tlb_int_select == gru_cpu_fault_map_id()) 608*9a0deeccSJack Steiner return 0; 609*9a0deeccSJack Steiner 610*9a0deeccSJack Steiner gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select, 611*9a0deeccSJack Steiner gru_cpu_fault_map_id()); 612*9a0deeccSJack Steiner return gru_update_cch(gts, gru_cpu_fault_map_id()); 613*9a0deeccSJack Steiner } 614*9a0deeccSJack Steiner 615*9a0deeccSJack Steiner 616*9a0deeccSJack Steiner /* 617*9a0deeccSJack Steiner * Insufficient GRU resources available on the local blade. Steal a context from 618*9a0deeccSJack Steiner * a process. This is a hack until a _real_ resource scheduler is written.... 619*9a0deeccSJack Steiner */ 620*9a0deeccSJack Steiner #define next_ctxnum(n) ((n) < GRU_NUM_CCH - 2 ? (n) + 1 : 0) 621*9a0deeccSJack Steiner #define next_gru(b, g) (((g) < &(b)->bs_grus[GRU_CHIPLETS_PER_BLADE - 1]) ? \ 622*9a0deeccSJack Steiner ((g)+1) : &(b)->bs_grus[0]) 623*9a0deeccSJack Steiner 624*9a0deeccSJack Steiner static void gru_steal_context(struct gru_thread_state *gts) 625*9a0deeccSJack Steiner { 626*9a0deeccSJack Steiner struct gru_blade_state *blade; 627*9a0deeccSJack Steiner struct gru_state *gru, *gru0; 628*9a0deeccSJack Steiner struct gru_thread_state *ngts = NULL; 629*9a0deeccSJack Steiner int ctxnum, ctxnum0, flag = 0, cbr, dsr; 630*9a0deeccSJack Steiner 631*9a0deeccSJack Steiner cbr = gts->ts_cbr_au_count; 632*9a0deeccSJack Steiner dsr = gts->ts_dsr_au_count; 633*9a0deeccSJack Steiner 634*9a0deeccSJack Steiner preempt_disable(); 635*9a0deeccSJack Steiner blade = gru_base[uv_numa_blade_id()]; 636*9a0deeccSJack Steiner spin_lock(&blade->bs_lock); 637*9a0deeccSJack Steiner 638*9a0deeccSJack Steiner ctxnum = next_ctxnum(blade->bs_lru_ctxnum); 639*9a0deeccSJack Steiner gru = blade->bs_lru_gru; 640*9a0deeccSJack Steiner if (ctxnum == 0) 641*9a0deeccSJack Steiner gru = next_gru(blade, gru); 642*9a0deeccSJack Steiner ctxnum0 = ctxnum; 643*9a0deeccSJack Steiner gru0 = gru; 644*9a0deeccSJack Steiner while (1) { 645*9a0deeccSJack Steiner if (check_gru_resources(gru, cbr, dsr, GRU_NUM_CCH)) 646*9a0deeccSJack Steiner break; 647*9a0deeccSJack Steiner spin_lock(&gru->gs_lock); 648*9a0deeccSJack Steiner for (; ctxnum < GRU_NUM_CCH; ctxnum++) { 649*9a0deeccSJack Steiner if (flag && gru == gru0 && ctxnum == ctxnum0) 650*9a0deeccSJack Steiner break; 651*9a0deeccSJack Steiner ngts = gru->gs_gts[ctxnum]; 652*9a0deeccSJack Steiner /* 653*9a0deeccSJack Steiner * We are grabbing locks out of order, so trylock is 654*9a0deeccSJack Steiner * needed. GTSs are usually not locked, so the odds of 655*9a0deeccSJack Steiner * success are high. If trylock fails, try to steal a 656*9a0deeccSJack Steiner * different GSEG. 657*9a0deeccSJack Steiner */ 658*9a0deeccSJack Steiner if (ngts && mutex_trylock(&ngts->ts_ctxlock)) 659*9a0deeccSJack Steiner break; 660*9a0deeccSJack Steiner ngts = NULL; 661*9a0deeccSJack Steiner flag = 1; 662*9a0deeccSJack Steiner } 663*9a0deeccSJack Steiner spin_unlock(&gru->gs_lock); 664*9a0deeccSJack Steiner if (ngts || (flag && gru == gru0 && ctxnum == ctxnum0)) 665*9a0deeccSJack Steiner break; 666*9a0deeccSJack Steiner ctxnum = 0; 667*9a0deeccSJack Steiner gru = next_gru(blade, gru); 668*9a0deeccSJack Steiner } 669*9a0deeccSJack Steiner blade->bs_lru_gru = gru; 670*9a0deeccSJack Steiner blade->bs_lru_ctxnum = ctxnum; 671*9a0deeccSJack Steiner spin_unlock(&blade->bs_lock); 672*9a0deeccSJack Steiner preempt_enable(); 673*9a0deeccSJack Steiner 674*9a0deeccSJack Steiner if (ngts) { 675*9a0deeccSJack Steiner STAT(steal_context); 676*9a0deeccSJack Steiner ngts->ts_steal_jiffies = jiffies; 677*9a0deeccSJack Steiner gru_unload_context(ngts, 1); 678*9a0deeccSJack Steiner mutex_unlock(&ngts->ts_ctxlock); 679*9a0deeccSJack Steiner } else { 680*9a0deeccSJack Steiner STAT(steal_context_failed); 681*9a0deeccSJack Steiner } 682*9a0deeccSJack Steiner gru_dbg(grudev, 683*9a0deeccSJack Steiner "stole gru %x, ctxnum %d from gts %p. Need cb %d, ds %d;" 684*9a0deeccSJack Steiner " avail cb %ld, ds %ld\n", 685*9a0deeccSJack Steiner gru->gs_gid, ctxnum, ngts, cbr, dsr, hweight64(gru->gs_cbr_map), 686*9a0deeccSJack Steiner hweight64(gru->gs_dsr_map)); 687*9a0deeccSJack Steiner } 688*9a0deeccSJack Steiner 689*9a0deeccSJack Steiner /* 690*9a0deeccSJack Steiner * Scan the GRUs on the local blade & assign a GRU context. 691*9a0deeccSJack Steiner */ 692*9a0deeccSJack Steiner static struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts) 693*9a0deeccSJack Steiner { 694*9a0deeccSJack Steiner struct gru_state *gru, *grux; 695*9a0deeccSJack Steiner int i, max_active_contexts; 696*9a0deeccSJack Steiner 697*9a0deeccSJack Steiner preempt_disable(); 698*9a0deeccSJack Steiner 699*9a0deeccSJack Steiner again: 700*9a0deeccSJack Steiner gru = NULL; 701*9a0deeccSJack Steiner max_active_contexts = GRU_NUM_CCH; 702*9a0deeccSJack Steiner for_each_gru_on_blade(grux, uv_numa_blade_id(), i) { 703*9a0deeccSJack Steiner if (check_gru_resources(grux, gts->ts_cbr_au_count, 704*9a0deeccSJack Steiner gts->ts_dsr_au_count, 705*9a0deeccSJack Steiner max_active_contexts)) { 706*9a0deeccSJack Steiner gru = grux; 707*9a0deeccSJack Steiner max_active_contexts = grux->gs_active_contexts; 708*9a0deeccSJack Steiner if (max_active_contexts == 0) 709*9a0deeccSJack Steiner break; 710*9a0deeccSJack Steiner } 711*9a0deeccSJack Steiner } 712*9a0deeccSJack Steiner 713*9a0deeccSJack Steiner if (gru) { 714*9a0deeccSJack Steiner spin_lock(&gru->gs_lock); 715*9a0deeccSJack Steiner if (!check_gru_resources(gru, gts->ts_cbr_au_count, 716*9a0deeccSJack Steiner gts->ts_dsr_au_count, GRU_NUM_CCH)) { 717*9a0deeccSJack Steiner spin_unlock(&gru->gs_lock); 718*9a0deeccSJack Steiner goto again; 719*9a0deeccSJack Steiner } 720*9a0deeccSJack Steiner reserve_gru_resources(gru, gts); 721*9a0deeccSJack Steiner gts->ts_gru = gru; 722*9a0deeccSJack Steiner gts->ts_ctxnum = 723*9a0deeccSJack Steiner find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH); 724*9a0deeccSJack Steiner BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH); 725*9a0deeccSJack Steiner atomic_inc(>s->ts_refcnt); 726*9a0deeccSJack Steiner gru->gs_gts[gts->ts_ctxnum] = gts; 727*9a0deeccSJack Steiner __set_bit(gts->ts_ctxnum, &gru->gs_context_map); 728*9a0deeccSJack Steiner spin_unlock(&gru->gs_lock); 729*9a0deeccSJack Steiner 730*9a0deeccSJack Steiner STAT(assign_context); 731*9a0deeccSJack Steiner gru_dbg(grudev, 732*9a0deeccSJack Steiner "gseg %p, gts %p, gru %x, ctx %d, cbr %d, dsr %d\n", 733*9a0deeccSJack Steiner gseg_virtual_address(gts->ts_gru, gts->ts_ctxnum), gts, 734*9a0deeccSJack Steiner gts->ts_gru->gs_gid, gts->ts_ctxnum, 735*9a0deeccSJack Steiner gts->ts_cbr_au_count, gts->ts_dsr_au_count); 736*9a0deeccSJack Steiner } else { 737*9a0deeccSJack Steiner gru_dbg(grudev, "failed to allocate a GTS %s\n", ""); 738*9a0deeccSJack Steiner STAT(assign_context_failed); 739*9a0deeccSJack Steiner } 740*9a0deeccSJack Steiner 741*9a0deeccSJack Steiner preempt_enable(); 742*9a0deeccSJack Steiner return gru; 743*9a0deeccSJack Steiner } 744*9a0deeccSJack Steiner 745*9a0deeccSJack Steiner /* 746*9a0deeccSJack Steiner * gru_nopage 747*9a0deeccSJack Steiner * 748*9a0deeccSJack Steiner * Map the user's GRU segment 749*9a0deeccSJack Steiner */ 750*9a0deeccSJack Steiner int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 751*9a0deeccSJack Steiner { 752*9a0deeccSJack Steiner struct gru_thread_state *gts; 753*9a0deeccSJack Steiner unsigned long paddr, vaddr; 754*9a0deeccSJack Steiner 755*9a0deeccSJack Steiner vaddr = (unsigned long)vmf->virtual_address; 756*9a0deeccSJack Steiner gru_dbg(grudev, "vma %p, vaddr 0x%lx (0x%lx)\n", 757*9a0deeccSJack Steiner vma, vaddr, GSEG_BASE(vaddr)); 758*9a0deeccSJack Steiner STAT(nopfn); 759*9a0deeccSJack Steiner 760*9a0deeccSJack Steiner gts = gru_find_thread_state(vma, TSID(vaddr, vma)); 761*9a0deeccSJack Steiner if (!gts) 762*9a0deeccSJack Steiner return VM_FAULT_SIGBUS; 763*9a0deeccSJack Steiner 764*9a0deeccSJack Steiner again: 765*9a0deeccSJack Steiner preempt_disable(); 766*9a0deeccSJack Steiner mutex_lock(>s->ts_ctxlock); 767*9a0deeccSJack Steiner if (gts->ts_gru) { 768*9a0deeccSJack Steiner if (gts->ts_gru->gs_blade_id != uv_numa_blade_id()) { 769*9a0deeccSJack Steiner STAT(migrated_nopfn_unload); 770*9a0deeccSJack Steiner gru_unload_context(gts, 1); 771*9a0deeccSJack Steiner } else { 772*9a0deeccSJack Steiner if (gru_retarget_intr(gts)) 773*9a0deeccSJack Steiner STAT(migrated_nopfn_retarget); 774*9a0deeccSJack Steiner } 775*9a0deeccSJack Steiner } 776*9a0deeccSJack Steiner 777*9a0deeccSJack Steiner if (!gts->ts_gru) { 778*9a0deeccSJack Steiner while (!gru_assign_gru_context(gts)) { 779*9a0deeccSJack Steiner mutex_unlock(>s->ts_ctxlock); 780*9a0deeccSJack Steiner preempt_enable(); 781*9a0deeccSJack Steiner schedule_timeout(GRU_ASSIGN_DELAY); /* true hack ZZZ */ 782*9a0deeccSJack Steiner if (gts->ts_steal_jiffies + GRU_STEAL_DELAY < jiffies) 783*9a0deeccSJack Steiner gru_steal_context(gts); 784*9a0deeccSJack Steiner goto again; 785*9a0deeccSJack Steiner } 786*9a0deeccSJack Steiner gru_load_context(gts); 787*9a0deeccSJack Steiner paddr = gseg_physical_address(gts->ts_gru, gts->ts_ctxnum); 788*9a0deeccSJack Steiner remap_pfn_range(vma, vaddr & ~(GRU_GSEG_PAGESIZE - 1), 789*9a0deeccSJack Steiner paddr >> PAGE_SHIFT, GRU_GSEG_PAGESIZE, 790*9a0deeccSJack Steiner vma->vm_page_prot); 791*9a0deeccSJack Steiner } 792*9a0deeccSJack Steiner 793*9a0deeccSJack Steiner mutex_unlock(>s->ts_ctxlock); 794*9a0deeccSJack Steiner preempt_enable(); 795*9a0deeccSJack Steiner 796*9a0deeccSJack Steiner return VM_FAULT_NOPAGE; 797*9a0deeccSJack Steiner } 798*9a0deeccSJack Steiner 799