* [Patch 0/2] GRU - GRU Updates - GRU Update for cross SSI interrupts
@ 2009-12-03 22:34 steiner
2009-12-03 22:34 ` [Patch 1/2] GRU - function to generate chipset IPI values steiner
2009-12-03 22:34 ` [Patch 2/2] GRU - send cross partition interrupts using the gru steiner
0 siblings, 2 replies; 5+ messages in thread
From: steiner @ 2009-12-03 22:34 UTC (permalink / raw)
To: akpm, linux-kernel
This patchset contains two patches to the GRU driver for
sending interrupts to other SSIs in the numalink domain.
No changes are made to non-UV files.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [Patch 1/2] GRU - function to generate chipset IPI values
2009-12-03 22:34 [Patch 0/2] GRU - GRU Updates - GRU Update for cross SSI interrupts steiner
@ 2009-12-03 22:34 ` steiner
2009-12-03 23:19 ` Andrew Morton
2009-12-03 22:34 ` [Patch 2/2] GRU - send cross partition interrupts using the gru steiner
1 sibling, 1 reply; 5+ messages in thread
From: steiner @ 2009-12-03 22:34 UTC (permalink / raw)
To: akpm, linux-kernel
[-- Attachment #1: uv_ipi_macro --]
[-- Type: text/plain, Size: 2274 bytes --]
From: Jack Steiner <steiner@sgi.com>
Create a function to generate the value that is written to the UV hub
MMR to cause an IPI interrupt to be sent. The function will be
used in the GRU message queue error recovery code that sends IPIs to
nodes in remote partitions.
Signed-off-by: Jack Steiner <steiner@sgi.com>
---
arch/x86/include/asm/uv/uv_hub.h | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
Index: linux/arch/x86/include/asm/uv/uv_hub.h
===================================================================
--- linux.orig/arch/x86/include/asm/uv/uv_hub.h 2009-12-03 07:36:31.000000000 -0600
+++ linux/arch/x86/include/asm/uv/uv_hub.h 2009-12-03 07:52:04.000000000 -0600
@@ -172,6 +172,8 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __
#define UV_LOCAL_MMR_SIZE (64UL * 1024 * 1024)
#define UV_GLOBAL_MMR32_SIZE (64UL * 1024 * 1024)
+#define UV_GLOBAL_GRU_MMR_BASE 0x4000000
+
#define UV_GLOBAL_MMR32_PNODE_SHIFT 15
#define UV_GLOBAL_MMR64_PNODE_SHIFT 26
@@ -308,6 +310,15 @@ static inline unsigned long uv_read_glob
}
/*
+ * Global MMR space addresses when referenced by the GRU. (GRU does
+ * NOT use socket addressing).
+ */
+static inline unsigned long uv_global_gru_mmr_address(int pnode, unsigned long offset)
+{
+ return UV_GLOBAL_GRU_MMR_BASE | offset | (pnode << uv_hub_info->m_val);
+}
+
+/*
* Access hub local MMRs. Faster than using global space but only local MMRs
* are accessible.
*/
@@ -434,6 +445,14 @@ static inline void uv_set_cpu_scir_bits(
}
}
+static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode)
+{
+ return (1UL << UVH_IPI_INT_SEND_SHFT) |
+ ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
+ (mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) |
+ (vector << UVH_IPI_INT_VECTOR_SHFT);
+}
+
static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
{
unsigned long val;
@@ -442,10 +461,7 @@ static inline void uv_hub_send_ipi(int p
if (vector == NMI_VECTOR)
dmode = dest_NMI;
- val = (1UL << UVH_IPI_INT_SEND_SHFT) |
- ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
- (dmode << UVH_IPI_INT_DELIVERY_MODE_SHFT) |
- (vector << UVH_IPI_INT_VECTOR_SHFT);
+ val = uv_hub_ipi_value(apicid, vector, dmode);
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
}
^ permalink raw reply [flat|nested] 5+ messages in thread
* [Patch 2/2] GRU - send cross partition interrupts using the gru
2009-12-03 22:34 [Patch 0/2] GRU - GRU Updates - GRU Update for cross SSI interrupts steiner
2009-12-03 22:34 ` [Patch 1/2] GRU - function to generate chipset IPI values steiner
@ 2009-12-03 22:34 ` steiner
1 sibling, 0 replies; 5+ messages in thread
From: steiner @ 2009-12-03 22:34 UTC (permalink / raw)
To: akpm, linux-kernel
[-- Attachment #1: uv_gru_message_queue_ipi --]
[-- Type: text/plain, Size: 4552 bytes --]
From: Jack Steiner <steiner@sgi.com>
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>
---
drivers/misc/sgi-gru/gru_instructions.h | 12 +++++++++
drivers/misc/sgi-gru/grukservices.c | 39 +++++++++++++++++++-------------
2 files changed, 36 insertions(+), 15 deletions(-)
Index: linux/drivers/misc/sgi-gru/gru_instructions.h
===================================================================
--- linux.orig/drivers/misc/sgi-gru/gru_instructions.h 2009-12-03 09:46:53.000000000 -0600
+++ linux/drivers/misc/sgi-gru/gru_instructions.h 2009-12-03 09:47:17.000000000 -0600
@@ -367,6 +367,18 @@ static inline void gru_vload_phys(void *
(unsigned long)tri0, CB_IMA(hints)));
}
+static inline void gru_vstore_phys(void *cb, unsigned long gpa,
+ unsigned int tri0, int iaa, unsigned long hints)
+{
+ struct gru_instruction *ins = (struct gru_instruction *)cb;
+
+ ins->baddr0 = (long)gpa | ((unsigned long)iaa << 62);
+ ins->nelem = 1;
+ ins->op1_stride = 1;
+ gru_start_instruction(ins, __opdword(OP_VSTORE, 0, XTYPE_DW, iaa, 0,
+ (unsigned long)tri0, CB_IMA(hints)));
+}
+
static inline void gru_vload(void *cb, unsigned long mem_addr,
unsigned int tri0, unsigned char xtype, unsigned long nelem,
unsigned long stride, unsigned long hints)
Index: linux/drivers/misc/sgi-gru/grukservices.c
===================================================================
--- linux.orig/drivers/misc/sgi-gru/grukservices.c 2009-12-03 09:46:53.000000000 -0600
+++ linux/drivers/misc/sgi-gru/grukservices.c 2009-12-03 09:46:57.000000000 -0600
@@ -31,6 +31,7 @@
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
+#include <asm/io_apic.h>
#include "gru.h"
#include "grulib.h"
#include "grutables.h"
@@ -566,7 +567,7 @@ int gru_create_message_queue(struct gru_
mqd->mq = mq;
mqd->mq_gpa = uv_gpa(mq);
mqd->qlines = qlines;
- mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid);
+ mqd->interrupt_pnode = nasid >> 1;
mqd->interrupt_vector = vector;
mqd->interrupt_apicid = apicid;
return 0;
@@ -703,18 +704,6 @@ cberr:
}
/*
- * Send a cross-partition interrupt to the SSI that contains the target
- * message queue. Normally, the interrupt is automatically delivered by hardware
- * but some error conditions require explicit delivery.
- */
-static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd)
-{
- if (mqd->interrupt_vector)
- uv_hub_send_ipi(mqd->interrupt_pnode, mqd->interrupt_apicid,
- mqd->interrupt_vector);
-}
-
-/*
* Handle a PUT failure. Note: if message was a 2-line message, one of the
* lines might have successfully have been written. Before sending the
* message, "present" must be cleared in BOTH lines to prevent the receiver
@@ -723,7 +712,8 @@ static void send_message_queue_interrupt
static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd,
void *mesg, int lines)
{
- unsigned long m;
+ unsigned long m, *val = mesg, gpa, save;
+ int ret;
m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
if (lines == 2) {
@@ -734,7 +724,26 @@ static int send_message_put_nacked(void
gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA);
if (gru_wait(cb) != CBS_IDLE)
return MQE_UNEXPECTED_CB_ERR;
- send_message_queue_interrupt(mqd);
+
+ if (!mqd->interrupt_vector)
+ return MQE_OK;
+
+ /*
+ * Send a cross-partition interrupt to the SSI that contains the target
+ * message queue. Normally, the interrupt is automatically delivered by
+ * hardware but some error conditions require explicit delivery.
+ * Use the GRU to deliver the interrupt. Otherwise partition failures
+ * could cause unrecovered errors.
+ */
+ gpa = uv_global_gru_mmr_address(mqd->interrupt_pnode, UVH_IPI_INT);
+ save = *val;
+ *val = uv_hub_ipi_value(mqd->interrupt_apicid, mqd->interrupt_vector,
+ dest_Fixed);
+ gru_vstore_phys(cb, gpa, gru_get_tri(mesg), IAA_REGISTER, IMA);
+ ret = gru_wait(cb);
+ *val = save;
+ if (ret != CBS_IDLE)
+ return MQE_UNEXPECTED_CB_ERR;
return MQE_OK;
}
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Patch 1/2] GRU - function to generate chipset IPI values
2009-12-03 22:34 ` [Patch 1/2] GRU - function to generate chipset IPI values steiner
@ 2009-12-03 23:19 ` Andrew Morton
2009-12-03 23:31 ` Jack Steiner
0 siblings, 1 reply; 5+ messages in thread
From: Andrew Morton @ 2009-12-03 23:19 UTC (permalink / raw)
To: steiner; +Cc: linux-kernel
On Thu, 03 Dec 2009 16:34:15 -0600
steiner@sgi.com wrote:
> From: Jack Steiner <steiner@sgi.com>
>
> Create a function to generate the value that is written to the UV hub
> MMR to cause an IPI interrupt to be sent. The function will be
> used in the GRU message queue error recovery code that sends IPIs to
> nodes in remote partitions.
>
> ...
>
> +static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode)
> +{
> + return (1UL << UVH_IPI_INT_SEND_SHFT) |
> + ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
> + (mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) |
> + (vector << UVH_IPI_INT_VECTOR_SHFT);
> +}
You've taken care to avoid a shift overflow of "1", but not of
`apicid', `vector' and `mode'.
Maybe the compiler does that, I forget.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Patch 1/2] GRU - function to generate chipset IPI values
2009-12-03 23:19 ` Andrew Morton
@ 2009-12-03 23:31 ` Jack Steiner
0 siblings, 0 replies; 5+ messages in thread
From: Jack Steiner @ 2009-12-03 23:31 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel
On Thu, Dec 03, 2009 at 03:19:12PM -0800, Andrew Morton wrote:
> On Thu, 03 Dec 2009 16:34:15 -0600
> steiner@sgi.com wrote:
>
> > From: Jack Steiner <steiner@sgi.com>
> >
> > Create a function to generate the value that is written to the UV hub
> > MMR to cause an IPI interrupt to be sent. The function will be
> > used in the GRU message queue error recovery code that sends IPIs to
> > nodes in remote partitions.
> >
> > ...
> >
> > +static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode)
> > +{
> > + return (1UL << UVH_IPI_INT_SEND_SHFT) |
> > + ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
> > + (mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) |
> > + (vector << UVH_IPI_INT_VECTOR_SHFT);
> > +}
>
> You've taken care to avoid a shift overflow of "1", but not of
> `apicid', `vector' and `mode'.
>
> Maybe the compiler does that, I forget.
I sure hate the 32/64 bit issues with shifts of ints. I am bitten by
that more than I'd like.
I think we are ok in this case. In the above code, all of the fields
of the result except bit 63 reside in the low 32 bits of the resulting
unsigned long. I think that makes it work.
--- jack
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-12-03 23:31 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-03 22:34 [Patch 0/2] GRU - GRU Updates - GRU Update for cross SSI interrupts steiner
2009-12-03 22:34 ` [Patch 1/2] GRU - function to generate chipset IPI values steiner
2009-12-03 23:19 ` Andrew Morton
2009-12-03 23:31 ` Jack Steiner
2009-12-03 22:34 ` [Patch 2/2] GRU - send cross partition interrupts using the gru steiner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox