aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorJack Steiner <steiner@sgi.com>2009-06-17 19:28:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-18 16:04:00 -0400
commit9120dec47f150636d85b3dba03318ccecd181c79 (patch)
tree8819f1aa2b71992c8a4d80e974e7236c0d762fdb /drivers/misc
parent4a7a17c1188a878e9f00e4ca8dc724c7cff17606 (diff)
gru: support for asynchronous gru instructions
Add support for asynchronous GRU instructions. Currently, asynchronous instructions are supported only for GRU instructions issued by the kernel. [akpm@linux-foundation.org: build fix] Signed-off-by: Jack Steiner <steiner@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/sgi-gru/grufault.c4
-rw-r--r--drivers/misc/sgi-gru/grukservices.c178
-rw-r--r--drivers/misc/sgi-gru/grukservices.h51
3 files changed, 213 insertions, 20 deletions
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
index 3220e95be6b5..8443e90f9f6c 100644
--- a/drivers/misc/sgi-gru/grufault.c
+++ b/drivers/misc/sgi-gru/grufault.c
@@ -468,10 +468,6 @@ irqreturn_t gru_intr(int irq, void *dev_id)
468 return IRQ_NONE; 468 return IRQ_NONE;
469 } 469 }
470 get_clear_fault_map(gru, &imap, &dmap); 470 get_clear_fault_map(gru, &imap, &dmap);
471 gru_dbg(grudev,
472 "irq %d, gid %d, imap %016lx %016lx, dmap %016lx %016lx\n",
473 irq, gru->gs_gid, dmap.fault_bits[0], dmap.fault_bits[1],
474 dmap.fault_bits[0], dmap.fault_bits[1]);
475 471
476 for_each_cbr_in_tfm(cbrnum, dmap.fault_bits) { 472 for_each_cbr_in_tfm(cbrnum, dmap.fault_bits) {
477 complete(gru->gs_blade->bs_async_wq); 473 complete(gru->gs_blade->bs_async_wq);
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c
index a0f981022a6c..9dff33cb72e3 100644
--- a/drivers/misc/sgi-gru/grukservices.c
+++ b/drivers/misc/sgi-gru/grukservices.c
@@ -52,7 +52,53 @@
52 * loaded on demand & can be stolen by a user if the user demand exceeds the 52 * loaded on demand & can be stolen by a user if the user demand exceeds the
53 * kernel demand. The kernel can always reload the kernel context but 53 * kernel demand. The kernel can always reload the kernel context but
54 * a SLEEP may be required!!!. 54 * a SLEEP may be required!!!.
55 *
56 * Async Overview:
57 *
58 * Each blade has one "kernel context" that owns GRU kernel resources
59 * located on the blade. Kernel drivers use GRU resources in this context
60 * for sending messages, zeroing memory, etc.
61 *
62 * The kernel context is dynamically loaded on demand. If it is not in
63 * use by the kernel, the kernel context can be unloaded & given to a user.
64 * The kernel context will be reloaded when needed. This may require that
65 * a context be stolen from a user.
66 * NOTE: frequent unloading/reloading of the kernel context is
67 * expensive. We are depending on batch schedulers, cpusets, sane
68 * drivers or some other mechanism to prevent the need for frequent
69 * stealing/reloading.
70 *
71 * The kernel context consists of two parts:
72 * - 1 CB & a few DSRs that are reserved for each cpu on the blade.
73 * Each cpu has it's own private resources & does not share them
74 * with other cpus. These resources are used serially, ie,
75 * locked, used & unlocked on each call to a function in
76 * grukservices.
77 * (Now that we have dynamic loading of kernel contexts, I
78 * may rethink this & allow sharing between cpus....)
79 *
80 * - Additional resources can be reserved long term & used directly
81 * by UV drivers located in the kernel. Drivers using these GRU
82 * resources can use asynchronous GRU instructions that send
83 * interrupts on completion.
84 * - these resources must be explicitly locked/unlocked
85 * - locked resources prevent (obviously) the kernel
86 * context from being unloaded.
87 * - drivers using these resource directly issue their own
88 * GRU instruction and must wait/check completion.
89 *
90 * When these resources are reserved, the caller can optionally
91 * associate a wait_queue with the resources and use asynchronous
92 * GRU instructions. When an async GRU instruction completes, the
93 * driver will do a wakeup on the event.
94 *
55 */ 95 */
96
97
98#define ASYNC_HAN_TO_BID(h) ((h) - 1)
99#define ASYNC_BID_TO_HAN(b) ((b) + 1)
100#define ASYNC_HAN_TO_BS(h) gru_base[ASYNC_HAN_TO_BID(h)]
101
56#define GRU_NUM_KERNEL_CBR 1 102#define GRU_NUM_KERNEL_CBR 1
57#define GRU_NUM_KERNEL_DSR_BYTES 256 103#define GRU_NUM_KERNEL_DSR_BYTES 256
58#define GRU_NUM_KERNEL_DSR_CL (GRU_NUM_KERNEL_DSR_BYTES / \ 104#define GRU_NUM_KERNEL_DSR_CL (GRU_NUM_KERNEL_DSR_BYTES / \
@@ -99,20 +145,6 @@ struct message_header {
99#define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h])) 145#define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h]))
100 146
101/* 147/*
102 * Allocate a kernel context (GTS) for the specified blade.
103 * - protected by writelock on bs_kgts_sema.
104 */
105static void gru_alloc_kernel_context(struct gru_blade_state *bs, int blade_id)
106{
107 int cbr_au_count, dsr_au_count, ncpus;
108
109 ncpus = uv_blade_nr_possible_cpus(blade_id);
110 cbr_au_count = GRU_CB_COUNT_TO_AU(GRU_NUM_KERNEL_CBR * ncpus);
111 dsr_au_count = GRU_DS_BYTES_TO_AU(GRU_NUM_KERNEL_DSR_BYTES * ncpus);
112 bs->bs_kgts = gru_alloc_gts(NULL, cbr_au_count, dsr_au_count, 0, 0);
113}
114
115/*
116 * Reload the blade's kernel context into a GRU chiplet. Called holding 148 * Reload the blade's kernel context into a GRU chiplet. Called holding
117 * the bs_kgts_sema for READ. Will steal user contexts if necessary. 149 * the bs_kgts_sema for READ. Will steal user contexts if necessary.
118 */ 150 */
@@ -121,17 +153,23 @@ static void gru_load_kernel_context(struct gru_blade_state *bs, int blade_id)
121 struct gru_state *gru; 153 struct gru_state *gru;
122 struct gru_thread_state *kgts; 154 struct gru_thread_state *kgts;
123 void *vaddr; 155 void *vaddr;
124 int ctxnum; 156 int ctxnum, ncpus;
125 157
126 up_read(&bs->bs_kgts_sema); 158 up_read(&bs->bs_kgts_sema);
127 down_write(&bs->bs_kgts_sema); 159 down_write(&bs->bs_kgts_sema);
128 160
129 if (!bs->bs_kgts) 161 if (!bs->bs_kgts)
130 gru_alloc_kernel_context(bs, blade_id); 162 bs->bs_kgts = gru_alloc_gts(NULL, 0, 0, 0, 0);
131 kgts = bs->bs_kgts; 163 kgts = bs->bs_kgts;
132 164
133 if (!kgts->ts_gru) { 165 if (!kgts->ts_gru) {
134 STAT(load_kernel_context); 166 STAT(load_kernel_context);
167 ncpus = uv_blade_nr_possible_cpus(blade_id);
168 kgts->ts_cbr_au_count = GRU_CB_COUNT_TO_AU(
169 GRU_NUM_KERNEL_CBR * ncpus + bs->bs_async_cbrs);
170 kgts->ts_dsr_au_count = GRU_DS_BYTES_TO_AU(
171 GRU_NUM_KERNEL_DSR_BYTES * ncpus +
172 bs->bs_async_dsr_bytes);
135 while (!gru_assign_gru_context(kgts, blade_id)) { 173 while (!gru_assign_gru_context(kgts, blade_id)) {
136 msleep(1); 174 msleep(1);
137 gru_steal_context(kgts, blade_id); 175 gru_steal_context(kgts, blade_id);
@@ -203,6 +241,114 @@ static void gru_free_cpu_resources(void *cb, void *dsr)
203 preempt_enable(); 241 preempt_enable();
204} 242}
205 243
244/*
245 * Reserve GRU resources to be used asynchronously.
246 * Note: currently supports only 1 reservation per blade.
247 *
248 * input:
249 * blade_id - blade on which resources should be reserved
250 * cbrs - number of CBRs
251 * dsr_bytes - number of DSR bytes needed
252 * output:
253 * handle to identify resource
254 * (0 = async resources already reserved)
255 */
256unsigned long gru_reserve_async_resources(int blade_id, int cbrs, int dsr_bytes,
257 struct completion *cmp)
258{
259 struct gru_blade_state *bs;
260 struct gru_thread_state *kgts;
261 int ret = 0;
262
263 bs = gru_base[blade_id];
264
265 down_write(&bs->bs_kgts_sema);
266
267 /* Verify no resources already reserved */
268 if (bs->bs_async_dsr_bytes + bs->bs_async_cbrs)
269 goto done;
270 bs->bs_async_dsr_bytes = dsr_bytes;
271 bs->bs_async_cbrs = cbrs;
272 bs->bs_async_wq = cmp;
273 kgts = bs->bs_kgts;
274
275 /* Resources changed. Unload context if already loaded */
276 if (kgts && kgts->ts_gru)
277 gru_unload_context(kgts, 0);
278 ret = ASYNC_BID_TO_HAN(blade_id);
279
280done:
281 up_write(&bs->bs_kgts_sema);
282 return ret;
283}
284
285/*
286 * Release async resources previously reserved.
287 *
288 * input:
289 * han - handle to identify resources
290 */
291void gru_release_async_resources(unsigned long han)
292{
293 struct gru_blade_state *bs = ASYNC_HAN_TO_BS(han);
294
295 down_write(&bs->bs_kgts_sema);
296 bs->bs_async_dsr_bytes = 0;
297 bs->bs_async_cbrs = 0;
298 bs->bs_async_wq = NULL;
299 up_write(&bs->bs_kgts_sema);
300}
301
302/*
303 * Wait for async GRU instructions to complete.
304 *
305 * input:
306 * han - handle to identify resources
307 */
308void gru_wait_async_cbr(unsigned long han)
309{
310 struct gru_blade_state *bs = ASYNC_HAN_TO_BS(han);
311
312 wait_for_completion(bs->bs_async_wq);
313 mb();
314}
315
316/*
317 * Lock previous reserved async GRU resources
318 *
319 * input:
320 * han - handle to identify resources
321 * output:
322 * cb - pointer to first CBR
323 * dsr - pointer to first DSR
324 */
325void gru_lock_async_resource(unsigned long han, void **cb, void **dsr)
326{
327 struct gru_blade_state *bs = ASYNC_HAN_TO_BS(han);
328 int blade_id = ASYNC_HAN_TO_BID(han);
329 int ncpus;
330
331 gru_lock_kernel_context(blade_id);
332 ncpus = uv_blade_nr_possible_cpus(blade_id);
333 if (cb)
334 *cb = bs->kernel_cb + ncpus * GRU_HANDLE_STRIDE;
335 if (dsr)
336 *dsr = bs->kernel_dsr + ncpus * GRU_NUM_KERNEL_DSR_BYTES;
337}
338
339/*
340 * Unlock previous reserved async GRU resources
341 *
342 * input:
343 * han - handle to identify resources
344 */
345void gru_unlock_async_resource(unsigned long han)
346{
347 int blade_id = ASYNC_HAN_TO_BID(han);
348
349 gru_unlock_kernel_context(blade_id);
350}
351
206/*----------------------------------------------------------------------*/ 352/*----------------------------------------------------------------------*/
207int gru_get_cb_exception_detail(void *cb, 353int gru_get_cb_exception_detail(void *cb,
208 struct control_block_extended_exc_detail *excdet) 354 struct control_block_extended_exc_detail *excdet)
diff --git a/drivers/misc/sgi-gru/grukservices.h b/drivers/misc/sgi-gru/grukservices.h
index 747ed315d56f..d60d34bca44d 100644
--- a/drivers/misc/sgi-gru/grukservices.h
+++ b/drivers/misc/sgi-gru/grukservices.h
@@ -146,4 +146,55 @@ extern void *gru_get_next_message(struct gru_message_queue_desc *mqd);
146extern int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa, 146extern int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa,
147 unsigned int bytes); 147 unsigned int bytes);
148 148
149/*
150 * Reserve GRU resources to be used asynchronously.
151 *
152 * input:
153 * blade_id - blade on which resources should be reserved
154 * cbrs - number of CBRs
155 * dsr_bytes - number of DSR bytes needed
156 * cmp - completion structure for waiting for
157 * async completions
158 * output:
159 * handle to identify resource
160 * (0 = no resources)
161 */
162extern unsigned long gru_reserve_async_resources(int blade_id, int cbrs, int dsr_bytes,
163 struct completion *cmp);
164
165/*
166 * Release async resources previously reserved.
167 *
168 * input:
169 * han - handle to identify resources
170 */
171extern void gru_release_async_resources(unsigned long han);
172
173/*
174 * Wait for async GRU instructions to complete.
175 *
176 * input:
177 * han - handle to identify resources
178 */
179extern void gru_wait_async_cbr(unsigned long han);
180
181/*
182 * Lock previous reserved async GRU resources
183 *
184 * input:
185 * han - handle to identify resources
186 * output:
187 * cb - pointer to first CBR
188 * dsr - pointer to first DSR
189 */
190extern void gru_lock_async_resource(unsigned long han, void **cb, void **dsr);
191
192/*
193 * Unlock previous reserved async GRU resources
194 *
195 * input:
196 * han - handle to identify resources
197 */
198extern void gru_unlock_async_resource(unsigned long han);
199
149#endif /* __GRU_KSERVICES_H_ */ 200#endif /* __GRU_KSERVICES_H_ */