Commit 76148df19cbd5437dc5358408a58c7cc6366ecf4

Authored by Jack Steiner
Committed by Linus Torvalds
1 parent 56abcf24ff

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>

Showing 2 changed files with 36 additions and 15 deletions Side-by-side Diff

drivers/misc/sgi-gru/gru_instructions.h
... ... @@ -367,6 +367,18 @@
367 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 382 static inline void gru_vload(void *cb, unsigned long mem_addr,
371 383 unsigned int tri0, unsigned char xtype, unsigned long nelem,
372 384 unsigned long stride, unsigned long hints)
drivers/misc/sgi-gru/grukservices.c
... ... @@ -31,6 +31,7 @@
31 31 #include <linux/interrupt.h>
32 32 #include <linux/uaccess.h>
33 33 #include <linux/delay.h>
  34 +#include <asm/io_apic.h>
34 35 #include "gru.h"
35 36 #include "grulib.h"
36 37 #include "grutables.h"
... ... @@ -566,7 +567,7 @@
566 567 mqd->mq = mq;
567 568 mqd->mq_gpa = uv_gpa(mq);
568 569 mqd->qlines = qlines;
569   - mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid);
  570 + mqd->interrupt_pnode = nasid >> 1;
570 571 mqd->interrupt_vector = vector;
571 572 mqd->interrupt_apicid = apicid;
572 573 return 0;
... ... @@ -703,18 +704,6 @@
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 707 * Handle a PUT failure. Note: if message was a 2-line message, one of the
719 708 * lines might have successfully have been written. Before sending the
720 709 * message, "present" must be cleared in BOTH lines to prevent the receiver
... ... @@ -723,7 +712,8 @@
723 712 static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd,
724 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 718 m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
729 719 if (lines == 2) {
... ... @@ -734,7 +724,26 @@
734 724 gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA);
735 725 if (gru_wait(cb) != CBS_IDLE)
736 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 747 return MQE_OK;
739 748 }
740 749