grumain.c 22.3 KB
Newer Older
Jack Steiner's avatar
Jack Steiner committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * SN Platform GRU Driver
 *
 *            DRIVER TABLE MANAGER + GRU CONTEXT LOAD/UNLOAD
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
 */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/list.h>
#include <asm/uv/uv_hub.h>
#include "gru.h"
#include "grutables.h"
#include "gruhandles.h"

25
unsigned long gru_options __read_mostly;
Jack Steiner's avatar
Jack Steiner committed
26
27
28
29
30
31

static struct device_driver gru_driver = {
	.name = "gru"
};

static struct device gru_device = {
32
	.init_name = "",
Jack Steiner's avatar
Jack Steiner committed
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
	.driver = &gru_driver,
};

struct device *grudev = &gru_device;

/*
 * Select a gru fault map to be used by the current cpu. Note that
 * multiple cpus may be using the same map.
 *	ZZZ should "shift" be used?? Depends on HT cpu numbering
 *	ZZZ should be inline but did not work on emulator
 */
int gru_cpu_fault_map_id(void)
{
	return uv_blade_processor_id() % GRU_NUM_TFM;
}

/*--------- ASID Management -------------------------------------------
 *
 *  Initially, assign asids sequentially from MIN_ASID .. MAX_ASID.
 *  Once MAX is reached, flush the TLB & start over. However,
 *  some asids may still be in use. There won't be many (percentage wise) still
 *  in use. Search active contexts & determine the value of the first
 *  asid in use ("x"s below). Set "limit" to this value.
 *  This defines a block of assignable asids.
 *
 *  When "limit" is reached, search forward from limit+1 and determine the
 *  next block of assignable asids.
 *
 *  Repeat until MAX_ASID is reached, then start over again.
 *
 *  Each time MAX_ASID is reached, increment the asid generation. Since
 *  the search for in-use asids only checks contexts with GRUs currently
 *  assigned, asids in some contexts will be missed. Prior to loading
 *  a context, the asid generation of the GTS asid is rechecked. If it
 *  doesn't match the current generation, a new asid will be assigned.
 *
 *   	0---------------x------------x---------------------x----|
 *	  ^-next	^-limit	   				^-MAX_ASID
 *
 * All asid manipulation & context loading/unloading is protected by the
 * gs_lock.
 */

/* Hit the asid limit. Start over */
static int gru_wrap_asid(struct gru_state *gru)
{
79
	gru_dbg(grudev, "gid %d\n", gru->gs_gid);
Jack Steiner's avatar
Jack Steiner committed
80
81
82
83
84
85
86
87
88
89
	STAT(asid_wrap);
	gru->gs_asid_gen++;
	return MIN_ASID;
}

/* Find the next chunk of unused asids */
static int gru_reset_asid_limit(struct gru_state *gru, int asid)
{
	int i, gid, inuse_asid, limit;

90
	gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid);
Jack Steiner's avatar
Jack Steiner committed
91
92
93
94
	STAT(asid_next);
	limit = MAX_ASID;
	if (asid >= limit)
		asid = gru_wrap_asid(gru);
95
	gru_flush_all_tlb(gru);
Jack Steiner's avatar
Jack Steiner committed
96
97
98
	gid = gru->gs_gid;
again:
	for (i = 0; i < GRU_NUM_CCH; i++) {
99
		if (!gru->gs_gts[i] || is_kernel_context(gru->gs_gts[i]))
Jack Steiner's avatar
Jack Steiner committed
100
101
			continue;
		inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid;
102
103
104
		gru_dbg(grudev, "gid %d, gts %p, gms %p, inuse 0x%x, cxt %d\n",
			gru->gs_gid, gru->gs_gts[i], gru->gs_gts[i]->ts_gms,
			inuse_asid, i);
Jack Steiner's avatar
Jack Steiner committed
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
		if (inuse_asid == asid) {
			asid += ASID_INC;
			if (asid >= limit) {
				/*
				 * empty range: reset the range limit and
				 * start over
				 */
				limit = MAX_ASID;
				if (asid >= MAX_ASID)
					asid = gru_wrap_asid(gru);
				goto again;
			}
		}

		if ((inuse_asid > asid) && (inuse_asid < limit))
			limit = inuse_asid;
	}
	gru->gs_asid_limit = limit;
	gru->gs_asid = asid;
124
125
	gru_dbg(grudev, "gid %d, new asid 0x%x, new_limit 0x%x\n", gru->gs_gid,
					asid, limit);
