2008-07-07 18:53:31

by Dean Nelson

[permalink] [raw]
Subject: [Patch 0/6] sgi-xp: add support for UV systems

This patchset adds most of the necessary code to support XPC/XPNET on a SGI UV
system, and as such is still under development. It compiles cleanly as is on
both x86_64 and IA64. And if brought up on anything but ia64-sn2 will return
an -ENODEV.

This patchset depends on the GRU driver which has recently been submitted.
http://marc.info/?l=linux-kernel&m=121512107123657&w=2


2008-07-07 18:55:08

by Dean Nelson

[permalink] [raw]
Subject: [Patch 1/6] sgi-xp: enable building of XPC/XPNET on x86_64

Get XPC/XPNET to build on x86_64. Trying to modprobe them up on a non-UV or
sn2 system will result in a -ENODEV.

Signed-off-by: Dean Nelson <[email protected]>

---

drivers/misc/Kconfig | 2 -
drivers/misc/sgi-xp/Makefile | 14 ++++++---
drivers/misc/sgi-xp/xp.h | 32 +++++++++++++-------
drivers/misc/sgi-xp/xp_main.c | 10 +++++-
drivers/misc/sgi-xp/xp_sn2.c | 10 ++++++
drivers/misc/sgi-xp/xpc.h | 34 +++++++++-------------
drivers/misc/sgi-xp/xpc_channel.c | 18 +++--------
drivers/misc/sgi-xp/xpc_main.c | 49 ++++++++++++++++----------------
drivers/misc/sgi-xp/xpc_partition.c | 47 +++++++++++++-----------------
drivers/misc/sgi-xp/xpc_sn2.c | 30 ++++++++++++++++---
drivers/misc/sgi-xp/xpc_uv.c | 7 +---
drivers/misc/sgi-xp/xpnet.c | 28 +++++++-----------
12 files changed, 155 insertions(+), 126 deletions(-)

Index: linux/drivers/misc/Kconfig
===================================================================
--- linux.orig/drivers/misc/Kconfig 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/Kconfig 2008-06-24 15:01:41.000000000 -0500
@@ -381,7 +381,7 @@ config ENCLOSURE_SERVICES

config SGI_XP
tristate "Support communication between SGI SSIs"
- depends on IA64_GENERIC || IA64_SGI_SN2
+ depends on IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || (X86_64 && SMP)
select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
---help---
Index: linux/drivers/misc/sgi-xp/xp.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp.h 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp.h 2008-06-27 07:14:16.000000000 -0500
@@ -13,18 +13,17 @@
#ifndef _DRIVERS_MISC_SGIXP_XP_H
#define _DRIVERS_MISC_SGIXP_XP_H

-#include <linux/cache.h>
-#include <linux/hardirq.h>
#include <linux/mutex.h>
-#include <asm/sn/types.h>
+
#ifdef CONFIG_IA64
-#include <asm/sn/arch.h>
+#include <asm/system.h>
+#include <asm/sn/arch.h> /* defines is_shub1() and is_shub2() */
+#define is_shub() ia64_platform_is("sn2")
+#define is_uv() ia64_platform_is("uv")
#endif
-
-#ifdef USE_DBUG_ON
-#define DBUG_ON(condition) BUG_ON(condition)
-#else
-#define DBUG_ON(condition)
+#ifdef CONFIG_X86_64
+#include <asm/genapic.h>
+#define is_uv() is_uv_system()
#endif

#ifndef is_shub1
@@ -36,13 +35,19 @@
#endif

#ifndef is_shub
-#define is_shub() (is_shub1() || is_shub2())
+#define is_shub() 0
#endif

#ifndef is_uv
#define is_uv() 0
#endif

+#ifdef USE_DBUG_ON
+#define DBUG_ON(condition) BUG_ON(condition)
+#else
+#define DBUG_ON(condition)
+#endif
+
/*
* Define the maximum number of partitions the system can possibly support.
* It is based on the maximum number of hardware partitionable regions. The
@@ -200,7 +205,9 @@ enum xp_retval {
xpPayloadTooBig, /* 55: payload too large for message slot */

xpUnsupported, /* 56: unsupported functionality or resource */
- xpUnknownReason /* 57: unknown reason - must be last in enum */
+ xpNeedMoreInfo, /* 57: more info is needed by SAL */
+
+ xpUnknownReason /* 58: unknown reason - must be last in enum */
};

/*
@@ -339,8 +346,11 @@ xpc_partid_to_nasids(short partid, void
}

extern short xp_max_npartitions;
+extern short xp_partition_id;
+extern u8 xp_region_size;

extern enum xp_retval (*xp_remote_memcpy) (void *, const void *, size_t);
+extern int (*xp_cpu_to_nasid) (int);

extern u64 xp_nofault_PIOR_target;
extern int xp_nofault_PIOR(void *);
Index: linux/drivers/misc/sgi-xp/xpc_main.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_main.c 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_main.c 2008-06-27 07:17:31.000000000 -0500
@@ -43,19 +43,13 @@
*
*/

-#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/cache.h>
-#include <linux/interrupt.h>
+#include <linux/sysctl.h>
+#include <linux/device.h>
#include <linux/delay.h>
#include <linux/reboot.h>
-#include <linux/completion.h>
#include <linux/kdebug.h>
#include <linux/kthread.h>
-#include <linux/uaccess.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/sn_sal.h>
#include "xpc.h"

/* define two XPC debug device structures to be used with dev_dbg() et al */
@@ -175,6 +169,8 @@ static struct notifier_block xpc_die_not
.notifier_call = xpc_system_die,
};

+enum xp_retval (*xpc_get_partition_rsvd_page_pa) (u64 buf, u64 *cookie,
+ u64 *paddr, size_t *len);
enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp);
void (*xpc_heartbeat_init) (void);
void (*xpc_heartbeat_exit) (void);
@@ -920,7 +916,8 @@ xpc_die_deactivate(void)
struct xpc_partition *part;
short partid;
int any_engaged;
- long time, printmsg_time, disengage_timeout;
+ long keep_waiting;
+ long wait_to_print;

/* keep xpc_hb_checker thread from doing anything (just in case) */
xpc_exiting = 1;
@@ -937,16 +934,17 @@ xpc_die_deactivate(void)
}
}

- time = rtc_time();
- printmsg_time = time +
- (XPC_DEACTIVATE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second);
- disengage_timeout = time +
- (xpc_disengage_timelimit * sn_rtc_cycles_per_second);
-
/*
* Though we requested that all other partitions deactivate from us,
- * we only wait until they've all disengaged.
+ * we only wait until they've all disengaged or we've reached the
+ * defined timelimit.
+ *
+ * Given that one iteration through the following while-loop takes
+ * approximately 200 microseconds, calculate the #of loops to take
+ * before bailing and the #of loops before printing a waiting message.
*/
+ keep_waiting = xpc_disengage_timelimit * 1000 * 5;
+ wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL * 1000 * 5;

while (1) {
any_engaged = xpc_any_partition_engaged();
@@ -955,8 +953,7 @@ xpc_die_deactivate(void)
break;
}

- time = rtc_time();
- if (time >= disengage_timeout) {
+ if (!keep_waiting--) {
for (partid = 0; partid < xp_max_npartitions;
partid++) {
if (xpc_partition_engaged(partid)) {
@@ -968,15 +965,15 @@ xpc_die_deactivate(void)
break;
}

- if (time >= printmsg_time) {
+ if (!wait_to_print--) {
dev_info(xpc_part, "waiting for remote partitions to "
"deactivate, timeout in %ld seconds\n",
- (disengage_timeout - time) /
- sn_rtc_cycles_per_second);
- printmsg_time = time +
- (XPC_DEACTIVATE_PRINTMSG_INTERVAL *
- sn_rtc_cycles_per_second);
+ keep_waiting / (1000 * 5));
+ wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL *
+ 1000 * 5;
}
+
+ udelay(200);
}
}

@@ -991,6 +988,7 @@ xpc_die_deactivate(void)
static int
xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
{
+#ifdef CONFIG_IA64 /* !!! temporary kludge */
switch (event) {
case DIE_MACHINE_RESTART:
case DIE_MACHINE_HALT:
@@ -1019,6 +1017,9 @@ xpc_system_die(struct notifier_block *nb
xpc_online_heartbeat();
break;
}
+#else
+ xpc_die_deactivate();
+#endif

return NOTIFY_DONE;
}
Index: linux/drivers/misc/sgi-xp/xpc.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc.h 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc.h 2008-06-27 07:06:09.000000000 -0500
@@ -13,17 +13,10 @@
#ifndef _DRIVERS_MISC_SGIXP_XPC_H
#define _DRIVERS_MISC_SGIXP_XPC_H

-#include <linux/interrupt.h>
-#include <linux/sysctl.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
+#include <linux/wait.h>
#include <linux/completion.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/sn/clksupport.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/mspec.h>
-#include <asm/sn/shub_mmr.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
#include "xp.h"

/*
@@ -179,7 +172,8 @@ struct xpc_vars_part_sn2 {
#define XPC_RP_HEADER_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page))
#define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars_sn2))

-#define XPC_RP_PART_NASIDS(_rp) ((u64 *)((u8 *)(_rp) + XPC_RP_HEADER_SIZE))
+#define XPC_RP_PART_NASIDS(_rp) ((unsigned long *)((u8 *)(_rp) + \
+ XPC_RP_HEADER_SIZE))
#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + \
xpc_nasid_mask_nlongs)
#define XPC_RP_VARS(_rp) ((struct xpc_vars_sn2 *) \
@@ -202,13 +196,13 @@ struct xpc_vars_part_sn2 {
/*
* Define a Get/Put value pair (pointers) used with a message queue.
*/
-struct xpc_gp {
+struct xpc_gp_sn2 {
s64 get; /* Get value */
s64 put; /* Put value */
};

#define XPC_GP_SIZE \
- L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_MAX_NCHANNELS)
+ L1_CACHE_ALIGN(sizeof(struct xpc_gp_sn2) * XPC_MAX_NCHANNELS)

/*
* Define a structure that contains arguments associated with opening and
@@ -340,10 +334,10 @@ struct xpc_channel_sn2 {

/* various flavors of local and remote Get/Put values */

- struct xpc_gp *local_GP; /* local Get/Put values */
- struct xpc_gp remote_GP; /* remote Get/Put values */
- struct xpc_gp w_local_GP; /* working local Get/Put values */
- struct xpc_gp w_remote_GP; /* working remote Get/Put values */
+ struct xpc_gp_sn2 *local_GP; /* local Get/Put values */
+ struct xpc_gp_sn2 remote_GP; /* remote Get/Put values */
+ struct xpc_gp_sn2 w_local_GP; /* working local Get/Put values */
+ struct xpc_gp_sn2 w_remote_GP; /* working remote Get/Put values */
s64 next_msg_to_pull; /* Put value of next msg to pull */

struct mutex msg_to_pull_mutex; /* next msg to pull serialization */
@@ -506,9 +500,9 @@ struct xpc_partition_sn2 {
u8 remote_vars_version; /* version# of partition's vars */

void *local_GPs_base; /* base address of kmalloc'd space */
- struct xpc_gp *local_GPs; /* local Get/Put values */
+ struct xpc_gp_sn2 *local_GPs; /* local Get/Put values */
void *remote_GPs_base; /* base address of kmalloc'd space */
- struct xpc_gp *remote_GPs; /* copy of remote partition's local */
+ struct xpc_gp_sn2 *remote_GPs; /* copy of remote partition's local */
/* Get/Put values */
u64 remote_GPs_pa; /* phys address of remote partition's local */
/* Get/Put values */
@@ -629,6 +623,8 @@ extern void xpc_activate_partition(struc
extern void xpc_activate_kthreads(struct xpc_channel *, int);
extern void xpc_create_kthreads(struct xpc_channel *, int, int);
extern void xpc_disconnect_wait(int);
+extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (u64, u64 *, u64 *,
+ size_t *);
extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *);
extern void (*xpc_heartbeat_init) (void);
extern void (*xpc_heartbeat_exit) (void);
Index: linux/drivers/misc/sgi-xp/xpc_sn2.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_sn2.c 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_sn2.c 2008-06-27 07:19:14.000000000 -0500
@@ -13,9 +13,9 @@
*
*/

-#include <linux/kernel.h>
#include <linux/delay.h>
#include <asm/uncached.h>
+#include <asm/sn/mspec.h>
#include <asm/sn/sn_sal.h>
#include "xpc.h"

@@ -176,7 +176,7 @@ xpc_send_IRQ_sn2(struct amo *amo, u64 fl

local_irq_restore(irq_flags);

- return ((ret == 0) ? xpSuccess : xpPioReadError);
+ return (ret == 0) ? xpSuccess : xpPioReadError;
}

static struct amo *
@@ -284,7 +284,7 @@ xpc_handle_notify_IRQ_sn2(int irq, void
short partid = (short)(u64)dev_id;
struct xpc_partition *part = &xpc_partitions[partid];

- DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
+ DBUG_ON(partid < 0 || partid >= XP_MAX_NPARTITIONS_SN2);

if (xpc_part_ref(part)) {
xpc_check_for_sent_chctl_flags_sn2(part);
@@ -577,6 +577,25 @@ xpc_allow_amo_ops_shub_wars_1_1_sn2(void
}

static enum xp_retval
+xpc_get_partition_rsvd_page_pa_sn2(u64 buf, u64 *cookie, u64 *paddr,
+ size_t *len)
+{
+ s64 status;
+ enum xp_retval ret;
+
+ status = sn_partition_reserved_page_pa(buf, cookie, paddr, len);
+ if (status == SALRET_OK)
+ ret = xpSuccess;
+ else if (status == SALRET_MORE_PASSES)
+ ret = xpNeedMoreInfo;
+ else
+ ret = xpSalError;
+
+ return ret;
+}
+
+
+static enum xp_retval
xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp)
{
struct amo *amos_page;
@@ -636,7 +655,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_p

/* clear xpc_vars_part_sn2 */
memset((u64 *)xpc_vars_part_sn2, 0, sizeof(struct xpc_vars_part_sn2) *
- xp_max_npartitions);
+ XP_MAX_NPARTITIONS_SN2);

/* initialize the activate IRQ related amo variables */
for (i = 0; i < xpc_nasid_mask_nlongs; i++)
@@ -699,7 +718,7 @@ xpc_check_remote_hb_sn2(void)

remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2;

- for (partid = 0; partid < xp_max_npartitions; partid++) {
+ for (partid = 0; partid < XP_MAX_NPARTITIONS_SN2; partid++) {

if (xpc_exiting)
break;
@@ -2386,6 +2405,7 @@ xpc_init_sn2(void)
int ret;
size_t buf_size;

+ xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2;
xpc_rsvd_page_init = xpc_rsvd_page_init_sn2;
xpc_increment_heartbeat = xpc_increment_heartbeat_sn2;
xpc_offline_heartbeat = xpc_offline_heartbeat_sn2;
Index: linux/drivers/misc/sgi-xp/xp_main.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp_main.c 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp_main.c 2008-06-27 07:06:09.000000000 -0500
@@ -14,7 +14,6 @@
*
*/

-#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include "xp.h"
@@ -36,9 +35,18 @@ struct device *xp = &xp_dbg_subname;
short xp_max_npartitions;
EXPORT_SYMBOL_GPL(xp_max_npartitions);

+short xp_partition_id;
+EXPORT_SYMBOL_GPL(xp_partition_id);
+
+u8 xp_region_size;
+EXPORT_SYMBOL_GPL(xp_region_size);
+
enum xp_retval (*xp_remote_memcpy) (void *dst, const void *src, size_t len);
EXPORT_SYMBOL_GPL(xp_remote_memcpy);

+int (*xp_cpu_to_nasid) (int cpuid);
+EXPORT_SYMBOL_GPL(xp_cpu_to_nasid);
+
/*
* xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level
* users of XPC.
Index: linux/drivers/misc/sgi-xp/xpc_channel.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_channel.c 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_channel.c 2008-06-27 07:06:09.000000000 -0500
@@ -14,14 +14,7 @@
*
*/

-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/cache.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-#include <linux/completion.h>
-#include <asm/sn/sn_sal.h>
+#include <linux/device.h>
#include "xpc.h"

/*
@@ -373,8 +366,9 @@ again:
dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY (local_msgqueue_pa="
"0x%lx, local_nentries=%d, remote_nentries=%d) "
"received from partid=%d, channel=%d\n",
- args->local_msgqueue_pa, args->local_nentries,
- args->remote_nentries, ch->partid, ch->number);
+ (unsigned long)args->local_msgqueue_pa,
+ args->local_nentries, args->remote_nentries,
+ ch->partid, ch->number);

if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) {
spin_unlock_irqrestore(&ch->lock, irq_flags);
@@ -940,7 +934,7 @@ xpc_deliver_msg(struct xpc_channel *ch)
if (ch->func != NULL) {
dev_dbg(xpc_chan, "ch->func() called, msg=0x%p, "
"msg_number=%ld, partid=%d, channel=%d\n",
- (void *)msg, msg->number, ch->partid,
+ msg, (signed long)msg->number, ch->partid,
ch->number);

/* deliver the message to its intended recipient */
@@ -949,7 +943,7 @@ xpc_deliver_msg(struct xpc_channel *ch)

dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, "
"msg_number=%ld, partid=%d, channel=%d\n",
- (void *)msg, msg->number, ch->partid,
+ msg, (signed long)msg->number, ch->partid,
ch->number);
}

Index: linux/drivers/misc/sgi-xp/xpc_partition.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_partition.c 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_partition.c 2008-06-27 07:06:09.000000000 -0500
@@ -15,15 +15,8 @@
*
*/

-#include <linux/kernel.h>
-#include <linux/sysctl.h>
-#include <linux/cache.h>
-#include <linux/mmzone.h>
-#include <linux/nodemask.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/nodepda.h>
-#include <asm/sn/addrs.h>
+#include <linux/device.h>
+#include <linux/hardirq.h>
#include "xpc.h"

/* XPC is exiting flag */
@@ -71,24 +64,23 @@ static u64
xpc_get_rsvd_page_pa(int nasid)
{
enum xp_retval ret;
- s64 status;
u64 cookie = 0;
u64 rp_pa = nasid; /* seed with nasid */
- u64 len = 0;
+ size_t len = 0;
u64 buf = buf;
u64 buf_len = 0;
void *buf_base = NULL;

while (1) {

- status = sn_partition_reserved_page_pa(buf, &cookie, &rp_pa,
- &len);
+ ret = xpc_get_partition_rsvd_page_pa(buf, &cookie, &rp_pa,
+ &len);

- dev_dbg(xpc_part, "SAL returned with status=%li, cookie="
- "0x%016lx, address=0x%016lx, len=0x%016lx\n",
- status, cookie, rp_pa, len);
+ dev_dbg(xpc_part, "SAL returned with ret=%d, cookie=0x%016lx, "
+ "address=0x%016lx, len=0x%016lx\n", ret,
+ (unsigned long)cookie, (unsigned long)rp_pa, len);

- if (status != SALRET_MORE_PASSES)
+ if (ret != xpNeedMoreInfo)
break;

/* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */
@@ -100,8 +92,9 @@ xpc_get_rsvd_page_pa(int nasid)
&buf_base);
if (buf_base == NULL) {
dev_err(xpc_part, "unable to kmalloc "
- "len=0x%016lx\n", buf_len);
- status = SALRET_ERROR;
+ "len=0x%016lx\n",
+ (unsigned long)buf_len);
+ ret = xpNoMemory;
break;
}
}
@@ -109,17 +102,17 @@ xpc_get_rsvd_page_pa(int nasid)
ret = xp_remote_memcpy((void *)buf, (void *)rp_pa, buf_len);
if (ret != xpSuccess) {
dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret);
- status = SALRET_ERROR;
break;
}
}

kfree(buf_base);

- if (status != SALRET_OK)
+ if (ret != xpSuccess)
rp_pa = 0;

- dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa);
+ dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n",
+ (unsigned long)rp_pa);
return rp_pa;
}

@@ -138,7 +131,7 @@ xpc_setup_rsvd_page(void)
/* get the local reserved page's address */

preempt_disable();
- rp_pa = xpc_get_rsvd_page_pa(cpuid_to_nasid(smp_processor_id()));
+ rp_pa = xpc_get_rsvd_page_pa(xp_cpu_to_nasid(smp_processor_id()));
preempt_enable();
if (rp_pa == 0) {
dev_err(xpc_part, "SAL failed to locate the reserved page\n");
@@ -150,7 +143,7 @@ xpc_setup_rsvd_page(void)
/* SAL_versions < 3 had a SAL_partid defined as a u8 */
rp->SAL_partid &= 0xff;
}
- BUG_ON(rp->SAL_partid != sn_partition_id);
+ BUG_ON(rp->SAL_partid != xp_partition_id);

if (rp->SAL_partid < 0 || rp->SAL_partid >= xp_max_npartitions) {
dev_err(xpc_part, "the reserved page's partid of %d is outside "
@@ -237,11 +230,11 @@ xpc_get_remote_rp(int nasid, unsigned lo
/* check that both remote and local partids are valid for each side */
if (remote_rp->SAL_partid < 0 ||
remote_rp->SAL_partid >= xp_max_npartitions ||
- remote_rp->max_npartitions <= sn_partition_id) {
+ remote_rp->max_npartitions <= xp_partition_id) {
return xpInvalidPartid;
}

- if (remote_rp->SAL_partid == sn_partition_id)
+ if (remote_rp->SAL_partid == xp_partition_id)
return xpLocalPartid;

return xpSuccess;
@@ -426,7 +419,7 @@ xpc_discovery(void)
* protection is in regards to memory, IOI and IPI.
*/
max_regions = 64;
- region_size = sn_region_size;
+ region_size = xp_region_size;

switch (region_size) {
case 128:
Index: linux/drivers/misc/sgi-xp/xp_sn2.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp_sn2.c 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp_sn2.c 2008-06-27 07:06:09.000000000 -0500
@@ -12,6 +12,7 @@
* Architecture specific implementation of common functions.
*/

+#include <linux/module.h>
#include <linux/device.h>
#include <asm/sn/bte.h>
#include <asm/sn/sn_sal.h>
@@ -116,14 +117,23 @@ xp_remote_memcpy_sn2(void *vdst, const v
return xpBteCopyError;
}

+static int
+xp_cpu_to_nasid_sn2(int cpuid)
+{
+ return cpuid_to_nasid(cpuid);
+}
+
enum xp_retval
xp_init_sn2(void)
{
BUG_ON(!is_shub());

xp_max_npartitions = XP_MAX_NPARTITIONS_SN2;
+ xp_partition_id = sn_partition_id;
+ xp_region_size = sn_region_size;

xp_remote_memcpy = xp_remote_memcpy_sn2;
+ xp_cpu_to_nasid = xp_cpu_to_nasid_sn2;

return xp_register_nofault_code_sn2();
}
Index: linux/drivers/misc/sgi-xp/xpnet.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpnet.c 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpnet.c 2008-06-27 07:06:09.000000000 -0500
@@ -21,17 +21,8 @@
*/

#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/smp.h>
-#include <linux/string.h>
-#include <asm/atomic.h>
#include "xp.h"

/*
@@ -175,8 +166,9 @@ xpnet_receive(short partid, int channel,

return;
}
- dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n", msg->buf_pa, msg->size,
- msg->leadin_ignore, msg->tailout_ignore);
+ dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n",
+ (unsigned long)msg->buf_pa, msg->size, msg->leadin_ignore,
+ msg->tailout_ignore);

/* reserve an extra cache line */
skb = dev_alloc_skb(msg->size + L1_CACHE_BYTES);
@@ -320,8 +312,10 @@ xpnet_dev_open(struct net_device *dev)

dev_dbg(xpnet, "calling xpc_connect(%d, 0x%p, NULL, %ld, %ld, %ld, "
"%ld)\n", XPC_NET_CHANNEL, xpnet_connection_activity,
- XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, XPNET_MAX_KTHREADS,
- XPNET_MAX_IDLE_KTHREADS);
+ (unsigned long)XPNET_MSG_SIZE,
+ (unsigned long)XPNET_MSG_NENTRIES,
+ (unsigned long)XPNET_MAX_KTHREADS,
+ (unsigned long)XPNET_MAX_IDLE_KTHREADS);

ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL,
XPNET_MSG_SIZE, XPNET_MSG_NENTRIES,
@@ -439,8 +433,8 @@ xpnet_send(struct sk_buff *skb, struct x
dev_dbg(xpnet, "sending XPC message to %d:%d\n"
KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, "
"msg->leadin_ignore=%u, msg->tailout_ignore=%u\n",
- dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size,
- msg->leadin_ignore, msg->tailout_ignore);
+ dest_partid, XPC_NET_CHANNEL, (unsigned long)msg->buf_pa,
+ msg->size, msg->leadin_ignore, msg->tailout_ignore);

atomic_inc(&queued_msg->use_count);

@@ -602,8 +596,8 @@ xpnet_init(void)
*/
xpnet_device->dev_addr[0] = 0x02; /* locally administered, no OUI */

- xpnet_device->dev_addr[XPNET_PARTID_OCTET + 1] = sn_partition_id;
- xpnet_device->dev_addr[XPNET_PARTID_OCTET + 0] = (sn_partition_id >> 8);
+ xpnet_device->dev_addr[XPNET_PARTID_OCTET + 1] = xp_partition_id;
+ xpnet_device->dev_addr[XPNET_PARTID_OCTET + 0] = (xp_partition_id >> 8);

/*
* ether_setup() sets this to a multicast device. We are
Index: linux/drivers/misc/sgi-xp/xpc_uv.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_uv.c 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_uv.c 2008-06-27 07:06:09.000000000 -0500
@@ -14,11 +14,8 @@
*/

#include <linux/kernel.h>
-
-/* !!! #include <gru/grukservices.h> */
-/* !!! uv_gpa() is defined in <gru/grukservices.h> */
-#define uv_gpa(_a) ((unsigned long)_a)
-
+#include <asm/uv/uv_hub.h>
+#include "../sgi-gru/grukservices.h"
#include "xpc.h"

static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV);
Index: linux/drivers/misc/sgi-xp/Makefile
===================================================================
--- linux.orig/drivers/misc/sgi-xp/Makefile 2008-06-24 15:01:36.000000000 -0500
+++ linux/drivers/misc/sgi-xp/Makefile 2008-06-24 15:01:41.000000000 -0500
@@ -3,11 +3,17 @@
#

obj-$(CONFIG_SGI_XP) += xp.o
-xp-y := xp_main.o xp_uv.o
-xp-$(CONFIG_IA64) += xp_sn2.o xp_nofault.o
+xp-y := xp_main.o
+xp-$(CONFIG_IA64_SGI_SN2) += xp_sn2.o xp_nofault.o
+xp-$(CONFIG_IA64_GENERIC) += xp_sn2.o xp_nofault.o xp_uv.o
+xp-$(CONFIG_IA64_SGI_UV) += xp_uv.o
+xp-$(CONFIG_X86_64) += xp_uv.o

obj-$(CONFIG_SGI_XP) += xpc.o
-xpc-y := xpc_main.o xpc_uv.o xpc_channel.o xpc_partition.o
-xpc-$(CONFIG_IA64) += xpc_sn2.o
+xpc-y := xpc_main.o xpc_channel.o xpc_partition.o
+xpc-$(CONFIG_IA64_SGI_SN2) += xpc_sn2.o
+xpc-$(CONFIG_IA64_GENERIC) += xpc_sn2.o xpc_uv.o
+xpc-$(CONFIG_IA64_SGI_UV) += xpc_uv.o
+xpc-$(CONFIG_X86_64) += xpc_uv.o

obj-$(CONFIG_SGI_XP) += xpnet.o

2008-07-07 18:55:57

by Dean Nelson

[permalink] [raw]
Subject: [Patch 2/6] sgi-xp: add usage of GRU driver by xpc_remote_memcpy()

Add UV support to xpc_remote_memcpy(), which involves interfacing to the GRU
driver.

Signed-off-by: Dean Nelson <[email protected]>

---

drivers/misc/sgi-xp/xp.h | 8 ++-
drivers/misc/sgi-xp/xp_main.c | 6 ++
drivers/misc/sgi-xp/xp_sn2.c | 50 +++++++++++------------
drivers/misc/sgi-xp/xp_uv.c | 27 +++++++++++-
drivers/misc/sgi-xp/xpc.h | 44 ++++++++++----------
drivers/misc/sgi-xp/xpc_channel.c | 5 --
drivers/misc/sgi-xp/xpc_main.c | 8 ++-
drivers/misc/sgi-xp/xpc_partition.c | 37 ++++++++---------
drivers/misc/sgi-xp/xpc_sn2.c | 68 ++++++++++++++++----------------
drivers/misc/sgi-xp/xpc_uv.c | 2
drivers/misc/sgi-xp/xpnet.c | 26 +++++-------
11 files changed, 154 insertions(+), 127 deletions(-)

Index: linux/drivers/misc/sgi-xp/xp.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp.h 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp.h 2008-07-07 12:20:35.000000000 -0500
@@ -207,7 +207,9 @@ enum xp_retval {
xpUnsupported, /* 56: unsupported functionality or resource */
xpNeedMoreInfo, /* 57: more info is needed by SAL */

- xpUnknownReason /* 58: unknown reason - must be last in enum */
+ xpGruCopyError, /* 58: gru_copy_gru() returned error */
+
+ xpUnknownReason /* 59: unknown reason - must be last in enum */
};

/*
@@ -349,7 +351,9 @@ extern short xp_max_npartitions;
extern short xp_partition_id;
extern u8 xp_region_size;

-extern enum xp_retval (*xp_remote_memcpy) (void *, const void *, size_t);
+extern unsigned long (*xp_pa) (void *);
+extern enum xp_retval (*xp_remote_memcpy) (unsigned long, const unsigned long,
+ size_t);
extern int (*xp_cpu_to_nasid) (int);

extern u64 xp_nofault_PIOR_target;
Index: linux/drivers/misc/sgi-xp/xp_main.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp_main.c 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp_main.c 2008-07-07 12:20:30.000000000 -0500
@@ -41,7 +41,11 @@ EXPORT_SYMBOL_GPL(xp_partition_id);
u8 xp_region_size;
EXPORT_SYMBOL_GPL(xp_region_size);

-enum xp_retval (*xp_remote_memcpy) (void *dst, const void *src, size_t len);
+unsigned long (*xp_pa) (void *addr);
+EXPORT_SYMBOL_GPL(xp_pa);
+
+enum xp_retval (*xp_remote_memcpy) (unsigned long dst_gpa,
+ const unsigned long src_gpa, size_t len);
EXPORT_SYMBOL_GPL(xp_remote_memcpy);

int (*xp_cpu_to_nasid) (int cpuid);
Index: linux/drivers/misc/sgi-xp/xp_sn2.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp_sn2.c 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp_sn2.c 2008-07-07 12:23:52.000000000 -0500
@@ -63,7 +63,7 @@ xp_register_nofault_code_sn2(void)
return xpSuccess;
}

-void
+static void
xp_unregister_nofault_code_sn2(void)
{
u64 func_addr = *(u64 *)xp_nofault_PIOR;
@@ -75,44 +75,41 @@ xp_unregister_nofault_code_sn2(void)
}

/*
+ * Convert a virtual memory address to a physical memory address.
+ */
+static unsigned long
+xp_pa_sn2(void *addr)
+{
+ return __pa(addr);
+}
+
+/*
* Wrapper for bte_copy().
*
- * vdst - virtual address of the destination of the transfer.
- * psrc - physical address of the source of the transfer.
+ * dst_pa - physical address of the destination of the transfer.
+ * src_pa - physical address of the source of the transfer.
* len - number of bytes to transfer from source to destination.
*
* Note: xp_remote_memcpy_sn2() should never be called while holding a spinlock.
*/
static enum xp_retval
-xp_remote_memcpy_sn2(void *vdst, const void *psrc, size_t len)
+xp_remote_memcpy_sn2(unsigned long dst_pa, const unsigned long src_pa,
+ size_t len)
{
bte_result_t ret;
- u64 pdst = ia64_tpa(vdst);
- /* ??? What are the rules governing the src and dst addresses passed in?
- * ??? Currently we're assuming that dst is a virtual address and src
- * ??? is a physical address, is this appropriate? Can we allow them to
- * ??? be whatever and we make the change here without damaging the
- * ??? addresses?
- */
-
- /*
- * Ensure that the physically mapped memory is contiguous.
- *
- * We do this by ensuring that the memory is from region 7 only.
- * If the need should arise to use memory from one of the other
- * regions, then modify the BUG_ON() statement to ensure that the
- * memory from that region is always physically contiguous.
- */
- BUG_ON(REGION_NUMBER(vdst) != RGN_KERNEL);

- ret = bte_copy((u64)psrc, pdst, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL);
+ ret = bte_copy(src_pa, dst_pa, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL);
if (ret == BTE_SUCCESS)
return xpSuccess;

- if (is_shub2())
- dev_err(xp, "bte_copy() on shub2 failed, error=0x%x\n", ret);
- else
- dev_err(xp, "bte_copy() failed, error=%d\n", ret);
+ if (is_shub2()) {
+ dev_err(xp, "bte_copy() on shub2 failed, error=0x%x dst_pa="
+ "0x%016lx src_pa=0x%016lx len=%ld\\n", ret, dst_pa,
+ src_pa, len);
+ } else {
+ dev_err(xp, "bte_copy() failed, error=%d dst_pa=0x%016lx "
+ "src_pa=0x%016lx len=%ld\\n", ret, dst_pa, src_pa, len);
+ }

return xpBteCopyError;
}
@@ -132,6 +129,7 @@ xp_init_sn2(void)
xp_partition_id = sn_partition_id;
xp_region_size = sn_region_size;

+ xp_pa = xp_pa_sn2;
xp_remote_memcpy = xp_remote_memcpy_sn2;
xp_cpu_to_nasid = xp_cpu_to_nasid_sn2;

Index: linux/drivers/misc/sgi-xp/xp_uv.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp_uv.c 2008-07-07 08:23:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp_uv.c 2008-07-07 12:20:35.000000000 -0500
@@ -13,13 +13,33 @@
*
*/

+#include <linux/device.h>
+#include <asm/uv/uv_hub.h>
+#include "../sgi-gru/grukservices.h"
#include "xp.h"

+/*
+ * Convert a virtual memory address to a physical memory address.
+ */
+static unsigned long
+xp_pa_uv(void *addr)
+{
+ return uv_gpa(addr);
+}
+
static enum xp_retval
-xp_remote_memcpy_uv(void *vdst, const void *psrc, size_t len)
+xp_remote_memcpy_uv(unsigned long dst_gpa, const unsigned long src_gpa,
+ size_t len)
{
- /* !!! this function needs fleshing out */
- return xpUnsupported;
+ int ret;
+
+ ret = gru_copy_gpa(dst_gpa, src_gpa, len);
+ if (ret == 0)
+ return xpSuccess;
+
+ dev_err(xp, "gru_copy_gpa() failed, dst_gpa=0x%016lx src_gpa=0x%016lx "
+ "len=%ld\n", dst_gpa, src_gpa, len);
+ return xpGruCopyError;
}

enum xp_retval
@@ -29,6 +49,7 @@ xp_init_uv(void)

xp_max_npartitions = XP_MAX_NPARTITIONS_UV;

+ xp_pa = xp_pa_uv;
xp_remote_memcpy = xp_remote_memcpy_uv;

return xpSuccess;
Index: linux/drivers/misc/sgi-xp/xpc_partition.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_partition.c 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_partition.c 2008-07-07 12:20:37.000000000 -0500
@@ -60,15 +60,15 @@ xpc_kmalloc_cacheline_aligned(size_t siz
* Given a nasid, get the physical address of the partition's reserved page
* for that nasid. This function returns 0 on any error.
*/
-static u64
+static unsigned long
xpc_get_rsvd_page_pa(int nasid)
{
enum xp_retval ret;
u64 cookie = 0;
- u64 rp_pa = nasid; /* seed with nasid */
+ unsigned long rp_pa = nasid; /* seed with nasid */
size_t len = 0;
- u64 buf = buf;
- u64 buf_len = 0;
+ size_t buf_len = 0;
+ void *buf = buf;
void *buf_base = NULL;

while (1) {
@@ -78,7 +78,7 @@ xpc_get_rsvd_page_pa(int nasid)

dev_dbg(xpc_part, "SAL returned with ret=%d, cookie=0x%016lx, "
"address=0x%016lx, len=0x%016lx\n", ret,
- (unsigned long)cookie, (unsigned long)rp_pa, len);
+ (unsigned long)cookie, rp_pa, len);

if (ret != xpNeedMoreInfo)
break;
@@ -87,19 +87,17 @@ xpc_get_rsvd_page_pa(int nasid)
if (L1_CACHE_ALIGN(len) > buf_len) {
kfree(buf_base);
buf_len = L1_CACHE_ALIGN(len);
- buf = (u64)xpc_kmalloc_cacheline_aligned(buf_len,
- GFP_KERNEL,
- &buf_base);
+ buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL,
+ &buf_base);
if (buf_base == NULL) {
dev_err(xpc_part, "unable to kmalloc "
- "len=0x%016lx\n",
- (unsigned long)buf_len);
+ "len=0x%016lx\n", buf_len);
ret = xpNoMemory;
break;
}
}

- ret = xp_remote_memcpy((void *)buf, (void *)rp_pa, buf_len);
+ ret = xp_remote_memcpy(xp_pa(buf), rp_pa, buf_len);
if (ret != xpSuccess) {
dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret);
break;
@@ -111,8 +109,7 @@ xpc_get_rsvd_page_pa(int nasid)
if (ret != xpSuccess)
rp_pa = 0;

- dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n",
- (unsigned long)rp_pa);
+ dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa);
return rp_pa;
}

@@ -125,7 +122,7 @@ struct xpc_rsvd_page *
xpc_setup_rsvd_page(void)
{
struct xpc_rsvd_page *rp;
- u64 rp_pa;
+ unsigned long rp_pa;
unsigned long new_ts_jiffies;

/* get the local reserved page's address */
@@ -193,7 +190,7 @@ xpc_setup_rsvd_page(void)
*/
enum xp_retval
xpc_get_remote_rp(int nasid, unsigned long *discovered_nasids,
- struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa)
+ struct xpc_rsvd_page *remote_rp, unsigned long *remote_rp_pa)
{
int l;
enum xp_retval ret;
@@ -205,7 +202,7 @@ xpc_get_remote_rp(int nasid, unsigned lo
return xpNoRsvdPageAddr;

/* pull over the reserved page header and part_nasids mask */
- ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa,
+ ret = xp_remote_memcpy(xp_pa(remote_rp), *remote_rp_pa,
XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes);
if (ret != xpSuccess)
return ret;
@@ -389,7 +386,7 @@ xpc_discovery(void)
{
void *remote_rp_base;
struct xpc_rsvd_page *remote_rp;
- u64 remote_rp_pa;
+ unsigned long remote_rp_pa;
int region;
int region_size;
int max_regions;
@@ -500,7 +497,7 @@ enum xp_retval
xpc_initiate_partid_to_nasids(short partid, void *nasid_mask)
{
struct xpc_partition *part;
- u64 part_nasid_pa;
+ unsigned long part_nasid_pa;

part = &xpc_partitions[partid];
if (part->remote_rp_pa == 0)
@@ -508,8 +505,8 @@ xpc_initiate_partid_to_nasids(short part

memset(nasid_mask, 0, xpc_nasid_mask_nbytes);

- part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa);
+ part_nasid_pa = (unsigned long)XPC_RP_PART_NASIDS(part->remote_rp_pa);

- return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa,
+ return xp_remote_memcpy(xp_pa(nasid_mask), part_nasid_pa,
xpc_nasid_mask_nbytes);
}
Index: linux/drivers/misc/sgi-xp/xpc_sn2.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_sn2.c 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_sn2.c 2008-07-07 12:20:40.000000000 -0500
@@ -207,8 +207,8 @@ xpc_handle_activate_IRQ_sn2(int irq, voi
* Flag the appropriate amo variable and send an IRQ to the specified node.
*/
static void
-xpc_send_activate_IRQ_sn2(u64 amos_page_pa, int from_nasid, int to_nasid,
- int to_phys_cpuid)
+xpc_send_activate_IRQ_sn2(unsigned long amos_page_pa, int from_nasid,
+ int to_nasid, int to_phys_cpuid)
{
struct amo *amos = (struct amo *)__va(amos_page_pa +
(XPC_ACTIVATE_IRQ_AMOS_SN2 *
@@ -404,7 +404,7 @@ xpc_send_chctl_openreply_sn2(struct xpc_

args->remote_nentries = ch->remote_nentries;
args->local_nentries = ch->local_nentries;
- args->local_msgqueue_pa = __pa(ch->local_msgqueue);
+ args->local_msgqueue_pa = xp_pa(ch->local_msgqueue);
XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREPLY, irq_flags);
}

@@ -577,13 +577,13 @@ xpc_allow_amo_ops_shub_wars_1_1_sn2(void
}

static enum xp_retval
-xpc_get_partition_rsvd_page_pa_sn2(u64 buf, u64 *cookie, u64 *paddr,
+xpc_get_partition_rsvd_page_pa_sn2(void *buf, u64 *cookie, unsigned long *rp_pa,
size_t *len)
{
s64 status;
enum xp_retval ret;

- status = sn_partition_reserved_page_pa(buf, cookie, paddr, len);
+ status = sn_partition_reserved_page_pa((u64)buf, cookie, rp_pa, len);
if (status == SALRET_OK)
ret = xpSuccess;
else if (status == SALRET_MORE_PASSES)
@@ -604,7 +604,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_p

xpc_vars_sn2 = XPC_RP_VARS(rp);

- rp->sn.vars_pa = __pa(xpc_vars_sn2);
+ rp->sn.vars_pa = xp_pa(xpc_vars_sn2);

/* vars_part array follows immediately after vars */
xpc_vars_part_sn2 = (struct xpc_vars_part_sn2 *)((u8 *)XPC_RP_VARS(rp) +
@@ -649,7 +649,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_p
xpc_vars_sn2->version = XPC_V_VERSION;
xpc_vars_sn2->activate_IRQ_nasid = cpuid_to_nasid(0);
xpc_vars_sn2->activate_IRQ_phys_cpuid = cpu_physical_id(0);
- xpc_vars_sn2->vars_part_pa = __pa(xpc_vars_part_sn2);
+ xpc_vars_sn2->vars_part_pa = xp_pa(xpc_vars_part_sn2);
xpc_vars_sn2->amos_page_pa = ia64_tpa((u64)amos_page);
xpc_vars_sn2->amos_page = amos_page; /* save for next load of XPC */

@@ -734,8 +734,8 @@ xpc_check_remote_hb_sn2(void)
}

/* pull the remote_hb cache line */
- ret = xp_remote_memcpy(remote_vars,
- (void *)part->sn.sn2.remote_vars_pa,
+ ret = xp_remote_memcpy(xp_pa(remote_vars),
+ part->sn.sn2.remote_vars_pa,
XPC_RP_VARS_SIZE);
if (ret != xpSuccess) {
XPC_DEACTIVATE_PARTITION(part, ret);
@@ -768,7 +768,8 @@ xpc_check_remote_hb_sn2(void)
* assumed to be of size XPC_RP_VARS_SIZE.
*/
static enum xp_retval
-xpc_get_remote_vars_sn2(u64 remote_vars_pa, struct xpc_vars_sn2 *remote_vars)
+xpc_get_remote_vars_sn2(unsigned long remote_vars_pa,
+ struct xpc_vars_sn2 *remote_vars)
{
enum xp_retval ret;

@@ -776,7 +777,7 @@ xpc_get_remote_vars_sn2(u64 remote_vars_
return xpVarsNotSet;

/* pull over the cross partition variables */
- ret = xp_remote_memcpy(remote_vars, (void *)remote_vars_pa,
+ ret = xp_remote_memcpy(xp_pa(remote_vars), remote_vars_pa,
XPC_RP_VARS_SIZE);
if (ret != xpSuccess)
return ret;
@@ -791,7 +792,7 @@ xpc_get_remote_vars_sn2(u64 remote_vars_

static void
xpc_request_partition_activation_sn2(struct xpc_rsvd_page *remote_rp,
- u64 remote_rp_pa, int nasid)
+ unsigned long remote_rp_pa, int nasid)
{
xpc_send_local_activate_IRQ_sn2(nasid);
}
@@ -883,7 +884,8 @@ xpc_partition_deactivation_requested_sn2
static void
xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version,
unsigned long *remote_rp_ts_jiffies,
- u64 remote_rp_pa, u64 remote_vars_pa,
+ unsigned long remote_rp_pa,
+ unsigned long remote_vars_pa,
struct xpc_vars_sn2 *remote_vars)
{
struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
@@ -948,8 +950,8 @@ xpc_identify_activate_IRQ_req_sn2(int na
{
struct xpc_rsvd_page *remote_rp;
struct xpc_vars_sn2 *remote_vars;
- u64 remote_rp_pa;
- u64 remote_vars_pa;
+ unsigned long remote_rp_pa;
+ unsigned long remote_vars_pa;
int remote_rp_version;
int reactivate = 0;
unsigned long remote_rp_ts_jiffies = 0;
@@ -1291,11 +1293,11 @@ xpc_setup_infrastructure_sn2(struct xpc_
* The setting of the magic # indicates that these per partition
* specific variables are ready to be used.
*/
- xpc_vars_part_sn2[partid].GPs_pa = __pa(part_sn2->local_GPs);
+ xpc_vars_part_sn2[partid].GPs_pa = xp_pa(part_sn2->local_GPs);
xpc_vars_part_sn2[partid].openclose_args_pa =
- __pa(part->local_openclose_args);
+ xp_pa(part->local_openclose_args);
xpc_vars_part_sn2[partid].chctl_amo_pa =
- __pa(part_sn2->local_chctl_amo_va);
+ xp_pa(part_sn2->local_chctl_amo_va);
cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */
xpc_vars_part_sn2[partid].notify_IRQ_nasid = cpuid_to_nasid(cpuid);
xpc_vars_part_sn2[partid].notify_IRQ_phys_cpuid =
@@ -1382,25 +1384,25 @@ xpc_teardown_infrastructure_sn2(struct x
* Create a wrapper that hides the underlying mechanism for pulling a cacheline
* (or multiple cachelines) from a remote partition.
*
- * src must be a cacheline aligned physical address on the remote partition.
+ * src_pa must be a cacheline aligned physical address on the remote partition.
* dst must be a cacheline aligned virtual address on this partition.
* cnt must be cacheline sized
*/
/* ??? Replace this function by call to xp_remote_memcpy() or bte_copy()? */
static enum xp_retval
xpc_pull_remote_cachelines_sn2(struct xpc_partition *part, void *dst,
- const void *src, size_t cnt)
+ const unsigned long src_pa, size_t cnt)
{
enum xp_retval ret;

- DBUG_ON((u64)src != L1_CACHE_ALIGN((u64)src));
- DBUG_ON((u64)dst != L1_CACHE_ALIGN((u64)dst));
+ DBUG_ON(src_pa != L1_CACHE_ALIGN(src_pa));
+ DBUG_ON((unsigned long)dst != L1_CACHE_ALIGN((unsigned long)dst));
DBUG_ON(cnt != L1_CACHE_ALIGN(cnt));

if (part->act_state == XPC_P_DEACTIVATING)
return part->reason;

- ret = xp_remote_memcpy(dst, src, cnt);
+ ret = xp_remote_memcpy(xp_pa(dst), src_pa, cnt);
if (ret != xpSuccess) {
dev_dbg(xpc_chan, "xp_remote_memcpy() from partition %d failed,"
" ret=%d\n", XPC_PARTID(part), ret);
@@ -1420,7 +1422,8 @@ xpc_pull_remote_vars_part_sn2(struct xpc
struct xpc_vars_part_sn2 *pulled_entry_cacheline =
(struct xpc_vars_part_sn2 *)L1_CACHE_ALIGN((u64)buffer);
struct xpc_vars_part_sn2 *pulled_entry;
- u64 remote_entry_cacheline_pa, remote_entry_pa;
+ unsigned long remote_entry_cacheline_pa;
+ unsigned long remote_entry_pa;
short partid = XPC_PARTID(part);
enum xp_retval ret;

@@ -1440,7 +1443,7 @@ xpc_pull_remote_vars_part_sn2(struct xpc
(L1_CACHE_BYTES - 1)));

ret = xpc_pull_remote_cachelines_sn2(part, pulled_entry_cacheline,
- (void *)remote_entry_cacheline_pa,
+ remote_entry_cacheline_pa,
L1_CACHE_BYTES);
if (ret != xpSuccess) {
dev_dbg(xpc_chan, "failed to pull XPC vars_part from "
@@ -1587,7 +1590,7 @@ xpc_get_chctl_all_flags_sn2(struct xpc_p
if (xpc_any_openclose_chctl_flags_set(&chctl)) {
ret = xpc_pull_remote_cachelines_sn2(part, part->
remote_openclose_args,
- (void *)part_sn2->
+ part_sn2->
remote_openclose_args_pa,
XPC_OPENCLOSE_ARGS_SIZE);
if (ret != xpSuccess) {
@@ -1604,7 +1607,7 @@ xpc_get_chctl_all_flags_sn2(struct xpc_p

if (xpc_any_msg_chctl_flags_set(&chctl)) {
ret = xpc_pull_remote_cachelines_sn2(part, part_sn2->remote_GPs,
- (void *)part_sn2->remote_GPs_pa,
+ part_sn2->remote_GPs_pa,
XPC_GP_SIZE);
if (ret != xpSuccess) {
XPC_DEACTIVATE_PARTITION(part, ret);
@@ -1971,8 +1974,10 @@ xpc_pull_remote_msg_sn2(struct xpc_chann
{
struct xpc_partition *part = &xpc_partitions[ch->partid];
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg *remote_msg, *msg;
- u32 msg_index, nmsgs;
+ unsigned long remote_msg_pa;
+ struct xpc_msg *msg;
+ u32 msg_index;
+ u32 nmsgs;
u64 msg_offset;
enum xp_retval ret;

@@ -1996,10 +2001,9 @@ xpc_pull_remote_msg_sn2(struct xpc_chann

msg_offset = msg_index * ch->msg_size;
msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset);
- remote_msg = (struct xpc_msg *)(ch->remote_msgqueue_pa +
- msg_offset);
+ remote_msg_pa = ch->remote_msgqueue_pa + msg_offset;

- ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg,
+ ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg_pa,
nmsgs * ch->msg_size);
if (ret != xpSuccess) {

Index: linux/drivers/misc/sgi-xp/xpnet.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpnet.c 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpnet.c 2008-07-07 12:20:30.000000000 -0500
@@ -44,7 +44,7 @@ struct xpnet_message {
u16 version; /* Version for this message */
u16 embedded_bytes; /* #of bytes embedded in XPC message */
u32 magic; /* Special number indicating this is xpnet */
- u64 buf_pa; /* phys address of buffer to retrieve */
+ unsigned long buf_pa; /* phys address of buffer to retrieve */
u32 size; /* #of bytes in buffer */
u8 leadin_ignore; /* #of bytes to ignore at the beginning */
u8 tailout_ignore; /* #of bytes to ignore at the end */
@@ -152,6 +152,7 @@ static void
xpnet_receive(short partid, int channel, struct xpnet_message *msg)
{
struct sk_buff *skb;
+ void *dst;
enum xp_retval ret;
struct xpnet_dev_private *priv =
(struct xpnet_dev_private *)xpnet_device->priv;
@@ -166,9 +167,8 @@ xpnet_receive(short partid, int channel,

return;
}
- dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n",
- (unsigned long)msg->buf_pa, msg->size, msg->leadin_ignore,
- msg->tailout_ignore);
+ dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n", msg->buf_pa, msg->size,
+ msg->leadin_ignore, msg->tailout_ignore);

/* reserve an extra cache line */
skb = dev_alloc_skb(msg->size + L1_CACHE_BYTES);
@@ -210,15 +210,12 @@ xpnet_receive(short partid, int channel,
skb_copy_to_linear_data(skb, &msg->data,
(size_t)msg->embedded_bytes);
} else {
+ dst = (void *)((u64)skb->data & ~(L1_CACHE_BYTES - 1));
dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t"
- "xp_remote_memcpy(0x%p, 0x%p, %hu)\n", (void *)
- ((u64)skb->data & ~(L1_CACHE_BYTES - 1)),
+ "xp_remote_memcpy(0x%p, 0x%p, %hu)\n", dst,
(void *)msg->buf_pa, msg->size);

- ret = xp_remote_memcpy((void *)((u64)skb->data &
- ~(L1_CACHE_BYTES - 1)),
- (void *)msg->buf_pa, msg->size);
-
+ ret = xp_remote_memcpy(xp_pa(dst), msg->buf_pa, msg->size);
if (ret != xpSuccess) {
/*
* !!! Need better way of cleaning skb. Currently skb
@@ -226,8 +223,7 @@ xpnet_receive(short partid, int channel,
* !!! dev_kfree_skb.
*/
dev_err(xpnet, "xp_remote_memcpy(0x%p, 0x%p, 0x%hx) "
- "returned error=0x%x\n", (void *)
- ((u64)skb->data & ~(L1_CACHE_BYTES - 1)),
+ "returned error=0x%x\n", dst,
(void *)msg->buf_pa, msg->size, ret);

xpc_received(partid, channel, (void *)msg);
@@ -428,13 +424,13 @@ xpnet_send(struct sk_buff *skb, struct x
msg->size = end_addr - start_addr;
msg->leadin_ignore = (u64)skb->data - start_addr;
msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb);
- msg->buf_pa = __pa(start_addr);
+ msg->buf_pa = xp_pa((void *)start_addr);

dev_dbg(xpnet, "sending XPC message to %d:%d\n"
KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, "
"msg->leadin_ignore=%u, msg->tailout_ignore=%u\n",
- dest_partid, XPC_NET_CHANNEL, (unsigned long)msg->buf_pa,
- msg->size, msg->leadin_ignore, msg->tailout_ignore);
+ dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size,
+ msg->leadin_ignore, msg->tailout_ignore);

atomic_inc(&queued_msg->use_count);

Index: linux/drivers/misc/sgi-xp/xpc.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc.h 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc.h 2008-07-07 12:20:40.000000000 -0500
@@ -91,8 +91,8 @@ struct xpc_rsvd_page {
u8 version;
u8 pad1[3]; /* align to next u64 in 1st 64-byte cacheline */
union {
- u64 vars_pa; /* physical address of struct xpc_vars */
- u64 activate_mq_gpa; /* global phys address of activate_mq */
+ unsigned long vars_pa; /* phys address of struct xpc_vars */
+ unsigned long activate_mq_gpa; /* gru phy addr of activate_mq */
} sn;
unsigned long ts_jiffies; /* timestamp when rsvd pg was setup by XPC */
u64 pad2[10]; /* align to last u64 in 2nd 64-byte cacheline */
@@ -122,8 +122,8 @@ struct xpc_vars_sn2 {
u64 heartbeat_offline; /* if 0, heartbeat should be changing */
int activate_IRQ_nasid;
int activate_IRQ_phys_cpuid;
- u64 vars_part_pa;
- u64 amos_page_pa; /* paddr of page of amos from MSPEC driver */
+ unsigned long vars_part_pa;
+ unsigned long amos_page_pa;/* paddr of page of amos from MSPEC driver */
struct amo *amos_page; /* vaddr of page of amos from MSPEC driver */
};

@@ -142,10 +142,10 @@ struct xpc_vars_sn2 {
struct xpc_vars_part_sn2 {
u64 magic;

- u64 openclose_args_pa; /* physical address of open and close args */
- u64 GPs_pa; /* physical address of Get/Put values */
+ unsigned long openclose_args_pa; /* phys addr of open and close args */
+ unsigned long GPs_pa; /* physical address of Get/Put values */

- u64 chctl_amo_pa; /* physical address of chctl flags' amo */
+ unsigned long chctl_amo_pa; /* physical address of chctl flags' amo */

int notify_IRQ_nasid; /* nasid of where to send notify IRQs */
int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */
@@ -213,7 +213,7 @@ struct xpc_openclose_args {
u16 msg_size; /* sizeof each message entry */
u16 remote_nentries; /* #of message entries in remote msg queue */
u16 local_nentries; /* #of message entries in local msg queue */
- u64 local_msgqueue_pa; /* physical address of local message queue */
+ unsigned long local_msgqueue_pa; /* phys addr of local message queue */
};

#define XPC_OPENCLOSE_ARGS_SIZE \
@@ -366,8 +366,8 @@ struct xpc_channel {
void *remote_msgqueue_base; /* base address of kmalloc'd space */
struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */
/* local message queue */
- u64 remote_msgqueue_pa; /* phys addr of remote partition's */
- /* local message queue */
+ unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */
+ /* local message queue */

atomic_t references; /* #of external references to queues */

@@ -491,12 +491,12 @@ xpc_any_msg_chctl_flags_set(union xpc_ch
*/

struct xpc_partition_sn2 {
- u64 remote_amos_page_pa; /* phys addr of partition's amos page */
+ unsigned long remote_amos_page_pa; /* paddr of partition's amos page */
int activate_IRQ_nasid; /* active partition's act/deact nasid */
int activate_IRQ_phys_cpuid; /* active part's act/deact phys cpuid */

- u64 remote_vars_pa; /* phys addr of partition's vars */
- u64 remote_vars_part_pa; /* phys addr of partition's vars part */
+ unsigned long remote_vars_pa; /* phys addr of partition's vars */
+ unsigned long remote_vars_part_pa; /* paddr of partition's vars part */
u8 remote_vars_version; /* version# of partition's vars */

void *local_GPs_base; /* base address of kmalloc'd space */
@@ -504,10 +504,10 @@ struct xpc_partition_sn2 {
void *remote_GPs_base; /* base address of kmalloc'd space */
struct xpc_gp_sn2 *remote_GPs; /* copy of remote partition's local */
/* Get/Put values */
- u64 remote_GPs_pa; /* phys address of remote partition's local */
- /* Get/Put values */
+ unsigned long remote_GPs_pa; /* phys addr of remote partition's local */
+ /* Get/Put values */

- u64 remote_openclose_args_pa; /* phys addr of remote's args */
+ unsigned long remote_openclose_args_pa; /* phys addr of remote's args */

int notify_IRQ_nasid; /* nasid of where to send notify IRQs */
int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */
@@ -529,7 +529,7 @@ struct xpc_partition {

u8 remote_rp_version; /* version# of partition's rsvd pg */
unsigned long remote_rp_ts_jiffies; /* timestamp when rsvd pg setup */
- u64 remote_rp_pa; /* phys addr of partition's rsvd pg */
+ unsigned long remote_rp_pa; /* phys addr of partition's rsvd pg */
u64 last_heartbeat; /* HB at last read */
u32 activate_IRQ_rcvd; /* IRQs since activation */
spinlock_t act_lock; /* protect updating of act_state */
@@ -623,7 +623,8 @@ extern void xpc_activate_partition(struc
extern void xpc_activate_kthreads(struct xpc_channel *, int);
extern void xpc_create_kthreads(struct xpc_channel *, int, int);
extern void xpc_disconnect_wait(int);
-extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (u64, u64 *, u64 *,
+extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *, u64 *,
+ unsigned long *,
size_t *);
extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *);
extern void (*xpc_heartbeat_init) (void);
@@ -640,8 +641,8 @@ extern void (*xpc_notify_senders_of_disc
extern void (*xpc_process_msg_chctl_flags) (struct xpc_partition *, int);
extern int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *);
extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *);
-extern void (*xpc_request_partition_activation) (struct xpc_rsvd_page *, u64,
- int);
+extern void (*xpc_request_partition_activation) (struct xpc_rsvd_page *,
+ unsigned long, int);
extern void (*xpc_request_partition_reactivation) (struct xpc_partition *);
extern void (*xpc_request_partition_deactivation) (struct xpc_partition *);
extern void (*xpc_cancel_partition_deactivation_request) (
@@ -690,7 +691,8 @@ extern enum xp_retval xpc_mark_partition
extern void xpc_mark_partition_inactive(struct xpc_partition *);
extern void xpc_discovery(void);
extern enum xp_retval xpc_get_remote_rp(int, unsigned long *,
- struct xpc_rsvd_page *, u64 *);
+ struct xpc_rsvd_page *,
+ unsigned long *);
extern void xpc_deactivate_partition(const int, struct xpc_partition *,
enum xp_retval);
extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *);
Index: linux/drivers/misc/sgi-xp/xpc_main.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_main.c 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_main.c 2008-07-07 12:20:40.000000000 -0500
@@ -169,8 +169,9 @@ static struct notifier_block xpc_die_not
.notifier_call = xpc_system_die,
};

-enum xp_retval (*xpc_get_partition_rsvd_page_pa) (u64 buf, u64 *cookie,
- u64 *paddr, size_t *len);
+enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie,
+ unsigned long *rp_pa,
+ size_t *len);
enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp);
void (*xpc_heartbeat_init) (void);
void (*xpc_heartbeat_exit) (void);
@@ -189,7 +190,8 @@ int (*xpc_n_of_deliverable_msgs) (struct
struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch);

void (*xpc_request_partition_activation) (struct xpc_rsvd_page *remote_rp,
- u64 remote_rp_pa, int nasid);
+ unsigned long remote_rp_pa,
+ int nasid);
void (*xpc_request_partition_reactivation) (struct xpc_partition *part);
void (*xpc_request_partition_deactivation) (struct xpc_partition *part);
void (*xpc_cancel_partition_deactivation_request) (struct xpc_partition *part);
Index: linux/drivers/misc/sgi-xp/xpc_uv.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_uv.c 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_uv.c 2008-07-07 12:20:35.000000000 -0500
@@ -61,7 +61,7 @@ xpc_heartbeat_exit_uv(void)

static void
xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp,
- u64 remote_rp_pa, int nasid)
+ unsigned long remote_rp_pa, int nasid)
{
short partid = remote_rp->SAL_partid;
struct xpc_partition *part = &xpc_partitions[partid];
Index: linux/drivers/misc/sgi-xp/xpc_channel.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_channel.c 2008-07-07 08:23:05.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_channel.c 2008-07-07 12:20:37.000000000 -0500
@@ -366,9 +366,8 @@ again:
dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY (local_msgqueue_pa="
"0x%lx, local_nentries=%d, remote_nentries=%d) "
"received from partid=%d, channel=%d\n",
- (unsigned long)args->local_msgqueue_pa,
- args->local_nentries, args->remote_nentries,
- ch->partid, ch->number);
+ args->local_msgqueue_pa, args->local_nentries,
+ args->remote_nentries, ch->partid, ch->number);

if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) {
spin_unlock_irqrestore(&ch->lock, irq_flags);

2008-07-07 18:57:03

by Dean Nelson

[permalink] [raw]
Subject: [Patch 3/6] sgi-xp: move xpc_check_remote_hb() to support both SN2 and UV

Move xpc_check_remote_hb() so it can support both SN2 and UV.

Signed-off-by: Dean Nelson <[email protected]>

---

drivers/misc/sgi-xp/xpc.h | 2 -
drivers/misc/sgi-xp/xpc_main.c | 34 +++++++++++++++++
drivers/misc/sgi-xp/xpc_sn2.c | 70 ++++++++++++-------------------------
3 files changed, 57 insertions(+), 49 deletions(-)

Index: linux/drivers/misc/sgi-xp/xpc.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc.h 2008-06-24 09:19:06.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc.h 2008-06-24 09:19:17.000000000 -0500
@@ -632,7 +632,7 @@ extern void (*xpc_heartbeat_exit) (void)
extern void (*xpc_increment_heartbeat) (void);
extern void (*xpc_offline_heartbeat) (void);
extern void (*xpc_online_heartbeat) (void);
-extern void (*xpc_check_remote_hb) (void);
+extern enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *);
extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *);
extern u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *);
extern enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *);
Index: linux/drivers/misc/sgi-xp/xpc_main.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_main.c 2008-06-24 09:19:06.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_main.c 2008-06-24 09:19:17.000000000 -0500
@@ -178,7 +178,7 @@ void (*xpc_heartbeat_exit) (void);
void (*xpc_increment_heartbeat) (void);
void (*xpc_offline_heartbeat) (void);
void (*xpc_online_heartbeat) (void);
-void (*xpc_check_remote_hb) (void);
+enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *part);

enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part);
void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch);
@@ -270,6 +270,38 @@ xpc_stop_hb_beater(void)
}

/*
+ * At periodic intervals, scan through all active partitions and ensure
+ * their heartbeat is still active. If not, the partition is deactivated.
+ */
+static void
+xpc_check_remote_hb(void)
+{
+ struct xpc_partition *part;
+ short partid;
+ enum xp_retval ret;
+
+ for (partid = 0; partid < xp_max_npartitions; partid++) {
+
+ if (xpc_exiting)
+ break;
+
+ if (partid == xp_partition_id)
+ continue;
+
+ part = &xpc_partitions[partid];
+
+ if (part->act_state == XPC_P_INACTIVE ||
+ part->act_state == XPC_P_DEACTIVATING) {
+ continue;
+ }
+
+ ret = xpc_get_remote_heartbeat(part);
+ if (ret != xpSuccess)
+ XPC_DEACTIVATE_PARTITION(part, ret);
+ }
+}
+
+/*
* This thread is responsible for nearly all of the partition
* activation/deactivation.
*/
Index: linux/drivers/misc/sgi-xp/xpc_sn2.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_sn2.c 2008-06-24 09:19:06.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_sn2.c 2008-06-24 09:25:03.000000000 -0500
@@ -704,61 +704,37 @@ xpc_heartbeat_exit_sn2(void)
xpc_offline_heartbeat_sn2();
}

-/*
- * At periodic intervals, scan through all active partitions and ensure
- * their heartbeat is still active. If not, the partition is deactivated.
- */
-static void
-xpc_check_remote_hb_sn2(void)
+static enum xp_retval
+xpc_get_remote_heartbeat_sn2(struct xpc_partition *part)
{
struct xpc_vars_sn2 *remote_vars;
- struct xpc_partition *part;
- short partid;
enum xp_retval ret;

remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2;

- for (partid = 0; partid < XP_MAX_NPARTITIONS_SN2; partid++) {
-
- if (xpc_exiting)
- break;
-
- if (partid == sn_partition_id)
- continue;
-
- part = &xpc_partitions[partid];
-
- if (part->act_state == XPC_P_INACTIVE ||
- part->act_state == XPC_P_DEACTIVATING) {
- continue;
- }
-
- /* pull the remote_hb cache line */
- ret = xp_remote_memcpy(xp_pa(remote_vars),
- part->sn.sn2.remote_vars_pa,
- XPC_RP_VARS_SIZE);
- if (ret != xpSuccess) {
- XPC_DEACTIVATE_PARTITION(part, ret);
- continue;
- }
-
- dev_dbg(xpc_part, "partid = %d, heartbeat = %ld, last_heartbeat"
- " = %ld, heartbeat_offline = %ld, HB_mask[0] = 0x%lx\n",
- partid, remote_vars->heartbeat, part->last_heartbeat,
- remote_vars->heartbeat_offline,
- remote_vars->heartbeating_to_mask[0]);
-
- if (((remote_vars->heartbeat == part->last_heartbeat) &&
- (remote_vars->heartbeat_offline == 0)) ||
- !xpc_hb_allowed(sn_partition_id,
- &remote_vars->heartbeating_to_mask)) {
-
- XPC_DEACTIVATE_PARTITION(part, xpNoHeartbeat);
- continue;
- }
+ /* pull the remote vars structure that contains the heartbeat */
+ ret = xp_remote_memcpy(xp_pa(remote_vars),
+ part->sn.sn2.remote_vars_pa,
+ XPC_RP_VARS_SIZE);
+ if (ret != xpSuccess)
+ return ret;

+ dev_dbg(xpc_part, "partid=%d, heartbeat=%ld, last_heartbeat=%ld, "
+ "heartbeat_offline=%ld, HB_mask[0]=0x%lx\n", XPC_PARTID(part),
+ remote_vars->heartbeat, part->last_heartbeat,
+ remote_vars->heartbeat_offline,
+ remote_vars->heartbeating_to_mask[0]);
+
+ if ((remote_vars->heartbeat == part->last_heartbeat &&
+ remote_vars->heartbeat_offline == 0) ||
+ !xpc_hb_allowed(sn_partition_id,
+ &remote_vars->heartbeating_to_mask)) {
+ ret = xpNoHeartbeat;
+ } else {
part->last_heartbeat = remote_vars->heartbeat;
}
+
+ return ret;
}

/*
@@ -2416,7 +2392,7 @@ xpc_init_sn2(void)
xpc_online_heartbeat = xpc_online_heartbeat_sn2;
xpc_heartbeat_init = xpc_heartbeat_init_sn2;
xpc_heartbeat_exit = xpc_heartbeat_exit_sn2;
- xpc_check_remote_hb = xpc_check_remote_hb_sn2;
+ xpc_get_remote_heartbeat = xpc_get_remote_heartbeat_sn2;

xpc_request_partition_activation = xpc_request_partition_activation_sn2;
xpc_request_partition_reactivation =

2008-07-07 18:57:45

by Dean Nelson

[permalink] [raw]
Subject: [Patch 4/6] sgi-xp: cleanup naming of partition defines

Cleanup naming of partition defines.

Signed-off-by: Dean Nelson <[email protected]>

---

drivers/misc/sgi-xp/xpc.h | 22 +++++++++++-----------
drivers/misc/sgi-xp/xpc_channel.c | 10 +++++-----
drivers/misc/sgi-xp/xpc_main.c | 32 ++++++++++++++++----------------
drivers/misc/sgi-xp/xpc_partition.c | 18 +++++++++---------
drivers/misc/sgi-xp/xpc_sn2.c | 20 ++++++++++----------
5 files changed, 51 insertions(+), 51 deletions(-)

Index: linux/drivers/misc/sgi-xp/xpc.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc.h 2008-06-18 12:46:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc.h 2008-06-18 13:23:49.000000000 -0500
@@ -576,21 +576,21 @@ struct xpc_partition {

/* struct xpc_partition act_state values (for XPC HB) */

-#define XPC_P_INACTIVE 0x00 /* partition is not active */
-#define XPC_P_ACTIVATION_REQ 0x01 /* created thread to activate */
-#define XPC_P_ACTIVATING 0x02 /* activation thread started */
-#define XPC_P_ACTIVE 0x03 /* xpc_partition_up() was called */
-#define XPC_P_DEACTIVATING 0x04 /* partition deactivation initiated */
+#define XPC_P_AS_INACTIVE 0x00 /* partition is not active */
+#define XPC_P_AS_ACTIVATION_REQ 0x01 /* created thread to activate */
+#define XPC_P_AS_ACTIVATING 0x02 /* activation thread started */
+#define XPC_P_AS_ACTIVE 0x03 /* xpc_partition_up() was called */
+#define XPC_P_AS_DEACTIVATING 0x04 /* partition deactivation initiated */

#define XPC_DEACTIVATE_PARTITION(_p, _reason) \
xpc_deactivate_partition(__LINE__, (_p), (_reason))

/* struct xpc_partition setup_state values */

-#define XPC_P_UNSET 0x00 /* infrastructure was never setup */
-#define XPC_P_SETUP 0x01 /* infrastructure is setup */
-#define XPC_P_WTEARDOWN 0x02 /* waiting to teardown infrastructure */
-#define XPC_P_TORNDOWN 0x03 /* infrastructure is torndown */
+#define XPC_P_SS_UNSET 0x00 /* infrastructure was never setup */
+#define XPC_P_SS_SETUP 0x01 /* infrastructure is setup */
+#define XPC_P_SS_WTEARDOWN 0x02 /* waiting to teardown infrastructure */
+#define XPC_P_SS_TORNDOWN 0x03 /* infrastructure is torndown */

/*
* struct xpc_partition_sn2's dropped notify IRQ timer is set to wait the
@@ -787,7 +787,7 @@ xpc_part_deref(struct xpc_partition *par
s32 refs = atomic_dec_return(&part->references);

DBUG_ON(refs < 0);
- if (refs == 0 && part->setup_state == XPC_P_WTEARDOWN)
+ if (refs == 0 && part->setup_state == XPC_P_SS_WTEARDOWN)
wake_up(&part->teardown_wq);
}

@@ -797,7 +797,7 @@ xpc_part_ref(struct xpc_partition *part)
int setup;

atomic_inc(&part->references);
- setup = (part->setup_state == XPC_P_SETUP);
+ setup = (part->setup_state == XPC_P_SS_SETUP);
if (!setup)
xpc_part_deref(part);

Index: linux/drivers/misc/sgi-xp/xpc_channel.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_channel.c 2008-06-18 12:45:52.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_channel.c 2008-06-18 13:21:16.000000000 -0500
@@ -99,7 +99,7 @@ xpc_process_disconnect(struct xpc_channe
DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
!(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE));

- if (part->act_state == XPC_P_DEACTIVATING) {
+ if (part->act_state == XPC_P_AS_DEACTIVATING) {
/* can't proceed until the other side disengages from us */
if (xpc_partition_engaged(ch->partid))
return;
@@ -155,7 +155,7 @@ xpc_process_disconnect(struct xpc_channe
/* we won't lose the CPU since we're holding ch->lock */
complete(&ch->wdisconnect_wait);
} else if (ch->delayed_chctl_flags) {
- if (part->act_state != XPC_P_DEACTIVATING) {
+ if (part->act_state != XPC_P_AS_DEACTIVATING) {
/* time to take action on any delayed chctl flags */
spin_lock(&part->chctl_lock);
part->chctl.flags[ch->number] |=
@@ -276,7 +276,7 @@ again:
"%d, channel=%d\n", ch->partid, ch->number);

if (ch->flags & XPC_C_DISCONNECTED) {
- DBUG_ON(part->act_state != XPC_P_DEACTIVATING);
+ DBUG_ON(part->act_state != XPC_P_AS_DEACTIVATING);
spin_unlock_irqrestore(&ch->lock, irq_flags);
return;
}
@@ -312,7 +312,7 @@ again:
"channel=%d\n", args->msg_size, args->local_nentries,
ch->partid, ch->number);

- if (part->act_state == XPC_P_DEACTIVATING ||
+ if (part->act_state == XPC_P_AS_DEACTIVATING ||
(ch->flags & XPC_C_ROPENREQUEST)) {
spin_unlock_irqrestore(&ch->lock, irq_flags);
return;
@@ -546,7 +546,7 @@ xpc_process_sent_chctl_flags(struct xpc_
continue;
}

- if (part->act_state == XPC_P_DEACTIVATING)
+ if (part->act_state == XPC_P_AS_DEACTIVATING)
continue;

if (!(ch_flags & XPC_C_CONNECTED)) {
Index: linux/drivers/misc/sgi-xp/xpc_main.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_main.c 2008-06-18 12:46:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_main.c 2008-06-18 13:22:48.000000000 -0500
@@ -290,8 +290,8 @@ xpc_check_remote_hb(void)

part = &xpc_partitions[partid];

- if (part->act_state == XPC_P_INACTIVE ||
- part->act_state == XPC_P_DEACTIVATING) {
+ if (part->act_state == XPC_P_AS_INACTIVE ||
+ part->act_state == XPC_P_AS_DEACTIVATING) {
continue;
}

@@ -406,7 +406,7 @@ xpc_initiate_discovery(void *ignore)
static void
xpc_channel_mgr(struct xpc_partition *part)
{
- while (part->act_state != XPC_P_DEACTIVATING ||
+ while (part->act_state != XPC_P_AS_DEACTIVATING ||
atomic_read(&part->nchannels_active) > 0 ||
!xpc_partition_disengaged(part)) {

@@ -429,7 +429,7 @@ xpc_channel_mgr(struct xpc_partition *pa
(void)wait_event_interruptible(part->channel_mgr_wq,
(atomic_read(&part->channel_mgr_requests) > 0 ||
part->chctl.all_flags != 0 ||
- (part->act_state == XPC_P_DEACTIVATING &&
+ (part->act_state == XPC_P_AS_DEACTIVATING &&
atomic_read(&part->nchannels_active) == 0 &&
xpc_partition_disengaged(part))));
atomic_set(&part->channel_mgr_requests, 1);
@@ -458,16 +458,16 @@ xpc_activating(void *__partid)

spin_lock_irqsave(&part->act_lock, irq_flags);

- if (part->act_state == XPC_P_DEACTIVATING) {
- part->act_state = XPC_P_INACTIVE;
+ if (part->act_state == XPC_P_AS_DEACTIVATING) {
+ part->act_state = XPC_P_AS_INACTIVE;
spin_unlock_irqrestore(&part->act_lock, irq_flags);
part->remote_rp_pa = 0;
return 0;
}

/* indicate the thread is activating */
- DBUG_ON(part->act_state != XPC_P_ACTIVATION_REQ);
- part->act_state = XPC_P_ACTIVATING;
+ DBUG_ON(part->act_state != XPC_P_AS_ACTIVATION_REQ);
+ part->act_state = XPC_P_AS_ACTIVATING;

XPC_SET_REASON(part, 0, 0);
spin_unlock_irqrestore(&part->act_lock, irq_flags);
@@ -509,9 +509,9 @@ xpc_activate_partition(struct xpc_partit

spin_lock_irqsave(&part->act_lock, irq_flags);

- DBUG_ON(part->act_state != XPC_P_INACTIVE);
+ DBUG_ON(part->act_state != XPC_P_AS_INACTIVE);

- part->act_state = XPC_P_ACTIVATION_REQ;
+ part->act_state = XPC_P_AS_ACTIVATION_REQ;
XPC_SET_REASON(part, xpCloneKThread, __LINE__);

spin_unlock_irqrestore(&part->act_lock, irq_flags);
@@ -520,7 +520,7 @@ xpc_activate_partition(struct xpc_partit
partid);
if (IS_ERR(kthread)) {
spin_lock_irqsave(&part->act_lock, irq_flags);
- part->act_state = XPC_P_INACTIVE;
+ part->act_state = XPC_P_AS_INACTIVE;
XPC_SET_REASON(part, xpCloneKThreadFailed, __LINE__);
spin_unlock_irqrestore(&part->act_lock, irq_flags);
}
@@ -786,7 +786,7 @@ xpc_disconnect_wait(int ch_number)
wakeup_channel_mgr = 0;

if (ch->delayed_chctl_flags) {
- if (part->act_state != XPC_P_DEACTIVATING) {
+ if (part->act_state != XPC_P_AS_DEACTIVATING) {
spin_lock(&part->chctl_lock);
part->chctl.flags[ch->number] |=
ch->delayed_chctl_flags;
@@ -846,7 +846,7 @@ xpc_do_exit(enum xp_retval reason)
part = &xpc_partitions[partid];

if (xpc_partition_disengaged(part) &&
- part->act_state == XPC_P_INACTIVE) {
+ part->act_state == XPC_P_AS_INACTIVE) {
continue;
}

@@ -962,7 +962,7 @@ xpc_die_deactivate(void)
part = &xpc_partitions[partid];

if (xpc_partition_engaged(partid) ||
- part->act_state != XPC_P_INACTIVE) {
+ part->act_state != XPC_P_AS_INACTIVE) {
xpc_request_partition_deactivation(part);
xpc_indicate_partition_disengaged(part);
}
@@ -1113,7 +1113,7 @@ xpc_init(void)

part->activate_IRQ_rcvd = 0;
spin_lock_init(&part->act_lock);
- part->act_state = XPC_P_INACTIVE;
+ part->act_state = XPC_P_AS_INACTIVE;
XPC_SET_REASON(part, 0, 0);

init_timer(&part->disengage_timer);
@@ -1121,7 +1121,7 @@ xpc_init(void)
xpc_timeout_partition_disengage;
part->disengage_timer.data = (unsigned long)part;

- part->setup_state = XPC_P_UNSET;
+ part->setup_state = XPC_P_SS_UNSET;
init_waitqueue_head(&part->teardown_wq);
atomic_set(&part->references, 0);
}
Index: linux/drivers/misc/sgi-xp/xpc_partition.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_partition.c 2008-06-18 12:46:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_partition.c 2008-06-18 13:21:26.000000000 -0500
@@ -273,9 +273,9 @@ xpc_partition_disengaged(struct xpc_part
if (!in_interrupt())
del_singleshot_timer_sync(&part->disengage_timer);

- DBUG_ON(part->act_state != XPC_P_DEACTIVATING &&
- part->act_state != XPC_P_INACTIVE);
- if (part->act_state != XPC_P_INACTIVE)
+ DBUG_ON(part->act_state != XPC_P_AS_DEACTIVATING &&
+ part->act_state != XPC_P_AS_INACTIVE);
+ if (part->act_state != XPC_P_AS_INACTIVE)
xpc_wakeup_channel_mgr(part);

xpc_cancel_partition_deactivation_request(part);
@@ -295,8 +295,8 @@ xpc_mark_partition_active(struct xpc_par
dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part));

spin_lock_irqsave(&part->act_lock, irq_flags);
- if (part->act_state == XPC_P_ACTIVATING) {
- part->act_state = XPC_P_ACTIVE;
+ if (part->act_state == XPC_P_AS_ACTIVATING) {
+ part->act_state = XPC_P_AS_ACTIVE;
ret = xpSuccess;
} else {
DBUG_ON(part->reason == xpSuccess);
@@ -318,7 +318,7 @@ xpc_deactivate_partition(const int line,

spin_lock_irqsave(&part->act_lock, irq_flags);

- if (part->act_state == XPC_P_INACTIVE) {
+ if (part->act_state == XPC_P_AS_INACTIVE) {
XPC_SET_REASON(part, reason, line);
spin_unlock_irqrestore(&part->act_lock, irq_flags);
if (reason == xpReactivating) {
@@ -327,7 +327,7 @@ xpc_deactivate_partition(const int line,
}
return;
}
- if (part->act_state == XPC_P_DEACTIVATING) {
+ if (part->act_state == XPC_P_AS_DEACTIVATING) {
if ((part->reason == xpUnloading && reason != xpUnloading) ||
reason == xpReactivating) {
XPC_SET_REASON(part, reason, line);
@@ -336,7 +336,7 @@ xpc_deactivate_partition(const int line,
return;
}

- part->act_state = XPC_P_DEACTIVATING;
+ part->act_state = XPC_P_AS_DEACTIVATING;
XPC_SET_REASON(part, reason, line);

spin_unlock_irqrestore(&part->act_lock, irq_flags);
@@ -367,7 +367,7 @@ xpc_mark_partition_inactive(struct xpc_p
XPC_PARTID(part));

spin_lock_irqsave(&part->act_lock, irq_flags);
- part->act_state = XPC_P_INACTIVE;
+ part->act_state = XPC_P_AS_INACTIVE;
spin_unlock_irqrestore(&part->act_lock, irq_flags);
part->remote_rp_pa = 0;
}
Index: linux/drivers/misc/sgi-xp/xpc_sn2.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_sn2.c 2008-06-18 12:45:53.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_sn2.c 2008-06-18 13:23:32.000000000 -0500
@@ -327,7 +327,7 @@ xpc_send_notify_IRQ_sn2(struct xpc_chann
union xpc_channel_ctl_flags chctl = { 0 };
enum xp_retval ret;

- if (likely(part->act_state != XPC_P_DEACTIVATING)) {
+ if (likely(part->act_state != XPC_P_AS_DEACTIVATING)) {
chctl.flags[ch->number] = chctl_flag;
ret = xpc_send_IRQ_sn2(part_sn2->remote_chctl_amo_va,
chctl.all_flags,
@@ -975,7 +975,7 @@ xpc_identify_activate_IRQ_req_sn2(int na
remote_vars->heartbeat, remote_vars->heartbeating_to_mask[0]);

if (xpc_partition_disengaged(part) &&
- part->act_state == XPC_P_INACTIVE) {
+ part->act_state == XPC_P_AS_INACTIVE) {

xpc_update_partition_info_sn2(part, remote_rp_version,
&remote_rp_ts_jiffies,
@@ -1257,10 +1257,10 @@ xpc_setup_infrastructure_sn2(struct xpc_
}

/*
- * With the setting of the partition setup_state to XPC_P_SETUP, we're
- * declaring that this partition is ready to go.
+ * With the setting of the partition setup_state to XPC_P_SS_SETUP,
+ * we're declaring that this partition is ready to go.
*/
- part->setup_state = XPC_P_SETUP;
+ part->setup_state = XPC_P_SS_SETUP;

/*
* Setup the per partition specific variables required by the
@@ -1323,8 +1323,8 @@ xpc_teardown_infrastructure_sn2(struct x

DBUG_ON(atomic_read(&part->nchannels_engaged) != 0);
DBUG_ON(atomic_read(&part->nchannels_active) != 0);
- DBUG_ON(part->setup_state != XPC_P_SETUP);
- part->setup_state = XPC_P_WTEARDOWN;
+ DBUG_ON(part->setup_state != XPC_P_SS_SETUP);
+ part->setup_state = XPC_P_SS_WTEARDOWN;

xpc_vars_part_sn2[partid].magic = 0;

@@ -1338,7 +1338,7 @@ xpc_teardown_infrastructure_sn2(struct x

/* now we can begin tearing down the infrastructure */

- part->setup_state = XPC_P_TORNDOWN;
+ part->setup_state = XPC_P_SS_TORNDOWN;

/* in case we've still got outstanding timers registered... */
del_timer_sync(&part_sn2->dropped_notify_IRQ_timer);
@@ -1375,7 +1375,7 @@ xpc_pull_remote_cachelines_sn2(struct xp
DBUG_ON((unsigned long)dst != L1_CACHE_ALIGN((unsigned long)dst));
DBUG_ON(cnt != L1_CACHE_ALIGN(cnt));

- if (part->act_state == XPC_P_DEACTIVATING)
+ if (part->act_state == XPC_P_AS_DEACTIVATING)
return part->reason;

ret = xp_remote_memcpy(xp_pa(dst), src_pa, cnt);
@@ -1534,7 +1534,7 @@ xpc_make_first_contact_sn2(struct xpc_pa
/* wait a 1/4 of a second or so */
(void)msleep_interruptible(250);

- if (part->act_state == XPC_P_DEACTIVATING)
+ if (part->act_state == XPC_P_AS_DEACTIVATING)
return part->reason;
}

2008-07-07 18:58:52

by Dean Nelson

[permalink] [raw]
Subject: [Patch 5/6] sgi-xp: setup the activate GRU message queue

Setup the activate GRU message queue that is used for partition activation and
channel connection on UV systems.

Signed-off-by: Dean Nelson <[email protected]>

---

Note that the code to setup an irq on UV is incomplete, but is not an issue
since there aren't any UV systems at the moment. Code to resolve this will
be forthcoming.

drivers/misc/sgi-xp/xp.h | 3
drivers/misc/sgi-xp/xp_uv.c | 10
drivers/misc/sgi-xp/xpc.h | 158 +++++-
drivers/misc/sgi-xp/xpc_channel.c | 22
drivers/misc/sgi-xp/xpc_main.c | 329 ++++++++++---
drivers/misc/sgi-xp/xpc_partition.c | 28 -
drivers/misc/sgi-xp/xpc_sn2.c | 387 ++++++---------
drivers/misc/sgi-xp/xpc_uv.c | 781 ++++++++++++++++++++++++++++++--
8 files changed, 1328 insertions(+), 390 deletions(-)

Index: linux/drivers/misc/sgi-xp/xp_uv.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp_uv.c 2008-07-03 11:06:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp_uv.c 2008-07-03 11:06:20.000000000 -0500
@@ -42,15 +42,25 @@ xp_remote_memcpy_uv(unsigned long dst_gp
return xpGruCopyError;
}

+static int
+xp_cpu_to_nasid_uv(int cpuid)
+{
+ /* ??? Is this same as sn2 nasid in mach/part bitmaps set up by SAL? */
+ return UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpuid));
+}
+
enum xp_retval
xp_init_uv(void)
{
BUG_ON(!is_uv());

xp_max_npartitions = XP_MAX_NPARTITIONS_UV;
+ xp_partition_id = 0; /* !!! not correct value */
+ xp_region_size = 0; /* !!! not correct value */

xp_pa = xp_pa_uv;
xp_remote_memcpy = xp_remote_memcpy_uv;
+ xp_cpu_to_nasid = xp_cpu_to_nasid_uv;

return xpSuccess;
}
Index: linux/drivers/misc/sgi-xp/xpc_uv.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_uv.c 2008-07-03 11:06:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_uv.c 2008-07-03 11:15:20.000000000 -0500
@@ -14,41 +14,528 @@
*/

#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/device.h>
#include <asm/uv/uv_hub.h>
+#include "../sgi-gru/gru.h"
#include "../sgi-gru/grukservices.h"
#include "xpc.h"

+static atomic64_t xpc_heartbeat_uv;
static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV);

-static void *xpc_activate_mq;
+#define XPC_ACTIVATE_MSG_SIZE_UV (1 * GRU_CACHE_LINE_BYTES)
+#define XPC_NOTIFY_MSG_SIZE_UV (2 * GRU_CACHE_LINE_BYTES)
+
+#define XPC_ACTIVATE_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \
+ XPC_ACTIVATE_MSG_SIZE_UV)
+#define XPC_NOTIFY_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \
+ XPC_NOTIFY_MSG_SIZE_UV)
+
+static void *xpc_activate_mq_uv;
+static void *xpc_notify_mq_uv;
+
+static int
+xpc_setup_partitions_sn_uv(void)
+{
+ short partid;
+ struct xpc_partition_uv *part_uv;
+
+ for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
+ part_uv = &xpc_partitions[partid].sn.uv;
+
+ spin_lock_init(&part_uv->flags_lock);
+ part_uv->remote_act_state = XPC_P_AS_INACTIVE;
+ }
+ return 0;
+}
+
+static void *
+xpc_create_gru_mq_uv(unsigned int mq_size, int cpuid, unsigned int irq,
+ irq_handler_t irq_handler)
+{
+ int ret;
+ int nid;
+ int mq_order;
+ struct page *page;
+ void *mq;
+
+ nid = cpu_to_node(cpuid);
+ mq_order = get_order(mq_size);
+ page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+ mq_order);
+ if (page == NULL)
+ return NULL;
+
+ mq = page_address(page);
+ ret = gru_create_message_queue(mq, mq_size);
+ if (ret != 0) {
+ dev_err(xpc_part, "gru_create_message_queue() returned "
+ "error=%d\n", ret);
+ free_pages((unsigned long)mq, mq_order);
+ return NULL;
+ }
+
+ /* !!! Need to do some other things to set up IRQ */
+
+ ret = request_irq(irq, irq_handler, 0, "xpc", NULL);
+ if (ret != 0) {
+ dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n",
+ irq, ret);
+ free_pages((unsigned long)mq, mq_order);
+ return NULL;
+ }
+
+ /* !!! enable generation of irq when GRU mq op occurs to this mq */
+
+ /* ??? allow other partitions to access GRU mq? */
+
+ return mq;
+}
+
+static void
+xpc_destroy_gru_mq_uv(void *mq, unsigned int mq_size, unsigned int irq)
+{
+ /* ??? disallow other partitions to access GRU mq? */
+
+ /* !!! disable generation of irq when GRU mq op occurs to this mq */
+
+ free_irq(irq, NULL);
+
+ free_pages((unsigned long)mq, get_order(mq_size));
+}
+
+static enum xp_retval
+xpc_send_gru_msg(unsigned long mq_gpa, void *msg, size_t msg_size)
+{
+ enum xp_retval xp_ret;
+ int ret;
+
+ while (1) {
+ ret = gru_send_message_gpa(mq_gpa, msg, msg_size);
+ if (ret == MQE_OK) {
+ xp_ret = xpSuccess;
+ break;
+ }
+
+ if (ret == MQE_QUEUE_FULL) {
+ dev_dbg(xpc_chan, "gru_send_message_gpa() returned "
+ "error=MQE_QUEUE_FULL\n");
+ /* !!! handle QLimit reached; delay & try again */
+ /* ??? Do we add a limit to the number of retries? */
+ (void)msleep_interruptible(10);
+ } else if (ret == MQE_CONGESTION) {
+ dev_dbg(xpc_chan, "gru_send_message_gpa() returned "
+ "error=MQE_CONGESTION\n");
+ /* !!! handle LB Overflow; simply try again */
+ /* ??? Do we add a limit to the number of retries? */
+ } else {
+ /* !!! Currently this is MQE_UNEXPECTED_CB_ERR */
+ dev_err(xpc_chan, "gru_send_message_gpa() returned "
+ "error=%d\n", ret);
+ xp_ret = xpGruSendMqError;
+ break;
+ }
+ }
+ return xp_ret;
+}
+
+static void
+xpc_process_activate_IRQ_rcvd_uv(void)
+{
+ unsigned long irq_flags;
+ short partid;
+ struct xpc_partition *part;
+ u8 act_state_req;
+
+ DBUG_ON(xpc_activate_IRQ_rcvd == 0);
+
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
+ part = &xpc_partitions[partid];
+
+ if (part->sn.uv.act_state_req == 0)
+ continue;
+
+ xpc_activate_IRQ_rcvd--;
+ BUG_ON(xpc_activate_IRQ_rcvd < 0);
+
+ act_state_req = part->sn.uv.act_state_req;
+ part->sn.uv.act_state_req = 0;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+
+ if (act_state_req == XPC_P_ASR_ACTIVATE_UV) {
+ if (part->act_state == XPC_P_AS_INACTIVE)
+ xpc_activate_partition(part);
+ else if (part->act_state == XPC_P_AS_DEACTIVATING)
+ XPC_DEACTIVATE_PARTITION(part, xpReactivating);
+
+ } else if (act_state_req == XPC_P_ASR_REACTIVATE_UV) {
+ if (part->act_state == XPC_P_AS_INACTIVE)
+ xpc_activate_partition(part);
+ else
+ XPC_DEACTIVATE_PARTITION(part, xpReactivating);
+
+ } else if (act_state_req == XPC_P_ASR_DEACTIVATE_UV) {
+ XPC_DEACTIVATE_PARTITION(part, part->sn.uv.reason);
+
+ } else {
+ BUG();
+ }
+
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ if (xpc_activate_IRQ_rcvd == 0)
+ break;
+ }
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+
+}
+
+static irqreturn_t
+xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
+{
+ unsigned long irq_flags;
+ struct xpc_activate_mq_msghdr_uv *msg_hdr;
+ short partid;
+ struct xpc_partition *part;
+ struct xpc_partition_uv *part_uv;
+ struct xpc_openclose_args *args;
+ int wakeup_hb_checker = 0;
+
+ while ((msg_hdr = gru_get_next_message(xpc_activate_mq_uv)) != NULL) {
+
+ partid = msg_hdr->partid;
+ if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) {
+ dev_err(xpc_part, "xpc_handle_activate_IRQ_uv() invalid"
+ "partid=0x%x passed in message\n", partid);
+ gru_free_message(xpc_activate_mq_uv, msg_hdr);
+ continue;
+ }
+ part = &xpc_partitions[partid];
+ part_uv = &part->sn.uv;
+
+ part_uv->remote_act_state = msg_hdr->act_state;
+
+ switch (msg_hdr->type) {
+ case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV:
+ /* syncing of remote_act_state was just done above */
+ break;
+
+ case XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV: {
+ struct xpc_activate_mq_msg_heartbeat_req_uv *msg;
+
+ msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *)
+ msg_hdr;
+ part_uv->heartbeat = msg->heartbeat;
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV: {
+ struct xpc_activate_mq_msg_heartbeat_req_uv *msg;
+
+ msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *)
+ msg_hdr;
+ part_uv->heartbeat = msg->heartbeat;
+ spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ part_uv->flags |= XPC_P_HEARTBEAT_OFFLINE_UV;
+ spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV: {
+ struct xpc_activate_mq_msg_heartbeat_req_uv *msg;
+
+ msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *)
+ msg_hdr;
+ part_uv->heartbeat = msg->heartbeat;
+ spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ part_uv->flags &= ~XPC_P_HEARTBEAT_OFFLINE_UV;
+ spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: {
+ struct xpc_activate_mq_msg_activate_req_uv *msg;
+
+ /*
+ * ??? Do we deal here with ts_jiffies being different
+ * ??? if act_state != XPC_P_AS_INACTIVE instead of
+ * ??? below?
+ */
+ msg = (struct xpc_activate_mq_msg_activate_req_uv *)
+ msg_hdr;
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock,
+ irq_flags);
+ if (part_uv->act_state_req == 0)
+ xpc_activate_IRQ_rcvd++;
+ part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV;
+ part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */
+ part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies;
+ part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock,
+ irq_flags);
+ wakeup_hb_checker++;
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: {
+ struct xpc_activate_mq_msg_deactivate_req_uv *msg;
+
+ msg = (struct xpc_activate_mq_msg_deactivate_req_uv *)
+ msg_hdr;
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock,
+ irq_flags);
+ if (part_uv->act_state_req == 0)
+ xpc_activate_IRQ_rcvd++;
+ part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV;
+ part_uv->reason = msg->reason;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock,
+ irq_flags);
+ wakeup_hb_checker++;
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: {
+ struct xpc_activate_mq_msg_chctl_closerequest_uv *msg;
+
+ msg = (struct xpc_activate_mq_msg_chctl_closerequest_uv
+ *)msg_hdr;
+ args = &part->remote_openclose_args[msg->ch_number];
+ args->reason = msg->reason;
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ part->chctl.flags[msg->ch_number] |=
+ XPC_CHCTL_CLOSEREQUEST;
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+
+ xpc_wakeup_channel_mgr(part);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: {
+ struct xpc_activate_mq_msg_chctl_closereply_uv *msg;
+
+ msg = (struct xpc_activate_mq_msg_chctl_closereply_uv *)
+ msg_hdr;
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ part->chctl.flags[msg->ch_number] |=
+ XPC_CHCTL_CLOSEREPLY;
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+
+ xpc_wakeup_channel_mgr(part);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: {
+ struct xpc_activate_mq_msg_chctl_openrequest_uv *msg;
+
+ msg = (struct xpc_activate_mq_msg_chctl_openrequest_uv
+ *)msg_hdr;
+ args = &part->remote_openclose_args[msg->ch_number];
+ args->msg_size = msg->msg_size;
+ args->local_nentries = msg->local_nentries;
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ part->chctl.flags[msg->ch_number] |=
+ XPC_CHCTL_OPENREQUEST;
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+
+ xpc_wakeup_channel_mgr(part);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: {
+ struct xpc_activate_mq_msg_chctl_openreply_uv *msg;
+
+ msg = (struct xpc_activate_mq_msg_chctl_openreply_uv *)
+ msg_hdr;
+ args = &part->remote_openclose_args[msg->ch_number];
+ args->remote_nentries = msg->remote_nentries;
+ args->local_nentries = msg->local_nentries;
+ args->local_msgqueue_pa = msg->local_notify_mq_gpa;
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ part->chctl.flags[msg->ch_number] |=
+ XPC_CHCTL_OPENREPLY;
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+
+ xpc_wakeup_channel_mgr(part);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV:
+ spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ part_uv->flags |= XPC_P_ENGAGED_UV;
+ spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+ break;
+
+ case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV:
+ spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ part_uv->flags &= ~XPC_P_ENGAGED_UV;
+ spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+ break;
+
+ default:
+ dev_err(xpc_part, "received unknown activate_mq msg "
+ "type=%d from partition=%d\n", msg_hdr->type,
+ partid);
+ }
+
+ if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies &&
+ part->remote_rp_ts_jiffies != 0) {
+ /*
+ * ??? Does what we do here need to be sensitive to
+ * ??? act_state or remote_act_state?
+ */
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock,
+ irq_flags);
+ if (part_uv->act_state_req == 0)
+ xpc_activate_IRQ_rcvd++;
+ part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock,
+ irq_flags);
+ wakeup_hb_checker++;
+ }
+
+ gru_free_message(xpc_activate_mq_uv, msg_hdr);
+ }
+
+ if (wakeup_hb_checker)
+ wake_up_interruptible(&xpc_activate_IRQ_wq);
+
+ return IRQ_HANDLED;
+}
+
+static enum xp_retval
+xpc_send_activate_IRQ_uv(struct xpc_partition *part, void *msg, size_t msg_size,
+ int msg_type)
+{
+ struct xpc_activate_mq_msghdr_uv *msg_hdr = msg;
+
+ DBUG_ON(msg_size > XPC_ACTIVATE_MSG_SIZE_UV);
+
+ msg_hdr->type = msg_type;
+ msg_hdr->partid = XPC_PARTID(part);
+ msg_hdr->act_state = part->act_state;
+ msg_hdr->rp_ts_jiffies = xpc_rsvd_page->ts_jiffies;
+
+ /* ??? Is holding a spin_lock (ch->lock) during this call a bad idea? */
+ return xpc_send_gru_msg(part->sn.uv.remote_activate_mq_gpa, msg,
+ msg_size);
+}

static void
-xpc_send_local_activate_IRQ_uv(struct xpc_partition *part)
+xpc_send_activate_IRQ_part_uv(struct xpc_partition *part, void *msg,
+ size_t msg_size, int msg_type)
{
+ enum xp_retval ret;
+
+ ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type);
+ if (unlikely(ret != xpSuccess))
+ XPC_DEACTIVATE_PARTITION(part, ret);
+}
+
+static void
+xpc_send_activate_IRQ_ch_uv(struct xpc_channel *ch, unsigned long *irq_flags,
+ void *msg, size_t msg_size, int msg_type)
+{
+ struct xpc_partition *part = &xpc_partitions[ch->number];
+ enum xp_retval ret;
+
+ ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type);
+ if (unlikely(ret != xpSuccess)) {
+ if (irq_flags != NULL)
+ spin_unlock_irqrestore(&ch->lock, *irq_flags);
+
+ XPC_DEACTIVATE_PARTITION(part, ret);
+
+ if (irq_flags != NULL)
+ spin_lock_irqsave(&ch->lock, *irq_flags);
+ }
+}
+
+static void
+xpc_send_local_activate_IRQ_uv(struct xpc_partition *part, int act_state_req)
+{
+ unsigned long irq_flags;
+ struct xpc_partition_uv *part_uv = &part->sn.uv;
+
/*
* !!! Make our side think that the remote parition sent an activate
- * !!! message our way. Also do what the activate IRQ handler would
+ * !!! message our way by doing what the activate IRQ handler would
* !!! do had one really been sent.
*/
+
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ if (part_uv->act_state_req == 0)
+ xpc_activate_IRQ_rcvd++;
+ part_uv->act_state_req = act_state_req;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+
+ wake_up_interruptible(&xpc_activate_IRQ_wq);
}

static enum xp_retval
-xpc_rsvd_page_init_uv(struct xpc_rsvd_page *rp)
+xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa,
+ size_t *len)
{
- /* !!! need to have established xpc_activate_mq earlier */
- rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq);
- return xpSuccess;
+ /* !!! call the UV version of sn_partition_reserved_page_pa() */
+ return xpUnsupported;
+}
+
+static int
+xpc_setup_rsvd_page_sn_uv(struct xpc_rsvd_page *rp)
+{
+ rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv);
+ return 0;
+}
+
+static void
+xpc_send_heartbeat_uv(int msg_type)
+{
+ short partid;
+ struct xpc_partition *part;
+ struct xpc_activate_mq_msg_heartbeat_req_uv msg;
+
+ /*
+ * !!! On uv we're broadcasting a heartbeat message every 5 seconds.
+ * !!! Whereas on sn2 we're bte_copy'ng the heartbeat info every 20
+ * !!! seconds. This is an increase in numalink traffic.
+ * ??? Is this good?
+ */
+
+ msg.heartbeat = atomic64_inc_return(&xpc_heartbeat_uv);
+
+ partid = find_first_bit(xpc_heartbeating_to_mask_uv,
+ XP_MAX_NPARTITIONS_UV);
+
+ while (partid < XP_MAX_NPARTITIONS_UV) {
+ part = &xpc_partitions[partid];
+
+ xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
+ msg_type);
+
+ partid = find_next_bit(xpc_heartbeating_to_mask_uv,
+ XP_MAX_NPARTITIONS_UV, partid + 1);
+ }
}

static void
xpc_increment_heartbeat_uv(void)
{
- /* !!! send heartbeat msg to xpc_heartbeating_to_mask partids */
+ xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV);
+}
+
+static void
+xpc_offline_heartbeat_uv(void)
+{
+ xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV);
+}
+
+static void
+xpc_online_heartbeat_uv(void)
+{
+ xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV);
}

static void
xpc_heartbeat_init_uv(void)
{
+ atomic64_set(&xpc_heartbeat_uv, 0);
bitmap_zero(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV);
xpc_heartbeating_to_mask = &xpc_heartbeating_to_mask_uv[0];
}
@@ -56,48 +543,94 @@ xpc_heartbeat_init_uv(void)
static void
xpc_heartbeat_exit_uv(void)
{
- /* !!! send heartbeat_offline msg to xpc_heartbeating_to_mask partids */
+ xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV);
+}
+
+static enum xp_retval
+xpc_get_remote_heartbeat_uv(struct xpc_partition *part)
+{
+ struct xpc_partition_uv *part_uv = &part->sn.uv;
+ enum xp_retval ret = xpNoHeartbeat;
+
+ if (part_uv->remote_act_state != XPC_P_AS_INACTIVE &&
+ part_uv->remote_act_state != XPC_P_AS_DEACTIVATING) {
+
+ if (part_uv->heartbeat != part->last_heartbeat ||
+ (part_uv->flags & XPC_P_HEARTBEAT_OFFLINE_UV)) {
+
+ part->last_heartbeat = part_uv->heartbeat;
+ ret = xpSuccess;
+ }
+ }
+ return ret;
}

static void
xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp,
- unsigned long remote_rp_pa, int nasid)
+ unsigned long remote_rp_gpa, int nasid)
{
short partid = remote_rp->SAL_partid;
struct xpc_partition *part = &xpc_partitions[partid];
+ struct xpc_activate_mq_msg_activate_req_uv msg;

-/*
- * !!! Setup part structure with the bits of info we can glean from the rp:
- * !!! part->remote_rp_pa = remote_rp_pa;
- * !!! part->sn.uv.activate_mq_gpa = remote_rp->sn.activate_mq_gpa;
- */
+ part->remote_rp_pa = remote_rp_gpa; /* !!! _pa here is really _gpa */
+ part->remote_rp_ts_jiffies = remote_rp->ts_jiffies;
+ part->sn.uv.remote_activate_mq_gpa = remote_rp->sn.activate_mq_gpa;
+
+ /*
+ * ??? Is it a good idea to make this conditional on what is
+ * ??? potentially stale state information?
+ */
+ if (part->sn.uv.remote_act_state == XPC_P_AS_INACTIVE) {
+ msg.rp_gpa = uv_gpa(xpc_rsvd_page);
+ msg.activate_mq_gpa = xpc_rsvd_page->sn.activate_mq_gpa;
+ xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
+ XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV);
+ }

- xpc_send_local_activate_IRQ_uv(part);
+ if (part->act_state == XPC_P_AS_INACTIVE)
+ xpc_send_local_activate_IRQ_uv(part, XPC_P_ASR_ACTIVATE_UV);
}

static void
xpc_request_partition_reactivation_uv(struct xpc_partition *part)
{
- xpc_send_local_activate_IRQ_uv(part);
+ xpc_send_local_activate_IRQ_uv(part, XPC_P_ASR_ACTIVATE_UV);
+}
+
+static void
+xpc_request_partition_deactivation_uv(struct xpc_partition *part)
+{
+ struct xpc_activate_mq_msg_deactivate_req_uv msg;
+
+ /*
+ * ??? Is it a good idea to make this conditional on what is
+ * ??? potentially stale state information?
+ */
+ if (part->sn.uv.remote_act_state != XPC_P_AS_DEACTIVATING &&
+ part->sn.uv.remote_act_state != XPC_P_AS_INACTIVE) {
+
+ msg.reason = part->reason;
+ xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
+ XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV);
+ }
}

/*
- * Setup the infrastructure necessary to support XPartition Communication
- * between the specified remote partition and the local one.
+ * Setup the channel structures that are uv specific.
*/
static enum xp_retval
-xpc_setup_infrastructure_uv(struct xpc_partition *part)
+xpc_setup_ch_structures_sn_uv(struct xpc_partition *part)
{
/* !!! this function needs fleshing out */
return xpUnsupported;
}

/*
- * Teardown the infrastructure necessary to support XPartition Communication
- * between the specified remote partition and the local one.
+ * Teardown the channel structures that are uv specific.
*/
static void
-xpc_teardown_infrastructure_uv(struct xpc_partition *part)
+xpc_teardown_ch_structures_sn_uv(struct xpc_partition *part)
{
/* !!! this function needs fleshing out */
return;
@@ -106,15 +639,163 @@ xpc_teardown_infrastructure_uv(struct xp
static enum xp_retval
xpc_make_first_contact_uv(struct xpc_partition *part)
{
- /* !!! this function needs fleshing out */
- return xpUnsupported;
+ struct xpc_activate_mq_msg_uv msg;
+
+ /*
+ * We send a sync msg to get the remote partition's remote_act_state
+ * updated to our current act_state which at this point should
+ * be XPC_P_AS_ACTIVATING.
+ */
+ xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
+ XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV);
+
+ while (part->sn.uv.remote_act_state != XPC_P_AS_ACTIVATING) {
+
+ dev_dbg(xpc_part, "waiting to make first contact with "
+ "partition %d\n", XPC_PARTID(part));
+
+ /* wait a 1/4 of a second or so */
+ (void)msleep_interruptible(250);
+
+ if (part->act_state == XPC_P_AS_DEACTIVATING)
+ return part->reason;
+ }
+
+ return xpSuccess;
}

static u64
xpc_get_chctl_all_flags_uv(struct xpc_partition *part)
{
+ unsigned long irq_flags;
+ union xpc_channel_ctl_flags chctl;
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ chctl = part->chctl;
+ if (chctl.all_flags != 0)
+ part->chctl.all_flags = 0;
+
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+ return chctl.all_flags;
+}
+
+static enum xp_retval
+xpc_setup_msg_structures_uv(struct xpc_channel *ch)
+{
/* !!! this function needs fleshing out */
- return 0UL;
+ return xpUnsupported;
+}
+
+static void
+xpc_teardown_msg_structures_uv(struct xpc_channel *ch)
+{
+ struct xpc_channel_uv *ch_uv = &ch->sn.uv;
+
+ ch_uv->remote_notify_mq_gpa = 0;
+
+ /* !!! this function needs fleshing out */
+}
+
+static void
+xpc_send_chctl_closerequest_uv(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+ struct xpc_activate_mq_msg_chctl_closerequest_uv msg;
+
+ msg.ch_number = ch->number;
+ msg.reason = ch->reason;
+ xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
+ XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV);
+}
+
+static void
+xpc_send_chctl_closereply_uv(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+ struct xpc_activate_mq_msg_chctl_closereply_uv msg;
+
+ msg.ch_number = ch->number;
+ xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
+ XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV);
+}
+
+static void
+xpc_send_chctl_openrequest_uv(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+ struct xpc_activate_mq_msg_chctl_openrequest_uv msg;
+
+ msg.ch_number = ch->number;
+ msg.msg_size = ch->msg_size;
+ msg.local_nentries = ch->local_nentries;
+ xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
+ XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV);
+}
+
+static void
+xpc_send_chctl_openreply_uv(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+ struct xpc_activate_mq_msg_chctl_openreply_uv msg;
+
+ msg.ch_number = ch->number;
+ msg.local_nentries = ch->local_nentries;
+ msg.remote_nentries = ch->remote_nentries;
+ msg.local_notify_mq_gpa = uv_gpa(xpc_notify_mq_uv);
+ xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
+ XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV);
+}
+
+static void
+xpc_save_remote_msgqueue_pa_uv(struct xpc_channel *ch,
+ unsigned long msgqueue_pa)
+{
+ ch->sn.uv.remote_notify_mq_gpa = msgqueue_pa;
+}
+
+static void
+xpc_indicate_partition_engaged_uv(struct xpc_partition *part)
+{
+ struct xpc_activate_mq_msg_uv msg;
+
+ xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
+ XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV);
+}
+
+static void
+xpc_indicate_partition_disengaged_uv(struct xpc_partition *part)
+{
+ struct xpc_activate_mq_msg_uv msg;
+
+ xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
+ XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV);
+}
+
+static void
+xpc_assume_partition_disengaged_uv(short partid)
+{
+ struct xpc_partition_uv *part_uv = &xpc_partitions[partid].sn.uv;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ part_uv->flags &= ~XPC_P_ENGAGED_UV;
+ spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+}
+
+static int
+xpc_partition_engaged_uv(short partid)
+{
+ return (xpc_partitions[partid].sn.uv.flags & XPC_P_ENGAGED_UV) != 0;
+}
+
+static int
+xpc_any_partition_engaged_uv(void)
+{
+ struct xpc_partition_uv *part_uv;
+ short partid;
+
+ for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
+ part_uv = &xpc_partitions[partid].sn.uv;
+ if ((part_uv->flags & XPC_P_ENGAGED_UV) != 0)
+ return 1;
+ }
+ return 0;
}

static struct xpc_msg *
@@ -124,24 +805,64 @@ xpc_get_deliverable_msg_uv(struct xpc_ch
return NULL;
}

-void
+int
xpc_init_uv(void)
{
- xpc_rsvd_page_init = xpc_rsvd_page_init_uv;
+ xpc_setup_partitions_sn = xpc_setup_partitions_sn_uv;
+ xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_uv;
+ xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_uv;
+ xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_uv;
xpc_increment_heartbeat = xpc_increment_heartbeat_uv;
+ xpc_offline_heartbeat = xpc_offline_heartbeat_uv;
+ xpc_online_heartbeat = xpc_online_heartbeat_uv;
xpc_heartbeat_init = xpc_heartbeat_init_uv;
xpc_heartbeat_exit = xpc_heartbeat_exit_uv;
+ xpc_get_remote_heartbeat = xpc_get_remote_heartbeat_uv;
+
xpc_request_partition_activation = xpc_request_partition_activation_uv;
xpc_request_partition_reactivation =
xpc_request_partition_reactivation_uv;
- xpc_setup_infrastructure = xpc_setup_infrastructure_uv;
- xpc_teardown_infrastructure = xpc_teardown_infrastructure_uv;
+ xpc_request_partition_deactivation =
+ xpc_request_partition_deactivation_uv;
+
+ xpc_setup_ch_structures_sn = xpc_setup_ch_structures_sn_uv;
+ xpc_teardown_ch_structures_sn = xpc_teardown_ch_structures_sn_uv;
+
xpc_make_first_contact = xpc_make_first_contact_uv;
+
xpc_get_chctl_all_flags = xpc_get_chctl_all_flags_uv;
+ xpc_send_chctl_closerequest = xpc_send_chctl_closerequest_uv;
+ xpc_send_chctl_closereply = xpc_send_chctl_closereply_uv;
+ xpc_send_chctl_openrequest = xpc_send_chctl_openrequest_uv;
+ xpc_send_chctl_openreply = xpc_send_chctl_openreply_uv;
+
+ xpc_save_remote_msgqueue_pa = xpc_save_remote_msgqueue_pa_uv;
+
+ xpc_setup_msg_structures = xpc_setup_msg_structures_uv;
+ xpc_teardown_msg_structures = xpc_teardown_msg_structures_uv;
+
+ xpc_indicate_partition_engaged = xpc_indicate_partition_engaged_uv;
+ xpc_indicate_partition_disengaged =
+ xpc_indicate_partition_disengaged_uv;
+ xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_uv;
+ xpc_partition_engaged = xpc_partition_engaged_uv;
+ xpc_any_partition_engaged = xpc_any_partition_engaged_uv;
+
xpc_get_deliverable_msg = xpc_get_deliverable_msg_uv;
+
+ /* ??? The cpuid argument's value is 0, is that what we want? */
+ /* !!! The irq argument's value isn't correct. */
+ xpc_activate_mq_uv = xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, 0, 0,
+ xpc_handle_activate_IRQ_uv);
+ if (xpc_activate_mq_uv == NULL)
+ return -ENOMEM;
+
+ return 0;
}

void
xpc_exit_uv(void)
{
+ /* !!! The irq argument's value isn't correct. */
+ xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, XPC_ACTIVATE_MQ_SIZE_UV, 0);
}
Index: linux/drivers/misc/sgi-xp/xpc.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc.h 2008-07-03 11:06:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc.h 2008-07-03 11:09:18.000000000 -0500
@@ -164,8 +164,8 @@ struct xpc_vars_part_sn2 {
* MAGIC2 indicates that this partition has pulled the remote partititions
* per partition variables that pertain to this partition.
*/
-#define XPC_VP_MAGIC1 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */
-#define XPC_VP_MAGIC2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */
+#define XPC_VP_MAGIC1_SN2 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */
+#define XPC_VP_MAGIC2_SN2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */

/* the reserved page sizes and offsets */

@@ -181,6 +181,80 @@ struct xpc_vars_part_sn2 {
xpc_nasid_mask_nlongs))

/*
+ * The activate_mq is used to send/receive messages that affect XPC's heartbeat,
+ * partition active state, and channel state. This is UV only.
+ */
+struct xpc_activate_mq_msghdr_uv {
+ short partid; /* sender's partid */
+ u8 act_state; /* sender's act_state at time msg sent */
+ u8 type; /* message's type */
+ unsigned long rp_ts_jiffies; /* timestamp of sender's rp setup by XPC */
+};
+
+/* activate_mq defined message types */
+#define XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV 0
+#define XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV 1
+#define XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV 2
+#define XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV 3
+
+#define XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV 4
+#define XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV 5
+
+#define XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV 6
+#define XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV 7
+#define XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV 8
+#define XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV 9
+
+#define XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV 10
+#define XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV 11
+
+struct xpc_activate_mq_msg_uv {
+ struct xpc_activate_mq_msghdr_uv header;
+};
+
+struct xpc_activate_mq_msg_heartbeat_req_uv {
+ struct xpc_activate_mq_msghdr_uv header;
+ u64 heartbeat;
+};
+
+struct xpc_activate_mq_msg_activate_req_uv {
+ struct xpc_activate_mq_msghdr_uv header;
+ unsigned long rp_gpa;
+ unsigned long activate_mq_gpa;
+};
+
+struct xpc_activate_mq_msg_deactivate_req_uv {
+ struct xpc_activate_mq_msghdr_uv header;
+ enum xp_retval reason;
+};
+
+struct xpc_activate_mq_msg_chctl_closerequest_uv {
+ struct xpc_activate_mq_msghdr_uv header;
+ short ch_number;
+ enum xp_retval reason;
+};
+
+struct xpc_activate_mq_msg_chctl_closereply_uv {
+ struct xpc_activate_mq_msghdr_uv header;
+ short ch_number;
+};
+
+struct xpc_activate_mq_msg_chctl_openrequest_uv {
+ struct xpc_activate_mq_msghdr_uv header;
+ short ch_number;
+ short msg_size; /* size of notify_mq's messages */
+ short local_nentries; /* ??? Is this needed? What is? */
+};
+
+struct xpc_activate_mq_msg_chctl_openreply_uv {
+ struct xpc_activate_mq_msghdr_uv header;
+ short ch_number;
+ short remote_nentries; /* ??? Is this needed? What is? */
+ short local_nentries; /* ??? Is this needed? What is? */
+ unsigned long local_notify_mq_gpa;
+};
+
+/*
* Functions registered by add_timer() or called by kernel_thread() only
* allow for a single 64-bit argument. The following macros can be used to
* pack and unpack two (32-bit, 16-bit or 8-bit) arguments into or out from
@@ -331,6 +405,18 @@ struct xpc_notify {
*/

struct xpc_channel_sn2 {
+ struct xpc_openclose_args *local_openclose_args; /* args passed on */
+ /* opening or closing of channel */
+
+ void *local_msgqueue_base; /* base address of kmalloc'd space */
+ struct xpc_msg *local_msgqueue; /* local message queue */
+ void *remote_msgqueue_base; /* base address of kmalloc'd space */
+ struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */
+ /* local message queue */
+ unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */
+ /* local message queue */
+
+ struct xpc_notify *notify_queue; /* notify queue for messages sent */

/* various flavors of local and remote Get/Put values */

@@ -344,13 +430,14 @@ struct xpc_channel_sn2 {
};

struct xpc_channel_uv {
- /* !!! code is coming */
+ unsigned long remote_notify_mq_gpa; /* gru phys address of remote */
+ /* partition's notify mq */
};

struct xpc_channel {
short partid; /* ID of remote partition connected */
spinlock_t lock; /* lock for updating this structure */
- u32 flags; /* general flags */
+ unsigned int flags; /* general flags */

enum xp_retval reason; /* reason why channel is disconnect'g */
int reason_line; /* line# disconnect initiated from */
@@ -361,14 +448,6 @@ struct xpc_channel {
u16 local_nentries; /* #of msg entries in local msg queue */
u16 remote_nentries; /* #of msg entries in remote msg queue */

- void *local_msgqueue_base; /* base address of kmalloc'd space */
- struct xpc_msg *local_msgqueue; /* local message queue */
- void *remote_msgqueue_base; /* base address of kmalloc'd space */
- struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */
- /* local message queue */
- unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */
- /* local message queue */
-
atomic_t references; /* #of external references to queues */

atomic_t n_on_msg_allocate_wq; /* #on msg allocation wait queue */
@@ -377,19 +456,13 @@ struct xpc_channel {
u8 delayed_chctl_flags; /* chctl flags received, but delayed */
/* action until channel disconnected */

- /* queue of msg senders who want to be notified when msg received */
-
atomic_t n_to_notify; /* #of msg senders to notify */
- struct xpc_notify *notify_queue; /* notify queue for messages sent */

xpc_channel_func func; /* user's channel function */
void *key; /* pointer to user's key */

struct completion wdisconnect_wait; /* wait for channel disconnect */

- struct xpc_openclose_args *local_openclose_args; /* args passed on */
- /* opening or closing of channel */
-
/* kthread management related fields */

atomic_t kthreads_assigned; /* #of kthreads assigned to channel */
@@ -507,6 +580,8 @@ struct xpc_partition_sn2 {
unsigned long remote_GPs_pa; /* phys addr of remote partition's local */
/* Get/Put values */

+ void *local_openclose_args_base; /* base address of kmalloc'd space */
+ struct xpc_openclose_args *local_openclose_args; /* local's args */
unsigned long remote_openclose_args_pa; /* phys addr of remote's args */

int notify_IRQ_nasid; /* nasid of where to send notify IRQs */
@@ -520,9 +595,27 @@ struct xpc_partition_sn2 {
};

struct xpc_partition_uv {
- /* !!! code is coming */
+ unsigned long remote_activate_mq_gpa; /* gru phys address of remote */
+ /* partition's activate mq */
+ spinlock_t flags_lock; /* protect updating of flags */
+ unsigned int flags; /* general flags */
+ u8 remote_act_state; /* remote partition's act_state */
+ u8 act_state_req; /* act_state request from remote partition */
+ enum xp_retval reason; /* reason for deactivate act_state request */
+ u64 heartbeat; /* incremented by remote partition */
};

+/* struct xpc_partition_uv flags */
+
+#define XPC_P_HEARTBEAT_OFFLINE_UV 0x00000001
+#define XPC_P_ENGAGED_UV 0x00000002
+
+/* struct xpc_partition_uv act_state change requests */
+
+#define XPC_P_ASR_ACTIVATE_UV 0x01
+#define XPC_P_ASR_REACTIVATE_UV 0x02
+#define XPC_P_ASR_DEACTIVATE_UV 0x03
+
struct xpc_partition {

/* XPC HB infrastructure */
@@ -556,8 +649,6 @@ struct xpc_partition {
union xpc_channel_ctl_flags chctl; /* chctl flags yet to be processed */
spinlock_t chctl_lock; /* chctl flags lock */

- void *local_openclose_args_base; /* base address of kmalloc'd space */
- struct xpc_openclose_args *local_openclose_args; /* local's args */
void *remote_openclose_args_base; /* base address of kmalloc'd space */
struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */
/* args */
@@ -616,17 +707,20 @@ extern struct device *xpc_part;
extern struct device *xpc_chan;
extern int xpc_disengage_timelimit;
extern int xpc_disengage_timedout;
-extern atomic_t xpc_activate_IRQ_rcvd;
+extern int xpc_activate_IRQ_rcvd;
+extern spinlock_t xpc_activate_IRQ_rcvd_lock;
extern wait_queue_head_t xpc_activate_IRQ_wq;
extern void *xpc_heartbeating_to_mask;
+extern void *xpc_kzalloc_cacheline_aligned(size_t, gfp_t, void **);
extern void xpc_activate_partition(struct xpc_partition *);
extern void xpc_activate_kthreads(struct xpc_channel *, int);
extern void xpc_create_kthreads(struct xpc_channel *, int, int);
extern void xpc_disconnect_wait(int);
+extern int (*xpc_setup_partitions_sn) (void);
extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *, u64 *,
unsigned long *,
size_t *);
-extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *);
+extern int (*xpc_setup_rsvd_page_sn) (struct xpc_rsvd_page *);
extern void (*xpc_heartbeat_init) (void);
extern void (*xpc_heartbeat_exit) (void);
extern void (*xpc_increment_heartbeat) (void);
@@ -635,8 +729,8 @@ extern void (*xpc_online_heartbeat) (voi
extern enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *);
extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *);
extern u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *);
-extern enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *);
-extern void (*xpc_free_msgqueues) (struct xpc_channel *);
+extern enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *);
+extern void (*xpc_teardown_msg_structures) (struct xpc_channel *);
extern void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *);
extern void (*xpc_process_msg_chctl_flags) (struct xpc_partition *, int);
extern int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *);
@@ -647,9 +741,9 @@ extern void (*xpc_request_partition_reac
extern void (*xpc_request_partition_deactivation) (struct xpc_partition *);
extern void (*xpc_cancel_partition_deactivation_request) (
struct xpc_partition *);
-extern void (*xpc_process_activate_IRQ_rcvd) (int);
-extern enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *);
-extern void (*xpc_teardown_infrastructure) (struct xpc_partition *);
+extern void (*xpc_process_activate_IRQ_rcvd) (void);
+extern enum xp_retval (*xpc_setup_ch_structures_sn) (struct xpc_partition *);
+extern void (*xpc_teardown_ch_structures_sn) (struct xpc_partition *);

extern void (*xpc_indicate_partition_engaged) (struct xpc_partition *);
extern int (*xpc_partition_engaged) (short);
@@ -665,6 +759,9 @@ extern void (*xpc_send_chctl_openrequest
unsigned long *);
extern void (*xpc_send_chctl_openreply) (struct xpc_channel *, unsigned long *);

+extern void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *,
+ unsigned long);
+
extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, u32, void *, u16,
u8, xpc_notify_func, void *);
extern void (*xpc_received_msg) (struct xpc_channel *, struct xpc_msg *);
@@ -674,7 +771,7 @@ extern int xpc_init_sn2(void);
extern void xpc_exit_sn2(void);

/* found in xpc_uv.c */
-extern void xpc_init_uv(void);
+extern int xpc_init_uv(void);
extern void xpc_exit_uv(void);

/* found in xpc_partition.c */
@@ -684,7 +781,8 @@ extern struct xpc_rsvd_page *xpc_rsvd_pa
extern unsigned long *xpc_mach_nasids;
extern struct xpc_partition *xpc_partitions;
extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **);
-extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void);
+extern int xpc_setup_rsvd_page(void);
+extern void xpc_teardown_rsvd_page(void);
extern int xpc_identify_activate_IRQ_sender(void);
extern int xpc_partition_disengaged(struct xpc_partition *);
extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *);
Index: linux/drivers/misc/sgi-xp/xpc_main.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_main.c 2008-07-03 11:06:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_main.c 2008-07-03 11:09:27.000000000 -0500
@@ -141,8 +141,9 @@ static struct ctl_table_header *xpc_sysc
/* non-zero if any remote partition disengage was timed out */
int xpc_disengage_timedout;

-/* #of activate IRQs received */
-atomic_t xpc_activate_IRQ_rcvd = ATOMIC_INIT(0);
+/* #of activate IRQs received and not yet processed */
+int xpc_activate_IRQ_rcvd;
+DEFINE_SPINLOCK(xpc_activate_IRQ_rcvd_lock);

/* IRQ handler notifies this wait queue on receipt of an IRQ */
DECLARE_WAIT_QUEUE_HEAD(xpc_activate_IRQ_wq);
@@ -169,10 +170,11 @@ static struct notifier_block xpc_die_not
.notifier_call = xpc_system_die,
};

+int (*xpc_setup_partitions_sn) (void);
enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie,
unsigned long *rp_pa,
size_t *len);
-enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp);
+int (*xpc_setup_rsvd_page_sn) (struct xpc_rsvd_page *rp);
void (*xpc_heartbeat_init) (void);
void (*xpc_heartbeat_exit) (void);
void (*xpc_increment_heartbeat) (void);
@@ -183,8 +185,8 @@ enum xp_retval (*xpc_get_remote_heartbea
enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part);
void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch);
u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *part);
-enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *ch);
-void (*xpc_free_msgqueues) (struct xpc_channel *ch);
+enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *ch);
+void (*xpc_teardown_msg_structures) (struct xpc_channel *ch);
void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number);
int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch);
struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch);
@@ -196,9 +198,9 @@ void (*xpc_request_partition_reactivatio
void (*xpc_request_partition_deactivation) (struct xpc_partition *part);
void (*xpc_cancel_partition_deactivation_request) (struct xpc_partition *part);

-void (*xpc_process_activate_IRQ_rcvd) (int n_IRQs_expected);
-enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part);
-void (*xpc_teardown_infrastructure) (struct xpc_partition *part);
+void (*xpc_process_activate_IRQ_rcvd) (void);
+enum xp_retval (*xpc_setup_ch_structures_sn) (struct xpc_partition *part);
+void (*xpc_teardown_ch_structures_sn) (struct xpc_partition *part);

