diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/sgi-gru/gru_instructions.h | 12 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grukservices.c | 39 |
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 | ||
370 | static 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 | |||
370 | static inline void gru_vload(void *cb, unsigned long mem_addr, | 382 | static 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 | */ | ||
710 | static 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) | |||
723 | static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd, | 712 | static 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 | ||