Jack Steiner's avatar
Jack Steiner committed
126
127
128
129
130
131
132
133
134
135
136
137
138
	return asid;
}

/* Assign a new ASID to a thread context.  */
static int gru_assign_asid(struct gru_state *gru)
{
	int asid;

	gru->gs_asid += ASID_INC;
	asid = gru->gs_asid;
	if (asid >= gru->gs_asid_limit)
		asid = gru_reset_asid_limit(gru, asid);

139
	gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid);
Jack Steiner's avatar
Jack Steiner committed
140
141
142
143
144
145
146
147
148
149
150
151
152
	return asid;
}

/*
 * Clear n bits in a word. Return a word indicating the bits that were cleared.
 * Optionally, build an array of chars that contain the bit numbers allocated.
 */
static unsigned long reserve_resources(unsigned long *p, int n, int mmax,
				       char *idx)
{
	unsigned long bits = 0;
	int i;

153
	while (n--) {
Jack Steiner's avatar
Jack Steiner committed
154
155
156
157
158
159
160
		i = find_first_bit(p, mmax);
		if (i == mmax)
			BUG();
		__clear_bit(i, p);
		__set_bit(i, &bits);
		if (idx)
			*idx++ = i;
161
	}
Jack Steiner's avatar
Jack Steiner committed
162
163
164
	return bits;
}

165
unsigned long gru_reserve_cb_resources(struct gru_state *gru, int cbr_au_count,
Jack Steiner's avatar
Jack Steiner committed
166
167
168
169
170
171
				       char *cbmap)
{
	return reserve_resources(&gru->gs_cbr_map, cbr_au_count, GRU_CBR_AU,
				 cbmap);
}

172
unsigned long gru_reserve_ds_resources(struct gru_state *gru, int dsr_au_count,
Jack Steiner's avatar
Jack Steiner committed
173
174
175
176
177
178
179
180
181
182
183
				       char *dsmap)
{
	return reserve_resources(&gru->gs_dsr_map, dsr_au_count, GRU_DSR_AU,
				 dsmap);
}

static void reserve_gru_resources(struct gru_state *gru,
				  struct gru_thread_state *gts)
{
	gru->gs_active_contexts++;
	gts->ts_cbr_map =
184
	    gru_reserve_cb_resources(gru, gts->ts_cbr_au_count,
Jack Steiner's avatar
Jack Steiner committed
185
186
				     gts->ts_cbr_idx);
	gts->ts_dsr_map =
187
	    gru_reserve_ds_resources(gru, gts->ts_dsr_au_count, NULL);
Jack Steiner's avatar
Jack Steiner committed
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
}

static void free_gru_resources(struct gru_state *gru,
			       struct gru_thread_state *gts)
{
	gru->gs_active_contexts--;
	gru->gs_cbr_map |= gts->ts_cbr_map;
	gru->gs_dsr_map |= gts->ts_dsr_map;
}

/*
 * Check if a GRU has sufficient free resources to satisfy an allocation
 * request. Note: GRU locks may or may not be held when this is called. If
 * not held, recheck after acquiring the appropriate locks.
 *
 * Returns 1 if sufficient resources, 0 if not
 */
static int check_gru_resources(struct gru_state *gru, int cbr_au_count,
			       int dsr_au_count, int max_active_contexts)
{
	return hweight64(gru->gs_cbr_map) >= cbr_au_count
		&& hweight64(gru->gs_dsr_map) >= dsr_au_count
		&& gru->gs_active_contexts < max_active_contexts;
}

/*
 * TLB manangment requires tracking all GRU chiplets that have loaded a GSEG
 * context.
 */
217
218
static int gru_load_mm_tracker(struct gru_state *gru,
					struct gru_thread_state *gts)
