aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorJack Steiner <steiner@sgi.com>2009-12-15 19:48:21 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 10:20:17 -0500
commit76148df19cbd5437dc5358408a58c7cc6366ecf4 (patch)
treed592f1c21d072d9cefbf18f27081dca05ea655db /drivers/misc
parent56abcf24ff993291b20efd6e3402cd3d12f5cee2 (diff)
gru: send cross partition interrupts using the gru
GRU Message queue instructions are used to deliver messages to other SSIs within the numalink domain. In most cases, a single GRU mesq instruction will deliver both the message AND an interrupt to notify the other SSI that a messsage is present. In some cases, however, the interrupt must be sent explicitly. To improve resilency, the GRU driver should send these explicit interrupts using the GRU to write the remote chipset register. Current code sends the interrupt using a cpu instruction to write the chipset register. 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/gru_instructions.h12
-rw-r--r--drivers/misc/sgi-gru/grukservices.c39
2 files changed, 36 insertions, 15 deletions
diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h
index 848c7a8f02be..d95587cc794c 100644
--- a/drivers/misc/sgi-gru/gru_instructions.h
+++ b/drivers/misc/sgi-gru/gru_instructions.h
@@ -367,6 +367,18 @@ static inline void gru_vload_phys(void *cb, unsigned long gpa,
367 (unsigned long)tri0, CB_IMA(hints))); 367 (unsigned long)tri0, CB_IMA(hints)));
368} 368}
369 369
370static inline void gru_vstore_phys(void *cb, unsigned long gpa,
371 unsigned int tri0, int iaa, unsigned long hints)
372{
373 struct gru_instruction *ins = (struct gru_instruction *)cb;
374
375 ins->baddr0 = (long)gpa | ((unsigned long)iaa << 62);
376 ins->nelem = 1;
377 ins->op1_stride = 1;
378 gru_start_instruction(ins, __opdword(OP_VSTORE, 0, XTYPE_DW, iaa, 0,
379 (unsigned long)tri0, CB_IMA(hints)));
380}
381
370static inline void gru_vload(void *cb, unsigned long mem_addr, 382static inline void gru_vload(void *cb, unsigned long mem_addr,
371 unsigned int tri0, unsigned char xtype, unsigned long nelem, 383 unsigned int tri0, unsigned char xtype, unsigned long nelem,
372 unsigned long stride, unsigned long hints) 384 unsigned long stride, unsigned long hints)
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c
index bfbf8fdbcd37..34749ee88dfa 100644
--- a/drivers/misc/sgi-gru/grukservices.c
+++ b/drivers/misc/sgi-gru/grukservices.c
@@ -31,6 +31,7 @@
31#include <linux/interrupt.h> 31#include <linux/interrupt.h>
32#include <linux/uaccess.h> 32#include <linux/uaccess.h>
33#include <linux/delay.h> 33#include <linux/delay.h>
34#include <asm/io_apic.h>
34#include "gru.h" 35#include "gru.h"
35#include "grulib.h" 36#include "grulib.h"
36#include "grutables.h" 37#include "grutables.h"
@@ -566,7 +567,7 @@ int gru_create_message_queue(struct gru_message_queue_desc *mqd,
566 mqd->mq = mq; 567 mqd->mq = mq;
567 mqd->mq_gpa = uv_gpa(mq); 568 mqd->mq_gpa = uv_gpa(mq);
568 mqd->qlines = qlines; 569 mqd->qlines = qlines;
569 mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid); 570 mqd->interrupt_pnode = nasid >> 1;
570 mqd->interrupt_vector = vector; 571 mqd->interrupt_vector = vector;
571 mqd->interrupt_apicid = apicid; 572 mqd->interrupt_apicid = apicid;
572 return 0; 573 return 0;
@@ -703,18 +704,6 @@ cberr:
703} 704}
704 705
705/* 706/*
706 * Send a cross-partition interrupt to the SSI that contains the target
707 * message queue. Normally, the interrupt is automatically delivered by hardware
708 * but some error conditions require explicit delivery.
709 */
710static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd)
711{
712 if (mqd->interrupt_vector)
713 uv_hub_send_ipi(mqd->interrupt_pnode, mqd->interrupt_apicid,
714 mqd->interrupt_vector);
715}
716
717/*
718 * Handle a PUT failure. Note: if message was a 2-line message, one of the 707 * Handle a PUT failure. Note: if message was a 2-line message, one of the
719 * lines might have successfully have been written. Before sending the 708 * lines might have successfully have been written. Before sending the
720 * message, "present" must be cleared in BOTH lines to prevent the receiver 709 * message, "present" must be cleared in BOTH lines to prevent the receiver
@@ -723,7 +712,8 @@ static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd)
723static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd, 712static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd,
724 void *mesg, int lines) 713 void *mesg, int lines)
725{ 714{
726 unsigned long m; 715 unsigned long m, *val = mesg, gpa, save;
716 int ret;
727 717
728 m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6); 718 m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
729 if (lines == 2) { 719 if (lines == 2) {
@@ -734,7 +724,26 @@ static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd,
734 gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA); 724 gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA);
735 if (gru_wait(cb) != CBS_IDLE) 725 if (gru_wait(cb) != CBS_IDLE)
736 return MQE_UNEXPECTED_CB_ERR; 726 return MQE_UNEXPECTED_CB_ERR;
737 send_message_queue_interrupt(mqd); 727
728 if (!mqd->interrupt_vector)
729 return MQE_OK;
730
731 /*
732 * Send a cross-partition interrupt to the SSI that contains the target
733 * message queue. Normally, the interrupt is automatically delivered by
734 * hardware but some error conditions require explicit delivery.
735 * Use the GRU to deliver the interrupt. Otherwise partition failures
736 * could cause unrecovered errors.
737 */
738 gpa = uv_global_gru_mmr_address(mqd->interrupt_pnode, UVH_IPI_INT);
739 save = *val;
740 *val = uv_hub_ipi_value(mqd->interrupt_apicid, mqd->interrupt_vector,
741 dest_Fixed);
742 gru_vstore_phys(cb, gpa, gru_get_tri(mesg), IAA_REGISTER, IMA);
743 ret = gru_wait(cb);
744 *val = save;
745 if (ret != CBS_IDLE)
746 return MQE_UNEXPECTED_CB_ERR;
738 return MQE_OK; 747 return MQE_OK;
739} 748}
740 749