aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/sgi-gru
diff options
context:
space:
mode:
authorJack Steiner <steiner@sgi.com>2009-04-02 19:59:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-02 22:05:06 -0400
commit6f2584f47474d29ce829604bfc8b56c10b352fdb (patch)
treef5b5c63c7c73785a641c995c2fe48b4c5cc726eb /drivers/misc/sgi-gru
parentecdaf2b55251f718a1fbaf4a3f72bfd6e25c582c (diff)
sgi-gru: add support to the GRU driver for message queue interrupts
Add support to the GRU driver for message queue interrupts. Signed-off-by: Jack Steiner <steiner@sgi.com> Signed-off-by: Dean Nelson <dcn@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/sgi-gru')
-rw-r--r--drivers/misc/sgi-gru/grukservices.c104
-rw-r--r--drivers/misc/sgi-gru/grukservices.h33
2 files changed, 82 insertions, 55 deletions
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c
index 247635d6d6e0..a37128431155 100644
--- a/drivers/misc/sgi-gru/grukservices.c
+++ b/drivers/misc/sgi-gru/grukservices.c
@@ -52,8 +52,10 @@
52 */ 52 */
53 53
54/* Blade percpu resources PERMANENTLY reserved for kernel use */ 54/* Blade percpu resources PERMANENTLY reserved for kernel use */
55#define GRU_NUM_KERNEL_CBR 1 55#define GRU_NUM_KERNEL_CBR 1
56#define GRU_NUM_KERNEL_DSR_BYTES 256 56#define GRU_NUM_KERNEL_DSR_BYTES 256
57#define GRU_NUM_KERNEL_DSR_CL (GRU_NUM_KERNEL_DSR_BYTES / \
58 GRU_CACHE_LINE_BYTES)
57#define KERNEL_CTXNUM 15 59#define KERNEL_CTXNUM 15
58 60
59/* GRU instruction attributes for all instructions */ 61/* GRU instruction attributes for all instructions */
@@ -94,7 +96,6 @@ struct message_header {
94 char fill; 96 char fill;
95}; 97};
96 98
97#define QLINES(mq) ((mq) + offsetof(struct message_queue, qlines))
98#define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h])) 99#define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h]))
99 100
100static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr) 101static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr)
@@ -250,7 +251,8 @@ static inline void restore_present2(void *p, int val)
250 * Create a message queue. 251 * Create a message queue.
251 * qlines - message queue size in cache lines. Includes 2-line header. 252 * qlines - message queue size in cache lines. Includes 2-line header.
252 */ 253 */
253int gru_create_message_queue(void *p, unsigned int bytes) 254int gru_create_message_queue(struct gru_message_queue_desc *mqd,
255 void *p, unsigned int bytes, int nasid, int vector, int apicid)
254{ 256{
255 struct message_queue *mq = p; 257 struct message_queue *mq = p;
256 unsigned int qlines; 258 unsigned int qlines;
@@ -265,6 +267,12 @@ int gru_create_message_queue(void *p, unsigned int bytes)
265 mq->hstatus[0] = 0; 267 mq->hstatus[0] = 0;
266 mq->hstatus[1] = 1; 268 mq->hstatus[1] = 1;
267 mq->head = gru_mesq_head(2, qlines / 2 + 1); 269 mq->head = gru_mesq_head(2, qlines / 2 + 1);
270 mqd->mq = mq;
271 mqd->mq_gpa = uv_gpa(mq);
272 mqd->qlines = qlines;
273 mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid);
274 mqd->interrupt_vector = vector;
275 mqd->interrupt_apicid = apicid;
268 return 0; 276 return 0;
269} 277}
270EXPORT_SYMBOL_GPL(gru_create_message_queue); 278EXPORT_SYMBOL_GPL(gru_create_message_queue);
@@ -277,8 +285,8 @@ EXPORT_SYMBOL_GPL(gru_create_message_queue);
277 * -1 - if mesq sent successfully but queue not full 285 * -1 - if mesq sent successfully but queue not full
278 * >0 - unexpected error. MQE_xxx returned 286 * >0 - unexpected error. MQE_xxx returned
279 */ 287 */
280static int send_noop_message(void *cb, 288static int send_noop_message(void *cb, struct gru_message_queue_desc *mqd,
281 unsigned long mq, void *mesg) 289 void *mesg)
282{ 290{
283 const struct message_header noop_header = { 291 const struct message_header noop_header = {
284 .present = MQS_NOOP, .lines = 1}; 292 .present = MQS_NOOP, .lines = 1};
@@ -289,7 +297,7 @@ static int send_noop_message(void *cb,
289 STAT(mesq_noop); 297 STAT(mesq_noop);
290 save_mhdr = *mhdr; 298 save_mhdr = *mhdr;
291 *mhdr = noop_header; 299 *mhdr = noop_header;
292 gru_mesq(cb, mq, gru_get_tri(mhdr), 1, IMA); 300 gru_mesq(cb, mqd->mq_gpa, gru_get_tri(mhdr), 1, IMA);
293 ret = gru_wait(cb); 301 ret = gru_wait(cb);
294 302
295 if (ret) { 303 if (ret) {
@@ -313,7 +321,7 @@ static int send_noop_message(void *cb,
313 break; 321 break;
314 case CBSS_PUT_NACKED: 322 case CBSS_PUT_NACKED:
315 STAT(mesq_noop_put_nacked); 323 STAT(mesq_noop_put_nacked);
316 m = mq + (gru_get_amo_value_head(cb) << 6); 324 m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
317 gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, 1, 1, 325 gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, 1, 1,
318 IMA); 326 IMA);
319 if (gru_wait(cb) == CBS_IDLE) 327 if (gru_wait(cb) == CBS_IDLE)
@@ -333,30 +341,20 @@ static int send_noop_message(void *cb,
333/* 341/*
334 * Handle a gru_mesq full. 342 * Handle a gru_mesq full.
335 */ 343 */
336static int send_message_queue_full(void *cb, 344static int send_message_queue_full(void *cb, struct gru_message_queue_desc *mqd,
337 unsigned long mq, void *mesg, int lines) 345 void *mesg, int lines)
338{ 346{
339 union gru_mesqhead mqh; 347 union gru_mesqhead mqh;
340 unsigned int limit, head; 348 unsigned int limit, head;
341 unsigned long avalue; 349 unsigned long avalue;
342 int half, qlines, save; 350 int half, qlines;
343 351
344 /* Determine if switching to first/second half of q */ 352 /* Determine if switching to first/second half of q */
345 avalue = gru_get_amo_value(cb); 353 avalue = gru_get_amo_value(cb);
346 head = gru_get_amo_value_head(cb); 354 head = gru_get_amo_value_head(cb);
347 limit = gru_get_amo_value_limit(cb); 355 limit = gru_get_amo_value_limit(cb);
348 356
349 /* 357 qlines = mqd->qlines;
350 * Fetch "qlines" from the queue header. Since the queue may be
351 * in memory that can't be accessed using socket addresses, use
352 * the GRU to access the data. Use DSR space from the message.
353 */
354 save = *(int *)mesg;
355 gru_vload(cb, QLINES(mq), gru_get_tri(mesg), XTYPE_W, 1, 1, IMA);
356 if (gru_wait(cb) != CBS_IDLE)
357 goto cberr;
358 qlines = *(int *)mesg;
359 *(int *)mesg = save;
360 half = (limit != qlines); 358 half = (limit != qlines);
361 359
362 if (half) 360 if (half)
@@ -365,7 +363,7 @@ static int send_message_queue_full(void *cb,
365 mqh = gru_mesq_head(2, qlines / 2 + 1); 363 mqh = gru_mesq_head(2, qlines / 2 + 1);
366 364
367 /* Try to get lock for switching head pointer */ 365 /* Try to get lock for switching head pointer */
368 gru_gamir(cb, EOP_IR_CLR, HSTATUS(mq, half), XTYPE_DW, IMA); 366 gru_gamir(cb, EOP_IR_CLR, HSTATUS(mqd->mq_gpa, half), XTYPE_DW, IMA);
369 if (gru_wait(cb) != CBS_IDLE) 367 if (gru_wait(cb) != CBS_IDLE)
370 goto cberr; 368 goto cberr;
371 if (!gru_get_amo_value(cb)) { 369 if (!gru_get_amo_value(cb)) {
@@ -375,8 +373,8 @@ static int send_message_queue_full(void *cb,
375 373
376 /* Got the lock. Send optional NOP if queue not full, */ 374 /* Got the lock. Send optional NOP if queue not full, */
377 if (head != limit) { 375 if (head != limit) {
378 if (send_noop_message(cb, mq, mesg)) { 376 if (send_noop_message(cb, mqd, mesg)) {
379 gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), 377 gru_gamir(cb, EOP_IR_INC, HSTATUS(mqd->mq_gpa, half),
380 XTYPE_DW, IMA); 378 XTYPE_DW, IMA);
381 if (gru_wait(cb) != CBS_IDLE) 379 if (gru_wait(cb) != CBS_IDLE)
382 goto cberr; 380 goto cberr;
@@ -387,14 +385,16 @@ static int send_message_queue_full(void *cb,
387 } 385 }
388 386
389 /* Then flip queuehead to other half of queue. */ 387 /* Then flip queuehead to other half of queue. */
390 gru_gamer(cb, EOP_ERR_CSWAP, mq, XTYPE_DW, mqh.val, avalue, IMA); 388 gru_gamer(cb, EOP_ERR_CSWAP, mqd->mq_gpa, XTYPE_DW, mqh.val, avalue,
389 IMA);
391 if (gru_wait(cb) != CBS_IDLE) 390 if (gru_wait(cb) != CBS_IDLE)
392 goto cberr; 391 goto cberr;
393 392
394 /* If not successfully in swapping queue head, clear the hstatus lock */ 393 /* If not successfully in swapping queue head, clear the hstatus lock */
395 if (gru_get_amo_value(cb) != avalue) { 394 if (gru_get_amo_value(cb) != avalue) {
396 STAT(mesq_qf_switch_head_failed); 395 STAT(mesq_qf_switch_head_failed);
397 gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), XTYPE_DW, IMA); 396 gru_gamir(cb, EOP_IR_INC, HSTATUS(mqd->mq_gpa, half), XTYPE_DW,
397 IMA);
398 if (gru_wait(cb) != CBS_IDLE) 398 if (gru_wait(cb) != CBS_IDLE)
399 goto cberr; 399 goto cberr;
400 } 400 }
@@ -404,15 +404,25 @@ cberr:
404 return MQE_UNEXPECTED_CB_ERR; 404 return MQE_UNEXPECTED_CB_ERR;
405} 405}
406 406
407/*
408 * Send a cross-partition interrupt to the SSI that contains the target
409 * message queue. Normally, the interrupt is automatically delivered by hardware
410 * but some error conditions require explicit delivery.
411 */
412static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd)
413{
414 if (mqd->interrupt_vector)
415 uv_hub_send_ipi(mqd->interrupt_pnode, mqd->interrupt_apicid,
416 mqd->interrupt_vector);
417}
418
407 419
408/* 420/*
409 * Handle a gru_mesq failure. Some of these failures are software recoverable 421 * Handle a gru_mesq failure. Some of these failures are software recoverable
410 * or retryable. 422 * or retryable.
411 */ 423 */
412static int send_message_failure(void *cb, 424static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd,
413 unsigned long mq, 425 void *mesg, int lines)
414 void *mesg,
415 int lines)
416{ 426{
417 int substatus, ret = 0; 427 int substatus, ret = 0;
418 unsigned long m; 428 unsigned long m;
@@ -429,7 +439,7 @@ static int send_message_failure(void *cb,
429 break; 439 break;
430 case CBSS_QLIMIT_REACHED: 440 case CBSS_QLIMIT_REACHED:
431 STAT(mesq_send_qlimit_reached); 441 STAT(mesq_send_qlimit_reached);
432 ret = send_message_queue_full(cb, mq, mesg, lines); 442 ret = send_message_queue_full(cb, mqd, mesg, lines);
433 break; 443 break;
434 case CBSS_AMO_NACKED: 444 case CBSS_AMO_NACKED:
435 STAT(mesq_send_amo_nacked); 445 STAT(mesq_send_amo_nacked);
@@ -437,12 +447,14 @@ static int send_message_failure(void *cb,
437 break; 447 break;
438 case CBSS_PUT_NACKED: 448 case CBSS_PUT_NACKED:
439 STAT(mesq_send_put_nacked); 449 STAT(mesq_send_put_nacked);
440 m = mq + (gru_get_amo_value_head(cb) << 6); 450 m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
441 gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA); 451 gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA);
442 if (gru_wait(cb) == CBS_IDLE) 452 if (gru_wait(cb) == CBS_IDLE) {
443 ret = MQE_OK; 453 ret = MQE_OK;
444 else 454 send_message_queue_interrupt(mqd);
455 } else {
445 ret = MQE_UNEXPECTED_CB_ERR; 456 ret = MQE_UNEXPECTED_CB_ERR;
457 }
446 break; 458 break;
447 default: 459 default:
448 BUG(); 460 BUG();
@@ -452,12 +464,12 @@ static int send_message_failure(void *cb,
452 464
453/* 465/*
454 * Send a message to a message queue 466 * Send a message to a message queue
455 * cb GRU control block to use to send message 467 * mqd message queue descriptor
456 * mq message queue
457 * mesg message. ust be vaddr within a GSEG 468 * mesg message. ust be vaddr within a GSEG
458 * bytes message size (<= 2 CL) 469 * bytes message size (<= 2 CL)
459 */ 470 */
460int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes) 471int gru_send_message_gpa(struct gru_message_queue_desc *mqd, void *mesg,
472 unsigned int bytes)
461{ 473{
462 struct message_header *mhdr; 474 struct message_header *mhdr;
463 void *cb; 475 void *cb;
@@ -481,10 +493,10 @@ int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes)
481 493
482 do { 494 do {
483 ret = MQE_OK; 495 ret = MQE_OK;
484 gru_mesq(cb, mq, gru_get_tri(mhdr), clines, IMA); 496 gru_mesq(cb, mqd->mq_gpa, gru_get_tri(mhdr), clines, IMA);
485 istatus = gru_wait(cb); 497 istatus = gru_wait(cb);
486 if (istatus != CBS_IDLE) 498 if (istatus != CBS_IDLE)
487 ret = send_message_failure(cb, mq, dsr, clines); 499 ret = send_message_failure(cb, mqd, dsr, clines);
488 } while (ret == MQIE_AGAIN); 500 } while (ret == MQIE_AGAIN);
489 gru_free_cpu_resources(cb, dsr); 501 gru_free_cpu_resources(cb, dsr);
490 502
@@ -497,9 +509,9 @@ EXPORT_SYMBOL_GPL(gru_send_message_gpa);
497/* 509/*
498 * Advance the receive pointer for the queue to the next message. 510 * Advance the receive pointer for the queue to the next message.
499 */ 511 */
500void gru_free_message(void *rmq, void *mesg) 512void gru_free_message(struct gru_message_queue_desc *mqd, void *mesg)
501{ 513{
502 struct message_queue *mq = rmq; 514 struct message_queue *mq = mqd->mq;
503 struct message_header *mhdr = mq->next; 515 struct message_header *mhdr = mq->next;
504 void *next, *pnext; 516 void *next, *pnext;
505 int half = -1; 517 int half = -1;
@@ -529,16 +541,16 @@ EXPORT_SYMBOL_GPL(gru_free_message);
529 * present. User must call next_message() to move to next message. 541 * present. User must call next_message() to move to next message.
530 * rmq message queue 542 * rmq message queue
531 */ 543 */
532void *gru_get_next_message(void *rmq) 544void *gru_get_next_message(struct gru_message_queue_desc *mqd)
533{ 545{
534 struct message_queue *mq = rmq; 546 struct message_queue *mq = mqd->mq;
535 struct message_header *mhdr = mq->next; 547 struct message_header *mhdr = mq->next;
536 int present = mhdr->present; 548 int present = mhdr->present;
537 549
538 /* skip NOOP messages */ 550 /* skip NOOP messages */
539 STAT(mesq_receive); 551 STAT(mesq_receive);
540 while (present == MQS_NOOP) { 552 while (present == MQS_NOOP) {
541 gru_free_message(rmq, mhdr); 553 gru_free_message(mqd, mhdr);
542 mhdr = mq->next; 554 mhdr = mq->next;
543 present = mhdr->present; 555 present = mhdr->present;
544 } 556 }
@@ -576,7 +588,7 @@ int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa,
576 if (gru_get_cpu_resources(GRU_NUM_KERNEL_DSR_BYTES, &cb, &dsr)) 588 if (gru_get_cpu_resources(GRU_NUM_KERNEL_DSR_BYTES, &cb, &dsr))
577 return MQE_BUG_NO_RESOURCES; 589 return MQE_BUG_NO_RESOURCES;
578 gru_bcopy(cb, src_gpa, dest_gpa, gru_get_tri(dsr), 590 gru_bcopy(cb, src_gpa, dest_gpa, gru_get_tri(dsr),
579 XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_BYTES, IMA); 591 XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_CL, IMA);
580 ret = gru_wait(cb); 592 ret = gru_wait(cb);
581 gru_free_cpu_resources(cb, dsr); 593 gru_free_cpu_resources(cb, dsr);
582 return ret; 594 return ret;
@@ -611,7 +623,7 @@ static int quicktest(struct gru_state *gru)
611 623
612 if (word0 != word1 || word0 != MAGIC) { 624 if (word0 != word1 || word0 != MAGIC) {
613 printk 625 printk
614 ("GRU quicktest err: gru %d, found 0x%lx, expected 0x%lx\n", 626 ("GRU quicktest err: gid %d, found 0x%lx, expected 0x%lx\n",
615 gru->gs_gid, word1, MAGIC); 627 gru->gs_gid, word1, MAGIC);
616 BUG(); /* ZZZ should not be fatal */ 628 BUG(); /* ZZZ should not be fatal */
617 } 629 }
diff --git a/drivers/misc/sgi-gru/grukservices.h b/drivers/misc/sgi-gru/grukservices.h
index eb17e0a3ac61..747ed315d56f 100644
--- a/drivers/misc/sgi-gru/grukservices.h
+++ b/drivers/misc/sgi-gru/grukservices.h
@@ -41,6 +41,15 @@
41 * - gru_create_message_queue() needs interrupt vector info 41 * - gru_create_message_queue() needs interrupt vector info
42 */ 42 */
43 43
44struct gru_message_queue_desc {
45 void *mq; /* message queue vaddress */
46 unsigned long mq_gpa; /* global address of mq */
47 int qlines; /* queue size in CL */
48 int interrupt_vector; /* interrupt vector */
49 int interrupt_pnode; /* pnode for interrupt */
50 int interrupt_apicid; /* lapicid for interrupt */
51};
52
44/* 53/*
45 * Initialize a user allocated chunk of memory to be used as 54 * Initialize a user allocated chunk of memory to be used as
46 * a message queue. The caller must ensure that the queue is 55 * a message queue. The caller must ensure that the queue is
@@ -51,14 +60,19 @@
51 * to manage the queue. 60 * to manage the queue.
52 * 61 *
53 * Input: 62 * Input:
54 * p pointer to user allocated memory. 63 * mqd pointer to message queue descriptor
64 * p pointer to user allocated mesq memory.
55 * bytes size of message queue in bytes 65 * bytes size of message queue in bytes
66 * vector interrupt vector (zero if no interrupts)
67 * nasid nasid of blade where interrupt is delivered
68 * apicid apicid of cpu for interrupt
56 * 69 *
57 * Errors: 70 * Errors:
58 * 0 OK 71 * 0 OK
59 * >0 error 72 * >0 error
60 */ 73 */
61extern int gru_create_message_queue(void *p, unsigned int bytes); 74extern int gru_create_message_queue(struct gru_message_queue_desc *mqd,
75 void *p, unsigned int bytes, int nasid, int vector, int apicid);
62 76
63/* 77/*
64 * Send a message to a message queue. 78 * Send a message to a message queue.
@@ -68,7 +82,7 @@ extern int gru_create_message_queue(void *p, unsigned int bytes);
68 * 82 *
69 * 83 *
70 * Input: 84 * Input:
71 * xmq message queue - must be a UV global physical address 85 * mqd pointer to message queue descriptor
72 * mesg pointer to message. Must be 64-bit aligned 86 * mesg pointer to message. Must be 64-bit aligned
73 * bytes size of message in bytes 87 * bytes size of message in bytes
74 * 88 *
@@ -77,8 +91,8 @@ extern int gru_create_message_queue(void *p, unsigned int bytes);
77 * >0 Send failure - see error codes below 91 * >0 Send failure - see error codes below
78 * 92 *
79 */ 93 */
80extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg, 94extern int gru_send_message_gpa(struct gru_message_queue_desc *mqd,
81 unsigned int bytes); 95 void *mesg, unsigned int bytes);
82 96
83/* Status values for gru_send_message() */ 97/* Status values for gru_send_message() */
84#define MQE_OK 0 /* message sent successfully */ 98#define MQE_OK 0 /* message sent successfully */
@@ -94,10 +108,11 @@ extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg,
94 * API extensions may allow for out-of-order freeing. 108 * API extensions may allow for out-of-order freeing.
95 * 109 *
96 * Input 110 * Input
97 * mq message queue 111 * mqd pointer to message queue descriptor
98 * mesq message being freed 112 * mesq message being freed
99 */ 113 */
100extern void gru_free_message(void *mq, void *mesq); 114extern void gru_free_message(struct gru_message_queue_desc *mqd,
115 void *mesq);
101 116
102/* 117/*
103 * Get next message from message queue. Returns pointer to 118 * Get next message from message queue. Returns pointer to
@@ -106,13 +121,13 @@ extern void gru_free_message(void *mq, void *mesq);
106 * in order to move the queue pointers to next message. 121 * in order to move the queue pointers to next message.
107 * 122 *
108 * Input 123 * Input
109 * mq message queue 124 * mqd pointer to message queue descriptor
110 * 125 *
111 * Output: 126 * Output:
112 * p pointer to message 127 * p pointer to message
113 * NULL no message available 128 * NULL no message available
114 */ 129 */
115extern void *gru_get_next_message(void *mq); 130extern void *gru_get_next_message(struct gru_message_queue_desc *mqd);
116 131
117 132
118/* 133/*