Jack Steiner's avatar
Jack Steiner committed
219
{
220
	struct gru_mm_struct *gms = gts->ts_gms;
Jack Steiner's avatar
Jack Steiner committed
221
	struct gru_mm_tracker *asids = &gms->ms_asids[gru->gs_gid];
222
	unsigned short ctxbitmap = (1 << gts->ts_ctxnum);
Jack Steiner's avatar
Jack Steiner committed
223
224
225
226
227
	int asid;

	spin_lock(&gms->ms_asid_lock);
	asid = asids->mt_asid;

228
229
230
	spin_lock(&gru->gs_asid_lock);
	if (asid == 0 || (asids->mt_ctxbitmap == 0 && asids->mt_asid_gen !=
			  gru->gs_asid_gen)) {
Jack Steiner's avatar
Jack Steiner committed
231
232
233
234
235
236
237
		asid = gru_assign_asid(gru);
		asids->mt_asid = asid;
		asids->mt_asid_gen = gru->gs_asid_gen;
		STAT(asid_new);
	} else {
		STAT(asid_reuse);
	}
238
	spin_unlock(&gru->gs_asid_lock);
Jack Steiner's avatar
Jack Steiner committed
239
240
241
242
243
244
245
246

	BUG_ON(asids->mt_ctxbitmap & ctxbitmap);
	asids->mt_ctxbitmap |= ctxbitmap;
	if (!test_bit(gru->gs_gid, gms->ms_asidmap))
		__set_bit(gru->gs_gid, gms->ms_asidmap);
	spin_unlock(&gms->ms_asid_lock);

	gru_dbg(grudev,
247
248
249
		"gid %d, gts %p, gms %p, ctxnum %d, asid 0x%x, asidmap 0x%lx\n",
		gru->gs_gid, gts, gms, gts->ts_ctxnum, asid,
		gms->ms_asidmap[0]);
Jack Steiner's avatar
Jack Steiner committed
250
251
252
253
	return asid;
}

static void gru_unload_mm_tracker(struct gru_state *gru,
254
					struct gru_thread_state *gts)
Jack Steiner's avatar
Jack Steiner committed
255
{
256
	struct gru_mm_struct *gms = gts->ts_gms;
Jack Steiner's avatar
Jack Steiner committed
257
258
259
260
	struct gru_mm_tracker *asids;
	unsigned short ctxbitmap;

	asids = &gms->ms_asids[gru->gs_gid];
261
	ctxbitmap = (1 << gts->ts_ctxnum);
Jack Steiner's avatar
Jack Steiner committed
262
	spin_lock(&gms->ms_asid_lock);
263
	spin_lock(&gru->gs_asid_lock);
Jack Steiner's avatar
Jack Steiner committed
264
265
	BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap);
	asids->mt_ctxbitmap ^= ctxbitmap;
266
267
	gru_dbg(grudev, "gid %d, gts %p, gms %p, ctxnum 0x%d, asidmap 0x%lx\n",
		gru->gs_gid, gts, gms, gts->ts_ctxnum, gms->ms_asidmap[0]);
268
	spin_unlock(&gru->gs_asid_lock);
Jack Steiner's avatar
Jack Steiner committed
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
	spin_unlock(&gms->ms_asid_lock);
}

/*
 * Decrement the reference count on a GTS structure. Free the structure
 * if the reference count goes to zero.
 */
void gts_drop(struct gru_thread_state *gts)
{
	if (gts && atomic_dec_return(&gts->ts_refcnt) == 0) {
		gru_drop_mmu_notifier(gts->ts_gms);
		kfree(gts);
		STAT(gts_free);
	}
}

/*
 * Locate the GTS structure for the current thread.
 */
static struct gru_thread_state *gru_find_current_gts_nolock(struct gru_vma_data
			    *vdata, int tsid)
{
	struct gru_thread_state *gts;

	list_for_each_entry(gts, &vdata->vd_head, ts_next)
	    if (gts->ts_tsid == tsid)
		return gts;
	return NULL;
}

/*
 * Allocate a thread state structure.
 */
302
303
struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma,
		int cbr_au_count, int dsr_au_count, int options, int tsid)
Jack Steiner's avatar
Jack Steiner committed
304
305
306
307
{
	struct gru_thread_state *gts;
	int bytes;

308
	bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count);
Jack Steiner's avatar
Jack Steiner committed
309
310
311
312
313
314
315
316
	bytes += sizeof(struct gru_thread_state);
	gts = kzalloc(bytes, GFP_KERNEL);
	if (!gts)
		return NULL;

	STAT(gts_alloc);
	atomic_set(&gts->ts_refcnt, 1);
	mutex_init(&gts->ts_ctxlock);
317
318
319
	gts->ts_cbr_au_count = cbr_au_count;
	gts->ts_dsr_au_count = dsr_au_count;
	gts->ts_user_options = options;
Jack Steiner's avatar
Jack Steiner committed
320
321
322
	gts->ts_tsid = tsid;
	gts->ts_ctxnum = NULLCTX;
	gts->ts_tlb_int_select = -1;
323
	gts->ts_sizeavail = GRU_SIZEAVAIL(PAGE_SHIFT);