void (*xpc_indicate_partition_engaged) (struct xpc_partition *part);
int (*xpc_partition_engaged) (short partid);
@@ -215,6 +217,9 @@ void (*xpc_send_chctl_openrequest) (stru
void (*xpc_send_chctl_openreply) (struct xpc_channel *ch,
unsigned long *irq_flags);

+void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch,
+ unsigned long msgqueue_pa);
+
enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags,
void *payload, u16 payload_size, u8 notify_type,
xpc_notify_func func, void *key);
@@ -308,8 +313,6 @@ xpc_check_remote_hb(void)
static int
xpc_hb_checker(void *ignore)
{
- int last_IRQ_count = 0;
- int new_IRQ_count;
int force_IRQ = 0;

/* this thread was marked active by xpc_hb_init() */
@@ -325,43 +328,37 @@ xpc_hb_checker(void *ignore)
dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have "
"been received\n",
(int)(xpc_hb_check_timeout - jiffies),
- atomic_read(&xpc_activate_IRQ_rcvd) - last_IRQ_count);
+ xpc_activate_IRQ_rcvd);

/* checking of remote heartbeats is skewed by IRQ handling */
if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) {
+ xpc_hb_check_timeout = jiffies +
+ (xpc_hb_check_interval * HZ);
+
dev_dbg(xpc_part, "checking remote heartbeats\n");
xpc_check_remote_hb();

/*
- * We need to periodically recheck to ensure no
- * IRQ/amo pairs have been missed. That check
- * must always reset xpc_hb_check_timeout.
+ * On sn2 we need to periodically recheck to ensure no
+ * IRQ/amo pairs have been missed.
*/
- force_IRQ = 1;
+ if (is_shub())
+ force_IRQ = 1;
}

