diff options
Diffstat (limited to 'drivers/misc/sgi-gru/grukservices.c')
-rw-r--r-- | drivers/misc/sgi-gru/grukservices.c | 178 |
1 files changed, 162 insertions, 16 deletions
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 | */ | ||
105 | static 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 | */ | ||
256 | unsigned 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 | |||
280 | done: | ||
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 | */ | ||
291 | void 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 | */ | ||
308 | void 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 | */ | ||
325 | void 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 | */ | ||
345 | void 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 | /*----------------------------------------------------------------------*/ |
207 | int gru_get_cb_exception_detail(void *cb, | 353 | int gru_get_cb_exception_detail(void *cb, |
208 | struct control_block_extended_exc_detail *excdet) | 354 | struct control_block_extended_exc_detail *excdet) |