324
325
326
327
328
329
330
	if (vma) {
		gts->ts_mm = current->mm;
		gts->ts_vma = vma;
		gts->ts_gms = gru_register_mmu_notifier();
		if (!gts->ts_gms)
			goto err;
	}
Jack Steiner's avatar
Jack Steiner committed
331

332
	gru_dbg(grudev, "alloc gts %p\n", gts);
Jack Steiner's avatar
Jack Steiner committed
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
	return gts;

err:
	gts_drop(gts);
	return NULL;
}

/*
 * Allocate a vma private data structure.
 */
struct gru_vma_data *gru_alloc_vma_data(struct vm_area_struct *vma, int tsid)
{
	struct gru_vma_data *vdata = NULL;

	vdata = kmalloc(sizeof(*vdata), GFP_KERNEL);
	if (!vdata)
		return NULL;

	INIT_LIST_HEAD(&vdata->vd_head);
	spin_lock_init(&vdata->vd_lock);
	gru_dbg(grudev, "alloc vdata %p\n", vdata);
	return vdata;
}

/*
 * Find the thread state structure for the current thread.
 */
struct gru_thread_state *gru_find_thread_state(struct vm_area_struct *vma,
					int tsid)
{
	struct gru_vma_data *vdata = vma->vm_private_data;
	struct gru_thread_state *gts;

	spin_lock(&vdata->vd_lock);
	gts = gru_find_current_gts_nolock(vdata, tsid);
	spin_unlock(&vdata->vd_lock);
	gru_dbg(grudev, "vma %p, gts %p\n", vma, gts);
	return gts;
}

/*
 * Allocate a new thread state for a GSEG. Note that races may allow
 * another thread to race to create a gts.
 */
struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma,
					int tsid)
{
	struct gru_vma_data *vdata = vma->vm_private_data;
	struct gru_thread_state *gts, *ngts;

383
384
	gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, vdata->vd_dsr_au_count,
			    vdata->vd_user_options, tsid);
Jack Steiner's avatar
Jack Steiner committed
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
	if (!gts)
		return NULL;

	spin_lock(&vdata->vd_lock);
	ngts = gru_find_current_gts_nolock(vdata, tsid);
	if (ngts) {
		gts_drop(gts);
		gts = ngts;
		STAT(gts_double_allocate);
	} else {
		list_add(&gts->ts_next, &vdata->vd_head);
	}
	spin_unlock(&vdata->vd_lock);
	gru_dbg(grudev, "vma %p, gts %p\n", vma, gts);
	return gts;
}

/*
 * Free the GRU context assigned to the thread state.
 */
static void gru_free_gru_context(struct gru_thread_state *gts)
{
	struct gru_state *gru;

	gru = gts->ts_gru;
410
	gru_dbg(grudev, "gts %p, gid %d\n", gts, gru->gs_gid);
Jack Steiner's avatar
Jack Steiner committed
411
412
413
414
415
416
417
418

	spin_lock(&gru->gs_lock);
	gru->gs_gts[gts->ts_ctxnum] = NULL;
	free_gru_resources(gru, gts);
	BUG_ON(test_bit(gts->ts_ctxnum, &gru->gs_context_map) == 0);
	__clear_bit(gts->ts_ctxnum, &gru->gs_context_map);
	gts->ts_ctxnum = NULLCTX;
	gts->ts_gru = NULL;
419
	gts->ts_blade = -1;
Jack Steiner's avatar
Jack Steiner committed
420
421
422
423
424
425
426
427
	spin_unlock(&gru->gs_lock);

	gts_drop(gts);
	STAT(free_context);
}

/*
 * Prefetching cachelines help hardware performance.
428
 * (Strictly a performance enhancement. Not functionally required).
Jack Steiner's avatar
Jack Steiner committed
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
 */
static void prefetch_data(void *p, int num, int stride)
{
	while (num-- > 0) {
		prefetchw(p);
		p += stride;
	}
}

static inline long gru_copy_handle(void *d, void *s)
{
	memcpy(d, s, GRU_HANDLE_BYTES);
	return GRU_HANDLE_BYTES;
}

Jack Steiner's avatar
Jack Steiner committed
444
445
static void gru_prefetch_context(void *gseg, void *cb, void *cbe,
				unsigned long cbrmap, unsigned long length)
Jack Steiner's avatar
Jack Steiner committed
446
447
448
449
450
451
452
453
454
455
456
457
{
	int i, scr;

	prefetch_data(gseg + GRU_DS_BASE, length / GRU_CACHE_LINE_BYTES,
		      GRU_CACHE_LINE_BYTES);

	for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
		prefetch_data(cb, 1, GRU_CACHE_LINE_BYTES);
		prefetch_data(cbe + i * GRU_HANDLE_STRIDE, 1,
			      GRU_CACHE_LINE_BYTES);
		cb += GRU_HANDLE_STRIDE;
	}
Jack Steiner's avatar
Jack Steiner committed
458
459
460
461
462
463
464
465
}

static void gru_load_context_data(void *save, void *grubase, int ctxnum,
				  unsigned long cbrmap, unsigned long dsrmap)
{
	void *gseg, *cb, *cbe;
	unsigned long length;
	int i, scr;
Jack Steiner's avatar
Jack Steiner committed
466

Jack Steiner's avatar
Jack Steiner committed
467
	gseg = grubase + ctxnum * GRU_GSEG_STRIDE;
Jack Steiner's avatar
Jack Steiner committed
468
	cb = gseg + GRU_CB_BASE;
Jack Steiner's avatar
Jack Steiner committed
469
470
471
472
	cbe = grubase + GRU_CBE_BASE;
	length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
	gru_prefetch_context(gseg, cb, cbe, cbrmap, length);

Jack Steiner's avatar
Jack Steiner committed
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
	for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
		save += gru_copy_handle(cb, save);
		save += gru_copy_handle(cbe + i * GRU_HANDLE_STRIDE, save);
		cb += GRU_HANDLE_STRIDE;
	}

	memcpy(gseg + GRU_DS_BASE, save, length);
}

static void gru_unload_context_data(void *save, void *grubase, int ctxnum,
				    unsigned long cbrmap, unsigned long dsrmap)
{
	void *gseg, *cb, *cbe;
	unsigned long length;
	int i, scr;

	gseg = grubase + ctxnum * GRU_GSEG_STRIDE;
	cb = gseg + GRU_CB_BASE;
	cbe = grubase + GRU_CBE_BASE;
Jack Steiner's avatar
Jack Steiner committed
492
493
494
	length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
	gru_prefetch_context(gseg, cb, cbe, cbrmap, length);

Jack Steiner's avatar
Jack Steiner committed
495
496
497
498
499
500
501
502
503
504
505
506
507
508
	for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
		save += gru_copy_handle(save, cb);
		save += gru_copy_handle(save, cbe + i * GRU_HANDLE_STRIDE);
		cb += GRU_HANDLE_STRIDE;
	}
	memcpy(save, gseg + GRU_DS_BASE, length);
}

void gru_unload_context(struct gru_thread_state *gts, int savestate)
{
	struct gru_state *gru = gts->ts_gru;
	struct gru_context_configuration_handle *cch;
	int ctxnum = gts->ts_ctxnum;

509
510
	if (!is_kernel_context(gts))
		zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE);
Jack Steiner's avatar
Jack Steiner committed
511
512
	cch = get_cch(gru->gs_gru_base_vaddr, ctxnum);

513
	gru_dbg(grudev, "gts %p\n", gts);
Jack Steiner's avatar
Jack Steiner committed
514
515
516
517
	lock_cch_handle(cch);
	if (cch_interrupt_sync(cch))
		BUG();

518
519
	if (!is_kernel_context(gts))
		gru_unload_mm_tracker(gru, gts);
Jack Steiner's avatar
Jack Steiner committed
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
	if (savestate)
		gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr,
					ctxnum, gts->ts_cbr_map,
					gts->ts_dsr_map);

	if (cch_deallocate(cch))
		BUG();
	gts->ts_force_unload = 0;	/* ts_force_unload locked by CCH lock */
	unlock_cch_handle(cch);

	gru_free_gru_context(gts);
}

/*
 * Load a GRU context by copying it from the thread data structure in memory
 * to the GRU.
 */