/* check for outstanding IRQs */
- new_IRQ_count = atomic_read(&xpc_activate_IRQ_rcvd);
- if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) {
+ if (xpc_activate_IRQ_rcvd > 0 || force_IRQ != 0) {
force_IRQ = 0;
-
- dev_dbg(xpc_part, "found an IRQ to process; will be "
- "resetting xpc_hb_check_timeout\n");
-
- xpc_process_activate_IRQ_rcvd(new_IRQ_count -
- last_IRQ_count);
- last_IRQ_count = new_IRQ_count;
-
- xpc_hb_check_timeout = jiffies +
- (xpc_hb_check_interval * HZ);
+ dev_dbg(xpc_part, "processing activate IRQs "
+ "received\n");
+ xpc_process_activate_IRQ_rcvd();
}

/* wait for IRQ or timeout */
(void)wait_event_interruptible(xpc_activate_IRQ_wq,
- (last_IRQ_count < atomic_read(
- &xpc_activate_IRQ_rcvd)
- || time_is_before_eq_jiffies(
+ (time_is_before_eq_jiffies(
xpc_hb_check_timeout) ||
+ xpc_activate_IRQ_rcvd > 0 ||
xpc_exiting));
}

@@ -437,6 +434,153 @@ xpc_channel_mgr(struct xpc_partition *pa
}

/*
+ * Guarantee that the kzalloc'd memory is cacheline aligned.
+ */
+void *
+xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base)
+{
+ /* see if kzalloc will give us cachline aligned memory by default */
+ *base = kzalloc(size, flags);
+ if (*base == NULL)
+ return NULL;
+
+ if ((u64)*base == L1_CACHE_ALIGN((u64)*base))
+ return *base;
+
+ kfree(*base);
+
+ /* nope, we'll have to do it ourselves */
+ *base = kzalloc(size + L1_CACHE_BYTES, flags);
+ if (*base == NULL)
+ return NULL;
+
+ return (void *)L1_CACHE_ALIGN((u64)*base);
+}
+
+/*
+ * Setup the channel structures necessary to support XPartition Communication
+ * between the specified remote partition and the local one.
+ */
+static enum xp_retval
+xpc_setup_ch_structures(struct xpc_partition *part)
+{
+ enum xp_retval ret;
+ int ch_number;
+ struct xpc_channel *ch;
+ short partid = XPC_PARTID(part);
+
+ /*
+ * Allocate all of the channel structures as a contiguous chunk of
+ * memory.
+ */
+ DBUG_ON(part->channels != NULL);
+ part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS,
+ GFP_KERNEL);
+ if (part->channels == NULL) {
+ dev_err(xpc_chan, "can't get memory for channels\n");
+ return xpNoMemory;
+ }
+
+ /* allocate the remote open and close args */
+
+ part->remote_openclose_args =
+ xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE,
+ GFP_KERNEL, &part->
+ remote_openclose_args_base);
+ if (part->remote_openclose_args == NULL) {
+ dev_err(xpc_chan, "can't get memory for remote connect args\n");
+ ret = xpNoMemory;
+ goto out_1;
+ }
+
+ part->chctl.all_flags = 0;
+ spin_lock_init(&part->chctl_lock);
+
+ atomic_set(&part->channel_mgr_requests, 1);
+ init_waitqueue_head(&part->channel_mgr_wq);
+
+ part->nchannels = XPC_MAX_NCHANNELS;
+
+ atomic_set(&part->nchannels_active, 0);
+ atomic_set(&part->nchannels_engaged, 0);
+
+ for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
+ ch = &part->channels[ch_number];
+
+ ch->partid = partid;
+ ch->number = ch_number;
+ ch->flags = XPC_C_DISCONNECTED;
+
+ atomic_set(&ch->kthreads_assigned, 0);
+ atomic_set(&ch->kthreads_idle, 0);
+ atomic_set(&ch->kthreads_active, 0);
+
+ atomic_set(&ch->references, 0);
+ atomic_set(&ch->n_to_notify, 0);
+
+ spin_lock_init(&ch->lock);
+ init_completion(&ch->wdisconnect_wait);
+
+ atomic_set(&ch->n_on_msg_allocate_wq, 0);
+ init_waitqueue_head(&ch->msg_allocate_wq);
+ init_waitqueue_head(&ch->idle_wq);
+ }
+
+ ret = xpc_setup_ch_structures_sn(part);
+ if (ret != xpSuccess)
+ goto out_2;
+
+ /*
+ * With the setting of the partition setup_state to XPC_P_SS_SETUP,
+ * we're declaring that this partition is ready to go.
+ */
+ part->setup_state = XPC_P_SS_SETUP;
+
+ return xpSuccess;
+
+ /* setup of ch structures failed */
+out_2:
+ kfree(part->remote_openclose_args_base);
+ part->remote_openclose_args = NULL;
+out_1:
+ kfree(part->channels);
+ part->channels = NULL;
+ return ret;
+}
+
+/*
+ * Teardown the channel structures necessary to support XPartition Communication
+ * between the specified remote partition and the local one.
+ */
+static void
+xpc_teardown_ch_structures(struct xpc_partition *part)
+{
+ DBUG_ON(atomic_read(&part->nchannels_engaged) != 0);
+ DBUG_ON(atomic_read(&part->nchannels_active) != 0);
+
+ /*
+ * Make this partition inaccessible to local processes by marking it
+ * as no longer setup. Then wait before proceeding with the teardown
+ * until all existing references cease.
+ */
+ DBUG_ON(part->setup_state != XPC_P_SS_SETUP);
+ part->setup_state = XPC_P_SS_WTEARDOWN;
+
+ wait_event(part->teardown_wq, (atomic_read(&part->references) == 0));
+
+ /* now we can begin tearing down the infrastructure */
+
+ xpc_teardown_ch_structures_sn(part);
+
+ kfree(part->remote_openclose_args_base);
+ part->remote_openclose_args = NULL;
+ kfree(part->channels);
+ part->channels = NULL;
+
+ part->setup_state = XPC_P_SS_TORNDOWN;
+}
+
+/*
* When XPC HB determines that a partition has come up, it will create a new
* kthread and that kthread will call this function to attempt to set up the
* basic infrastructure used for Cross Partition Communication with the newly
@@ -476,7 +620,7 @@ xpc_activating(void *__partid)

xpc_allow_hb(partid);

- if (xpc_setup_infrastructure(part) == xpSuccess) {
+ if (xpc_setup_ch_structures(part) == xpSuccess) {
(void)xpc_part_ref(part); /* this will always succeed */