537
void gru_load_context(struct gru_thread_state *gts)
Jack Steiner's avatar
Jack Steiner committed
538
539
540
{
	struct gru_state *gru = gts->ts_gru;
	struct gru_context_configuration_handle *cch;
541
	int i, err, asid, ctxnum = gts->ts_ctxnum;
Jack Steiner's avatar
Jack Steiner committed
542
543
544
545
546
547
548
549
550
551
552
553
554
555

	gru_dbg(grudev, "gts %p\n", gts);
	cch = get_cch(gru->gs_gru_base_vaddr, ctxnum);

	lock_cch_handle(cch);
	cch->tfm_fault_bit_enable =
	    (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL
	     || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR);
	cch->tlb_int_enable = (gts->ts_user_options == GRU_OPT_MISS_FMM_INTR);
	if (cch->tlb_int_enable) {
		gts->ts_tlb_int_select = gru_cpu_fault_map_id();
		cch->tlb_int_select = gts->ts_tlb_int_select;
	}
	cch->tfm_done_bit_enable = 0;
556
557
	cch->dsr_allocation_map = gts->ts_dsr_map;
	cch->cbr_allocation_map = gts->ts_cbr_map;
558
559
560
561
562
563
564
565
566
567

	if (is_kernel_context(gts)) {
		cch->unmap_enable = 1;
	} else {
		cch->unmap_enable = 0;
		asid = gru_load_mm_tracker(gru, gts);
		for (i = 0; i < 8; i++) {
			cch->asid[i] = asid + i;
			cch->sizeavail[i] = gts->ts_sizeavail;
		}
568
569
570
	}

	err = cch_allocate(cch);
Jack Steiner's avatar
Jack Steiner committed
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
	if (err) {
		gru_dbg(grudev,
			"err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n",
			err, cch, gts, gts->ts_cbr_map, gts->ts_dsr_map);
		BUG();
	}

	gru_load_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, ctxnum,
			      gts->ts_cbr_map, gts->ts_dsr_map);

	if (cch_start(cch))
		BUG();
	unlock_cch_handle(cch);
}

/*
 * Update fields in an active CCH:
 * 	- retarget interrupts on local blade
589
 * 	- update sizeavail mask
Jack Steiner's avatar
Jack Steiner committed
590
591
592
593
 * 	- force a delayed context unload by clearing the CCH asids. This
 * 	  forces TLB misses for new GRU instructions. The context is unloaded
 * 	  when the next TLB miss occurs.
 */
594
int gru_update_cch(struct gru_thread_state *gts, int force_unload)
Jack Steiner's avatar
Jack Steiner committed
595
596
597
598
599
600
601
602
603
604
605
606
607
{
	struct gru_context_configuration_handle *cch;
	struct gru_state *gru = gts->ts_gru;
	int i, ctxnum = gts->ts_ctxnum, ret = 0;

	cch = get_cch(gru->gs_gru_base_vaddr, ctxnum);

	lock_cch_handle(cch);
	if (cch->state == CCHSTATE_ACTIVE) {
		if (gru->gs_gts[gts->ts_ctxnum] != gts)
			goto exit;
		if (cch_interrupt(cch))
			BUG();
608
609
610
611
612
		if (!force_unload) {
			for (i = 0; i < 8; i++)
				cch->sizeavail[i] = gts->ts_sizeavail;
			gts->ts_tlb_int_select = gru_cpu_fault_map_id();
			cch->tlb_int_select = gru_cpu_fault_map_id();
613
			cch->tfm_fault_bit_enable =
614
615
				(gts->ts_user_options == GRU_OPT_MISS_FMM_POLL
				|| gts->ts_user_options == GRU_OPT_MISS_FMM_INTR);
Jack Steiner's avatar
Jack Steiner committed
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
		} else {
			for (i = 0; i < 8; i++)
				cch->asid[i] = 0;
			cch->tfm_fault_bit_enable = 0;
			cch->tlb_int_enable = 0;
			gts->ts_force_unload = 1;
		}
		if (cch_start(cch))
			BUG();
		ret = 1;
	}
exit:
	unlock_cch_handle(cch);
	return ret;
}

/*
 * Update CCH tlb interrupt select. Required when all the following is true:
 * 	- task's GRU context is loaded into a GRU
 * 	- task is using interrupt notification for TLB faults
 * 	- task has migrated to a different cpu on the same blade where
 * 	  it was previously running.
 */
static int gru_retarget_intr(struct gru_thread_state *gts)
{
	if (gts->ts_tlb_int_select < 0
	    || gts->ts_tlb_int_select == gru_cpu_fault_map_id())
		return 0;

	gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select,
		gru_cpu_fault_map_id());
647
	return gru_update_cch(gts, 0);
Jack Steiner's avatar
Jack Steiner committed
648
649
650
651
652
653
654
655
656
657
658
}


/*
 * Insufficient GRU resources available on the local blade. Steal a context from
 * a process. This is a hack until a _real_ resource scheduler is written....
 */
#define next_ctxnum(n)	((n) <  GRU_NUM_CCH - 2 ? (n) + 1 : 0)
#define next_gru(b, g)	(((g) < &(b)->bs_grus[GRU_CHIPLETS_PER_BLADE - 1]) ?  \
				 ((g)+1) : &(b)->bs_grus[0])

659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
static int is_gts_stealable(struct gru_thread_state *gts,
		struct gru_blade_state *bs)
{
	if (is_kernel_context(gts))
		return down_write_trylock(&bs->bs_kgts_sema);
	else
		return mutex_trylock(&gts->ts_ctxlock);
}

static void gts_stolen(struct gru_thread_state *gts,
		struct gru_blade_state *bs)
{
	if (is_kernel_context(gts)) {
		up_write(&bs->bs_kgts_sema);
		STAT(steal_kernel_context);
	} else {
		mutex_unlock(&gts->ts_ctxlock);
		STAT(steal_user_context);
	}
}

680
void gru_steal_context(struct gru_thread_state *gts, int blade_id)
Jack Steiner's avatar
Jack Steiner committed
681
682
683
684
685
686
687
688
689
{
	struct gru_blade_state *blade;
	struct gru_state *gru, *gru0;
	struct gru_thread_state *ngts = NULL;
	int ctxnum, ctxnum0, flag = 0, cbr, dsr;

	cbr = gts->ts_cbr_au_count;
	dsr = gts->ts_dsr_au_count;

690
	blade = gru_base[blade_id];
Jack Steiner's avatar
Jack Steiner committed
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
	spin_lock(&blade->bs_lock);

	ctxnum = next_ctxnum(blade->bs_lru_ctxnum);
	gru = blade->bs_lru_gru;
	if (ctxnum == 0)
		gru = next_gru(blade, gru);
	ctxnum0 = ctxnum;
	gru0 = gru;
	while (1) {
		if (check_gru_resources(gru, cbr, dsr, GRU_NUM_CCH))
			break;
		spin_lock(&gru->gs_lock);
		for (; ctxnum < GRU_NUM_CCH; ctxnum++) {
			if (flag && gru == gru0 && ctxnum == ctxnum0)
				break;
			ngts = gru->gs_gts[ctxnum];
			/*
			 * We are grabbing locks out of order, so trylock is
			 * needed. GTSs are usually not locked, so the odds of
			 * success are high. If trylock fails, try to steal a
			 * different GSEG.
			 */
713
			if (ngts && is_gts_stealable(ngts, blade))
Jack Steiner's avatar
Jack Steiner committed
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
				break;
			ngts = NULL;
			flag = 1;
		}
		spin_unlock(&gru->gs_lock);
		if (ngts || (flag && gru == gru0 && ctxnum == ctxnum0))
			break;
		ctxnum = 0;
		gru = next_gru(blade, gru);
	}
	blade->bs_lru_gru = gru;
	blade->bs_lru_ctxnum = ctxnum;
	spin_unlock(&blade->bs_lock);

	if (ngts) {
		ngts->ts_steal_jiffies = jiffies;
730
731
		gru_unload_context(ngts, is_kernel_context(ngts) ? 0 : 1);
		gts_stolen(ngts, blade);
Jack Steiner's avatar
Jack Steiner committed
732
733
734
735
	} else {
		STAT(steal_context_failed);
	}
	gru_dbg(grudev,
736
		"stole gid %d, ctxnum %d from gts %p. Need cb %d, ds %d;"
Jack Steiner's avatar
Jack Steiner committed
737
738
739
740
741
742
743
744
		" avail cb %ld, ds %ld\n",
		gru->gs_gid, ctxnum, ngts, cbr, dsr, hweight64(gru->gs_cbr_map),
		hweight64(gru->gs_dsr_map));
}

/*
 * Scan the GRUs on the local blade & assign a GRU context.
 */
745
struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts,
746
						int blade)