if (xpc_make_first_contact(part) == xpSuccess) {
@@ -486,7 +630,7 @@ xpc_activating(void *__partid)
}

xpc_part_deref(part);
- xpc_teardown_infrastructure(part);
+ xpc_teardown_ch_structures(part);
}

xpc_disallow_hb(partid);
@@ -806,6 +950,56 @@ xpc_disconnect_wait(int ch_number)
}
}

+static int
+xpc_setup_partitions(void)
+{
+ short partid;
+ struct xpc_partition *part;
+
+ xpc_partitions = kzalloc(sizeof(struct xpc_partition) *
+ xp_max_npartitions, GFP_KERNEL);
+ if (xpc_partitions == NULL) {
+ dev_err(xpc_part, "can't get memory for partition structure\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * The first few fields of each entry of xpc_partitions[] need to
+ * be initialized now so that calls to xpc_connect() and
+ * xpc_disconnect() can be made prior to the activation of any remote
+ * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE
+ * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING
+ * PARTITION HAS BEEN ACTIVATED.
+ */
+ for (partid = 0; partid < xp_max_npartitions; partid++) {
+ part = &xpc_partitions[partid];
+
+ DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part));
+
+ part->activate_IRQ_rcvd = 0;
+ spin_lock_init(&part->act_lock);
+ part->act_state = XPC_P_AS_INACTIVE;
+ XPC_SET_REASON(part, 0, 0);
+
+ init_timer(&part->disengage_timer);
+ part->disengage_timer.function =
+ xpc_timeout_partition_disengage;
+ part->disengage_timer.data = (unsigned long)part;
+
+ part->setup_state = XPC_P_SS_UNSET;
+ init_waitqueue_head(&part->teardown_wq);
+ atomic_set(&part->references, 0);
+ }
+
+ return xpc_setup_partitions_sn();
+}
+
+static void
+xpc_teardown_partitions(void)
+{
+ kfree(xpc_partitions);
+}
+
static void
xpc_do_exit(enum xp_retval reason)
{
@@ -892,8 +1086,7 @@ xpc_do_exit(enum xp_retval reason)
DBUG_ON(xpc_any_partition_engaged());
DBUG_ON(xpc_any_hbs_allowed() != 0);

- /* a zero timestamp indicates our rsvd page is not initialized */
- xpc_rsvd_page->ts_jiffies = 0;
+ xpc_teardown_rsvd_page();

if (reason == xpUnloading) {
(void)unregister_die_notifier(&xpc_die_notifier);
@@ -906,7 +1099,7 @@ xpc_do_exit(enum xp_retval reason)
if (xpc_sysctl)
unregister_sysctl_table(xpc_sysctl);

- kfree(xpc_partitions);
+ xpc_teardown_partitions();

if (is_shub())
xpc_exit_sn2();
@@ -1062,8 +1255,6 @@ int __init
xpc_init(void)
{
int ret;
- short partid;
- struct xpc_partition *part;
struct task_struct *kthread;

snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part");
@@ -1076,56 +1267,29 @@ xpc_init(void)
* further to only support exactly 64 partitions on this
* architecture, no less.
*/
- if (xp_max_npartitions != 64)
- return -EINVAL;
-
- ret = xpc_init_sn2();
- if (ret != 0)
- return ret;
+ if (xp_max_npartitions != 64) {
+ dev_err(xpc_part, "max #of partitions not set to 64\n");
+ ret = -EINVAL;
+ } else {
+ ret = xpc_init_sn2();
+ }

} else if (is_uv()) {
- xpc_init_uv();
+ ret = xpc_init_uv();

} else {
- return -ENODEV;
+ ret = -ENODEV;
}

- xpc_partitions = kzalloc(sizeof(struct xpc_partition) *
- xp_max_npartitions, GFP_KERNEL);
- if (xpc_partitions == NULL) {
+ if (ret != 0)
+ return ret;
+
+ ret = xpc_setup_partitions();
+ if (ret != 0) {
dev_err(xpc_part, "can't get memory for partition structure\n");
- ret = -ENOMEM;
goto out_1;
}

- /*
- * The first few fields of each entry of xpc_partitions[] need to
- * be initialized now so that calls to xpc_connect() and
- * xpc_disconnect() can be made prior to the activation of any remote
- * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE
- * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING
- * PARTITION HAS BEEN ACTIVATED.
- */
- for (partid = 0; partid < xp_max_npartitions; partid++) {
- part = &xpc_partitions[partid];
-
- DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part));
-
- part->activate_IRQ_rcvd = 0;
- spin_lock_init(&part->act_lock);
- part->act_state = XPC_P_AS_INACTIVE;
- XPC_SET_REASON(part, 0, 0);
-
- init_timer(&part->disengage_timer);
- part->disengage_timer.function =
- xpc_timeout_partition_disengage;
- part->disengage_timer.data = (unsigned long)part;
-
- part->setup_state = XPC_P_SS_UNSET;
- init_waitqueue_head(&part->teardown_wq);
- atomic_set(&part->references, 0);
- }
-
xpc_sysctl = register_sysctl_table(xpc_sys_dir);

/*
@@ -1133,10 +1297,9 @@ xpc_init(void)
* other partitions to discover we are alive and establish initial
* communications.
*/
- xpc_rsvd_page = xpc_setup_rsvd_page();
- if (xpc_rsvd_page == NULL) {
+ ret = xpc_setup_rsvd_page();
+ if (ret != 0) {
dev_err(xpc_part, "can't setup our reserved page\n");
- ret = -EBUSY;
goto out_2;
}

@@ -1187,15 +1350,15 @@ xpc_init(void)

/* initialization was not successful */
out_3:
- /* a zero timestamp indicates our rsvd page is not initialized */
- xpc_rsvd_page->ts_jiffies = 0;
+ xpc_teardown_rsvd_page();

(void)unregister_die_notifier(&xpc_die_notifier);
(void)unregister_reboot_notifier(&xpc_reboot_notifier);
out_2:
if (xpc_sysctl)
unregister_sysctl_table(xpc_sysctl);
- kfree(xpc_partitions);
+
+ xpc_teardown_partitions();
out_1:
if (is_shub())
xpc_exit_sn2();
Index: linux/drivers/misc/sgi-xp/xpc_partition.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_partition.c 2008-07-03 11:06:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_partition.c 2008-07-03 11:06:20.000000000 -0500
@@ -73,6 +73,12 @@ xpc_get_rsvd_page_pa(int nasid)

while (1) {

+ /* !!! rp_pa will need to be _gpa on UV.
+ * ??? So do we save it into the architecture specific parts
+ * ??? of the xpc_partition structure? Do we rename this
+ * ??? function or have two versions? Rename rp_pa for UV to
+ * ??? rp_gpa?
+ */
ret = xpc_get_partition_rsvd_page_pa(buf, &cookie, &rp_pa,
&len);

@@ -118,9 +124,10 @@ xpc_get_rsvd_page_pa(int nasid)
* other partitions to discover we are alive and establish initial
* communications.
*/
-struct xpc_rsvd_page *
+int
xpc_setup_rsvd_page(void)
{
+ int ret;
struct xpc_rsvd_page *rp;
unsigned long rp_pa;
unsigned long new_ts_jiffies;
@@ -132,7 +139,7 @@ xpc_setup_rsvd_page(void)
preempt_enable();
if (rp_pa == 0) {
dev_err(xpc_part, "SAL failed to locate the reserved page\n");
- return NULL;
+ return -ESRCH;
}
rp = (struct xpc_rsvd_page *)__va(rp_pa);

@@ -146,7 +153,7 @@ xpc_setup_rsvd_page(void)
dev_err(xpc_part, "the reserved page's partid of %d is outside "
"supported range (< 0 || >= %d)\n", rp->SAL_partid,
xp_max_npartitions);
- return NULL;
+ return -EINVAL;
}

rp->version = XPC_RP_VERSION;
@@ -165,8 +172,9 @@ xpc_setup_rsvd_page(void)
xpc_part_nasids = XPC_RP_PART_NASIDS(rp);
xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp);

- if (xpc_rsvd_page_init(rp) != xpSuccess)
- return NULL;
+ ret = xpc_setup_rsvd_page_sn(rp);
+ if (ret != 0)
+ return ret;

/*
* Set timestamp of when reserved page was setup by XPC.
@@ -178,7 +186,15 @@ xpc_setup_rsvd_page(void)
new_ts_jiffies++;
rp->ts_jiffies = new_ts_jiffies;

- return rp;
+ xpc_rsvd_page = rp;
+ return 0;
+}
+
+void
+xpc_teardown_rsvd_page(void)
+{
+ /* a zero timestamp indicates our rsvd page is not initialized */
+ xpc_rsvd_page->ts_jiffies = 0;
}

/*
Index: linux/drivers/misc/sgi-xp/xpc_sn2.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_sn2.c 2008-07-03 11:06:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_sn2.c 2008-07-03 11:07:53.000000000 -0500
@@ -53,12 +53,19 @@
* Buffer used to store a local copy of portions of a remote partition's
* reserved page (either its header and part_nasids mask, or its vars).
*/
-static char *xpc_remote_copy_buffer_sn2;
static void *xpc_remote_copy_buffer_base_sn2;
+static char *xpc_remote_copy_buffer_sn2;

static struct xpc_vars_sn2 *xpc_vars_sn2;
static struct xpc_vars_part_sn2 *xpc_vars_part_sn2;

+static int
+xpc_setup_partitions_sn_sn2(void)
+{
+ /* nothing needs to be done */
+ return 0;
+}
+
/* SH_IPI_ACCESS shub register value on startup */
static u64 xpc_sh1_IPI_access_sn2;
static u64 xpc_sh2_IPI_access0_sn2;
@@ -198,7 +205,12 @@ xpc_init_IRQ_amo_sn2(int index)
static irqreturn_t
xpc_handle_activate_IRQ_sn2(int irq, void *dev_id)
{
- atomic_inc(&xpc_activate_IRQ_rcvd);
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ xpc_activate_IRQ_rcvd++;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+
wake_up_interruptible(&xpc_activate_IRQ_wq);
return IRQ_HANDLED;
}
@@ -222,6 +234,7 @@ xpc_send_activate_IRQ_sn2(unsigned long
static void
xpc_send_local_activate_IRQ_sn2(int from_nasid)
{
+ unsigned long irq_flags;
struct amo *amos = (struct amo *)__va(xpc_vars_sn2->amos_page_pa +
(XPC_ACTIVATE_IRQ_AMOS_SN2 *
sizeof(struct amo)));
@@ -230,7 +243,10 @@ xpc_send_local_activate_IRQ_sn2(int from
FETCHOP_STORE_OP(TO_AMO((u64)&amos[BIT_WORD(from_nasid / 2)].variable),
FETCHOP_OR, BIT_MASK(from_nasid / 2));

- atomic_inc(&xpc_activate_IRQ_rcvd);
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ xpc_activate_IRQ_rcvd++;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+
wake_up_interruptible(&xpc_activate_IRQ_wq);
}

@@ -375,7 +391,7 @@ static void
xpc_send_chctl_closerequest_sn2(struct xpc_channel *ch,
unsigned long *irq_flags)
{
- struct xpc_openclose_args *args = ch->local_openclose_args;
+ struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;

args->reason = ch->reason;
XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREQUEST, irq_flags);
@@ -390,7 +406,7 @@ xpc_send_chctl_closereply_sn2(struct xpc
static void
xpc_send_chctl_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags)
{
- struct xpc_openclose_args *args = ch->local_openclose_args;
+ struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;

args->msg_size = ch->msg_size;
args->local_nentries = ch->local_nentries;
@@ -400,11 +416,11 @@ xpc_send_chctl_openrequest_sn2(struct xp
static void
xpc_send_chctl_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags)
{
- struct xpc_openclose_args *args = ch->local_openclose_args;
+ struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;

args->remote_nentries = ch->remote_nentries;
args->local_nentries = ch->local_nentries;
- args->local_msgqueue_pa = xp_pa(ch->local_msgqueue);
+ args->local_msgqueue_pa = xp_pa(ch->sn.sn2.local_msgqueue);
XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREPLY, irq_flags);
}

@@ -420,6 +436,13 @@ xpc_send_chctl_local_msgrequest_sn2(stru
XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST);
}

+static void
+xpc_save_remote_msgqueue_pa_sn2(struct xpc_channel *ch,
+ unsigned long msgqueue_pa)
+{
+ ch->sn.sn2.remote_msgqueue_pa = msgqueue_pa;
+}
+
/*
* This next set of functions are used to keep track of when a partition is
* potentially engaged in accessing memory belonging to another partition.
@@ -489,6 +512,17 @@ xpc_indicate_partition_disengaged_sn2(st
part_sn2->activate_IRQ_phys_cpuid);
}

+static void
+xpc_assume_partition_disengaged_sn2(short partid)
+{
+ struct amo *amo = xpc_vars_sn2->amos_page +
+ XPC_ENGAGED_PARTITIONS_AMO_SN2;
+
+ /* clear bit(s) based on partid mask in our partition's amo */
+ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
+ ~BIT(partid));
+}
+
static int
xpc_partition_engaged_sn2(short partid)
{
@@ -510,17 +544,6 @@ xpc_any_partition_engaged_sn2(void)
return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) != 0;
}

-static void
-xpc_assume_partition_disengaged_sn2(short partid)
-{
- struct amo *amo = xpc_vars_sn2->amos_page +
- XPC_ENGAGED_PARTITIONS_AMO_SN2;
-
- /* clear bit(s) based on partid mask in our partition's amo */
- FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
- ~BIT(partid));
-}
-
/* original protection values for each node */
static u64 xpc_prot_vec_sn2[MAX_NUMNODES];

@@ -595,8 +618,8 @@ xpc_get_partition_rsvd_page_pa_sn2(void
}


-static enum xp_retval
-xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp)
+static int
+xpc_setup_rsvd_page_sn_sn2(struct xpc_rsvd_page *rp)
{
struct amo *amos_page;
int i;
@@ -627,7 +650,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_p
amos_page = (struct amo *)TO_AMO(uncached_alloc_page(0, 1));
if (amos_page == NULL) {
dev_err(xpc_part, "can't allocate page of amos\n");
- return xpNoMemory;
+ return -ENOMEM;
}

/*
@@ -639,7 +662,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_p
dev_err(xpc_part, "can't allow amo operations\n");
uncached_free_page(__IA64_UNCACHED_OFFSET |
TO_PHYS((u64)amos_page), 1);
- return ret;
+ return -EPERM;
}
}

@@ -665,7 +688,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_p
(void)xpc_init_IRQ_amo_sn2(XPC_ENGAGED_PARTITIONS_AMO_SN2);
(void)xpc_init_IRQ_amo_sn2(XPC_DEACTIVATE_REQUEST_AMO_SN2);

- return xpSuccess;
+ return 0;
}

static void
@@ -1082,10 +1105,19 @@ xpc_identify_activate_IRQ_sender_sn2(voi
}

static void
-xpc_process_activate_IRQ_rcvd_sn2(int n_IRQs_expected)
+xpc_process_activate_IRQ_rcvd_sn2(void)
{
+ unsigned long irq_flags;
+ int n_IRQs_expected;
int n_IRQs_detected;

+ DBUG_ON(xpc_activate_IRQ_rcvd == 0);
+
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ n_IRQs_expected = xpc_activate_IRQ_rcvd;
+ xpc_activate_IRQ_rcvd = 0;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+
n_IRQs_detected = xpc_identify_activate_IRQ_sender_sn2();
if (n_IRQs_detected < n_IRQs_expected) {
/* retry once to help avoid missing amo */
@@ -1094,116 +1126,63 @@ xpc_process_activate_IRQ_rcvd_sn2(int n_
}

/*
- * Guarantee that the kzalloc'd memory is cacheline aligned.
- */
-static void *
-xpc_kzalloc_cacheline_aligned_sn2(size_t size, gfp_t flags, void **base)
-{
- /* see if kzalloc will give us cachline aligned memory by default */
- *base = kzalloc(size, flags);
- if (*base == NULL)
- return NULL;
-
- if ((u64)*base == L1_CACHE_ALIGN((u64)*base))
- return *base;
-
- kfree(*base);
-
- /* nope, we'll have to do it ourselves */
- *base = kzalloc(size + L1_CACHE_BYTES, flags);
- if (*base == NULL)
- return NULL;
-
- return (void *)L1_CACHE_ALIGN((u64)*base);
-}
-
-/*
- * Setup the infrastructure necessary to support XPartition Communication
- * between the specified remote partition and the local one.
+ * Setup the channel structures that are sn2 specific.
*/
static enum xp_retval
-xpc_setup_infrastructure_sn2(struct xpc_partition *part)
+xpc_setup_ch_structures_sn_sn2(struct xpc_partition *part)
{
struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
+ struct xpc_channel_sn2 *ch_sn2;
enum xp_retval retval;
int ret;
int cpuid;
int ch_number;
- struct xpc_channel *ch;
struct timer_list *timer;
short partid = XPC_PARTID(part);

- /*
- * Allocate all of the channel structures as a contiguous chunk of
- * memory.
- */
- DBUG_ON(part->channels != NULL);
- part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS,
- GFP_KERNEL);
- if (part->channels == NULL) {
- dev_err(xpc_chan, "can't get memory for channels\n");
- return xpNoMemory;
- }
-
/* allocate all the required GET/PUT values */

part_sn2->local_GPs =
- xpc_kzalloc_cacheline_aligned_sn2(XPC_GP_SIZE, GFP_KERNEL,
- &part_sn2->local_GPs_base);
+ xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL,
+ &part_sn2->local_GPs_base);
if (part_sn2->local_GPs == NULL) {
dev_err(xpc_chan, "can't get memory for local get/put "
"values\n");
- retval = xpNoMemory;
- goto out_1;
+ return xpNoMemory;
}

part_sn2->remote_GPs =
- xpc_kzalloc_cacheline_aligned_sn2(XPC_GP_SIZE, GFP_KERNEL,
- &part_sn2->remote_GPs_base);
+ xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL,
+ &part_sn2->remote_GPs_base);
if (part_sn2->remote_GPs == NULL) {
dev_err(xpc_chan, "can't get memory for remote get/put "
"values\n");
retval = xpNoMemory;
- goto out_2;
+ goto out_1;
}

part_sn2->remote_GPs_pa = 0;

/* allocate all the required open and close args */

- part->local_openclose_args =
- xpc_kzalloc_cacheline_aligned_sn2(XPC_OPENCLOSE_ARGS_SIZE,
- GFP_KERNEL,
- &part->local_openclose_args_base);
- if (part->local_openclose_args == NULL) {
+ part_sn2->local_openclose_args =
+ xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE,
+ GFP_KERNEL, &part_sn2->
+ local_openclose_args_base);
+ if (part_sn2->local_openclose_args == NULL) {
dev_err(xpc_chan, "can't get memory for local connect args\n");
retval = xpNoMemory;
- goto out_3;
- }
-
- part->remote_openclose_args =
- xpc_kzalloc_cacheline_aligned_sn2(XPC_OPENCLOSE_ARGS_SIZE,
- GFP_KERNEL,
- &part->remote_openclose_args_base);
- if (part->remote_openclose_args == NULL) {
- dev_err(xpc_chan, "can't get memory for remote connect args\n");
- retval = xpNoMemory;
- goto out_4;
+ goto out_2;
}

part_sn2->remote_openclose_args_pa = 0;

part_sn2->local_chctl_amo_va = xpc_init_IRQ_amo_sn2(partid);
- part->chctl.all_flags = 0;
- spin_lock_init(&part->chctl_lock);

part_sn2->notify_IRQ_nasid = 0;
part_sn2->notify_IRQ_phys_cpuid = 0;
part_sn2->remote_chctl_amo_va = NULL;

- atomic_set(&part->channel_mgr_requests, 1);
- init_waitqueue_head(&part->channel_mgr_wq);
-
sprintf(part_sn2->notify_IRQ_owner, "xpc%02d", partid);
ret = request_irq(SGI_XPC_NOTIFY, xpc_handle_notify_IRQ_sn2,
IRQF_SHARED, part_sn2->notify_IRQ_owner,
@@ -1212,7 +1191,7 @@ xpc_setup_infrastructure_sn2(struct xpc_
dev_err(xpc_chan, "can't register NOTIFY IRQ handler, "
"errno=%d\n", -ret);
retval = xpLackOfResources;
- goto out_5;
+ goto out_3;
}

/* Setup a timer to check for dropped notify IRQs */
@@ -1224,45 +1203,17 @@ xpc_setup_infrastructure_sn2(struct xpc_
timer->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL;
add_timer(timer);

- part->nchannels = XPC_MAX_NCHANNELS;
-
- atomic_set(&part->nchannels_active, 0);
- atomic_set(&part->nchannels_engaged, 0);
-
for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
- ch = &part->channels[ch_number];
-
- ch->partid = partid;
- ch->number = ch_number;
- ch->flags = XPC_C_DISCONNECTED;
-
- ch->sn.sn2.local_GP = &part_sn2->local_GPs[ch_number];
- ch->local_openclose_args =
- &part->local_openclose_args[ch_number];
-
- atomic_set(&ch->kthreads_assigned, 0);
- atomic_set(&ch->kthreads_idle, 0);
- atomic_set(&ch->kthreads_active, 0);
+ ch_sn2 = &part->channels[ch_number].sn.sn2;

- atomic_set(&ch->references, 0);
- atomic_set(&ch->n_to_notify, 0);
+ ch_sn2->local_GP = &part_sn2->local_GPs[ch_number];
+ ch_sn2->local_openclose_args =
+ &part_sn2->local_openclose_args[ch_number];

- spin_lock_init(&ch->lock);
- mutex_init(&ch->sn.sn2.msg_to_pull_mutex);
- init_completion(&ch->wdisconnect_wait);
-
- atomic_set(&ch->n_on_msg_allocate_wq, 0);
- init_waitqueue_head(&ch->msg_allocate_wq);
- init_waitqueue_head(&ch->idle_wq);
+ mutex_init(&ch_sn2->msg_to_pull_mutex);
}

/*
- * With the setting of the partition setup_state to XPC_P_SS_SETUP,
- * we're declaring that this partition is ready to go.
- */
- part->setup_state = XPC_P_SS_SETUP;
-
- /*
* Setup the per partition specific variables required by the
* remote partition to establish channel connections with us.
*
@@ -1271,7 +1222,7 @@ xpc_setup_infrastructure_sn2(struct xpc_
*/
xpc_vars_part_sn2[partid].GPs_pa = xp_pa(part_sn2->local_GPs);
xpc_vars_part_sn2[partid].openclose_args_pa =
- xp_pa(part->local_openclose_args);
+ xp_pa(part_sn2->local_openclose_args);
xpc_vars_part_sn2[partid].chctl_amo_pa =
xp_pa(part_sn2->local_chctl_amo_va);
cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */
@@ -1279,80 +1230,48 @@ xpc_setup_infrastructure_sn2(struct xpc_
xpc_vars_part_sn2[partid].notify_IRQ_phys_cpuid =
cpu_physical_id(cpuid);
xpc_vars_part_sn2[partid].nchannels = part->nchannels;
- xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC1;
+ xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC1_SN2;

return xpSuccess;

- /* setup of infrastructure failed */
-out_5:
- kfree(part->remote_openclose_args_base);
- part->remote_openclose_args = NULL;
-out_4:
- kfree(part->local_openclose_args_base);
- part->local_openclose_args = NULL;
+ /* setup of ch structures failed */
out_3:
+ kfree(part_sn2->local_openclose_args_base);
+ part_sn2->local_openclose_args = NULL;
+out_2:
kfree(part_sn2->remote_GPs_base);
part_sn2->remote_GPs = NULL;
-out_2:
+out_1:
kfree(part_sn2->local_GPs_base);
part_sn2->local_GPs = NULL;
-out_1:
- kfree(part->channels);
- part->channels = NULL;
return retval;
}

/*
- * Teardown the infrastructure necessary to support XPartition Communication
- * between the specified remote partition and the local one.
+ * Teardown the channel structures that are sn2 specific.
*/
static void
-xpc_teardown_infrastructure_sn2(struct xpc_partition *part)
+xpc_teardown_ch_structures_sn_sn2(struct xpc_partition *part)
{
struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
short partid = XPC_PARTID(part);

/*
- * We start off by making this partition inaccessible to local
- * processes by marking it as no longer setup. Then we make it
- * inaccessible to remote processes by clearing the XPC per partition
- * specific variable's magic # (which indicates that these variables
- * are no longer valid) and by ignoring all XPC notify IRQs sent to
- * this partition.
+ * Indicate that the variables specific to the remote partition are no
+ * longer available for its use.
*/
-
- DBUG_ON(atomic_read(&part->nchannels_engaged) != 0);
- DBUG_ON(atomic_read(&part->nchannels_active) != 0);
- DBUG_ON(part->setup_state != XPC_P_SS_SETUP);
- part->setup_state = XPC_P_SS_WTEARDOWN;
-
xpc_vars_part_sn2[partid].magic = 0;

- free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid);
-
- /*
- * Before proceeding with the teardown we have to wait until all
- * existing references cease.
- */
- wait_event(part->teardown_wq, (atomic_read(&part->references) == 0));
-
- /* now we can begin tearing down the infrastructure */
-
- part->setup_state = XPC_P_SS_TORNDOWN;
-
/* in case we've still got outstanding timers registered... */
del_timer_sync(&part_sn2->dropped_notify_IRQ_timer);
+ free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid);

- kfree(part->remote_openclose_args_base);
- part->remote_openclose_args = NULL;
- kfree(part->local_openclose_args_base);
- part->local_openclose_args = NULL;
+ kfree(part_sn2->local_openclose_args_base);
+ part_sn2->local_openclose_args = NULL;
kfree(part_sn2->remote_GPs_base);
part_sn2->remote_GPs = NULL;
kfree(part_sn2->local_GPs_base);
part_sn2->local_GPs = NULL;
- kfree(part->channels);
- part->channels = NULL;
part_sn2->local_chctl_amo_va = NULL;
}

@@ -1429,8 +1348,8 @@ xpc_pull_remote_vars_part_sn2(struct xpc

/* see if they've been set up yet */

- if (pulled_entry->magic != XPC_VP_MAGIC1 &&
- pulled_entry->magic != XPC_VP_MAGIC2) {
+ if (pulled_entry->magic != XPC_VP_MAGIC1_SN2 &&
+ pulled_entry->magic != XPC_VP_MAGIC2_SN2) {

if (pulled_entry->magic != 0) {
dev_dbg(xpc_chan, "partition %d's XPC vars_part for "
@@ -1443,7 +1362,7 @@ xpc_pull_remote_vars_part_sn2(struct xpc
return xpRetry;
}

- if (xpc_vars_part_sn2[partid].magic == XPC_VP_MAGIC1) {
+ if (xpc_vars_part_sn2[partid].magic == XPC_VP_MAGIC1_SN2) {

/* validate the variables */

@@ -1473,10 +1392,10 @@ xpc_pull_remote_vars_part_sn2(struct xpc

/* let the other side know that we've pulled their variables */

- xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC2;
+ xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC2_SN2;
}

- if (pulled_entry->magic == XPC_VP_MAGIC1)
+ if (pulled_entry->magic == XPC_VP_MAGIC1_SN2)
return xpRetry;

return xpSuccess;
@@ -1605,6 +1524,7 @@ xpc_get_chctl_all_flags_sn2(struct xpc_p
static enum xp_retval
xpc_allocate_local_msgqueue_sn2(struct xpc_channel *ch)
{
+ struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
unsigned long irq_flags;
int nentries;
size_t nbytes;
@@ -1612,17 +1532,17 @@ xpc_allocate_local_msgqueue_sn2(struct x
for (nentries = ch->local_nentries; nentries > 0; nentries--) {

nbytes = nentries * ch->msg_size;
- ch->local_msgqueue =
- xpc_kzalloc_cacheline_aligned_sn2(nbytes, GFP_KERNEL,
- &ch->local_msgqueue_base);
- if (ch->local_msgqueue == NULL)
+ ch_sn2->local_msgqueue =
+ xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL,
+ &ch_sn2->local_msgqueue_base);
+ if (ch_sn2->local_msgqueue == NULL)
continue;

nbytes = nentries * sizeof(struct xpc_notify);
- ch->notify_queue = kzalloc(nbytes, GFP_KERNEL);
- if (ch->notify_queue == NULL) {
- kfree(ch->local_msgqueue_base);
- ch->local_msgqueue = NULL;
+ ch_sn2->notify_queue = kzalloc(nbytes, GFP_KERNEL);
+ if (ch_sn2->notify_queue == NULL) {
+ kfree(ch_sn2->local_msgqueue_base);
+ ch_sn2->local_msgqueue = NULL;
continue;
}

@@ -1649,6 +1569,7 @@ xpc_allocate_local_msgqueue_sn2(struct x
static enum xp_retval
xpc_allocate_remote_msgqueue_sn2(struct xpc_channel *ch)
{
+ struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
unsigned long irq_flags;
int nentries;
size_t nbytes;
@@ -1658,10 +1579,10 @@ xpc_allocate_remote_msgqueue_sn2(struct
for (nentries = ch->remote_nentries; nentries > 0; nentries--) {

nbytes = nentries * ch->msg_size;
- ch->remote_msgqueue =
- xpc_kzalloc_cacheline_aligned_sn2(nbytes, GFP_KERNEL,
- &ch->remote_msgqueue_base);
- if (ch->remote_msgqueue == NULL)
+ ch_sn2->remote_msgqueue =
+ xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, &ch_sn2->
+ remote_msgqueue_base);
+ if (ch_sn2->remote_msgqueue == NULL)
continue;

spin_lock_irqsave(&ch->lock, irq_flags);
@@ -1687,8 +1608,9 @@ xpc_allocate_remote_msgqueue_sn2(struct
* Note: Assumes all of the channel sizes are filled in.
*/
static enum xp_retval
-xpc_allocate_msgqueues_sn2(struct xpc_channel *ch)
+xpc_setup_msg_structures_sn2(struct xpc_channel *ch)
{
+ struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
enum xp_retval ret;

DBUG_ON(ch->flags & XPC_C_SETUP);
@@ -1698,10 +1620,10 @@ xpc_allocate_msgqueues_sn2(struct xpc_ch

ret = xpc_allocate_remote_msgqueue_sn2(ch);
if (ret != xpSuccess) {
- kfree(ch->local_msgqueue_base);
- ch->local_msgqueue = NULL;
- kfree(ch->notify_queue);
- ch->notify_queue = NULL;
+ kfree(ch_sn2->local_msgqueue_base);
+ ch_sn2->local_msgqueue = NULL;
+ kfree(ch_sn2->notify_queue);
+ ch_sn2->notify_queue = NULL;
}
}
return ret;
@@ -1715,21 +1637,13 @@ xpc_allocate_msgqueues_sn2(struct xpc_ch
* they're cleared when XPC_C_DISCONNECTED is cleared.
*/
static void
-xpc_free_msgqueues_sn2(struct xpc_channel *ch)
+xpc_teardown_msg_structures_sn2(struct xpc_channel *ch)
{
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;

DBUG_ON(!spin_is_locked(&ch->lock));
- DBUG_ON(atomic_read(&ch->n_to_notify) != 0);

- ch->remote_msgqueue_pa = 0;
- ch->func = NULL;
- ch->key = NULL;
- ch->msg_size = 0;
- ch->local_nentries = 0;
- ch->remote_nentries = 0;
- ch->kthreads_assigned_limit = 0;
- ch->kthreads_idle_limit = 0;
+ ch_sn2->remote_msgqueue_pa = 0;

ch_sn2->local_GP->get = 0;
ch_sn2->local_GP->put = 0;
@@ -1745,12 +1659,12 @@ xpc_free_msgqueues_sn2(struct xpc_channe
dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n",
ch->flags, ch->partid, ch->number);

- kfree(ch->local_msgqueue_base);
- ch->local_msgqueue = NULL;
- kfree(ch->remote_msgqueue_base);
- ch->remote_msgqueue = NULL;
- kfree(ch->notify_queue);
- ch->notify_queue = NULL;
+ kfree(ch_sn2->local_msgqueue_base);
+ ch_sn2->local_msgqueue = NULL;
+ kfree(ch_sn2->remote_msgqueue_base);
+ ch_sn2->remote_msgqueue = NULL;
+ kfree(ch_sn2->notify_queue);
+ ch_sn2->notify_queue = NULL;
}
}

@@ -1766,7 +1680,7 @@ xpc_notify_senders_sn2(struct xpc_channe

while (++get < put && atomic_read(&ch->n_to_notify) > 0) {

- notify = &ch->notify_queue[get % ch->local_nentries];
+ notify = &ch->sn.sn2.notify_queue[get % ch->local_nentries];

/*
* See if the notify entry indicates it was associated with
@@ -1818,7 +1732,7 @@ xpc_clear_local_msgqueue_flags_sn2(struc

get = ch_sn2->w_remote_GP.get;
do {
- msg = (struct xpc_msg *)((u64)ch->local_msgqueue +
+ msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue +
(get % ch->local_nentries) *
ch->msg_size);
msg->flags = 0;
@@ -1837,7 +1751,7 @@ xpc_clear_remote_msgqueue_flags_sn2(stru

put = ch_sn2->w_remote_GP.put;
do {
- msg = (struct xpc_msg *)((u64)ch->remote_msgqueue +
+ msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue +
(put % ch->remote_nentries) *
ch->msg_size);
msg->flags = 0;
@@ -1976,8 +1890,9 @@ xpc_pull_remote_msg_sn2(struct xpc_chann
}

msg_offset = msg_index * ch->msg_size;
- msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset);
- remote_msg_pa = ch->remote_msgqueue_pa + msg_offset;
+ msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue +
+ msg_offset);
+ remote_msg_pa = ch_sn2->remote_msgqueue_pa + msg_offset;

ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg_pa,
nmsgs * ch->msg_size);
@@ -2001,7 +1916,7 @@ xpc_pull_remote_msg_sn2(struct xpc_chann

/* return the message we were looking for */
msg_offset = (get % ch->remote_nentries) * ch->msg_size;
- msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset);
+ msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + msg_offset);

return msg;
}
@@ -2080,7 +1995,7 @@ xpc_send_msgs_sn2(struct xpc_channel *ch
if (put == ch_sn2->w_local_GP.put)
break;

- msg = (struct xpc_msg *)((u64)ch->local_msgqueue +
+ msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue +
(put % ch->local_nentries) *
ch->msg_size);

@@ -2182,7 +2097,7 @@ xpc_allocate_msg_sn2(struct xpc_channel
}

/* get the message's address and initialize it */
- msg = (struct xpc_msg *)((u64)ch->local_msgqueue +
+ msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue +
(put % ch->local_nentries) * ch->msg_size);

DBUG_ON(msg->flags != 0);
@@ -2207,6 +2122,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch,
void *key)
{
enum xp_retval ret = xpSuccess;
+ struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
struct xpc_msg *msg = msg;
struct xpc_notify *notify = notify;
s64 msg_number;
@@ -2243,7 +2159,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch,

atomic_inc(&ch->n_to_notify);

- notify = &ch->notify_queue[msg_number % ch->local_nentries];
+ notify = &ch_sn2->notify_queue[msg_number % ch->local_nentries];
notify->func = func;
notify->key = key;
notify->type = notify_type;
@@ -2279,7 +2195,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch,

/* see if the message is next in line to be sent, if so send it */

- put = ch->sn.sn2.local_GP->put;
+ put = ch_sn2->local_GP->put;
if (put == msg_number)
xpc_send_msgs_sn2(ch, put);

@@ -2307,7 +2223,7 @@ xpc_acknowledge_msgs_sn2(struct xpc_chan
if (get == ch_sn2->w_local_GP.get)
break;

- msg = (struct xpc_msg *)((u64)ch->remote_msgqueue +
+ msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue +
(get % ch->remote_nentries) *
ch->msg_size);

@@ -2385,8 +2301,9 @@ xpc_init_sn2(void)
int ret;
size_t buf_size;

+ xpc_setup_partitions_sn = xpc_setup_partitions_sn_sn2;
xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2;
- xpc_rsvd_page_init = xpc_rsvd_page_init_sn2;
+ xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_sn2;
xpc_increment_heartbeat = xpc_increment_heartbeat_sn2;
xpc_offline_heartbeat = xpc_offline_heartbeat_sn2;
xpc_online_heartbeat = xpc_online_heartbeat_sn2;
@@ -2403,29 +2320,33 @@ xpc_init_sn2(void)
xpc_cancel_partition_deactivation_request_sn2;

xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_sn2;
- xpc_setup_infrastructure = xpc_setup_infrastructure_sn2;
- xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2;
+ xpc_setup_ch_structures_sn = xpc_setup_ch_structures_sn_sn2;
+ xpc_teardown_ch_structures_sn = xpc_teardown_ch_structures_sn_sn2;
xpc_make_first_contact = xpc_make_first_contact_sn2;
+
xpc_get_chctl_all_flags = xpc_get_chctl_all_flags_sn2;
- xpc_allocate_msgqueues = xpc_allocate_msgqueues_sn2;
- xpc_free_msgqueues = xpc_free_msgqueues_sn2;
+ xpc_send_chctl_closerequest = xpc_send_chctl_closerequest_sn2;
+ xpc_send_chctl_closereply = xpc_send_chctl_closereply_sn2;
+ xpc_send_chctl_openrequest = xpc_send_chctl_openrequest_sn2;
+ xpc_send_chctl_openreply = xpc_send_chctl_openreply_sn2;
+
+ xpc_save_remote_msgqueue_pa = xpc_save_remote_msgqueue_pa_sn2;
+
+ xpc_setup_msg_structures = xpc_setup_msg_structures_sn2;
+ xpc_teardown_msg_structures = xpc_teardown_msg_structures_sn2;
+
xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2;
xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_sn2;
xpc_n_of_deliverable_msgs = xpc_n_of_deliverable_msgs_sn2;
xpc_get_deliverable_msg = xpc_get_deliverable_msg_sn2;

xpc_indicate_partition_engaged = xpc_indicate_partition_engaged_sn2;
- xpc_partition_engaged = xpc_partition_engaged_sn2;
- xpc_any_partition_engaged = xpc_any_partition_engaged_sn2;
xpc_indicate_partition_disengaged =
xpc_indicate_partition_disengaged_sn2;
+ xpc_partition_engaged = xpc_partition_engaged_sn2;
+ xpc_any_partition_engaged = xpc_any_partition_engaged_sn2;
xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_sn2;

- xpc_send_chctl_closerequest = xpc_send_chctl_closerequest_sn2;
- xpc_send_chctl_closereply = xpc_send_chctl_closereply_sn2;
- xpc_send_chctl_openrequest = xpc_send_chctl_openrequest_sn2;
- xpc_send_chctl_openreply = xpc_send_chctl_openreply_sn2;
-
xpc_send_msg = xpc_send_msg_sn2;
xpc_received_msg = xpc_received_msg_sn2;

Index: linux/drivers/misc/sgi-xp/xp.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp.h 2008-07-03 11:06:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp.h 2008-07-03 11:06:20.000000000 -0500
@@ -208,8 +208,9 @@ enum xp_retval {
xpNeedMoreInfo, /* 57: more info is needed by SAL */

xpGruCopyError, /* 58: gru_copy_gru() returned error */
+ xpGruSendMqError, /* 59: gru send message queue related error */

- xpUnknownReason /* 59: unknown reason - must be last in enum */
+ xpUnknownReason /* 60: unknown reason - must be last in enum */
};

/*
Index: linux/drivers/misc/sgi-xp/xpc_channel.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_channel.c 2008-07-03 11:06:04.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_channel.c 2008-07-03 11:06:20.000000000 -0500
@@ -39,7 +39,7 @@ xpc_process_connect(struct xpc_channel *

if (!(ch->flags & XPC_C_SETUP)) {
spin_unlock_irqrestore(&ch->lock, *irq_flags);
- ret = xpc_allocate_msgqueues(ch);
+ ret = xpc_setup_msg_structures(ch);
spin_lock_irqsave(&ch->lock, *irq_flags);

if (ret != xpSuccess)
@@ -62,8 +62,6 @@ xpc_process_connect(struct xpc_channel *
if (!(ch->flags & XPC_C_ROPENREPLY))
return;

- DBUG_ON(ch->remote_msgqueue_pa == 0);
-
ch->flags = (XPC_C_CONNECTED | XPC_C_SETUP); /* clear all else */

dev_info(xpc_chan, "channel %d to partition %d connected\n",
@@ -134,13 +132,23 @@ xpc_process_disconnect(struct xpc_channe
spin_lock_irqsave(&ch->lock, *irq_flags);
}

+ DBUG_ON(atomic_read(&ch->n_to_notify) != 0);
+
/* it's now safe to free the channel's message queues */
- xpc_free_msgqueues(ch);
+ xpc_teardown_msg_structures(ch);
+
+ ch->func = NULL;
+ ch->key = NULL;
+ ch->msg_size = 0;
+ ch->local_nentries = 0;
+ ch->remote_nentries = 0;
+ ch->kthreads_assigned_limit = 0;
+ ch->kthreads_idle_limit = 0;

/*
* Mark the channel disconnected and clear all other flags, including
- * XPC_C_SETUP (because of call to xpc_free_msgqueues()) but not
- * including XPC_C_WDISCONNECT (if it was set).
+ * XPC_C_SETUP (because of call to xpc_teardown_msg_structures()) but
+ * not including XPC_C_WDISCONNECT (if it was set).
*/
ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT));

@@ -395,7 +403,7 @@ again:
DBUG_ON(args->remote_nentries == 0);

ch->flags |= XPC_C_ROPENREPLY;
- ch->remote_msgqueue_pa = args->local_msgqueue_pa;
+ xpc_save_remote_msgqueue_pa(ch, args->local_msgqueue_pa);

if (args->local_nentries < ch->remote_nentries) {
dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new "

2008-07-07 19:00:16

by Dean Nelson

[permalink] [raw]
Subject: [Patch 6/6] sgi-xp: setup the notify GRU message queue

Setup the notify GRU message queue that is used for sending user messages
on UV systems.

Signed-off-by: Dean Nelson <[email protected]>

---

drivers/misc/sgi-xp/xp.h | 45 -
drivers/misc/sgi-xp/xp_main.c | 7
drivers/misc/sgi-xp/xpc.h | 140 +++--
drivers/misc/sgi-xp/xpc_channel.c | 63 +-
drivers/misc/sgi-xp/xpc_main.c | 21
drivers/misc/sgi-xp/xpc_sn2.c | 178 +++---
drivers/misc/sgi-xp/xpc_uv.c | 943 +++++++++++++++++++++++++++-------
drivers/misc/sgi-xp/xpnet.c | 11
8 files changed, 1028 insertions(+), 380 deletions(-)

Index: linux/drivers/misc/sgi-xp/xpc.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc.h 2008-07-07 12:25:58.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc.h 2008-07-07 12:26:00.000000000 -0500
@@ -181,8 +181,8 @@ struct xpc_vars_part_sn2 {
xpc_nasid_mask_nlongs))

/*
- * The activate_mq is used to send/receive messages that affect XPC's heartbeat,
- * partition active state, and channel state. This is UV only.
+ * The activate_mq is used to send/receive GRU messages that affect XPC's
+ * heartbeat, partition active state, and channel state. This is UV only.
*/
struct xpc_activate_mq_msghdr_uv {
short partid; /* sender's partid */
@@ -209,45 +209,45 @@ struct xpc_activate_mq_msghdr_uv {
#define XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV 11

struct xpc_activate_mq_msg_uv {
- struct xpc_activate_mq_msghdr_uv header;
+ struct xpc_activate_mq_msghdr_uv hdr;
};

struct xpc_activate_mq_msg_heartbeat_req_uv {
- struct xpc_activate_mq_msghdr_uv header;
+ struct xpc_activate_mq_msghdr_uv hdr;
u64 heartbeat;
};

struct xpc_activate_mq_msg_activate_req_uv {
- struct xpc_activate_mq_msghdr_uv header;
+ struct xpc_activate_mq_msghdr_uv hdr;
unsigned long rp_gpa;
unsigned long activate_mq_gpa;
};

struct xpc_activate_mq_msg_deactivate_req_uv {
- struct xpc_activate_mq_msghdr_uv header;
+ struct xpc_activate_mq_msghdr_uv hdr;
enum xp_retval reason;
};

struct xpc_activate_mq_msg_chctl_closerequest_uv {
- struct xpc_activate_mq_msghdr_uv header;
+ struct xpc_activate_mq_msghdr_uv hdr;
short ch_number;
enum xp_retval reason;
};

struct xpc_activate_mq_msg_chctl_closereply_uv {
- struct xpc_activate_mq_msghdr_uv header;
+ struct xpc_activate_mq_msghdr_uv hdr;
short ch_number;
};

struct xpc_activate_mq_msg_chctl_openrequest_uv {
- struct xpc_activate_mq_msghdr_uv header;
+ struct xpc_activate_mq_msghdr_uv hdr;
short ch_number;
- short msg_size; /* size of notify_mq's messages */
+ short entry_size; /* size of notify_mq's GRU messages */
short local_nentries; /* ??? Is this needed? What is? */
};

struct xpc_activate_mq_msg_chctl_openreply_uv {
- struct xpc_activate_mq_msghdr_uv header;
+ struct xpc_activate_mq_msghdr_uv hdr;
short ch_number;
short remote_nentries; /* ??? Is this needed? What is? */
short local_nentries; /* ??? Is this needed? What is? */
@@ -284,7 +284,7 @@ struct xpc_gp_sn2 {
*/
struct xpc_openclose_args {
u16 reason; /* reason why channel is closing */
- u16 msg_size; /* sizeof each message entry */
+ u16 entry_size; /* sizeof each message entry */
u16 remote_nentries; /* #of message entries in remote msg queue */
u16 local_nentries; /* #of message entries in local msg queue */
unsigned long local_msgqueue_pa; /* phys addr of local message queue */
@@ -294,22 +294,79 @@ struct xpc_openclose_args {
L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * \
XPC_MAX_NCHANNELS)

-/* struct xpc_msg flags */

-#define XPC_M_DONE 0x01 /* msg has been received/consumed */
-#define XPC_M_READY 0x02 /* msg is ready to be sent */
-#define XPC_M_INTERRUPT 0x04 /* send interrupt when msg consumed */
+/*
+ * Structures to define a fifo singly-linked list.
+ */
+
+struct xpc_fifo_entry_uv {
+ struct xpc_fifo_entry_uv *next;
+};
+
+struct xpc_fifo_head_uv {
+ struct xpc_fifo_entry_uv *first;
+ struct xpc_fifo_entry_uv *last;
+ spinlock_t lock;
+ int n_entries;
+};
+
+/*
+ * Define a sn2 styled message.
+ *
+ * A user-defined message resides in the payload area. The max size of the
+ * payload is defined by the user via xpc_connect().
+ *
+ * The size of a message entry (within a message queue) must be a 128-byte
+ * cacheline sized multiple in order to facilitate the BTE transfer of messages
+ * from one message queue to another.
+ */
+struct xpc_msg_sn2 {
+ u8 flags; /* FOR XPC INTERNAL USE ONLY */
+ u8 reserved[7]; /* FOR XPC INTERNAL USE ONLY */
+ s64 number; /* FOR XPC INTERNAL USE ONLY */
+
+ u64 payload; /* user defined portion of message */
+};
+
+/* struct xpc_msg_sn2 flags */
+
+#define XPC_M_SN2_DONE 0x01 /* msg has been received/consumed */
+#define XPC_M_SN2_READY 0x02 /* msg is ready to be sent */
+#define XPC_M_SN2_INTERRUPT 0x04 /* send interrupt when msg consumed */
+
+/*
+ * The format of a uv XPC notify_mq GRU message is as follows:
+ *
+ * A user-defined message resides in the payload area. The max size of the
+ * payload is defined by the user via xpc_connect().
+ *
+ * The size of a message (payload and header) sent via the GRU must be either 1
+ * or 2 GRU_CACHE_LINE_BYTES in length.
+ */

-#define XPC_MSG_ADDRESS(_payload) \
- ((struct xpc_msg *)((u8 *)(_payload) - XPC_MSG_PAYLOAD_OFFSET))
+struct xpc_notify_mq_msghdr_uv {
+ union {
+ unsigned int gru_msg_hdr; /* FOR GRU INTERNAL USE ONLY */
+ struct xpc_fifo_entry_uv next; /* FOR XPC INTERNAL USE ONLY */
+ } u;
+ short partid; /* FOR XPC INTERNAL USE ONLY */
+ u8 ch_number; /* FOR XPC INTERNAL USE ONLY */
+ u8 size; /* FOR XPC INTERNAL USE ONLY */
+ unsigned int msg_slot_number; /* FOR XPC INTERNAL USE ONLY */
+};
+
+struct xpc_notify_mq_msg_uv {
+ struct xpc_notify_mq_msghdr_uv hdr;
+ unsigned long payload;
+};

/*
- * Defines notify entry.
+ * Define sn2's notify entry.
*
* This is used to notify a message's sender that their message was received
* and consumed by the intended recipient.
*/
-struct xpc_notify {
+struct xpc_notify_sn2 {
u8 type; /* type of notification */

/* the following two fields are only used if type == XPC_N_CALL */
@@ -317,9 +374,20 @@ struct xpc_notify {
void *key; /* pointer to user's key */
};

-/* struct xpc_notify type of notification */
+/* struct xpc_notify_sn2 type of notification */

-#define XPC_N_CALL 0x01 /* notify function provided by user */
+#define XPC_N_CALL 0x01 /* notify function provided by user */
+
+/*
+ * Define uv's version of the notify entry. It additionally is used to allocate
+ * a msg slot on the remote partition into which is copied a sent message.
+ */
+struct xpc_send_msg_slot_uv {
+ struct xpc_fifo_entry_uv next;
+ unsigned int msg_slot_number;
+ xpc_notify_func func; /* user's notify function */
+ void *key; /* pointer to user's key */
+};

/*
* Define the structure that manages all the stuff required by a channel. In
@@ -409,14 +477,14 @@ struct xpc_channel_sn2 {
/* opening or closing of channel */

void *local_msgqueue_base; /* base address of kmalloc'd space */
- struct xpc_msg *local_msgqueue; /* local message queue */
+ struct xpc_msg_sn2 *local_msgqueue; /* local message queue */
void *remote_msgqueue_base; /* base address of kmalloc'd space */
- struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */
- /* local message queue */
+ struct xpc_msg_sn2 *remote_msgqueue; /* cached copy of remote */
+ /* partition's local message queue */
unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */
/* local message queue */

- struct xpc_notify *notify_queue; /* notify queue for messages sent */
+ struct xpc_notify_sn2 *notify_queue;/* notify queue for messages sent */

/* various flavors of local and remote Get/Put values */

@@ -432,6 +500,12 @@ struct xpc_channel_sn2 {
struct xpc_channel_uv {
unsigned long remote_notify_mq_gpa; /* gru phys address of remote */
/* partition's notify mq */
+
+ struct xpc_send_msg_slot_uv *send_msg_slots;
+ struct xpc_notify_mq_msg_uv *recv_msg_slots;
+
+ struct xpc_fifo_head_uv msg_slot_free_list;
+ struct xpc_fifo_head_uv recv_msg_list; /* deliverable payloads */
};

struct xpc_channel {
@@ -444,7 +518,7 @@ struct xpc_channel {

u16 number; /* channel # */

- u16 msg_size; /* sizeof each msg entry */
+ u16 entry_size; /* sizeof each msg entry */
u16 local_nentries; /* #of msg entries in local msg queue */
u16 remote_nentries; /* #of msg entries in remote msg queue */

@@ -733,8 +807,8 @@ extern enum xp_retval (*xpc_setup_msg_st
extern void (*xpc_teardown_msg_structures) (struct xpc_channel *);
extern void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *);
extern void (*xpc_process_msg_chctl_flags) (struct xpc_partition *, int);
-extern int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *);
-extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *);
+extern int (*xpc_n_of_deliverable_payloads) (struct xpc_channel *);
+extern void *(*xpc_get_deliverable_payload) (struct xpc_channel *);
extern void (*xpc_request_partition_activation) (struct xpc_rsvd_page *,
unsigned long, int);
extern void (*xpc_request_partition_reactivation) (struct xpc_partition *);
@@ -762,9 +836,9 @@ extern void (*xpc_send_chctl_openreply)
extern void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *,
unsigned long);

-extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, u32, void *, u16,
- u8, xpc_notify_func, void *);
-extern void (*xpc_received_msg) (struct xpc_channel *, struct xpc_msg *);
+extern enum xp_retval (*xpc_send_payload) (struct xpc_channel *, u32, void *,
+ u16, u8, xpc_notify_func, void *);
+extern void (*xpc_received_payload) (struct xpc_channel *, void *);

/* found in xpc_sn2.c */
extern int xpc_init_sn2(void);
@@ -805,7 +879,7 @@ extern enum xp_retval xpc_initiate_send_
extern void xpc_initiate_received(short, int, void *);
extern void xpc_process_sent_chctl_flags(struct xpc_partition *);
extern void xpc_connected_callout(struct xpc_channel *);
-extern void xpc_deliver_msg(struct xpc_channel *);
+extern void xpc_deliver_payload(struct xpc_channel *);
extern void xpc_disconnect_channel(const int, struct xpc_channel *,
enum xp_retval, unsigned long *);
extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval);
Index: linux/drivers/misc/sgi-xp/xpc_sn2.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_sn2.c 2008-07-07 12:25:58.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_sn2.c 2008-07-07 12:26:00.000000000 -0500
@@ -408,7 +408,7 @@ xpc_send_chctl_openrequest_sn2(struct xp
{
struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;

- args->msg_size = ch->msg_size;
+ args->entry_size = ch->entry_size;
args->local_nentries = ch->local_nentries;
XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREQUEST, irq_flags);
}
@@ -1531,14 +1531,14 @@ xpc_allocate_local_msgqueue_sn2(struct x

for (nentries = ch->local_nentries; nentries > 0; nentries--) {

- nbytes = nentries * ch->msg_size;
+ nbytes = nentries * ch->entry_size;
ch_sn2->local_msgqueue =
xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL,
&ch_sn2->local_msgqueue_base);
if (ch_sn2->local_msgqueue == NULL)
continue;

- nbytes = nentries * sizeof(struct xpc_notify);
+ nbytes = nentries * sizeof(struct xpc_notify_sn2);
ch_sn2->notify_queue = kzalloc(nbytes, GFP_KERNEL);
if (ch_sn2->notify_queue == NULL) {
kfree(ch_sn2->local_msgqueue_base);
@@ -1578,7 +1578,7 @@ xpc_allocate_remote_msgqueue_sn2(struct

for (nentries = ch->remote_nentries; nentries > 0; nentries--) {

- nbytes = nentries * ch->msg_size;
+ nbytes = nentries * ch->entry_size;
ch_sn2->remote_msgqueue =
xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, &ch_sn2->
remote_msgqueue_base);
@@ -1632,9 +1632,6 @@ xpc_setup_msg_structures_sn2(struct xpc_
/*
* Free up message queues and other stuff that were allocated for the specified
* channel.
- *
- * Note: ch->reason and ch->reason_line are left set for debugging purposes,
- * they're cleared when XPC_C_DISCONNECTED is cleared.
*/
static void
xpc_teardown_msg_structures_sn2(struct xpc_channel *ch)
@@ -1674,7 +1671,7 @@ xpc_teardown_msg_structures_sn2(struct x
static void
xpc_notify_senders_sn2(struct xpc_channel *ch, enum xp_retval reason, s64 put)
{
- struct xpc_notify *notify;
+ struct xpc_notify_sn2 *notify;
u8 notify_type;
s64 get = ch->sn.sn2.w_remote_GP.get - 1;

@@ -1699,17 +1696,16 @@ xpc_notify_senders_sn2(struct xpc_channe
atomic_dec(&ch->n_to_notify);

if (notify->func != NULL) {
- dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, "
- "msg_number=%ld, partid=%d, channel=%d\n",
+ dev_dbg(xpc_chan, "notify->func() called, notify=0x%p "
+ "msg_number=%ld partid=%d channel=%d\n",
(void *)notify, get, ch->partid, ch->number);

notify->func(reason, ch->partid, ch->number,
notify->key);

- dev_dbg(xpc_chan, "notify->func() returned, "
- "notify=0x%p, msg_number=%ld, partid=%d, "
- "channel=%d\n", (void *)notify, get,
- ch->partid, ch->number);
+ dev_dbg(xpc_chan, "notify->func() returned, notify=0x%p"
+ " msg_number=%ld partid=%d channel=%d\n",
+ (void *)notify, get, ch->partid, ch->number);
}
}
}
@@ -1727,14 +1723,14 @@ static inline void
xpc_clear_local_msgqueue_flags_sn2(struct xpc_channel *ch)
{
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg *msg;
+ struct xpc_msg_sn2 *msg;
s64 get;

get = ch_sn2->w_remote_GP.get;
do {
- msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue +
- (get % ch->local_nentries) *
- ch->msg_size);
+ msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue +
+ (get % ch->local_nentries) *
+ ch->entry_size);
msg->flags = 0;
} while (++get < ch_sn2->remote_GP.get);
}
@@ -1746,24 +1742,30 @@ static inline void
xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch)
{
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg *msg;
+ struct xpc_msg_sn2 *msg;
s64 put;

put = ch_sn2->w_remote_GP.put;
do {
- msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue +
- (put % ch->remote_nentries) *
- ch->msg_size);
+ msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue +
+ (put % ch->remote_nentries) *
+ ch->entry_size);
msg->flags = 0;
} while (++put < ch_sn2->remote_GP.put);
}

+static int
+xpc_n_of_deliverable_payloads_sn2(struct xpc_channel *ch)
+{
+ return ch->sn.sn2.w_remote_GP.put - ch->sn.sn2.w_local_GP.get;
+}
+
static void
xpc_process_msg_chctl_flags_sn2(struct xpc_partition *part, int ch_number)
{
struct xpc_channel *ch = &part->channels[ch_number];
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- int nmsgs_sent;
+ int npayloads_sent;

ch_sn2->remote_GP = part->sn.sn2.remote_GPs[ch_number];

@@ -1835,7 +1837,7 @@ xpc_process_msg_chctl_flags_sn2(struct x
if (ch_sn2->w_remote_GP.put != ch_sn2->remote_GP.put) {
/*
* Clear msg->flags in previously received messages, so that
- * they're ready for xpc_get_deliverable_msg().
+ * they're ready for xpc_get_deliverable_payload_sn2().
*/
xpc_clear_remote_msgqueue_flags_sn2(ch);

@@ -1845,27 +1847,27 @@ xpc_process_msg_chctl_flags_sn2(struct x
"channel=%d\n", ch_sn2->w_remote_GP.put, ch->partid,
ch->number);

- nmsgs_sent = ch_sn2->w_remote_GP.put - ch_sn2->w_local_GP.get;
- if (nmsgs_sent > 0) {
+ npayloads_sent = xpc_n_of_deliverable_payloads_sn2(ch);
+ if (npayloads_sent > 0) {
dev_dbg(xpc_chan, "msgs waiting to be copied and "
"delivered=%d, partid=%d, channel=%d\n",
- nmsgs_sent, ch->partid, ch->number);
+ npayloads_sent, ch->partid, ch->number);

if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE)
- xpc_activate_kthreads(ch, nmsgs_sent);
+ xpc_activate_kthreads(ch, npayloads_sent);
}
}

xpc_msgqueue_deref(ch);
}

-static struct xpc_msg *
+static struct xpc_msg_sn2 *
xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get)
{
struct xpc_partition *part = &xpc_partitions[ch->partid];
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
unsigned long remote_msg_pa;
- struct xpc_msg *msg;
+ struct xpc_msg_sn2 *msg;
u32 msg_index;
u32 nmsgs;
u64 msg_offset;
@@ -1889,13 +1891,13 @@ xpc_pull_remote_msg_sn2(struct xpc_chann
nmsgs = ch->remote_nentries - msg_index;
}

- msg_offset = msg_index * ch->msg_size;
- msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue +
+ msg_offset = msg_index * ch->entry_size;
+ msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue +
msg_offset);
remote_msg_pa = ch_sn2->remote_msgqueue_pa + msg_offset;

ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg_pa,
- nmsgs * ch->msg_size);
+ nmsgs * ch->entry_size);
if (ret != xpSuccess) {

dev_dbg(xpc_chan, "failed to pull %d msgs starting with"
@@ -1915,26 +1917,21 @@ xpc_pull_remote_msg_sn2(struct xpc_chann
mutex_unlock(&ch_sn2->msg_to_pull_mutex);

/* return the message we were looking for */
- msg_offset = (get % ch->remote_nentries) * ch->msg_size;
- msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + msg_offset);
+ msg_offset = (get % ch->remote_nentries) * ch->entry_size;
+ msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + msg_offset);

return msg;
}

-static int
-xpc_n_of_deliverable_msgs_sn2(struct xpc_channel *ch)
-{
- return ch->sn.sn2.w_remote_GP.put - ch->sn.sn2.w_local_GP.get;
-}
-
/*
- * Get a message to be delivered.
+ * Get the next deliverable message's payload.
*/
-static struct xpc_msg *
-xpc_get_deliverable_msg_sn2(struct xpc_channel *ch)
+static void *
+xpc_get_deliverable_payload_sn2(struct xpc_channel *ch)
{
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg *msg = NULL;
+ struct xpc_msg_sn2 *msg;
+ void *payload = NULL;
s64 get;

do {
@@ -1965,15 +1962,16 @@ xpc_get_deliverable_msg_sn2(struct xpc_c
msg = xpc_pull_remote_msg_sn2(ch, get);

DBUG_ON(msg != NULL && msg->number != get);
- DBUG_ON(msg != NULL && (msg->flags & XPC_M_DONE));
- DBUG_ON(msg != NULL && !(msg->flags & XPC_M_READY));
+ DBUG_ON(msg != NULL && (msg->flags & XPC_M_SN2_DONE));
+ DBUG_ON(msg != NULL && !(msg->flags & XPC_M_SN2_READY));

+ payload = &msg->payload;
break;
}

} while (1);

- return msg;
+ return payload;
}

/*
@@ -1985,7 +1983,7 @@ static void
xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put)
{
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg *msg;
+ struct xpc_msg_sn2 *msg;
s64 put = initial_put + 1;
int send_msgrequest = 0;

@@ -1995,11 +1993,12 @@ xpc_send_msgs_sn2(struct xpc_channel *ch
if (put == ch_sn2->w_local_GP.put)
break;

- msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue +
- (put % ch->local_nentries) *
- ch->msg_size);
+ msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->
+ local_msgqueue + (put %
+ ch->local_nentries) *
+ ch->entry_size);

- if (!(msg->flags & XPC_M_READY))
+ if (!(msg->flags & XPC_M_SN2_READY))
break;

put++;
@@ -2026,7 +2025,7 @@ xpc_send_msgs_sn2(struct xpc_channel *ch

/*
* We need to ensure that the message referenced by
- * local_GP->put is not XPC_M_READY or that local_GP->put
+ * local_GP->put is not XPC_M_SN2_READY or that local_GP->put
* equals w_local_GP.put, so we'll go have a look.
*/
initial_put = put;
@@ -2042,10 +2041,10 @@ xpc_send_msgs_sn2(struct xpc_channel *ch
*/
static enum xp_retval
xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags,
- struct xpc_msg **address_of_msg)
+ struct xpc_msg_sn2 **address_of_msg)
{
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg *msg;
+ struct xpc_msg_sn2 *msg;
enum xp_retval ret;
s64 put;

@@ -2097,8 +2096,9 @@ xpc_allocate_msg_sn2(struct xpc_channel
}

/* get the message's address and initialize it */
- msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue +
- (put % ch->local_nentries) * ch->msg_size);
+ msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue +
+ (put % ch->local_nentries) *
+ ch->entry_size);

DBUG_ON(msg->flags != 0);
msg->number = put;
@@ -2117,20 +2117,20 @@ xpc_allocate_msg_sn2(struct xpc_channel
* partition the message is being sent to.
*/
static enum xp_retval
-xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload,
- u16 payload_size, u8 notify_type, xpc_notify_func func,
- void *key)
+xpc_send_payload_sn2(struct xpc_channel *ch, u32 flags, void *payload,
+ u16 payload_size, u8 notify_type, xpc_notify_func func,
+ void *key)
{
enum xp_retval ret = xpSuccess;
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg *msg = msg;
- struct xpc_notify *notify = notify;
+ struct xpc_msg_sn2 *msg = msg;
+ struct xpc_notify_sn2 *notify = notify;
s64 msg_number;
s64 put;

DBUG_ON(notify_type == XPC_N_CALL && func == NULL);

- if (XPC_MSG_SIZE(payload_size) > ch->msg_size)
+ if (XPC_MSG_SIZE(payload_size) > ch->entry_size)
return xpPayloadTooBig;

xpc_msgqueue_ref(ch);
@@ -2155,7 +2155,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch,
* Tell the remote side to send an ACK interrupt when the
* message has been delivered.
*/
- msg->flags |= XPC_M_INTERRUPT;
+ msg->flags |= XPC_M_SN2_INTERRUPT;

atomic_inc(&ch->n_to_notify);

@@ -2185,7 +2185,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch,

memcpy(&msg->payload, payload, payload_size);

- msg->flags |= XPC_M_READY;
+ msg->flags |= XPC_M_SN2_READY;

/*
* The preceding store of msg->flags must occur before the following
@@ -2208,12 +2208,15 @@ out_1:
* Now we actually acknowledge the messages that have been delivered and ack'd
* by advancing the cached remote message queue's Get value and if requested
* send a chctl msgrequest to the message sender's partition.
+ *
+ * If a message has XPC_M_SN2_INTERRUPT set, send an interrupt to the partition
+ * that sent the message.
*/
static void
xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags)
{
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg *msg;
+ struct xpc_msg_sn2 *msg;
s64 get = initial_get + 1;
int send_msgrequest = 0;

@@ -2223,11 +2226,12 @@ xpc_acknowledge_msgs_sn2(struct xpc_chan
if (get == ch_sn2->w_local_GP.get)
break;

- msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue +
- (get % ch->remote_nentries) *
- ch->msg_size);
+ msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->
+ remote_msgqueue + (get %
+ ch->remote_nentries) *
+ ch->entry_size);

- if (!(msg->flags & XPC_M_DONE))
+ if (!(msg->flags & XPC_M_SN2_DONE))
break;

msg_flags |= msg->flags;
@@ -2251,11 +2255,11 @@ xpc_acknowledge_msgs_sn2(struct xpc_chan
dev_dbg(xpc_chan, "local_GP->get changed to %ld, partid=%d, "
"channel=%d\n", get, ch->partid, ch->number);

- send_msgrequest = (msg_flags & XPC_M_INTERRUPT);
+ send_msgrequest = (msg_flags & XPC_M_SN2_INTERRUPT);

/*
* We need to ensure that the message referenced by
- * local_GP->get is not XPC_M_DONE or that local_GP->get
+ * local_GP->get is not XPC_M_SN2_DONE or that local_GP->get
* equals w_local_GP.get, so we'll go have a look.
*/
initial_get = get;
@@ -2266,19 +2270,23 @@ xpc_acknowledge_msgs_sn2(struct xpc_chan
}

static void
-xpc_received_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg)
+xpc_received_payload_sn2(struct xpc_channel *ch, void *payload)
{
+ struct xpc_msg_sn2 *msg;
+ s64 msg_number;
s64 get;
- s64 msg_number = msg->number;
+
+ msg = container_of(payload, struct xpc_msg_sn2, payload);
+ msg_number = msg->number;

dev_dbg(xpc_chan, "msg=0x%p, msg_number=%ld, partid=%d, channel=%d\n",
(void *)msg, msg_number, ch->partid, ch->number);

- DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->msg_size) !=
+ DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->entry_size) !=
msg_number % ch->remote_nentries);
- DBUG_ON(msg->flags & XPC_M_DONE);
+ DBUG_ON(msg->flags & XPC_M_SN2_DONE);

- msg->flags |= XPC_M_DONE;
+ msg->flags |= XPC_M_SN2_DONE;

/*
* The preceding store of msg->flags must occur before the following
@@ -2337,8 +2345,8 @@ xpc_init_sn2(void)

xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2;
xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_sn2;
- xpc_n_of_deliverable_msgs = xpc_n_of_deliverable_msgs_sn2;
- xpc_get_deliverable_msg = xpc_get_deliverable_msg_sn2;
+ xpc_n_of_deliverable_payloads = xpc_n_of_deliverable_payloads_sn2;
+ xpc_get_deliverable_payload = xpc_get_deliverable_payload_sn2;

xpc_indicate_partition_engaged = xpc_indicate_partition_engaged_sn2;
xpc_indicate_partition_disengaged =
@@ -2347,8 +2355,14 @@ xpc_init_sn2(void)
xpc_any_partition_engaged = xpc_any_partition_engaged_sn2;
xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_sn2;

- xpc_send_msg = xpc_send_msg_sn2;
- xpc_received_msg = xpc_received_msg_sn2;
+ xpc_send_payload = xpc_send_payload_sn2;
+ xpc_received_payload = xpc_received_payload_sn2;
+
+ if (offsetof(struct xpc_msg_sn2, payload) > XPC_MSG_HDR_MAX_SIZE) {
+ dev_err(xpc_part, "header portion of struct xpc_msg_sn2 is "
+ "larger than %d\n", XPC_MSG_HDR_MAX_SIZE);
+ return -E2BIG;
+ }

buf_size = max(XPC_RP_VARS_SIZE,
XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES_SN2);
Index: linux/drivers/misc/sgi-xp/xpc_uv.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_uv.c 2008-07-07 12:25:58.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_uv.c 2008-07-07 12:26:00.000000000 -0500
@@ -66,8 +66,11 @@ xpc_create_gru_mq_uv(unsigned int mq_siz
mq_order = get_order(mq_size);
page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
mq_order);
- if (page == NULL)
+ if (page == NULL) {
+ dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
+ "bytes of memory on nid=%d for GRU mq\n", mq_size, nid);
return NULL;
+ }

mq = page_address(page);
ret = gru_create_message_queue(mq, mq_size);
@@ -193,202 +196,226 @@ xpc_process_activate_IRQ_rcvd_uv(void)

}

-static irqreturn_t
-xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
+static void
+xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
+ struct xpc_activate_mq_msghdr_uv *msg_hdr,
+ int *wakeup_hb_checker)
{
unsigned long irq_flags;
- struct xpc_activate_mq_msghdr_uv *msg_hdr;
- short partid;
- struct xpc_partition *part;
- struct xpc_partition_uv *part_uv;
+ struct xpc_partition_uv *part_uv = &part->sn.uv;
struct xpc_openclose_args *args;
- int wakeup_hb_checker = 0;

- while ((msg_hdr = gru_get_next_message(xpc_activate_mq_uv)) != NULL) {
+ part_uv->remote_act_state = msg_hdr->act_state;

- partid = msg_hdr->partid;
- if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) {
- dev_err(xpc_part, "xpc_handle_activate_IRQ_uv() invalid"
- "partid=0x%x passed in message\n", partid);
- gru_free_message(xpc_activate_mq_uv, msg_hdr);
- continue;
- }
- part = &xpc_partitions[partid];
- part_uv = &part->sn.uv;
+ switch (msg_hdr->type) {
+ case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV:
+ /* syncing of remote_act_state was just done above */
+ break;
+
+ case XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV: {
+ struct xpc_activate_mq_msg_heartbeat_req_uv *msg;
+
+ msg = container_of(msg_hdr,
+ struct xpc_activate_mq_msg_heartbeat_req_uv,
+ hdr);
+ part_uv->heartbeat = msg->heartbeat;
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV: {
+ struct xpc_activate_mq_msg_heartbeat_req_uv *msg;

- part_uv->remote_act_state = msg_hdr->act_state;
+ msg = container_of(msg_hdr,
+ struct xpc_activate_mq_msg_heartbeat_req_uv,
+ hdr);
+ part_uv->heartbeat = msg->heartbeat;
+
+ spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ part_uv->flags |= XPC_P_HEARTBEAT_OFFLINE_UV;
+ spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV: {
+ struct xpc_activate_mq_msg_heartbeat_req_uv *msg;

- switch (msg_hdr->type) {
- case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV:
- /* syncing of remote_act_state was just done above */
- break;
+ msg = container_of(msg_hdr,
+ struct xpc_activate_mq_msg_heartbeat_req_uv,
+ hdr);
+ part_uv->heartbeat = msg->heartbeat;
+
+ spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ part_uv->flags &= ~XPC_P_HEARTBEAT_OFFLINE_UV;
+ spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: {
+ struct xpc_activate_mq_msg_activate_req_uv *msg;

- case XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV: {
- struct xpc_activate_mq_msg_heartbeat_req_uv *msg;
+ /*
+ * ??? Do we deal here with ts_jiffies being different
+ * ??? if act_state != XPC_P_AS_INACTIVE instead of
+ * ??? below?
+ */
+ msg = container_of(msg_hdr, struct
+ xpc_activate_mq_msg_activate_req_uv, hdr);

- msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *)
- msg_hdr;
- part_uv->heartbeat = msg->heartbeat;
- break;
- }
- case XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV: {
- struct xpc_activate_mq_msg_heartbeat_req_uv *msg;
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ if (part_uv->act_state_req == 0)
+ xpc_activate_IRQ_rcvd++;
+ part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV;
+ part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */
+ part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies;
+ part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);

- msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *)
- msg_hdr;
- part_uv->heartbeat = msg->heartbeat;
- spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
- part_uv->flags |= XPC_P_HEARTBEAT_OFFLINE_UV;
- spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
- break;
- }
- case XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV: {
- struct xpc_activate_mq_msg_heartbeat_req_uv *msg;
+ (*wakeup_hb_checker)++;
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: {
+ struct xpc_activate_mq_msg_deactivate_req_uv *msg;

- msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *)
- msg_hdr;
- part_uv->heartbeat = msg->heartbeat;
- spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
- part_uv->flags &= ~XPC_P_HEARTBEAT_OFFLINE_UV;
- spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
- break;
- }
- case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: {
- struct xpc_activate_mq_msg_activate_req_uv *msg;
+ msg = container_of(msg_hdr, struct
+ xpc_activate_mq_msg_deactivate_req_uv, hdr);

- /*
- * ??? Do we deal here with ts_jiffies being different
- * ??? if act_state != XPC_P_AS_INACTIVE instead of
- * ??? below?
- */
- msg = (struct xpc_activate_mq_msg_activate_req_uv *)
- msg_hdr;
- spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock,
- irq_flags);
- if (part_uv->act_state_req == 0)
- xpc_activate_IRQ_rcvd++;
- part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV;
- part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */
- part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies;
- part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa;
- spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock,
- irq_flags);
- wakeup_hb_checker++;
- break;
- }
- case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: {
- struct xpc_activate_mq_msg_deactivate_req_uv *msg;
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ if (part_uv->act_state_req == 0)
+ xpc_activate_IRQ_rcvd++;
+ part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV;
+ part_uv->reason = msg->reason;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);

- msg = (struct xpc_activate_mq_msg_deactivate_req_uv *)
- msg_hdr;
- spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock,
- irq_flags);
- if (part_uv->act_state_req == 0)
- xpc_activate_IRQ_rcvd++;
- part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV;
- part_uv->reason = msg->reason;
- spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock,
- irq_flags);
- wakeup_hb_checker++;
- break;
- }
- case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: {
- struct xpc_activate_mq_msg_chctl_closerequest_uv *msg;
+ (*wakeup_hb_checker)++;
+ return;
+ }
+ case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: {
+ struct xpc_activate_mq_msg_chctl_closerequest_uv *msg;

- msg = (struct xpc_activate_mq_msg_chctl_closerequest_uv
- *)msg_hdr;
- args = &part->remote_openclose_args[msg->ch_number];
- args->reason = msg->reason;
-
- spin_lock_irqsave(&part->chctl_lock, irq_flags);
- part->chctl.flags[msg->ch_number] |=
- XPC_CHCTL_CLOSEREQUEST;
- spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+ msg = container_of(msg_hdr, struct
+ xpc_activate_mq_msg_chctl_closerequest_uv,
+ hdr);
+ args = &part->remote_openclose_args[msg->ch_number];
+ args->reason = msg->reason;
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREQUEST;
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);

- xpc_wakeup_channel_mgr(part);
- break;
- }
- case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: {
- struct xpc_activate_mq_msg_chctl_closereply_uv *msg;
+ xpc_wakeup_channel_mgr(part);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: {
+ struct xpc_activate_mq_msg_chctl_closereply_uv *msg;

- msg = (struct xpc_activate_mq_msg_chctl_closereply_uv *)
- msg_hdr;
+ msg = container_of(msg_hdr, struct
+ xpc_activate_mq_msg_chctl_closereply_uv,
+ hdr);
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREPLY;
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);

- spin_lock_irqsave(&part->chctl_lock, irq_flags);
- part->chctl.flags[msg->ch_number] |=
- XPC_CHCTL_CLOSEREPLY;
- spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+ xpc_wakeup_channel_mgr(part);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: {
+ struct xpc_activate_mq_msg_chctl_openrequest_uv *msg;

- xpc_wakeup_channel_mgr(part);
- break;
- }
- case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: {
- struct xpc_activate_mq_msg_chctl_openrequest_uv *msg;
+ msg = container_of(msg_hdr, struct
+ xpc_activate_mq_msg_chctl_openrequest_uv,
+ hdr);
+ args = &part->remote_openclose_args[msg->ch_number];
+ args->entry_size = msg->entry_size;
+ args->local_nentries = msg->local_nentries;
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREQUEST;
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);

- msg = (struct xpc_activate_mq_msg_chctl_openrequest_uv
- *)msg_hdr;
- args = &part->remote_openclose_args[msg->ch_number];
- args->msg_size = msg->msg_size;
- args->local_nentries = msg->local_nentries;
-
- spin_lock_irqsave(&part->chctl_lock, irq_flags);
- part->chctl.flags[msg->ch_number] |=
- XPC_CHCTL_OPENREQUEST;
- spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+ xpc_wakeup_channel_mgr(part);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: {
+ struct xpc_activate_mq_msg_chctl_openreply_uv *msg;

- xpc_wakeup_channel_mgr(part);
- break;
- }
- case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: {
- struct xpc_activate_mq_msg_chctl_openreply_uv *msg;
+ msg = container_of(msg_hdr, struct
+ xpc_activate_mq_msg_chctl_openreply_uv, hdr);
+ args = &part->remote_openclose_args[msg->ch_number];
+ args->remote_nentries = msg->remote_nentries;
+ args->local_nentries = msg->local_nentries;
+ args->local_msgqueue_pa = msg->local_notify_mq_gpa;
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREPLY;
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);

- msg = (struct xpc_activate_mq_msg_chctl_openreply_uv *)
- msg_hdr;
- args = &part->remote_openclose_args[msg->ch_number];
- args->remote_nentries = msg->remote_nentries;
- args->local_nentries = msg->local_nentries;
- args->local_msgqueue_pa = msg->local_notify_mq_gpa;
-
- spin_lock_irqsave(&part->chctl_lock, irq_flags);
- part->chctl.flags[msg->ch_number] |=
- XPC_CHCTL_OPENREPLY;
- spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+ xpc_wakeup_channel_mgr(part);
+ break;
+ }
+ case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV:
+ spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ part_uv->flags |= XPC_P_ENGAGED_UV;
+ spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+ break;
+
+ case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV:
+ spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ part_uv->flags &= ~XPC_P_ENGAGED_UV;
+ spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+ break;
+
+ default:
+ dev_err(xpc_part, "received unknown activate_mq msg type=%d "
+ "from partition=%d\n", msg_hdr->type, XPC_PARTID(part));

- xpc_wakeup_channel_mgr(part);
- break;
- }
- case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV:
- spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
- part_uv->flags |= XPC_P_ENGAGED_UV;
- spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
- break;
+ /* get hb checker to deactivate from the remote partition */
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ if (part_uv->act_state_req == 0)
+ xpc_activate_IRQ_rcvd++;
+ part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV;
+ part_uv->reason = xpBadMsgType;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);

- case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV:
- spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
- part_uv->flags &= ~XPC_P_ENGAGED_UV;
- spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
- break;
+ (*wakeup_hb_checker)++;
+ return;
+ }

- default:
- dev_err(xpc_part, "received unknown activate_mq msg "
- "type=%d from partition=%d\n", msg_hdr->type,
- partid);
- }
+ if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies &&
+ part->remote_rp_ts_jiffies != 0) {
+ /*
+ * ??? Does what we do here need to be sensitive to
+ * ??? act_state or remote_act_state?
+ */
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ if (part_uv->act_state_req == 0)
+ xpc_activate_IRQ_rcvd++;
+ part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+
+ (*wakeup_hb_checker)++;
+ }
+}
+
+static irqreturn_t
+xpc_handle_activate_IRQ_uv(int irq, void *dev_id)
+{
+ struct xpc_activate_mq_msghdr_uv *msg_hdr;
+ short partid;
+ struct xpc_partition *part;
+ int wakeup_hb_checker = 0;

- if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies &&
- part->remote_rp_ts_jiffies != 0) {
- /*
- * ??? Does what we do here need to be sensitive to
- * ??? act_state or remote_act_state?
- */
- spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock,
- irq_flags);
- if (part_uv->act_state_req == 0)
- xpc_activate_IRQ_rcvd++;
- part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV;
- spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock,
- irq_flags);
- wakeup_hb_checker++;
+ while ((msg_hdr = gru_get_next_message(xpc_activate_mq_uv)) != NULL) {
+
+ partid = msg_hdr->partid;
+ if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) {
+ dev_err(xpc_part, "xpc_handle_activate_IRQ_uv() "
+ "received invalid partid=0x%x in message\n",
+ partid);
+ } else {
+ part = &xpc_partitions[partid];
+ if (xpc_part_ref(part)) {
+ xpc_handle_activate_mq_msg_uv(part, msg_hdr,
+ &wakeup_hb_checker);
+ xpc_part_deref(part);
+ }
}

gru_free_message(xpc_activate_mq_uv, msg_hdr);
@@ -616,14 +643,82 @@ xpc_request_partition_deactivation_uv(st
}
}

+static void
+xpc_cancel_partition_deactivation_request_uv(struct xpc_partition *part)
+{
+ /* nothing needs to be done */
+ return;
+}
+
+static void
+xpc_init_fifo_uv(struct xpc_fifo_head_uv *head)
+{
+ head->first = NULL;
+ head->last = NULL;
+ spin_lock_init(&head->lock);
+ head->n_entries = 0;
+}
+
+static void *
+xpc_get_fifo_entry_uv(struct xpc_fifo_head_uv *head)
+{
+ unsigned long irq_flags;
+ struct xpc_fifo_entry_uv *first;
+
+ spin_lock_irqsave(&head->lock, irq_flags);
+ first = head->first;
+ if (head->first != NULL) {
+ head->first = first->next;
+ if (head->first == NULL)
+ head->last = NULL;
+ }
+ head->n_entries++;
+ spin_unlock_irqrestore(&head->lock, irq_flags);
+ first->next = NULL;
+ return first;
+}
+
+static void
+xpc_put_fifo_entry_uv(struct xpc_fifo_head_uv *head,
+ struct xpc_fifo_entry_uv *last)
+{
+ unsigned long irq_flags;
+
+ last->next = NULL;
+ spin_lock_irqsave(&head->lock, irq_flags);
+ if (head->last != NULL)
+ head->last->next = last;
+ else
+ head->first = last;
+ head->last = last;
+ head->n_entries--;
+ BUG_ON(head->n_entries < 0);
+ spin_unlock_irqrestore(&head->lock, irq_flags);
+}
+
+static int
+xpc_n_of_fifo_entries_uv(struct xpc_fifo_head_uv *head)
+{
+ return head->n_entries;
+}
+
/*
* Setup the channel structures that are uv specific.
*/
static enum xp_retval
xpc_setup_ch_structures_sn_uv(struct xpc_partition *part)
{
- /* !!! this function needs fleshing out */
- return xpUnsupported;
+ struct xpc_channel_uv *ch_uv;
+ int ch_number;
+
+ for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
+ ch_uv = &part->channels[ch_number].sn.uv;
+
+ xpc_init_fifo_uv(&ch_uv->msg_slot_free_list);
+ xpc_init_fifo_uv(&ch_uv->recv_msg_list);
+ }
+
+ return xpSuccess;
}

/*
@@ -632,7 +727,7 @@ xpc_setup_ch_structures_sn_uv(struct xpc
static void
xpc_teardown_ch_structures_sn_uv(struct xpc_partition *part)
{
- /* !!! this function needs fleshing out */
+ /* nothing needs to be done */
return;
}

@@ -680,20 +775,114 @@ xpc_get_chctl_all_flags_uv(struct xpc_pa
}

static enum xp_retval
+xpc_allocate_send_msg_slot_uv(struct xpc_channel *ch)
+{
+ struct xpc_channel_uv *ch_uv = &ch->sn.uv;
+ struct xpc_send_msg_slot_uv *msg_slot;
+ unsigned long irq_flags;
+ int nentries;
+ int entry;
+ size_t nbytes;
+
+ for (nentries = ch->local_nentries; nentries > 0; nentries--) {
+ nbytes = nentries * sizeof(struct xpc_send_msg_slot_uv);
+ ch_uv->send_msg_slots = kzalloc(nbytes, GFP_KERNEL);
+ if (ch_uv->send_msg_slots == NULL)
+ continue;
+
+ for (entry = 0; entry < nentries; entry++) {
+ msg_slot = &ch_uv->send_msg_slots[entry];
+
+ msg_slot->msg_slot_number = entry;
+ xpc_put_fifo_entry_uv(&ch_uv->msg_slot_free_list,
+ &msg_slot->next);
+ }
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ if (nentries < ch->local_nentries)
+ ch->local_nentries = nentries;
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+ return xpSuccess;
+ }
+
+ return xpNoMemory;
+}
+
+static enum xp_retval
+xpc_allocate_recv_msg_slot_uv(struct xpc_channel *ch)
+{
+ struct xpc_channel_uv *ch_uv = &ch->sn.uv;
+ struct xpc_notify_mq_msg_uv *msg_slot;
+ unsigned long irq_flags;
+ int nentries;
+ int entry;
+ size_t nbytes;
+
+ for (nentries = ch->remote_nentries; nentries > 0; nentries--) {
+ nbytes = nentries * ch->entry_size;
+ ch_uv->recv_msg_slots = kzalloc(nbytes, GFP_KERNEL);
+ if (ch_uv->recv_msg_slots == NULL)
+ continue;
+
+ for (entry = 0; entry < nentries; entry++) {
+ msg_slot = ch_uv->recv_msg_slots + entry *
+ ch->entry_size;
+
+ msg_slot->hdr.msg_slot_number = entry;
+ }
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ if (nentries < ch->remote_nentries)
+ ch->remote_nentries = nentries;
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+ return xpSuccess;
+ }
+
+ return xpNoMemory;
+}
+
+/*
+ * Allocate msg_slots associated with the channel.
+ */
+static enum xp_retval
xpc_setup_msg_structures_uv(struct xpc_channel *ch)
{
- /* !!! this function needs fleshing out */
- return xpUnsupported;
+ static enum xp_retval ret;
+ struct xpc_channel_uv *ch_uv = &ch->sn.uv;
+
+ DBUG_ON(ch->flags & XPC_C_SETUP);
+
+ ret = xpc_allocate_send_msg_slot_uv(ch);
+ if (ret == xpSuccess) {
+
+ ret = xpc_allocate_recv_msg_slot_uv(ch);
+ if (ret != xpSuccess) {
+ kfree(ch_uv->send_msg_slots);
+ xpc_init_fifo_uv(&ch_uv->msg_slot_free_list);
+ }
+ }
+ return ret;
}

+/*
+ * Free up msg_slots and clear other stuff that were setup for the specified
+ * channel.
+ */
static void
xpc_teardown_msg_structures_uv(struct xpc_channel *ch)
{
struct xpc_channel_uv *ch_uv = &ch->sn.uv;

+ DBUG_ON(!spin_is_locked(&ch->lock));
+
ch_uv->remote_notify_mq_gpa = 0;

- /* !!! this function needs fleshing out */
+ if (ch->flags & XPC_C_SETUP) {
+ xpc_init_fifo_uv(&ch_uv->msg_slot_free_list);
+ kfree(ch_uv->send_msg_slots);
+ xpc_init_fifo_uv(&ch_uv->recv_msg_list);
+ kfree(ch_uv->recv_msg_slots);
+ }
}

static void
@@ -723,7 +912,7 @@ xpc_send_chctl_openrequest_uv(struct xpc
struct xpc_activate_mq_msg_chctl_openrequest_uv msg;

msg.ch_number = ch->number;
- msg.msg_size = ch->msg_size;
+ msg.entry_size = ch->entry_size;
msg.local_nentries = ch->local_nentries;
xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV);
@@ -743,6 +932,18 @@ xpc_send_chctl_openreply_uv(struct xpc_c
}

static void
+xpc_send_chctl_local_msgrequest_uv(struct xpc_partition *part, int ch_number)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&part->chctl_lock, irq_flags);
+ part->chctl.flags[ch_number] |= XPC_CHCTL_MSGREQUEST;
+ spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
+
+ xpc_wakeup_channel_mgr(part);
+}
+
+static void
xpc_save_remote_msgqueue_pa_uv(struct xpc_channel *ch,
unsigned long msgqueue_pa)
{
@@ -798,11 +999,358 @@ xpc_any_partition_engaged_uv(void)
return 0;
}

-static struct xpc_msg *
-xpc_get_deliverable_msg_uv(struct xpc_channel *ch)
+static enum xp_retval
+xpc_allocate_msg_slot_uv(struct xpc_channel *ch, u32 flags,
+ struct xpc_send_msg_slot_uv **address_of_msg_slot)
+{
+ enum xp_retval ret;
+ struct xpc_send_msg_slot_uv *msg_slot;
+ struct xpc_fifo_entry_uv *entry;
+
+ while (1) {
+ entry = xpc_get_fifo_entry_uv(&ch->sn.uv.msg_slot_free_list);
+ if (entry != NULL)
+ break;
+
+ if (flags & XPC_NOWAIT)
+ return xpNoWait;
+
+ ret = xpc_allocate_msg_wait(ch);
+ if (ret != xpInterrupted && ret != xpTimeout)
+ return ret;
+ }
+
+ msg_slot = container_of(entry, struct xpc_send_msg_slot_uv, next);
+ *address_of_msg_slot = msg_slot;
+ return xpSuccess;
+}
+
+static void
+xpc_free_msg_slot_uv(struct xpc_channel *ch,
+ struct xpc_send_msg_slot_uv *msg_slot)
+{
+ xpc_put_fifo_entry_uv(&ch->sn.uv.msg_slot_free_list, &msg_slot->next);
+
+ /* wakeup anyone waiting for a free msg slot */
+ if (atomic_read(&ch->n_on_msg_allocate_wq) > 0)
+ wake_up(&ch->msg_allocate_wq);
+}
+
+static void
+xpc_notify_sender_uv(struct xpc_channel *ch,
+ struct xpc_send_msg_slot_uv *msg_slot,
+ enum xp_retval reason)
+{
+ xpc_notify_func func = msg_slot->func;
+
+ if (func != NULL && cmpxchg(&msg_slot->func, func, NULL) == func) {
+
+ atomic_dec(&ch->n_to_notify);
+
+ dev_dbg(xpc_chan, "msg_slot->func() called, msg_slot=0x%p "
+ "msg_slot_number=%d partid=%d channel=%d\n", msg_slot,
+ msg_slot->msg_slot_number, ch->partid, ch->number);
+
+ func(reason, ch->partid, ch->number, msg_slot->key);
+
+ dev_dbg(xpc_chan, "msg_slot->func() returned, msg_slot=0x%p "
+ "msg_slot_number=%d partid=%d channel=%d\n", msg_slot,
+ msg_slot->msg_slot_number, ch->partid, ch->number);
+ }
+}
+
+static void
+xpc_handle_notify_mq_ack_uv(struct xpc_channel *ch,
+ struct xpc_notify_mq_msg_uv *msg)
+{
+ struct xpc_send_msg_slot_uv *msg_slot;
+ int entry = msg->hdr.msg_slot_number % ch->local_nentries;
+
+ msg_slot = &ch->sn.uv.send_msg_slots[entry];
+
+ BUG_ON(msg_slot->msg_slot_number != msg->hdr.msg_slot_number);
+ msg_slot->msg_slot_number += ch->local_nentries;
+
+ if (msg_slot->func != NULL)
+ xpc_notify_sender_uv(ch, msg_slot, xpMsgDelivered);
+
+ xpc_free_msg_slot_uv(ch, msg_slot);
+}
+
+static void
+xpc_handle_notify_mq_msg_uv(struct xpc_partition *part,
+ struct xpc_notify_mq_msg_uv *msg)
+{
+ struct xpc_partition_uv *part_uv = &part->sn.uv;
+ struct xpc_channel *ch;
+ struct xpc_channel_uv *ch_uv;
+ struct xpc_notify_mq_msg_uv *msg_slot;
+ unsigned long irq_flags;
+ int ch_number = msg->hdr.ch_number;
+
+ if (unlikely(ch_number >= part->nchannels)) {
+ dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received invalid "
+ "channel number=0x%x in message from partid=%d\n",
+ ch_number, XPC_PARTID(part));
+
+ /* get hb checker to deactivate from the remote partition */
+ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+ if (part_uv->act_state_req == 0)
+ xpc_activate_IRQ_rcvd++;
+ part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV;
+ part_uv->reason = xpBadChannelNumber;
+ spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
+
+ wake_up_interruptible(&xpc_activate_IRQ_wq);
+ return;
+ }
+
+ ch = &part->channels[ch_number];
+ xpc_msgqueue_ref(ch);
+
+ if (!(ch->flags & XPC_C_CONNECTED)) {
+ xpc_msgqueue_deref(ch);
+ return;
+ }
+
+ /* see if we're really dealing with an ACK for a previously sent msg */
+ if (msg->hdr.size == 0) {
+ xpc_handle_notify_mq_ack_uv(ch, msg);
+ xpc_msgqueue_deref(ch);
+ return;
+ }
+
+ /* we're dealing with a normal message sent via the notify_mq */
+ ch_uv = &ch->sn.uv;
+
+ msg_slot = (struct xpc_notify_mq_msg_uv *)((u64)ch_uv->recv_msg_slots +
+ (msg->hdr.msg_slot_number % ch->remote_nentries) *
+ ch->entry_size);
+
+ BUG_ON(msg->hdr.msg_slot_number != msg_slot->hdr.msg_slot_number);
+ BUG_ON(msg_slot->hdr.size != 0);
+
+ memcpy(msg_slot, msg, msg->hdr.size);
+
+ xpc_put_fifo_entry_uv(&ch_uv->recv_msg_list, &msg_slot->hdr.u.next);
+
+ if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) {
+ /*
+ * If there is an existing idle kthread get it to deliver
+ * the payload, otherwise we'll have to get the channel mgr
+ * for this partition to create a kthread to do the delivery.
+ */
+ if (atomic_read(&ch->kthreads_idle) > 0)
+ wake_up_nr(&ch->idle_wq, 1);
+ else
+ xpc_send_chctl_local_msgrequest_uv(part, ch->number);
+ }
+ xpc_msgqueue_deref(ch);
+}
+
+static irqreturn_t
+xpc_handle_notify_IRQ_uv(int irq, void *dev_id)
+{
+ struct xpc_notify_mq_msg_uv *msg;
+ short partid;
+ struct xpc_partition *part;
+
+ while ((msg = gru_get_next_message(xpc_notify_mq_uv)) != NULL) {
+
+ partid = msg->hdr.partid;
+ if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) {
+ dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received "
+ "invalid partid=0x%x in message\n", partid);
+ } else {
+ part = &xpc_partitions[partid];
+
+ if (xpc_part_ref(part)) {
+ xpc_handle_notify_mq_msg_uv(part, msg);
+ xpc_part_deref(part);
+ }
+ }
+
+ gru_free_message(xpc_notify_mq_uv, msg);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int
+xpc_n_of_deliverable_payloads_uv(struct xpc_channel *ch)
+{
+ return xpc_n_of_fifo_entries_uv(&ch->sn.uv.recv_msg_list);
+}
+
+static void
+xpc_process_msg_chctl_flags_uv(struct xpc_partition *part, int ch_number)
+{
+ struct xpc_channel *ch = &part->channels[ch_number];
+ int ndeliverable_payloads;
+
+ xpc_msgqueue_ref(ch);
+
+ ndeliverable_payloads = xpc_n_of_deliverable_payloads_uv(ch);
+
+ if (ndeliverable_payloads > 0 &&
+ (ch->flags & XPC_C_CONNECTED) &&
+ (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE)) {
+
+ xpc_activate_kthreads(ch, ndeliverable_payloads);
+ }
+
+ xpc_msgqueue_deref(ch);
+}
+
+static enum xp_retval
+xpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload,
+ u16 payload_size, u8 notify_type, xpc_notify_func func,
+ void *key)
+{
+ enum xp_retval ret = xpSuccess;
+ struct xpc_send_msg_slot_uv *msg_slot = NULL;
+ struct xpc_notify_mq_msg_uv *msg;
+ u8 msg_buffer[XPC_NOTIFY_MSG_SIZE_UV];
+ size_t msg_size;
+
+ DBUG_ON(notify_type != XPC_N_CALL);
+
+ msg_size = sizeof(struct xpc_notify_mq_msghdr_uv) + payload_size;
+ if (msg_size > ch->entry_size)
+ return xpPayloadTooBig;
+
+ xpc_msgqueue_ref(ch);
+
+ if (ch->flags & XPC_C_DISCONNECTING) {
+ ret = ch->reason;
+ goto out_1;
+ }
+ if (!(ch->flags & XPC_C_CONNECTED)) {
+ ret = xpNotConnected;
+ goto out_1;
+ }
+
+ ret = xpc_allocate_msg_slot_uv(ch, flags, &msg_slot);
+ if (ret != xpSuccess)
+ goto out_1;
+
+ if (func != NULL) {
+ atomic_inc(&ch->n_to_notify);
+
+ msg_slot->key = key;
+ wmb(); /* a non-NULL func must hit memory after the key */
+ msg_slot->func = func;
+
+ if (ch->flags & XPC_C_DISCONNECTING) {
+ ret = ch->reason;
+ goto out_2;
+ }
+ }
+
+ msg = (struct xpc_notify_mq_msg_uv *)&msg_buffer;
+ msg->hdr.partid = xp_partition_id;
+ msg->hdr.ch_number = ch->number;
+ msg->hdr.size = msg_size;
+ msg->hdr.msg_slot_number = msg_slot->msg_slot_number;
+ memcpy(&msg->payload, payload, payload_size);
+
+ ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg, msg_size);
+ if (ret == xpSuccess)
+ goto out_1;
+
+ XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret);
+out_2:
+ if (func != NULL) {
+ /*
+ * Try to NULL the msg_slot's func field. If we fail, then
+ * xpc_notify_senders_of_disconnect_uv() beat us to it, in which
+ * case we need to pretend we succeeded to send the message
+ * since the user will get a callout for the disconnect error
+ * by xpc_notify_senders_of_disconnect_uv(), and to also get an
+ * error returned here will confuse them. Additionally, since
+ * in this case the channel is being disconnected we don't need
+ * to put the the msg_slot back on the free list.
+ */
+ if (cmpxchg(&msg_slot->func, func, NULL) != func) {
+ ret = xpSuccess;
+ goto out_1;
+ }
+
+ msg_slot->key = NULL;
+ atomic_dec(&ch->n_to_notify);
+ }
+ xpc_free_msg_slot_uv(ch, msg_slot);
+out_1:
+ xpc_msgqueue_deref(ch);
+ return ret;
+}
+
+/*
+ * Tell the callers of xpc_send_notify() that the status of their payloads
+ * is unknown because the channel is now disconnecting.
+ *
+ * We don't worry about putting these msg_slots on the free list since the
+ * msg_slots themselves are about to be kfree'd.
+ */
+static void
+xpc_notify_senders_of_disconnect_uv(struct xpc_channel *ch)
+{
+ struct xpc_send_msg_slot_uv *msg_slot;
+ int entry;
+
+ DBUG_ON(!(ch->flags & XPC_C_DISCONNECTING));
+
+ for (entry = 0; entry < ch->local_nentries; entry++) {
+
+ if (atomic_read(&ch->n_to_notify) == 0)
+ break;
+
+ msg_slot = &ch->sn.uv.send_msg_slots[entry];
+ if (msg_slot->func != NULL)
+ xpc_notify_sender_uv(ch, msg_slot, ch->reason);
+ }
+}
+
+/*
+ * Get the next deliverable message's payload.
+ */
+static void *
+xpc_get_deliverable_payload_uv(struct xpc_channel *ch)
+{
+ struct xpc_fifo_entry_uv *entry;
+ struct xpc_notify_mq_msg_uv *msg;
+ void *payload = NULL;
+
+ if (!(ch->flags & XPC_C_DISCONNECTING)) {
+ entry = xpc_get_fifo_entry_uv(&ch->sn.uv.recv_msg_list);
+ if (entry != NULL) {
+ msg = container_of(entry, struct xpc_notify_mq_msg_uv,
+ hdr.u.next);
+ payload = &msg->payload;
+ }
+ }
+ return payload;
+}
+
+static void
+xpc_received_payload_uv(struct xpc_channel *ch, void *payload)
{
- /* !!! this function needs fleshing out */
- return NULL;
+ struct xpc_notify_mq_msg_uv *msg;
+ enum xp_retval ret;
+
+ msg = container_of(payload, struct xpc_notify_mq_msg_uv, payload);
+
+ /* return an ACK to the sender of this message */
+
+ msg->hdr.partid = xp_partition_id;
+ msg->hdr.size = 0; /* size of zero indicates this is an ACK */
+
+ ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg,
+ sizeof(struct xpc_notify_mq_msghdr_uv));
+ if (ret != xpSuccess)
+ XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret);
+
+ msg->hdr.msg_slot_number += ch->remote_nentries;
}

int
@@ -824,6 +1372,8 @@ xpc_init_uv(void)
xpc_request_partition_reactivation_uv;
xpc_request_partition_deactivation =
xpc_request_partition_deactivation_uv;
+ xpc_cancel_partition_deactivation_request =
+ xpc_cancel_partition_deactivation_request_uv;

xpc_setup_ch_structures_sn = xpc_setup_ch_structures_sn_uv;
xpc_teardown_ch_structures_sn = xpc_teardown_ch_structures_sn_uv;
@@ -848,7 +1398,18 @@ xpc_init_uv(void)
xpc_partition_engaged = xpc_partition_engaged_uv;
xpc_any_partition_engaged = xpc_any_partition_engaged_uv;

- xpc_get_deliverable_msg = xpc_get_deliverable_msg_uv;
+ xpc_n_of_deliverable_payloads = xpc_n_of_deliverable_payloads_uv;
+ xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_uv;
+ xpc_send_payload = xpc_send_payload_uv;
+ xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_uv;
+ xpc_get_deliverable_payload = xpc_get_deliverable_payload_uv;
+ xpc_received_payload = xpc_received_payload_uv;
+
+ if (sizeof(struct xpc_notify_mq_msghdr_uv) > XPC_MSG_HDR_MAX_SIZE) {
+ dev_err(xpc_part, "xpc_notify_mq_msghdr_uv is larger than %d\n",
+ XPC_MSG_HDR_MAX_SIZE);
+ return -E2BIG;
+ }

/* ??? The cpuid argument's value is 0, is that what we want? */
/* !!! The irq argument's value isn't correct. */
@@ -857,6 +1418,17 @@ xpc_init_uv(void)
if (xpc_activate_mq_uv == NULL)
return -ENOMEM;

+ /* ??? The cpuid argument's value is 0, is that what we want? */
+ /* !!! The irq argument's value isn't correct. */
+ xpc_notify_mq_uv = xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, 0, 0,
+ xpc_handle_notify_IRQ_uv);
+ if (xpc_notify_mq_uv == NULL) {
+ /* !!! The irq argument's value isn't correct. */
+ xpc_destroy_gru_mq_uv(xpc_activate_mq_uv,
+ XPC_ACTIVATE_MQ_SIZE_UV, 0);
+ return -ENOMEM;
+ }
+
return 0;
}

@@ -864,5 +1436,8 @@ void
xpc_exit_uv(void)
{
/* !!! The irq argument's value isn't correct. */
+ xpc_destroy_gru_mq_uv(xpc_notify_mq_uv, XPC_NOTIFY_MQ_SIZE_UV, 0);
+
+ /* !!! The irq argument's value isn't correct. */
xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, XPC_ACTIVATE_MQ_SIZE_UV, 0);
}
Index: linux/drivers/misc/sgi-xp/xp.h
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp.h 2008-07-07 12:25:58.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp.h 2008-07-07 12:33:11.000000000 -0500
@@ -87,39 +87,18 @@
#endif

/*
- * The format of an XPC message is as follows:
- *
- * +-------+--------------------------------+
- * | flags |////////////////////////////////|
- * +-------+--------------------------------+
- * | message # |
- * +----------------------------------------+
- * | payload (user-defined message) |
- * | |
- * :
- * | |
- * +----------------------------------------+
- *
- * The size of the payload is defined by the user via xpc_connect(). A user-
- * defined message resides in the payload area.
- *
- * The size of a message entry (within a message queue) must be a cacheline
- * sized multiple in order to facilitate the BTE transfer of messages from one
- * message queue to another. A macro, XPC_MSG_SIZE(), is provided for the user
+ * Define macro, XPC_MSG_SIZE(), is provided for the user
* that wants to fit as many msg entries as possible in a given memory size
* (e.g. a memory page).
*/
-struct xpc_msg {
- u8 flags; /* FOR XPC INTERNAL USE ONLY */
- u8 reserved[7]; /* FOR XPC INTERNAL USE ONLY */
- s64 number; /* FOR XPC INTERNAL USE ONLY */
-
- u64 payload; /* user defined portion of message */
-};
+#define XPC_MSG_MAX_SIZE 128
+#define XPC_MSG_HDR_MAX_SIZE 16
+#define XPC_MSG_PAYLOAD_MAX_SIZE (XPC_MSG_MAX_SIZE - XPC_MSG_HDR_MAX_SIZE)

-#define XPC_MSG_PAYLOAD_OFFSET (u64) (&((struct xpc_msg *)0)->payload)
#define XPC_MSG_SIZE(_payload_size) \
- L1_CACHE_ALIGN(XPC_MSG_PAYLOAD_OFFSET + (_payload_size))
+ ALIGN(XPC_MSG_HDR_MAX_SIZE + (_payload_size), \
+ is_uv() ? 64 : 128)
+

/*
* Define the return values and values passed to user's callout functions.
@@ -210,7 +189,10 @@ enum xp_retval {
xpGruCopyError, /* 58: gru_copy_gru() returned error */
xpGruSendMqError, /* 59: gru send message queue related error */

- xpUnknownReason /* 60: unknown reason - must be last in enum */
+ xpBadChannelNumber, /* 60: invalid channel number */
+ xpBadMsgType, /* 60: invalid message type */
+
+ xpUnknownReason /* 61: unknown reason - must be last in enum */
};

/*
@@ -261,6 +243,9 @@ typedef void (*xpc_channel_func) (enum x
* calling xpc_received().
*
* All other reason codes indicate failure.
+ *
+ * NOTE: The user defined function must be callable by an interrupt handler
+ * and thus cannot block.
*/
typedef void (*xpc_notify_func) (enum xp_retval reason, short partid,
int ch_number, void *key);
@@ -284,7 +269,7 @@ struct xpc_registration {
xpc_channel_func func; /* function to call */
void *key; /* pointer to user's key */
u16 nentries; /* #of msg entries in local msg queue */
- u16 msg_size; /* message queue's message size */
+ u16 entry_size; /* message queue's message entry size */
u32 assigned_limit; /* limit on #of assigned kthreads */
u32 idle_limit; /* limit on #of idle kthreads */
} ____cacheline_aligned;
Index: linux/drivers/misc/sgi-xp/xpc_channel.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_channel.c 2008-07-07 12:25:58.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_channel.c 2008-07-07 12:26:00.000000000 -0500
@@ -139,7 +139,7 @@ xpc_process_disconnect(struct xpc_channe

ch->func = NULL;
ch->key = NULL;
- ch->msg_size = 0;
+ ch->entry_size = 0;
ch->local_nentries = 0;
ch->remote_nentries = 0;
ch->kthreads_assigned_limit = 0;
@@ -315,9 +315,9 @@ again:

if (chctl_flags & XPC_CHCTL_OPENREQUEST) {

- dev_dbg(xpc_chan, "XPC_CHCTL_OPENREQUEST (msg_size=%d, "
+ dev_dbg(xpc_chan, "XPC_CHCTL_OPENREQUEST (entry_size=%d, "
"local_nentries=%d) received from partid=%d, "
- "channel=%d\n", args->msg_size, args->local_nentries,
+ "channel=%d\n", args->entry_size, args->local_nentries,
ch->partid, ch->number);

if (part->act_state == XPC_P_AS_DEACTIVATING ||
@@ -338,10 +338,10 @@ again:

/*
* The meaningful OPENREQUEST connection state fields are:
- * msg_size = size of channel's messages in bytes
+ * entry_size = size of channel's messages in bytes
* local_nentries = remote partition's local_nentries
*/
- if (args->msg_size == 0 || args->local_nentries == 0) {
+ if (args->entry_size == 0 || args->local_nentries == 0) {
/* assume OPENREQUEST was delayed by mistake */
spin_unlock_irqrestore(&ch->lock, irq_flags);
return;
@@ -351,14 +351,14 @@ again:
ch->remote_nentries = args->local_nentries;

if (ch->flags & XPC_C_OPENREQUEST) {
- if (args->msg_size != ch->msg_size) {
+ if (args->entry_size != ch->entry_size) {
XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes,
&irq_flags);
spin_unlock_irqrestore(&ch->lock, irq_flags);
return;
}
} else {
- ch->msg_size = args->msg_size;
+ ch->entry_size = args->entry_size;

XPC_SET_REASON(ch, 0, 0);
ch->flags &= ~XPC_C_DISCONNECTED;
@@ -473,7 +473,7 @@ xpc_connect_channel(struct xpc_channel *
ch->local_nentries = registration->nentries;

if (ch->flags & XPC_C_ROPENREQUEST) {
- if (registration->msg_size != ch->msg_size) {
+ if (registration->entry_size != ch->entry_size) {
/* the local and remote sides aren't the same */

/*
@@ -492,7 +492,7 @@ xpc_connect_channel(struct xpc_channel *
return xpUnequalMsgSizes;
}
} else {
- ch->msg_size = registration->msg_size;
+ ch->entry_size = registration->entry_size;

XPC_SET_REASON(ch, 0, 0);
ch->flags &= ~XPC_C_DISCONNECTED;
@@ -859,8 +859,8 @@ xpc_initiate_send(short partid, int ch_n
DBUG_ON(payload == NULL);

if (xpc_part_ref(part)) {
- ret = xpc_send_msg(&part->channels[ch_number], flags, payload,
- payload_size, 0, NULL, NULL);
+ ret = xpc_send_payload(&part->channels[ch_number], flags,
+ payload, payload_size, 0, NULL, NULL);
xpc_part_deref(part);
}

@@ -911,23 +911,24 @@ xpc_initiate_send_notify(short partid, i
DBUG_ON(func == NULL);

if (xpc_part_ref(part)) {
- ret = xpc_send_msg(&part->channels[ch_number], flags, payload,
- payload_size, XPC_N_CALL, func, key);
+ ret = xpc_send_payload(&part->channels[ch_number], flags,
+ payload, payload_size, XPC_N_CALL, func,
+ key);
xpc_part_deref(part);
}
return ret;
}

/*
- * Deliver a message to its intended recipient.
+ * Deliver a message's payload to its intended recipient.
*/
void
-xpc_deliver_msg(struct xpc_channel *ch)
+xpc_deliver_payload(struct xpc_channel *ch)
{
- struct xpc_msg *msg;
+ void *payload;

- msg = xpc_get_deliverable_msg(ch);
- if (msg != NULL) {
+ payload = xpc_get_deliverable_payload(ch);
+ if (payload != NULL) {

/*
* This ref is taken to protect the payload itself from being
@@ -939,18 +940,16 @@ xpc_deliver_msg(struct xpc_channel *ch)
atomic_inc(&ch->kthreads_active);

if (ch->func != NULL) {
- dev_dbg(xpc_chan, "ch->func() called, msg=0x%p, "
- "msg_number=%ld, partid=%d, channel=%d\n",
- msg, (signed long)msg->number, ch->partid,
+ dev_dbg(xpc_chan, "ch->func() called, payload=0x%p "
+ "partid=%d channel=%d\n", payload, ch->partid,
ch->number);

/* deliver the message to its intended recipient */
- ch->func(xpMsgReceived, ch->partid, ch->number,
- &msg->payload, ch->key);
+ ch->func(xpMsgReceived, ch->partid, ch->number, payload,
+ ch->key);

- dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, "
- "msg_number=%ld, partid=%d, channel=%d\n",
- msg, (signed long)msg->number, ch->partid,
+ dev_dbg(xpc_chan, "ch->func() returned, payload=0x%p "
+ "partid=%d channel=%d\n", payload, ch->partid,
ch->number);
}

@@ -959,14 +958,11 @@ xpc_deliver_msg(struct xpc_channel *ch)
}

/*
- * Acknowledge receipt of a delivered message.
- *
- * If a message has XPC_M_INTERRUPT set, send an interrupt to the partition
- * that sent the message.
+ * Acknowledge receipt of a delivered message's payload.
*
* This function, although called by users, does not call xpc_part_ref() to
* ensure that the partition infrastructure is in place. It relies on the
- * fact that we called xpc_msgqueue_ref() in xpc_deliver_msg().
+ * fact that we called xpc_msgqueue_ref() in xpc_deliver_payload().
*
* Arguments:
*
@@ -980,14 +976,13 @@ xpc_initiate_received(short partid, int
{
struct xpc_partition *part = &xpc_partitions[partid];
struct xpc_channel *ch;
- struct xpc_msg *msg = XPC_MSG_ADDRESS(payload);

DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
DBUG_ON(ch_number < 0 || ch_number >= part->nchannels);

ch = &part->channels[ch_number];
- xpc_received_msg(ch, msg);
+ xpc_received_payload(ch, payload);

- /* the call to xpc_msgqueue_ref() was done by xpc_deliver_msg() */
+ /* the call to xpc_msgqueue_ref() was done by xpc_deliver_payload() */
xpc_msgqueue_deref(ch);
}
Index: linux/drivers/misc/sgi-xp/xp_main.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xp_main.c 2008-07-07 12:25:52.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xp_main.c 2008-07-07 12:26:00.000000000 -0500
@@ -154,6 +154,9 @@ xpc_connect(int ch_number, xpc_channel_f
DBUG_ON(func == NULL);
DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit);

+ if (XPC_MSG_SIZE(payload_size) > XPC_MSG_MAX_SIZE)
+ return xpPayloadTooBig;
+
registration = &xpc_registrations[ch_number];

if (mutex_lock_interruptible(&registration->mutex) != 0)
@@ -166,7 +169,7 @@ xpc_connect(int ch_number, xpc_channel_f
}

/* register the channel for connection */
- registration->msg_size = XPC_MSG_SIZE(payload_size);
+ registration->entry_size = XPC_MSG_SIZE(payload_size);
registration->nentries = nentries;
registration->assigned_limit = assigned_limit;
registration->idle_limit = idle_limit;
@@ -220,7 +223,7 @@ xpc_disconnect(int ch_number)
registration->func = NULL;
registration->key = NULL;
registration->nentries = 0;
- registration->msg_size = 0;
+ registration->entry_size = 0;
registration->assigned_limit = 0;
registration->idle_limit = 0;

Index: linux/drivers/misc/sgi-xp/xpc_main.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpc_main.c 2008-07-07 12:25:58.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpc_main.c 2008-07-07 12:26:00.000000000 -0500
@@ -188,8 +188,8 @@ u64 (*xpc_get_chctl_all_flags) (struct x
enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *ch);
void (*xpc_teardown_msg_structures) (struct xpc_channel *ch);
void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number);
-int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch);
-struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch);
+int (*xpc_n_of_deliverable_payloads) (struct xpc_channel *ch);
+void *(*xpc_get_deliverable_payload) (struct xpc_channel *ch);

void (*xpc_request_partition_activation) (struct xpc_rsvd_page *remote_rp,
unsigned long remote_rp_pa,
@@ -220,10 +220,11 @@ void (*xpc_send_chctl_openreply) (struct
void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch,
unsigned long msgqueue_pa);

-enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags,
- void *payload, u16 payload_size, u8 notify_type,
- xpc_notify_func func, void *key);
-void (*xpc_received_msg) (struct xpc_channel *ch, struct xpc_msg *msg);
+enum xp_retval (*xpc_send_payload) (struct xpc_channel *ch, u32 flags,
+ void *payload, u16 payload_size,
+ u8 notify_type, xpc_notify_func func,
+ void *key);
+void (*xpc_received_payload) (struct xpc_channel *ch, void *payload);

/*
* Timer function to enforce the timelimit on the partition disengage.
@@ -714,9 +715,9 @@ xpc_kthread_waitmsgs(struct xpc_partitio
do {
/* deliver messages to their intended recipients */

- while (xpc_n_of_deliverable_msgs(ch) > 0 &&
+ while (xpc_n_of_deliverable_payloads(ch) > 0 &&
!(ch->flags & XPC_C_DISCONNECTING)) {
- xpc_deliver_msg(ch);
+ xpc_deliver_payload(ch);
}

if (atomic_inc_return(&ch->kthreads_idle) >
@@ -730,7 +731,7 @@ xpc_kthread_waitmsgs(struct xpc_partitio
"wait_event_interruptible_exclusive()\n");

(void)wait_event_interruptible_exclusive(ch->idle_wq,
- (xpc_n_of_deliverable_msgs(ch) > 0 ||
+ (xpc_n_of_deliverable_payloads(ch) > 0 ||
(ch->flags & XPC_C_DISCONNECTING)));

atomic_dec(&ch->kthreads_idle);
@@ -775,7 +776,7 @@ xpc_kthread_start(void *args)
* additional kthreads to help deliver them. We only
* need one less than total #of messages to deliver.
*/
- n_needed = xpc_n_of_deliverable_msgs(ch) - 1;
+ n_needed = xpc_n_of_deliverable_payloads(ch) - 1;
if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING))
xpc_activate_kthreads(ch, n_needed);

Index: linux/drivers/misc/sgi-xp/xpnet.c
===================================================================
--- linux.orig/drivers/misc/sgi-xp/xpnet.c 2008-07-07 12:25:52.000000000 -0500
+++ linux/drivers/misc/sgi-xp/xpnet.c 2008-07-07 12:26:00.000000000 -0500
@@ -57,11 +57,10 @@ struct xpnet_message {
*
* XPC expects each message to exist in an individual cacheline.
*/
-#define XPNET_MSG_SIZE (L1_CACHE_BYTES - XPC_MSG_PAYLOAD_OFFSET)
+#define XPNET_MSG_SIZE XPC_MSG_PAYLOAD_MAX_SIZE
#define XPNET_MSG_DATA_MAX \
- (XPNET_MSG_SIZE - (u64)(&((struct xpnet_message *)0)->data))
-#define XPNET_MSG_ALIGNED_SIZE (L1_CACHE_ALIGN(XPNET_MSG_SIZE))
-#define XPNET_MSG_NENTRIES (PAGE_SIZE / XPNET_MSG_ALIGNED_SIZE)
+ (XPNET_MSG_SIZE - offsetof(struct xpnet_message, data))
+#define XPNET_MSG_NENTRIES (PAGE_SIZE / XPC_MSG_MAX_SIZE)

#define XPNET_MAX_KTHREADS (XPNET_MSG_NENTRIES + 1)
#define XPNET_MAX_IDLE_KTHREADS (XPNET_MSG_NENTRIES + 1)
@@ -408,6 +407,7 @@ xpnet_send(struct sk_buff *skb, struct x
{
u8 msg_buffer[XPNET_MSG_SIZE];
struct xpnet_message *msg = (struct xpnet_message *)&msg_buffer;
+ u16 msg_size = sizeof(struct xpnet_message);
enum xp_retval ret;

msg->embedded_bytes = embedded_bytes;
@@ -417,6 +417,7 @@ xpnet_send(struct sk_buff *skb, struct x
&msg->data, skb->data, (size_t)embedded_bytes);
skb_copy_from_linear_data(skb, &msg->data,
(size_t)embedded_bytes);
+ msg_size += embedded_bytes - 1;
} else {
msg->version = XPNET_VERSION;
}
@@ -435,7 +436,7 @@ xpnet_send(struct sk_buff *skb, struct x
atomic_inc(&queued_msg->use_count);

ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT, msg,
- XPNET_MSG_SIZE, xpnet_send_completed, queued_msg);
+ msg_size, xpnet_send_completed, queued_msg);
if (unlikely(ret != xpSuccess))
atomic_dec(&queued_msg->use_count);
}