Jack Steiner's avatar
Jack Steiner committed
747
748
749
750
751
752
753
754
{
	struct gru_state *gru, *grux;
	int i, max_active_contexts;


again:
	gru = NULL;
	max_active_contexts = GRU_NUM_CCH;
755
	for_each_gru_on_blade(grux, blade, i) {
Jack Steiner's avatar
Jack Steiner committed
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
		if (check_gru_resources(grux, gts->ts_cbr_au_count,
					gts->ts_dsr_au_count,
					max_active_contexts)) {
			gru = grux;
			max_active_contexts = grux->gs_active_contexts;
			if (max_active_contexts == 0)
				break;
		}
	}

	if (gru) {
		spin_lock(&gru->gs_lock);
		if (!check_gru_resources(gru, gts->ts_cbr_au_count,
					 gts->ts_dsr_au_count, GRU_NUM_CCH)) {
			spin_unlock(&gru->gs_lock);
			goto again;
		}
		reserve_gru_resources(gru, gts);
		gts->ts_gru = gru;
775
		gts->ts_blade = gru->gs_blade_id;
Jack Steiner's avatar
Jack Steiner committed
776
777
778
779
780
781
782
783
784
785
		gts->ts_ctxnum =
		    find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH);
		BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH);
		atomic_inc(&gts->ts_refcnt);
		gru->gs_gts[gts->ts_ctxnum] = gts;
		__set_bit(gts->ts_ctxnum, &gru->gs_context_map);
		spin_unlock(&gru->gs_lock);

		STAT(assign_context);
		gru_dbg(grudev,
786
			"gseg %p, gts %p, gid %d, ctx %d, cbr %d, dsr %d\n",
Jack Steiner's avatar
Jack Steiner committed
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
			gseg_virtual_address(gts->ts_gru, gts->ts_ctxnum), gts,
			gts->ts_gru->gs_gid, gts->ts_ctxnum,
			gts->ts_cbr_au_count, gts->ts_dsr_au_count);
	} else {
		gru_dbg(grudev, "failed to allocate a GTS %s\n", "");
		STAT(assign_context_failed);
	}

	return gru;
}

/*
 * gru_nopage
 *
 * Map the user's GRU segment
802
803
 *
 * 	Note: gru segments alway mmaped on GRU_GSEG_PAGESIZE boundaries.
Jack Steiner's avatar
Jack Steiner committed
804
805
806
807
808
 */
int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
	struct gru_thread_state *gts;
	unsigned long paddr, vaddr;
809
	int blade_id;
Jack Steiner's avatar
Jack Steiner committed
810
811
812
813
814
815

	vaddr = (unsigned long)vmf->virtual_address;
	gru_dbg(grudev, "vma %p, vaddr 0x%lx (0x%lx)\n",
		vma, vaddr, GSEG_BASE(vaddr));
	STAT(nopfn);

816
	/* The following check ensures vaddr is a valid address in the VMA */
Jack Steiner's avatar
Jack Steiner committed
817
818
819
820
821
822
	gts = gru_find_thread_state(vma, TSID(vaddr, vma));
	if (!gts)
		return VM_FAULT_SIGBUS;

again:
	mutex_lock(&gts->ts_ctxlock);
Jack Steiner's avatar
Jack Steiner committed
823
	preempt_disable();
824
825
	blade_id = uv_numa_blade_id();

Jack Steiner's avatar
Jack Steiner committed
826
	if (gts->ts_gru) {
827
		if (gts->ts_gru->gs_blade_id != blade_id) {
Jack Steiner's avatar
Jack Steiner committed
828
829
830
831
832
833
834
835
836
			STAT(migrated_nopfn_unload);
			gru_unload_context(gts, 1);
		} else {
			if (gru_retarget_intr(gts))
				STAT(migrated_nopfn_retarget);
		}
	}

	if (!gts->ts_gru) {
837
		STAT(load_user_context);
838
		if (!gru_assign_gru_context(gts, blade_id)) {
Jack Steiner's avatar
Jack Steiner committed
839
			preempt_enable();
840
841
			mutex_unlock(&gts->ts_ctxlock);
			set_current_state(TASK_INTERRUPTIBLE);
Jack Steiner's avatar
Jack Steiner committed
842
			schedule_timeout(GRU_ASSIGN_DELAY);  /* true hack ZZZ */
843
			blade_id = uv_numa_blade_id();
Jack Steiner's avatar
Jack Steiner committed
844
			if (gts->ts_steal_jiffies + GRU_STEAL_DELAY < jiffies)
845
				gru_steal_context(gts, blade_id);
Jack Steiner's avatar
Jack Steiner committed
846
847
848
849
850
851
852
853
854
855
			goto again;
		}
		gru_load_context(gts);
		paddr = gseg_physical_address(gts->ts_gru, gts->ts_ctxnum);
		remap_pfn_range(vma, vaddr & ~(GRU_GSEG_PAGESIZE - 1),
				paddr >> PAGE_SHIFT, GRU_GSEG_PAGESIZE,
				vma->vm_page_prot);
	}

	preempt_enable();
856
	mutex_unlock(&gts->ts_ctxlock);
Jack Steiner's avatar
Jack Steiner committed
857
858
859
860

	return VM_FAULT_NOPAGE;
}