From 45d9ca492e4bd1522d1b5bd125c2908f1cee3d4a Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 22 Apr 2008 14:46:56 -0500 Subject: [IA64] move XP and XPC to drivers/misc/sgi-xp Move XPC and XPNET from arch/ia64/sn/kernel to drivers/misc/sgi-xp. Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- drivers/misc/Kconfig | 12 + drivers/misc/Makefile | 1 + drivers/misc/sgi-xp/Makefile | 11 + drivers/misc/sgi-xp/xp.h | 485 +++++++ drivers/misc/sgi-xp/xp_main.c | 290 +++++ drivers/misc/sgi-xp/xp_nofault.S | 36 + drivers/misc/sgi-xp/xpc.h | 1267 +++++++++++++++++++ drivers/misc/sgi-xp/xpc_channel.c | 2379 +++++++++++++++++++++++++++++++++++ drivers/misc/sgi-xp/xpc_main.c | 1431 +++++++++++++++++++++ drivers/misc/sgi-xp/xpc_partition.c | 1239 ++++++++++++++++++ drivers/misc/sgi-xp/xpnet.c | 718 +++++++++++ 11 files changed, 7869 insertions(+) create mode 100644 drivers/misc/sgi-xp/Makefile create mode 100644 drivers/misc/sgi-xp/xp.h create mode 100644 drivers/misc/sgi-xp/xp_main.c create mode 100644 drivers/misc/sgi-xp/xp_nofault.S create mode 100644 drivers/misc/sgi-xp/xpc.h create mode 100644 drivers/misc/sgi-xp/xpc_channel.c create mode 100644 drivers/misc/sgi-xp/xpc_main.c create mode 100644 drivers/misc/sgi-xp/xpc_partition.c create mode 100644 drivers/misc/sgi-xp/xpnet.c (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index bb94ce78a6d..297a48f8544 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -360,4 +360,16 @@ config ENCLOSURE_SERVICES driver (SCSI/ATA) which supports enclosures or a SCSI enclosure device (SES) to use these services. +config SGI_XP + tristate "Support communication between SGI SSIs" + depends on IA64_GENERIC || IA64_SGI_SN2 + select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 + select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 + ---help--- + An SGI machine can be divided into multiple Single System + Images which act independently of each other and have + hardware based memory protection from the others. Enabling + this feature will allow for direct communication between SSIs + based on a network adapter and DMA messaging. + endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 4581b253311..5914da43485 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o +obj-$(CONFIG_SGI_XP) += sgi-xp/ diff --git a/drivers/misc/sgi-xp/Makefile b/drivers/misc/sgi-xp/Makefile new file mode 100644 index 00000000000..b6e40a7958c --- /dev/null +++ b/drivers/misc/sgi-xp/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for SGI's XP devices. +# + +obj-$(CONFIG_SGI_XP) += xp.o +xp-y := xp_main.o xp_nofault.o + +obj-$(CONFIG_SGI_XP) += xpc.o +xpc-y := xpc_main.o xpc_channel.o xpc_partition.o + +obj-$(CONFIG_SGI_XP) += xpnet.o diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h new file mode 100644 index 00000000000..fb65981754c --- /dev/null +++ b/drivers/misc/sgi-xp/xp.h @@ -0,0 +1,485 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004-2008 Silicon Graphics, Inc. All rights reserved. + */ + + +/* + * External Cross Partition (XP) structures and defines. + */ + + +#ifndef _DRIVERS_MISC_SGIXP_XP_H +#define _DRIVERS_MISC_SGIXP_XP_H + + +#include +#include +#include +#include +#include + + +#ifdef USE_DBUG_ON +#define DBUG_ON(condition) BUG_ON(condition) +#else +#define DBUG_ON(condition) +#endif + + +/* + * Define the maximum number of logically defined partitions the system + * can support. It is constrained by the maximum number of hardware + * partitionable regions. The term 'region' in this context refers to the + * minimum number of nodes that can comprise an access protection grouping. + * The access protection is in regards to memory, IPI and IOI. + * + * The maximum number of hardware partitionable regions is equal to the + * maximum number of nodes in the entire system divided by the minimum number + * of nodes that comprise an access protection grouping. + */ +#define XP_MAX_PARTITIONS 64 + + +/* + * Define the number of u64s required to represent all the C-brick nasids + * as a bitmap. The cross-partition kernel modules deal only with + * C-brick nasids, thus the need for bitmaps which don't account for + * odd-numbered (non C-brick) nasids. + */ +#define XP_MAX_PHYSNODE_ID (MAX_NUMALINK_NODES / 2) +#define XP_NASID_MASK_BYTES ((XP_MAX_PHYSNODE_ID + 7) / 8) +#define XP_NASID_MASK_WORDS ((XP_MAX_PHYSNODE_ID + 63) / 64) + + +/* + * Wrapper for bte_copy() that should it return a failure status will retry + * the bte_copy() once in the hope that the failure was due to a temporary + * aberration (i.e., the link going down temporarily). + * + * src - physical address of the source of the transfer. + * vdst - virtual address of the destination of the transfer. + * len - number of bytes to transfer from source to destination. + * mode - see bte_copy() for definition. + * notification - see bte_copy() for definition. + * + * Note: xp_bte_copy() should never be called while holding a spinlock. + */ +static inline bte_result_t +xp_bte_copy(u64 src, u64 vdst, u64 len, u64 mode, void *notification) +{ + bte_result_t ret; + u64 pdst = ia64_tpa(vdst); + + + /* + * 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(src, pdst, len, mode, notification); + if ((ret != BTE_SUCCESS) && BTE_ERROR_RETRY(ret)) { + if (!in_interrupt()) { + cond_resched(); + } + ret = bte_copy(src, pdst, len, mode, notification); + } + + return ret; +} + + +/* + * XPC establishes channel connections between the local partition and any + * other partition that is currently up. Over these channels, kernel-level + * `users' can communicate with their counterparts on the other partitions. + * + * The maxinum number of channels is limited to eight. For performance reasons, + * the internal cross partition structures require sixteen bytes per channel, + * and eight allows all of this interface-shared info to fit in one cache line. + * + * XPC_NCHANNELS reflects the total number of channels currently defined. + * If the need for additional channels arises, one can simply increase + * XPC_NCHANNELS accordingly. If the day should come where that number + * exceeds the MAXIMUM number of channels allowed (eight), then one will need + * to make changes to the XPC code to allow for this. + */ +#define XPC_MEM_CHANNEL 0 /* memory channel number */ +#define XPC_NET_CHANNEL 1 /* network channel number */ + +#define XPC_NCHANNELS 2 /* #of defined channels */ +#define XPC_MAX_NCHANNELS 8 /* max #of channels allowed */ + +#if XPC_NCHANNELS > XPC_MAX_NCHANNELS +#error XPC_NCHANNELS exceeds MAXIMUM allowed. +#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 user should have no dealings with the message header, but only the + * message's payload. When a message entry is allocated (via xpc_allocate()) + * a pointer to the payload area is returned and not the actual beginning of + * the XPC message. The user then constructs a message in the payload area + * and passes that pointer as an argument on xpc_send() or xpc_send_notify(). + * + * 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 + * 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_PAYLOAD_OFFSET (u64) (&((struct xpc_msg *)0)->payload) +#define XPC_MSG_SIZE(_payload_size) \ + L1_CACHE_ALIGN(XPC_MSG_PAYLOAD_OFFSET + (_payload_size)) + + +/* + * Define the return values and values passed to user's callout functions. + * (It is important to add new value codes at the end just preceding + * xpcUnknownReason, which must have the highest numerical value.) + */ +enum xpc_retval { + xpcSuccess = 0, + + xpcNotConnected, /* 1: channel is not connected */ + xpcConnected, /* 2: channel connected (opened) */ + xpcRETIRED1, /* 3: (formerly xpcDisconnected) */ + + xpcMsgReceived, /* 4: message received */ + xpcMsgDelivered, /* 5: message delivered and acknowledged */ + + xpcRETIRED2, /* 6: (formerly xpcTransferFailed) */ + + xpcNoWait, /* 7: operation would require wait */ + xpcRetry, /* 8: retry operation */ + xpcTimeout, /* 9: timeout in xpc_allocate_msg_wait() */ + xpcInterrupted, /* 10: interrupted wait */ + + xpcUnequalMsgSizes, /* 11: message size disparity between sides */ + xpcInvalidAddress, /* 12: invalid address */ + + xpcNoMemory, /* 13: no memory available for XPC structures */ + xpcLackOfResources, /* 14: insufficient resources for operation */ + xpcUnregistered, /* 15: channel is not registered */ + xpcAlreadyRegistered, /* 16: channel is already registered */ + + xpcPartitionDown, /* 17: remote partition is down */ + xpcNotLoaded, /* 18: XPC module is not loaded */ + xpcUnloading, /* 19: this side is unloading XPC module */ + + xpcBadMagic, /* 20: XPC MAGIC string not found */ + + xpcReactivating, /* 21: remote partition was reactivated */ + + xpcUnregistering, /* 22: this side is unregistering channel */ + xpcOtherUnregistering, /* 23: other side is unregistering channel */ + + xpcCloneKThread, /* 24: cloning kernel thread */ + xpcCloneKThreadFailed, /* 25: cloning kernel thread failed */ + + xpcNoHeartbeat, /* 26: remote partition has no heartbeat */ + + xpcPioReadError, /* 27: PIO read error */ + xpcPhysAddrRegFailed, /* 28: registration of phys addr range failed */ + + xpcBteDirectoryError, /* 29: maps to BTEFAIL_DIR */ + xpcBtePoisonError, /* 30: maps to BTEFAIL_POISON */ + xpcBteWriteError, /* 31: maps to BTEFAIL_WERR */ + xpcBteAccessError, /* 32: maps to BTEFAIL_ACCESS */ + xpcBtePWriteError, /* 33: maps to BTEFAIL_PWERR */ + xpcBtePReadError, /* 34: maps to BTEFAIL_PRERR */ + xpcBteTimeOutError, /* 35: maps to BTEFAIL_TOUT */ + xpcBteXtalkError, /* 36: maps to BTEFAIL_XTERR */ + xpcBteNotAvailable, /* 37: maps to BTEFAIL_NOTAVAIL */ + xpcBteUnmappedError, /* 38: unmapped BTEFAIL_ error */ + + xpcBadVersion, /* 39: bad version number */ + xpcVarsNotSet, /* 40: the XPC variables are not set up */ + xpcNoRsvdPageAddr, /* 41: unable to get rsvd page's phys addr */ + xpcInvalidPartid, /* 42: invalid partition ID */ + xpcLocalPartid, /* 43: local partition ID */ + + xpcOtherGoingDown, /* 44: other side going down, reason unknown */ + xpcSystemGoingDown, /* 45: system is going down, reason unknown */ + xpcSystemHalt, /* 46: system is being halted */ + xpcSystemReboot, /* 47: system is being rebooted */ + xpcSystemPoweroff, /* 48: system is being powered off */ + + xpcDisconnecting, /* 49: channel disconnecting (closing) */ + + xpcOpenCloseError, /* 50: channel open/close protocol error */ + + xpcDisconnected, /* 51: channel disconnected (closed) */ + + xpcBteSh2Start, /* 52: BTE CRB timeout */ + + /* 53: 0x1 BTE Error Response Short */ + xpcBteSh2RspShort = xpcBteSh2Start + BTEFAIL_SH2_RESP_SHORT, + + /* 54: 0x2 BTE Error Response Long */ + xpcBteSh2RspLong = xpcBteSh2Start + BTEFAIL_SH2_RESP_LONG, + + /* 56: 0x4 BTE Error Response DSB */ + xpcBteSh2RspDSB = xpcBteSh2Start + BTEFAIL_SH2_RESP_DSP, + + /* 60: 0x8 BTE Error Response Access */ + xpcBteSh2RspAccess = xpcBteSh2Start + BTEFAIL_SH2_RESP_ACCESS, + + /* 68: 0x10 BTE Error CRB timeout */ + xpcBteSh2CRBTO = xpcBteSh2Start + BTEFAIL_SH2_CRB_TO, + + /* 84: 0x20 BTE Error NACK limit */ + xpcBteSh2NACKLimit = xpcBteSh2Start + BTEFAIL_SH2_NACK_LIMIT, + + /* 115: BTE end */ + xpcBteSh2End = xpcBteSh2Start + BTEFAIL_SH2_ALL, + + xpcUnknownReason /* 116: unknown reason -- must be last in list */ +}; + + +/* + * Define the callout function types used by XPC to update the user on + * connection activity and state changes (via the user function registered by + * xpc_connect()) and to notify them of messages received and delivered (via + * the user function registered by xpc_send_notify()). + * + * The two function types are xpc_channel_func and xpc_notify_func and + * both share the following arguments, with the exception of "data", which + * only xpc_channel_func has. + * + * Arguments: + * + * reason - reason code. (See following table.) + * partid - partition ID associated with condition. + * ch_number - channel # associated with condition. + * data - pointer to optional data. (See following table.) + * key - pointer to optional user-defined value provided as the "key" + * argument to xpc_connect() or xpc_send_notify(). + * + * In the following table the "Optional Data" column applies to callouts made + * to functions registered by xpc_connect(). A "NA" in that column indicates + * that this reason code can be passed to functions registered by + * xpc_send_notify() (i.e. they don't have data arguments). + * + * Also, the first three reason codes in the following table indicate + * success, whereas the others indicate failure. When a failure reason code + * is received, one can assume that the channel is not connected. + * + * + * Reason Code | Cause | Optional Data + * =====================+================================+===================== + * xpcConnected | connection has been established| max #of entries + * | to the specified partition on | allowed in message + * | the specified channel | queue + * ---------------------+--------------------------------+--------------------- + * xpcMsgReceived | an XPC message arrived from | address of payload + * | the specified partition on the | + * | specified channel | [the user must call + * | | xpc_received() when + * | | finished with the + * | | payload] + * ---------------------+--------------------------------+--------------------- + * xpcMsgDelivered | notification that the message | NA + * | was delivered to the intended | + * | recipient and that they have | + * | acknowledged its receipt by | + * | calling xpc_received() | + * =====================+================================+===================== + * xpcUnequalMsgSizes | can't connect to the specified | NULL + * | partition on the specified | + * | channel because of mismatched | + * | message sizes | + * ---------------------+--------------------------------+--------------------- + * xpcNoMemory | insufficient memory avaiable | NULL + * | to allocate message queue | + * ---------------------+--------------------------------+--------------------- + * xpcLackOfResources | lack of resources to create | NULL + * | the necessary kthreads to | + * | support the channel | + * ---------------------+--------------------------------+--------------------- + * xpcUnregistering | this side's user has | NULL or NA + * | unregistered by calling | + * | xpc_disconnect() | + * ---------------------+--------------------------------+--------------------- + * xpcOtherUnregistering| the other side's user has | NULL or NA + * | unregistered by calling | + * | xpc_disconnect() | + * ---------------------+--------------------------------+--------------------- + * xpcNoHeartbeat | the other side's XPC is no | NULL or NA + * | longer heartbeating | + * | | + * ---------------------+--------------------------------+--------------------- + * xpcUnloading | this side's XPC module is | NULL or NA + * | being unloaded | + * | | + * ---------------------+--------------------------------+--------------------- + * xpcOtherUnloading | the other side's XPC module is | NULL or NA + * | is being unloaded | + * | | + * ---------------------+--------------------------------+--------------------- + * xpcPioReadError | xp_nofault_PIOR() returned an | NULL or NA + * | error while sending an IPI | + * | | + * ---------------------+--------------------------------+--------------------- + * xpcInvalidAddress | the address either received or | NULL or NA + * | sent by the specified partition| + * | is invalid | + * ---------------------+--------------------------------+--------------------- + * xpcBteNotAvailable | attempt to pull data from the | NULL or NA + * xpcBtePoisonError | specified partition over the | + * xpcBteWriteError | specified channel via a | + * xpcBteAccessError | bte_copy() failed | + * xpcBteTimeOutError | | + * xpcBteXtalkError | | + * xpcBteDirectoryError | | + * xpcBteGenericError | | + * xpcBteUnmappedError | | + * ---------------------+--------------------------------+--------------------- + * xpcUnknownReason | the specified channel to the | NULL or NA + * | specified partition was | + * | unavailable for unknown reasons| + * =====================+================================+===================== + */ + +typedef void (*xpc_channel_func)(enum xpc_retval reason, partid_t partid, + int ch_number, void *data, void *key); + +typedef void (*xpc_notify_func)(enum xpc_retval reason, partid_t partid, + int ch_number, void *key); + + +/* + * The following is a registration entry. There is a global array of these, + * one per channel. It is used to record the connection registration made + * by the users of XPC. As long as a registration entry exists, for any + * partition that comes up, XPC will attempt to establish a connection on + * that channel. Notification that a connection has been made will occur via + * the xpc_channel_func function. + * + * The 'func' field points to the function to call when aynchronous + * notification is required for such events as: a connection established/lost, + * or an incoming message received, or an error condition encountered. A + * non-NULL 'func' field indicates that there is an active registration for + * the channel. + */ +struct xpc_registration { + struct mutex mutex; + 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 */ + u32 assigned_limit; /* limit on #of assigned kthreads */ + u32 idle_limit; /* limit on #of idle kthreads */ +} ____cacheline_aligned; + + +#define XPC_CHANNEL_REGISTERED(_c) (xpc_registrations[_c].func != NULL) + + +/* the following are valid xpc_allocate() flags */ +#define XPC_WAIT 0 /* wait flag */ +#define XPC_NOWAIT 1 /* no wait flag */ + + +struct xpc_interface { + void (*connect)(int); + void (*disconnect)(int); + enum xpc_retval (*allocate)(partid_t, int, u32, void **); + enum xpc_retval (*send)(partid_t, int, void *); + enum xpc_retval (*send_notify)(partid_t, int, void *, + xpc_notify_func, void *); + void (*received)(partid_t, int, void *); + enum xpc_retval (*partid_to_nasids)(partid_t, void *); +}; + + +extern struct xpc_interface xpc_interface; + +extern void xpc_set_interface(void (*)(int), + void (*)(int), + enum xpc_retval (*)(partid_t, int, u32, void **), + enum xpc_retval (*)(partid_t, int, void *), + enum xpc_retval (*)(partid_t, int, void *, xpc_notify_func, + void *), + void (*)(partid_t, int, void *), + enum xpc_retval (*)(partid_t, void *)); +extern void xpc_clear_interface(void); + + +extern enum xpc_retval xpc_connect(int, xpc_channel_func, void *, u16, + u16, u32, u32); +extern void xpc_disconnect(int); + +static inline enum xpc_retval +xpc_allocate(partid_t partid, int ch_number, u32 flags, void **payload) +{ + return xpc_interface.allocate(partid, ch_number, flags, payload); +} + +static inline enum xpc_retval +xpc_send(partid_t partid, int ch_number, void *payload) +{ + return xpc_interface.send(partid, ch_number, payload); +} + +static inline enum xpc_retval +xpc_send_notify(partid_t partid, int ch_number, void *payload, + xpc_notify_func func, void *key) +{ + return xpc_interface.send_notify(partid, ch_number, payload, func, key); +} + +static inline void +xpc_received(partid_t partid, int ch_number, void *payload) +{ + return xpc_interface.received(partid, ch_number, payload); +} + +static inline enum xpc_retval +xpc_partid_to_nasids(partid_t partid, void *nasids) +{ + return xpc_interface.partid_to_nasids(partid, nasids); +} + + +extern u64 xp_nofault_PIOR_target; +extern int xp_nofault_PIOR(void *); +extern int xp_error_PIOR(void); + + +#endif /* _DRIVERS_MISC_SGIXP_XP_H */ + diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c new file mode 100644 index 00000000000..5f9f9c2e929 --- /dev/null +++ b/drivers/misc/sgi-xp/xp_main.c @@ -0,0 +1,290 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * Cross Partition (XP) base. + * + * XP provides a base from which its users can interact + * with XPC, yet not be dependent on XPC. + * + */ + + +#include +#include +#include +#include +#include +#include +#include "xp.h" + + +/* + * Target of nofault PIO read. + */ +u64 xp_nofault_PIOR_target; + + +/* + * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level + * users of XPC. + */ +struct xpc_registration xpc_registrations[XPC_NCHANNELS]; + + +/* + * Initialize the XPC interface to indicate that XPC isn't loaded. + */ +static enum xpc_retval xpc_notloaded(void) { return xpcNotLoaded; } + +struct xpc_interface xpc_interface = { + (void (*)(int)) xpc_notloaded, + (void (*)(int)) xpc_notloaded, + (enum xpc_retval (*)(partid_t, int, u32, void **)) xpc_notloaded, + (enum xpc_retval (*)(partid_t, int, void *)) xpc_notloaded, + (enum xpc_retval (*)(partid_t, int, void *, xpc_notify_func, void *)) + xpc_notloaded, + (void (*)(partid_t, int, void *)) xpc_notloaded, + (enum xpc_retval (*)(partid_t, void *)) xpc_notloaded +}; + + +/* + * XPC calls this when it (the XPC module) has been loaded. + */ +void +xpc_set_interface(void (*connect)(int), + void (*disconnect)(int), + enum xpc_retval (*allocate)(partid_t, int, u32, void **), + enum xpc_retval (*send)(partid_t, int, void *), + enum xpc_retval (*send_notify)(partid_t, int, void *, + xpc_notify_func, void *), + void (*received)(partid_t, int, void *), + enum xpc_retval (*partid_to_nasids)(partid_t, void *)) +{ + xpc_interface.connect = connect; + xpc_interface.disconnect = disconnect; + xpc_interface.allocate = allocate; + xpc_interface.send = send; + xpc_interface.send_notify = send_notify; + xpc_interface.received = received; + xpc_interface.partid_to_nasids = partid_to_nasids; +} + + +/* + * XPC calls this when it (the XPC module) is being unloaded. + */ +void +xpc_clear_interface(void) +{ + xpc_interface.connect = (void (*)(int)) xpc_notloaded; + xpc_interface.disconnect = (void (*)(int)) xpc_notloaded; + xpc_interface.allocate = (enum xpc_retval (*)(partid_t, int, u32, + void **)) xpc_notloaded; + xpc_interface.send = (enum xpc_retval (*)(partid_t, int, void *)) + xpc_notloaded; + xpc_interface.send_notify = (enum xpc_retval (*)(partid_t, int, void *, + xpc_notify_func, void *)) xpc_notloaded; + xpc_interface.received = (void (*)(partid_t, int, void *)) + xpc_notloaded; + xpc_interface.partid_to_nasids = (enum xpc_retval (*)(partid_t, void *)) + xpc_notloaded; +} + + +/* + * Register for automatic establishment of a channel connection whenever + * a partition comes up. + * + * Arguments: + * + * ch_number - channel # to register for connection. + * func - function to call for asynchronous notification of channel + * state changes (i.e., connection, disconnection, error) and + * the arrival of incoming messages. + * key - pointer to optional user-defined value that gets passed back + * to the user on any callouts made to func. + * payload_size - size in bytes of the XPC message's payload area which + * contains a user-defined message. The user should make + * this large enough to hold their largest message. + * nentries - max #of XPC message entries a message queue can contain. + * The actual number, which is determined when a connection + * is established and may be less then requested, will be + * passed to the user via the xpcConnected callout. + * assigned_limit - max number of kthreads allowed to be processing + * messages (per connection) at any given instant. + * idle_limit - max number of kthreads allowed to be idle at any given + * instant. + */ +enum xpc_retval +xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, + u16 nentries, u32 assigned_limit, u32 idle_limit) +{ + struct xpc_registration *registration; + + + DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + DBUG_ON(payload_size == 0 || nentries == 0); + DBUG_ON(func == NULL); + DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit); + + registration = &xpc_registrations[ch_number]; + + if (mutex_lock_interruptible(®istration->mutex) != 0) { + return xpcInterrupted; + } + + /* if XPC_CHANNEL_REGISTERED(ch_number) */ + if (registration->func != NULL) { + mutex_unlock(®istration->mutex); + return xpcAlreadyRegistered; + } + + /* register the channel for connection */ + registration->msg_size = XPC_MSG_SIZE(payload_size); + registration->nentries = nentries; + registration->assigned_limit = assigned_limit; + registration->idle_limit = idle_limit; + registration->key = key; + registration->func = func; + + mutex_unlock(®istration->mutex); + + xpc_interface.connect(ch_number); + + return xpcSuccess; +} + + +/* + * Remove the registration for automatic connection of the specified channel + * when a partition comes up. + * + * Before returning this xpc_disconnect() will wait for all connections on the + * specified channel have been closed/torndown. So the caller can be assured + * that they will not be receiving any more callouts from XPC to their + * function registered via xpc_connect(). + * + * Arguments: + * + * ch_number - channel # to unregister. + */ +void +xpc_disconnect(int ch_number) +{ + struct xpc_registration *registration; + + + DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + + registration = &xpc_registrations[ch_number]; + + /* + * We've decided not to make this a down_interruptible(), since we + * figured XPC's users will just turn around and call xpc_disconnect() + * again anyways, so we might as well wait, if need be. + */ + mutex_lock(®istration->mutex); + + /* if !XPC_CHANNEL_REGISTERED(ch_number) */ + if (registration->func == NULL) { + mutex_unlock(®istration->mutex); + return; + } + + /* remove the connection registration for the specified channel */ + registration->func = NULL; + registration->key = NULL; + registration->nentries = 0; + registration->msg_size = 0; + registration->assigned_limit = 0; + registration->idle_limit = 0; + + xpc_interface.disconnect(ch_number); + + mutex_unlock(®istration->mutex); + + return; +} + + +int __init +xp_init(void) +{ + int ret, ch_number; + u64 func_addr = *(u64 *) xp_nofault_PIOR; + u64 err_func_addr = *(u64 *) xp_error_PIOR; + + + if (!ia64_platform_is("sn2")) { + return -ENODEV; + } + + /* + * Register a nofault code region which performs a cross-partition + * PIO read. If the PIO read times out, the MCA handler will consume + * the error and return to a kernel-provided instruction to indicate + * an error. This PIO read exists because it is guaranteed to timeout + * if the destination is down (AMO operations do not timeout on at + * least some CPUs on Shubs <= v1.2, which unfortunately we have to + * work around). + */ + if ((ret = sn_register_nofault_code(func_addr, err_func_addr, + err_func_addr, 1, 1)) != 0) { + printk(KERN_ERR "XP: can't register nofault code, error=%d\n", + ret); + } + /* + * Setup the nofault PIO read target. (There is no special reason why + * SH_IPI_ACCESS was selected.) + */ + if (is_shub2()) { + xp_nofault_PIOR_target = SH2_IPI_ACCESS0; + } else { + xp_nofault_PIOR_target = SH1_IPI_ACCESS; + } + + /* initialize the connection registration mutex */ + for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) { + mutex_init(&xpc_registrations[ch_number].mutex); + } + + return 0; +} +module_init(xp_init); + + +void __exit +xp_exit(void) +{ + u64 func_addr = *(u64 *) xp_nofault_PIOR; + u64 err_func_addr = *(u64 *) xp_error_PIOR; + + + /* unregister the PIO read nofault code region */ + (void) sn_register_nofault_code(func_addr, err_func_addr, + err_func_addr, 1, 0); +} +module_exit(xp_exit); + + +MODULE_AUTHOR("Silicon Graphics, Inc."); +MODULE_DESCRIPTION("Cross Partition (XP) base"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(xp_nofault_PIOR); +EXPORT_SYMBOL(xp_nofault_PIOR_target); +EXPORT_SYMBOL(xpc_registrations); +EXPORT_SYMBOL(xpc_interface); +EXPORT_SYMBOL(xpc_clear_interface); +EXPORT_SYMBOL(xpc_set_interface); +EXPORT_SYMBOL(xpc_connect); +EXPORT_SYMBOL(xpc_disconnect); + diff --git a/drivers/misc/sgi-xp/xp_nofault.S b/drivers/misc/sgi-xp/xp_nofault.S new file mode 100644 index 00000000000..c13a709c4db --- /dev/null +++ b/drivers/misc/sgi-xp/xp_nofault.S @@ -0,0 +1,36 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * The xp_nofault_PIOR function takes a pointer to a remote PIO register + * and attempts to load and consume a value from it. This function + * will be registered as a nofault code block. In the event that the + * PIO read fails, the MCA handler will force the error to look + * corrected and vector to the xp_error_PIOR which will return an error. + * + * The definition of "consumption" and the time it takes for an MCA + * to surface is processor implementation specific. This code + * is sufficient on Itanium through the Montvale processor family. + * It may need to be adjusted for future processor implementations. + * + * extern int xp_nofault_PIOR(void *remote_register); + */ + + .global xp_nofault_PIOR +xp_nofault_PIOR: + mov r8=r0 // Stage a success return value + ld8.acq r9=[r32];; // PIO Read the specified register + adds r9=1,r9;; // Add to force consumption + srlz.i;; // Allow time for MCA to surface + br.ret.sptk.many b0;; // Return success + + .global xp_error_PIOR +xp_error_PIOR: + mov r8=1 // Return value of 1 + br.ret.sptk.many b0;; // Return failure diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h new file mode 100644 index 00000000000..14e70ee53eb --- /dev/null +++ b/drivers/misc/sgi-xp/xpc.h @@ -0,0 +1,1267 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * Cross Partition Communication (XPC) structures and macros. + */ + +#ifndef _DRIVERS_MISC_SGIXP_XPC_H +#define _DRIVERS_MISC_SGIXP_XPC_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xp.h" + + +/* + * XPC Version numbers consist of a major and minor number. XPC can always + * talk to versions with same major #, and never talk to versions with a + * different major #. + */ +#define _XPC_VERSION(_maj, _min) (((_maj) << 4) | ((_min) & 0xf)) +#define XPC_VERSION_MAJOR(_v) ((_v) >> 4) +#define XPC_VERSION_MINOR(_v) ((_v) & 0xf) + + +/* + * The next macros define word or bit representations for given + * C-brick nasid in either the SAL provided bit array representing + * nasids in the partition/machine or the AMO_t array used for + * inter-partition initiation communications. + * + * For SN2 machines, C-Bricks are alway even numbered NASIDs. As + * such, some space will be saved by insisting that nasid information + * passed from SAL always be packed for C-Bricks and the + * cross-partition interrupts use the same packing scheme. + */ +#define XPC_NASID_W_INDEX(_n) (((_n) / 64) / 2) +#define XPC_NASID_B_INDEX(_n) (((_n) / 2) & (64 - 1)) +#define XPC_NASID_IN_ARRAY(_n, _p) ((_p)[XPC_NASID_W_INDEX(_n)] & \ + (1UL << XPC_NASID_B_INDEX(_n))) +#define XPC_NASID_FROM_W_B(_w, _b) (((_w) * 64 + (_b)) * 2) + +#define XPC_HB_DEFAULT_INTERVAL 5 /* incr HB every x secs */ +#define XPC_HB_CHECK_DEFAULT_INTERVAL 20 /* check HB every x secs */ + +/* define the process name of HB checker and the CPU it is pinned to */ +#define XPC_HB_CHECK_THREAD_NAME "xpc_hb" +#define XPC_HB_CHECK_CPU 0 + +/* define the process name of the discovery thread */ +#define XPC_DISCOVERY_THREAD_NAME "xpc_discovery" + + +/* + * the reserved page + * + * SAL reserves one page of memory per partition for XPC. Though a full page + * in length (16384 bytes), its starting address is not page aligned, but it + * is cacheline aligned. The reserved page consists of the following: + * + * reserved page header + * + * The first cacheline of the reserved page contains the header + * (struct xpc_rsvd_page). Before SAL initialization has completed, + * SAL has set up the following fields of the reserved page header: + * SAL_signature, SAL_version, partid, and nasids_size. The other + * fields are set up by XPC. (xpc_rsvd_page points to the local + * partition's reserved page.) + * + * part_nasids mask + * mach_nasids mask + * + * SAL also sets up two bitmaps (or masks), one that reflects the actual + * nasids in this partition (part_nasids), and the other that reflects + * the actual nasids in the entire machine (mach_nasids). We're only + * interested in the even numbered nasids (which contain the processors + * and/or memory), so we only need half as many bits to represent the + * nasids. The part_nasids mask is located starting at the first cacheline + * following the reserved page header. The mach_nasids mask follows right + * after the part_nasids mask. The size in bytes of each mask is reflected + * by the reserved page header field 'nasids_size'. (Local partition's + * mask pointers are xpc_part_nasids and xpc_mach_nasids.) + * + * vars + * vars part + * + * Immediately following the mach_nasids mask are the XPC variables + * required by other partitions. First are those that are generic to all + * partitions (vars), followed on the next available cacheline by those + * which are partition specific (vars part). These are setup by XPC. + * (Local partition's vars pointers are xpc_vars and xpc_vars_part.) + * + * Note: Until vars_pa is set, the partition XPC code has not been initialized. + */ +struct xpc_rsvd_page { + u64 SAL_signature; /* SAL: unique signature */ + u64 SAL_version; /* SAL: version */ + u8 partid; /* SAL: partition ID */ + u8 version; + u8 pad1[6]; /* align to next u64 in cacheline */ + volatile u64 vars_pa; + struct timespec stamp; /* time when reserved page was setup by XPC */ + u64 pad2[9]; /* align to last u64 in cacheline */ + u64 nasids_size; /* SAL: size of each nasid mask in bytes */ +}; + +#define XPC_RP_VERSION _XPC_VERSION(1,1) /* version 1.1 of the reserved page */ + +#define XPC_SUPPORTS_RP_STAMP(_version) \ + (_version >= _XPC_VERSION(1,1)) + +/* + * compare stamps - the return value is: + * + * < 0, if stamp1 < stamp2 + * = 0, if stamp1 == stamp2 + * > 0, if stamp1 > stamp2 + */ +static inline int +xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2) +{ + int ret; + + + if ((ret = stamp1->tv_sec - stamp2->tv_sec) == 0) { + ret = stamp1->tv_nsec - stamp2->tv_nsec; + } + return ret; +} + + +/* + * Define the structures by which XPC variables can be exported to other + * partitions. (There are two: struct xpc_vars and struct xpc_vars_part) + */ + +/* + * The following structure describes the partition generic variables + * needed by other partitions in order to properly initialize. + * + * struct xpc_vars version number also applies to struct xpc_vars_part. + * Changes to either structure and/or related functionality should be + * reflected by incrementing either the major or minor version numbers + * of struct xpc_vars. + */ +struct xpc_vars { + u8 version; + u64 heartbeat; + u64 heartbeating_to_mask; + u64 heartbeat_offline; /* if 0, heartbeat should be changing */ + int act_nasid; + int act_phys_cpuid; + u64 vars_part_pa; + u64 amos_page_pa; /* paddr of page of AMOs from MSPEC driver */ + AMO_t *amos_page; /* vaddr of page of AMOs from MSPEC driver */ +}; + +#define XPC_V_VERSION _XPC_VERSION(3,1) /* version 3.1 of the cross vars */ + +#define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \ + (_version >= _XPC_VERSION(3,1)) + + +static inline int +xpc_hb_allowed(partid_t partid, struct xpc_vars *vars) +{ + return ((vars->heartbeating_to_mask & (1UL << partid)) != 0); +} + +static inline void +xpc_allow_hb(partid_t partid, struct xpc_vars *vars) +{ + u64 old_mask, new_mask; + + do { + old_mask = vars->heartbeating_to_mask; + new_mask = (old_mask | (1UL << partid)); + } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != + old_mask); +} + +static inline void +xpc_disallow_hb(partid_t partid, struct xpc_vars *vars) +{ + u64 old_mask, new_mask; + + do { + old_mask = vars->heartbeating_to_mask; + new_mask = (old_mask & ~(1UL << partid)); + } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != + old_mask); +} + + +/* + * The AMOs page consists of a number of AMO variables which are divided into + * four groups, The first two groups are used to identify an IRQ's sender. + * These two groups consist of 64 and 128 AMO variables respectively. The last + * two groups, consisting of just one AMO variable each, are used to identify + * the remote partitions that are currently engaged (from the viewpoint of + * the XPC running on the remote partition). + */ +#define XPC_NOTIFY_IRQ_AMOS 0 +#define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_PARTITIONS) +#define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS) +#define XPC_DISENGAGE_REQUEST_AMO (XPC_ENGAGED_PARTITIONS_AMO + 1) + + +/* + * The following structure describes the per partition specific variables. + * + * An array of these structures, one per partition, will be defined. As a + * partition becomes active XPC will copy the array entry corresponding to + * itself from that partition. It is desirable that the size of this + * structure evenly divide into a cacheline, such that none of the entries + * in this array crosses a cacheline boundary. As it is now, each entry + * occupies half a cacheline. + */ +struct xpc_vars_part { + volatile u64 magic; + + u64 openclose_args_pa; /* physical address of open and close args */ + u64 GPs_pa; /* physical address of Get/Put values */ + + u64 IPI_amo_pa; /* physical address of IPI AMO_t structure */ + int IPI_nasid; /* nasid of where to send IPIs */ + int IPI_phys_cpuid; /* physical CPU ID of where to send IPIs */ + + u8 nchannels; /* #of defined channels supported */ + + u8 reserved[23]; /* pad to a full 64 bytes */ +}; + +/* + * The vars_part MAGIC numbers play a part in the first contact protocol. + * + * MAGIC1 indicates that the per partition specific variables for a remote + * partition have been initialized by this partition. + * + * 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) */ + + +/* the reserved page sizes and offsets */ + +#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)) + +#define XPC_RP_PART_NASIDS(_rp) (u64 *) ((u8 *) _rp + XPC_RP_HEADER_SIZE) +#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words) +#define XPC_RP_VARS(_rp) ((struct xpc_vars *) XPC_RP_MACH_NASIDS(_rp) + xp_nasid_mask_words) +#define XPC_RP_VARS_PART(_rp) (struct xpc_vars_part *) ((u8 *) XPC_RP_VARS(rp) + XPC_RP_VARS_SIZE) + + +/* + * 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 + * the passed argument. + */ +#define XPC_PACK_ARGS(_arg1, _arg2) \ + ((((u64) _arg1) & 0xffffffff) | \ + ((((u64) _arg2) & 0xffffffff) << 32)) + +#define XPC_UNPACK_ARG1(_args) (((u64) _args) & 0xffffffff) +#define XPC_UNPACK_ARG2(_args) ((((u64) _args) >> 32) & 0xffffffff) + + + +/* + * Define a Get/Put value pair (pointers) used with a message queue. + */ +struct xpc_gp { + volatile s64 get; /* Get value */ + volatile s64 put; /* Put value */ +}; + +#define XPC_GP_SIZE \ + L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_NCHANNELS) + + + +/* + * Define a structure that contains arguments associated with opening and + * closing a channel. + */ +struct xpc_openclose_args { + u16 reason; /* reason why channel is closing */ + 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 */ +}; + +#define XPC_OPENCLOSE_ARGS_SIZE \ + L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * XPC_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 */ + + +#define XPC_MSG_ADDRESS(_payload) \ + ((struct xpc_msg *)((u8 *)(_payload) - XPC_MSG_PAYLOAD_OFFSET)) + + + +/* + * Defines 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 { + volatile u8 type; /* type of notification */ + + /* the following two fields are only used if type == XPC_N_CALL */ + xpc_notify_func func; /* user's notify function */ + void *key; /* pointer to user's key */ +}; + +/* struct xpc_notify type of notification */ + +#define XPC_N_CALL 0x01 /* notify function provided by user */ + + + +/* + * Define the structure that manages all the stuff required by a channel. In + * particular, they are used to manage the messages sent across the channel. + * + * This structure is private to a partition, and is NOT shared across the + * partition boundary. + * + * There is an array of these structures for each remote partition. It is + * allocated at the time a partition becomes active. The array contains one + * of these structures for each potential channel connection to that partition. + * + * Each of these structures manages two message queues (circular buffers). + * They are allocated at the time a channel connection is made. One of + * these message queues (local_msgqueue) holds the locally created messages + * that are destined for the remote partition. The other of these message + * queues (remote_msgqueue) is a locally cached copy of the remote partition's + * own local_msgqueue. + * + * The following is a description of the Get/Put pointers used to manage these + * two message queues. Consider the local_msgqueue to be on one partition + * and the remote_msgqueue to be its cached copy on another partition. A + * description of what each of the lettered areas contains is included. + * + * + * local_msgqueue remote_msgqueue + * + * |/////////| |/////////| + * w_remote_GP.get --> +---------+ |/////////| + * | F | |/////////| + * remote_GP.get --> +---------+ +---------+ <-- local_GP->get + * | | | | + * | | | E | + * | | | | + * | | +---------+ <-- w_local_GP.get + * | B | |/////////| + * | | |////D////| + * | | |/////////| + * | | +---------+ <-- w_remote_GP.put + * | | |////C////| + * local_GP->put --> +---------+ +---------+ <-- remote_GP.put + * | | |/////////| + * | A | |/////////| + * | | |/////////| + * w_local_GP.put --> +---------+ |/////////| + * |/////////| |/////////| + * + * + * ( remote_GP.[get|put] are cached copies of the remote + * partition's local_GP->[get|put], and thus their values can + * lag behind their counterparts on the remote partition. ) + * + * + * A - Messages that have been allocated, but have not yet been sent to the + * remote partition. + * + * B - Messages that have been sent, but have not yet been acknowledged by the + * remote partition as having been received. + * + * C - Area that needs to be prepared for the copying of sent messages, by + * the clearing of the message flags of any previously received messages. + * + * D - Area into which sent messages are to be copied from the remote + * partition's local_msgqueue and then delivered to their intended + * recipients. [ To allow for a multi-message copy, another pointer + * (next_msg_to_pull) has been added to keep track of the next message + * number needing to be copied (pulled). It chases after w_remote_GP.put. + * Any messages lying between w_local_GP.get and next_msg_to_pull have + * been copied and are ready to be delivered. ] + * + * E - Messages that have been copied and delivered, but have not yet been + * acknowledged by the recipient as having been received. + * + * F - Messages that have been acknowledged, but XPC has not yet notified the + * sender that the message was received by its intended recipient. + * This is also an area that needs to be prepared for the allocating of + * new messages, by the clearing of the message flags of the acknowledged + * messages. + */ +struct xpc_channel { + partid_t partid; /* ID of remote partition connected */ + spinlock_t lock; /* lock for updating this structure */ + u32 flags; /* general flags */ + + enum xpc_retval reason; /* reason why channel is disconnect'g */ + int reason_line; /* line# disconnect initiated from */ + + u16 number; /* channel # */ + + u16 msg_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*/ + + 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 */ + u64 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 */ + wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */ + + u8 delayed_IPI_flags; /* IPI 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 mutex msg_to_pull_mutex; /* next msg to pull serialization */ + struct completion wdisconnect_wait; /* wait for channel disconnect */ + + struct xpc_openclose_args *local_openclose_args; /* args passed on */ + /* opening or closing of channel */ + + /* 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 */ + s64 next_msg_to_pull; /* Put value of next msg to pull */ + + /* kthread management related fields */ + +// >>> rethink having kthreads_assigned_limit and kthreads_idle_limit; perhaps +// >>> allow the assigned limit be unbounded and let the idle limit be dynamic +// >>> dependent on activity over the last interval of time + atomic_t kthreads_assigned; /* #of kthreads assigned to channel */ + u32 kthreads_assigned_limit; /* limit on #of kthreads assigned */ + atomic_t kthreads_idle; /* #of kthreads idle waiting for work */ + u32 kthreads_idle_limit; /* limit on #of kthreads idle */ + atomic_t kthreads_active; /* #of kthreads actively working */ + // >>> following field is temporary + u32 kthreads_created; /* total #of kthreads created */ + + wait_queue_head_t idle_wq; /* idle kthread wait queue */ + +} ____cacheline_aligned; + + +/* struct xpc_channel flags */ + +#define XPC_C_WASCONNECTED 0x00000001 /* channel was connected */ + +#define XPC_C_ROPENREPLY 0x00000002 /* remote open channel reply */ +#define XPC_C_OPENREPLY 0x00000004 /* local open channel reply */ +#define XPC_C_ROPENREQUEST 0x00000008 /* remote open channel request */ +#define XPC_C_OPENREQUEST 0x00000010 /* local open channel request */ + +#define XPC_C_SETUP 0x00000020 /* channel's msgqueues are alloc'd */ +#define XPC_C_CONNECTEDCALLOUT 0x00000040 /* connected callout initiated */ +#define XPC_C_CONNECTEDCALLOUT_MADE \ + 0x00000080 /* connected callout completed */ +#define XPC_C_CONNECTED 0x00000100 /* local channel is connected */ +#define XPC_C_CONNECTING 0x00000200 /* channel is being connected */ + +#define XPC_C_RCLOSEREPLY 0x00000400 /* remote close channel reply */ +#define XPC_C_CLOSEREPLY 0x00000800 /* local close channel reply */ +#define XPC_C_RCLOSEREQUEST 0x00001000 /* remote close channel request */ +#define XPC_C_CLOSEREQUEST 0x00002000 /* local close channel request */ + +#define XPC_C_DISCONNECTED 0x00004000 /* channel is disconnected */ +#define XPC_C_DISCONNECTING 0x00008000 /* channel is being disconnected */ +#define XPC_C_DISCONNECTINGCALLOUT \ + 0x00010000 /* disconnecting callout initiated */ +#define XPC_C_DISCONNECTINGCALLOUT_MADE \ + 0x00020000 /* disconnecting callout completed */ +#define XPC_C_WDISCONNECT 0x00040000 /* waiting for channel disconnect */ + + + +/* + * Manages channels on a partition basis. There is one of these structures + * for each partition (a partition will never utilize the structure that + * represents itself). + */ +struct xpc_partition { + + /* XPC HB infrastructure */ + + u8 remote_rp_version; /* version# of partition's rsvd pg */ + struct timespec remote_rp_stamp;/* time when rsvd pg was initialized */ + u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ + u64 remote_vars_pa; /* phys addr of partition's vars */ + u64 remote_vars_part_pa; /* phys addr of partition's vars part */ + u64 last_heartbeat; /* HB at last read */ + u64 remote_amos_page_pa; /* phys addr of partition's amos page */ + int remote_act_nasid; /* active part's act/deact nasid */ + int remote_act_phys_cpuid; /* active part's act/deact phys cpuid */ + u32 act_IRQ_rcvd; /* IRQs since activation */ + spinlock_t act_lock; /* protect updating of act_state */ + u8 act_state; /* from XPC HB viewpoint */ + u8 remote_vars_version; /* version# of partition's vars */ + enum xpc_retval reason; /* reason partition is deactivating */ + int reason_line; /* line# deactivation initiated from */ + int reactivate_nasid; /* nasid in partition to reactivate */ + + unsigned long disengage_request_timeout; /* timeout in jiffies */ + struct timer_list disengage_request_timer; + + + /* XPC infrastructure referencing and teardown control */ + + volatile u8 setup_state; /* infrastructure setup state */ + wait_queue_head_t teardown_wq; /* kthread waiting to teardown infra */ + atomic_t references; /* #of references to infrastructure */ + + + /* + * NONE OF THE PRECEDING FIELDS OF THIS STRUCTURE WILL BE CLEARED WHEN + * XPC SETS UP THE NECESSARY INFRASTRUCTURE TO SUPPORT CROSS PARTITION + * COMMUNICATION. ALL OF THE FOLLOWING FIELDS WILL BE CLEARED. (THE + * 'nchannels' FIELD MUST BE THE FIRST OF THE FIELDS TO BE CLEARED.) + */ + + + u8 nchannels; /* #of defined channels supported */ + atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */ + atomic_t nchannels_engaged;/* #of channels engaged with remote part */ + struct xpc_channel *channels;/* array of channel structures */ + + void *local_GPs_base; /* base address of kmalloc'd space */ + struct xpc_gp *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 Get/Put */ + /* values */ + u64 remote_GPs_pa; /* phys address of remote partition's local */ + /* Get/Put values */ + + + /* fields used to pass args when opening or closing a channel */ + + 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 */ + u64 remote_openclose_args_pa; /* phys addr of remote's args */ + + + /* IPI sending, receiving and handling related fields */ + + int remote_IPI_nasid; /* nasid of where to send IPIs */ + int remote_IPI_phys_cpuid; /* phys CPU ID of where to send IPIs */ + AMO_t *remote_IPI_amo_va; /* address of remote IPI AMO_t structure */ + + AMO_t *local_IPI_amo_va; /* address of IPI AMO_t structure */ + u64 local_IPI_amo; /* IPI amo flags yet to be handled */ + char IPI_owner[8]; /* IPI owner's name */ + struct timer_list dropped_IPI_timer; /* dropped IPI timer */ + + spinlock_t IPI_lock; /* IPI handler lock */ + + + /* channel manager related fields */ + + atomic_t channel_mgr_requests; /* #of requests to activate chan mgr */ + wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */ + +} ____cacheline_aligned; + + +/* 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_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 */ + + + +/* + * struct xpc_partition IPI_timer #of seconds to wait before checking for + * dropped IPIs. These occur whenever an IPI amo write doesn't complete until + * after the IPI was received. + */ +#define XPC_P_DROPPED_IPI_WAIT (0.25 * HZ) + + +/* number of seconds to wait for other partitions to disengage */ +#define XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT 90 + +/* interval in seconds to print 'waiting disengagement' messages */ +#define XPC_DISENGAGE_PRINTMSG_INTERVAL 10 + + +#define XPC_PARTID(_p) ((partid_t) ((_p) - &xpc_partitions[0])) + + + +/* found in xp_main.c */ +extern struct xpc_registration xpc_registrations[]; + + +/* found in xpc_main.c */ +extern struct device *xpc_part; +extern struct device *xpc_chan; +extern int xpc_disengage_request_timelimit; +extern int xpc_disengage_request_timedout; +extern irqreturn_t xpc_notify_IRQ_handler(int, void *); +extern void xpc_dropped_IPI_check(struct xpc_partition *); +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); + + +/* found in xpc_partition.c */ +extern int xpc_exiting; +extern struct xpc_vars *xpc_vars; +extern struct xpc_rsvd_page *xpc_rsvd_page; +extern struct xpc_vars_part *xpc_vars_part; +extern struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1]; +extern char *xpc_remote_copy_buffer; +extern void *xpc_remote_copy_buffer_base; +extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); +extern struct xpc_rsvd_page *xpc_rsvd_page_init(void); +extern void xpc_allow_IPI_ops(void); +extern void xpc_restrict_IPI_ops(void); +extern int xpc_identify_act_IRQ_sender(void); +extern int xpc_partition_disengaged(struct xpc_partition *); +extern enum xpc_retval xpc_mark_partition_active(struct xpc_partition *); +extern void xpc_mark_partition_inactive(struct xpc_partition *); +extern void xpc_discovery(void); +extern void xpc_check_remote_hb(void); +extern void xpc_deactivate_partition(const int, struct xpc_partition *, + enum xpc_retval); +extern enum xpc_retval xpc_initiate_partid_to_nasids(partid_t, void *); + + +/* found in xpc_channel.c */ +extern void xpc_initiate_connect(int); +extern void xpc_initiate_disconnect(int); +extern enum xpc_retval xpc_initiate_allocate(partid_t, int, u32, void **); +extern enum xpc_retval xpc_initiate_send(partid_t, int, void *); +extern enum xpc_retval xpc_initiate_send_notify(partid_t, int, void *, + xpc_notify_func, void *); +extern void xpc_initiate_received(partid_t, int, void *); +extern enum xpc_retval xpc_setup_infrastructure(struct xpc_partition *); +extern enum xpc_retval xpc_pull_remote_vars_part(struct xpc_partition *); +extern void xpc_process_channel_activity(struct xpc_partition *); +extern void xpc_connected_callout(struct xpc_channel *); +extern void xpc_deliver_msg(struct xpc_channel *); +extern void xpc_disconnect_channel(const int, struct xpc_channel *, + enum xpc_retval, unsigned long *); +extern void xpc_disconnect_callout(struct xpc_channel *, enum xpc_retval); +extern void xpc_partition_going_down(struct xpc_partition *, enum xpc_retval); +extern void xpc_teardown_infrastructure(struct xpc_partition *); + + + +static inline void +xpc_wakeup_channel_mgr(struct xpc_partition *part) +{ + if (atomic_inc_return(&part->channel_mgr_requests) == 1) { + wake_up(&part->channel_mgr_wq); + } +} + + + +/* + * These next two inlines are used to keep us from tearing down a channel's + * msg queues while a thread may be referencing them. + */ +static inline void +xpc_msgqueue_ref(struct xpc_channel *ch) +{ + atomic_inc(&ch->references); +} + +static inline void +xpc_msgqueue_deref(struct xpc_channel *ch) +{ + s32 refs = atomic_dec_return(&ch->references); + + DBUG_ON(refs < 0); + if (refs == 0) { + xpc_wakeup_channel_mgr(&xpc_partitions[ch->partid]); + } +} + + + +#define XPC_DISCONNECT_CHANNEL(_ch, _reason, _irqflgs) \ + xpc_disconnect_channel(__LINE__, _ch, _reason, _irqflgs) + + +/* + * These two inlines are used to keep us from tearing down a partition's + * setup infrastructure while a thread may be referencing it. + */ +static inline void +xpc_part_deref(struct xpc_partition *part) +{ + s32 refs = atomic_dec_return(&part->references); + + + DBUG_ON(refs < 0); + if (refs == 0 && part->setup_state == XPC_P_WTEARDOWN) { + wake_up(&part->teardown_wq); + } +} + +static inline int +xpc_part_ref(struct xpc_partition *part) +{ + int setup; + + + atomic_inc(&part->references); + setup = (part->setup_state == XPC_P_SETUP); + if (!setup) { + xpc_part_deref(part); + } + return setup; +} + + + +/* + * The following macro is to be used for the setting of the reason and + * reason_line fields in both the struct xpc_channel and struct xpc_partition + * structures. + */ +#define XPC_SET_REASON(_p, _reason, _line) \ + { \ + (_p)->reason = _reason; \ + (_p)->reason_line = _line; \ + } + + + +/* + * This next set of inlines are used to keep track of when a partition is + * potentially engaged in accessing memory belonging to another partition. + */ + +static inline void +xpc_mark_partition_engaged(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t))); + + + local_irq_save(irq_flags); + + /* set bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, + (1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static inline void +xpc_mark_partition_disengaged(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t))); + + + local_irq_save(irq_flags); + + /* clear bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, + ~(1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static inline void +xpc_request_partition_disengage(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + + (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); + + + local_irq_save(irq_flags); + + /* set bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, + (1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static inline void +xpc_cancel_partition_disengage_request(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + + (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); + + + local_irq_save(irq_flags); + + /* clear bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, + ~(1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static inline u64 +xpc_partition_engaged(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + + + /* return our partition's AMO variable ANDed with partid_mask */ + return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) & + partid_mask); +} + +static inline u64 +xpc_partition_disengage_requested(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; + + + /* return our partition's AMO variable ANDed with partid_mask */ + return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) & + partid_mask); +} + +static inline void +xpc_clear_partition_engaged(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + + + /* clear bit(s) based on partid_mask in our partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, + ~partid_mask); +} + +static inline void +xpc_clear_partition_disengage_request(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; + + + /* clear bit(s) based on partid_mask in our partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, + ~partid_mask); +} + + + +/* + * The following set of macros and inlines are used for the sending and + * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, + * one that is associated with partition activity (SGI_XPC_ACTIVATE) and + * the other that is associated with channel activity (SGI_XPC_NOTIFY). + */ + +static inline u64 +xpc_IPI_receive(AMO_t *amo) +{ + return FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_CLEAR); +} + + +static inline enum xpc_retval +xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) +{ + int ret = 0; + unsigned long irq_flags; + + + local_irq_save(irq_flags); + + FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, flag); + sn_send_IPI_phys(nasid, phys_cpuid, vector, 0); + + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + ret = xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->variable), + xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); + + return ((ret == 0) ? xpcSuccess : xpcPioReadError); +} + + +/* + * IPIs associated with SGI_XPC_ACTIVATE IRQ. + */ + +/* + * Flag the appropriate AMO variable and send an IPI to the specified node. + */ +static inline void +xpc_activate_IRQ_send(u64 amos_page_pa, int from_nasid, int to_nasid, + int to_phys_cpuid) +{ + int w_index = XPC_NASID_W_INDEX(from_nasid); + int b_index = XPC_NASID_B_INDEX(from_nasid); + AMO_t *amos = (AMO_t *) __va(amos_page_pa + + (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); + + + (void) xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid, + to_phys_cpuid, SGI_XPC_ACTIVATE); +} + +static inline void +xpc_IPI_send_activate(struct xpc_vars *vars) +{ + xpc_activate_IRQ_send(vars->amos_page_pa, cnodeid_to_nasid(0), + vars->act_nasid, vars->act_phys_cpuid); +} + +static inline void +xpc_IPI_send_activated(struct xpc_partition *part) +{ + xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0), + part->remote_act_nasid, part->remote_act_phys_cpuid); +} + +static inline void +xpc_IPI_send_reactivate(struct xpc_partition *part) +{ + xpc_activate_IRQ_send(xpc_vars->amos_page_pa, part->reactivate_nasid, + xpc_vars->act_nasid, xpc_vars->act_phys_cpuid); +} + +static inline void +xpc_IPI_send_disengage(struct xpc_partition *part) +{ + xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0), + part->remote_act_nasid, part->remote_act_phys_cpuid); +} + + +/* + * IPIs associated with SGI_XPC_NOTIFY IRQ. + */ + +/* + * Send an IPI to the remote partition that is associated with the + * specified channel. + */ +#define XPC_NOTIFY_IRQ_SEND(_ch, _ipi_f, _irq_f) \ + xpc_notify_IRQ_send(_ch, _ipi_f, #_ipi_f, _irq_f) + +static inline void +xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string, + unsigned long *irq_flags) +{ + struct xpc_partition *part = &xpc_partitions[ch->partid]; + enum xpc_retval ret; + + + if (likely(part->act_state != XPC_P_DEACTIVATING)) { + ret = xpc_IPI_send(part->remote_IPI_amo_va, + (u64) ipi_flag << (ch->number * 8), + part->remote_IPI_nasid, + part->remote_IPI_phys_cpuid, + SGI_XPC_NOTIFY); + dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n", + ipi_flag_string, ch->partid, ch->number, ret); + if (unlikely(ret != xpcSuccess)) { + 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); + } + } + } +} + + +/* + * Make it look like the remote partition, which is associated with the + * specified channel, sent us an IPI. This faked IPI will be handled + * by xpc_dropped_IPI_check(). + */ +#define XPC_NOTIFY_IRQ_SEND_LOCAL(_ch, _ipi_f) \ + xpc_notify_IRQ_send_local(_ch, _ipi_f, #_ipi_f) + +static inline void +xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag, + char *ipi_flag_string) +{ + struct xpc_partition *part = &xpc_partitions[ch->partid]; + + + FETCHOP_STORE_OP(TO_AMO((u64) &part->local_IPI_amo_va->variable), + FETCHOP_OR, ((u64) ipi_flag << (ch->number * 8))); + dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n", + ipi_flag_string, ch->partid, ch->number); +} + + +/* + * The sending and receiving of IPIs includes the setting of an AMO variable + * to indicate the reason the IPI was sent. The 64-bit variable is divided + * up into eight bytes, ordered from right to left. Byte zero pertains to + * channel 0, byte one to channel 1, and so on. Each byte is described by + * the following IPI flags. + */ + +#define XPC_IPI_CLOSEREQUEST 0x01 +#define XPC_IPI_CLOSEREPLY 0x02 +#define XPC_IPI_OPENREQUEST 0x04 +#define XPC_IPI_OPENREPLY 0x08 +#define XPC_IPI_MSGREQUEST 0x10 + + +/* given an AMO variable and a channel#, get its associated IPI flags */ +#define XPC_GET_IPI_FLAGS(_amo, _c) ((u8) (((_amo) >> ((_c) * 8)) & 0xff)) +#define XPC_SET_IPI_FLAGS(_amo, _c, _f) (_amo) |= ((u64) (_f) << ((_c) * 8)) + +#define XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & __IA64_UL_CONST(0x0f0f0f0f0f0f0f0f)) +#define XPC_ANY_MSG_IPI_FLAGS_SET(_amo) ((_amo) & __IA64_UL_CONST(0x1010101010101010)) + + +static inline void +xpc_IPI_send_closerequest(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_openclose_args *args = ch->local_openclose_args; + + + args->reason = ch->reason; + + XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREQUEST, irq_flags); +} + +static inline void +xpc_IPI_send_closereply(struct xpc_channel *ch, unsigned long *irq_flags) +{ + XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREPLY, irq_flags); +} + +static inline void +xpc_IPI_send_openrequest(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_openclose_args *args = ch->local_openclose_args; + + + args->msg_size = ch->msg_size; + args->local_nentries = ch->local_nentries; + + XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREQUEST, irq_flags); +} + +static inline void +xpc_IPI_send_openreply(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_openclose_args *args = ch->local_openclose_args; + + + args->remote_nentries = ch->remote_nentries; + args->local_nentries = ch->local_nentries; + args->local_msgqueue_pa = __pa(ch->local_msgqueue); + + XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREPLY, irq_flags); +} + +static inline void +xpc_IPI_send_msgrequest(struct xpc_channel *ch) +{ + XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_MSGREQUEST, NULL); +} + +static inline void +xpc_IPI_send_local_msgrequest(struct xpc_channel *ch) +{ + XPC_NOTIFY_IRQ_SEND_LOCAL(ch, XPC_IPI_MSGREQUEST); +} + + +/* + * Memory for XPC's AMO variables is allocated by the MSPEC driver. These + * pages are located in the lowest granule. The lowest granule uses 4k pages + * for cached references and an alternate TLB handler to never provide a + * cacheable mapping for the entire region. This will prevent speculative + * reading of cached copies of our lines from being issued which will cause + * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 + * AMO variables (based on XP_MAX_PARTITIONS) for message notification and an + * additional 128 AMO variables (based on XP_NASID_MASK_WORDS) for partition + * activation and 2 AMO variables for partition deactivation. + */ +static inline AMO_t * +xpc_IPI_init(int index) +{ + AMO_t *amo = xpc_vars->amos_page + index; + + + (void) xpc_IPI_receive(amo); /* clear AMO variable */ + return amo; +} + + + +static inline enum xpc_retval +xpc_map_bte_errors(bte_result_t error) +{ + if (error == BTE_SUCCESS) + return xpcSuccess; + + if (is_shub2()) { + if (BTE_VALID_SH2_ERROR(error)) + return xpcBteSh2Start + error; + return xpcBteUnmappedError; + } + switch (error) { + case BTE_SUCCESS: return xpcSuccess; + case BTEFAIL_DIR: return xpcBteDirectoryError; + case BTEFAIL_POISON: return xpcBtePoisonError; + case BTEFAIL_WERR: return xpcBteWriteError; + case BTEFAIL_ACCESS: return xpcBteAccessError; + case BTEFAIL_PWERR: return xpcBtePWriteError; + case BTEFAIL_PRERR: return xpcBtePReadError; + case BTEFAIL_TOUT: return xpcBteTimeOutError; + case BTEFAIL_XTERR: return xpcBteXtalkError; + case BTEFAIL_NOTAVAIL: return xpcBteNotAvailable; + default: return xpcBteUnmappedError; + } +} + + + +/* + * Check to see if there is any channel activity to/from the specified + * partition. + */ +static inline void +xpc_check_for_channel_activity(struct xpc_partition *part) +{ + u64 IPI_amo; + unsigned long irq_flags; + + + IPI_amo = xpc_IPI_receive(part->local_IPI_amo_va); + if (IPI_amo == 0) { + return; + } + + spin_lock_irqsave(&part->IPI_lock, irq_flags); + part->local_IPI_amo |= IPI_amo; + spin_unlock_irqrestore(&part->IPI_lock, irq_flags); + + dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n", + XPC_PARTID(part), IPI_amo); + + xpc_wakeup_channel_mgr(part); +} + + +#endif /* _DRIVERS_MISC_SGIXP_XPC_H */ + diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c new file mode 100644 index 00000000000..d7a215eeaaf --- /dev/null +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -0,0 +1,2379 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * Cross Partition Communication (XPC) channel support. + * + * This is the part of XPC that manages the channels and + * sends/receives messages across them to/from other partitions. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xpc.h" + + +/* + * Guarantee that the kzalloc'd memory is cacheline aligned. + */ +static 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); +} + + +/* + * Set up the initial values for the XPartition Communication channels. + */ +static void +xpc_initialize_channels(struct xpc_partition *part, partid_t partid) +{ + int ch_number; + struct xpc_channel *ch; + + + 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->local_GP = &part->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); + + atomic_set(&ch->references, 0); + atomic_set(&ch->n_to_notify, 0); + + spin_lock_init(&ch->lock); + mutex_init(&ch->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); + } +} + + +/* + * Setup the infrastructure necessary to support XPartition Communication + * between the specified remote partition and the local one. + */ +enum xpc_retval +xpc_setup_infrastructure(struct xpc_partition *part) +{ + int ret, cpuid; + struct timer_list *timer; + partid_t partid = XPC_PARTID(part); + + + /* + * Zero out MOST of the entry for this partition. Only the fields + * starting with `nchannels' will be zeroed. The preceding fields must + * remain `viable' across partition ups and downs, since they may be + * referenced during this memset() operation. + */ + memset(&part->nchannels, 0, sizeof(struct xpc_partition) - + offsetof(struct xpc_partition, nchannels)); + + /* + * Allocate all of the channel structures as a contiguous chunk of + * memory. + */ + part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_NCHANNELS, + GFP_KERNEL); + if (part->channels == NULL) { + dev_err(xpc_chan, "can't get memory for channels\n"); + return xpcNoMemory; + } + + part->nchannels = XPC_NCHANNELS; + + + /* allocate all the required GET/PUT values */ + + part->local_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, + GFP_KERNEL, &part->local_GPs_base); + if (part->local_GPs == NULL) { + kfree(part->channels); + part->channels = NULL; + dev_err(xpc_chan, "can't get memory for local get/put " + "values\n"); + return xpcNoMemory; + } + + part->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, + GFP_KERNEL, &part->remote_GPs_base); + if (part->remote_GPs == NULL) { + dev_err(xpc_chan, "can't get memory for remote get/put " + "values\n"); + kfree(part->local_GPs_base); + part->local_GPs = NULL; + kfree(part->channels); + part->channels = NULL; + return xpcNoMemory; + } + + + /* allocate all the required open and close args */ + + part->local_openclose_args = xpc_kzalloc_cacheline_aligned( + XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, + &part->local_openclose_args_base); + if (part->local_openclose_args == NULL) { + dev_err(xpc_chan, "can't get memory for local connect args\n"); + kfree(part->remote_GPs_base); + part->remote_GPs = NULL; + kfree(part->local_GPs_base); + part->local_GPs = NULL; + kfree(part->channels); + part->channels = NULL; + return xpcNoMemory; + } + + 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"); + kfree(part->local_openclose_args_base); + part->local_openclose_args = NULL; + kfree(part->remote_GPs_base); + part->remote_GPs = NULL; + kfree(part->local_GPs_base); + part->local_GPs = NULL; + kfree(part->channels); + part->channels = NULL; + return xpcNoMemory; + } + + + xpc_initialize_channels(part, partid); + + atomic_set(&part->nchannels_active, 0); + atomic_set(&part->nchannels_engaged, 0); + + + /* local_IPI_amo were set to 0 by an earlier memset() */ + + /* Initialize this partitions AMO_t structure */ + part->local_IPI_amo_va = xpc_IPI_init(partid); + + spin_lock_init(&part->IPI_lock); + + atomic_set(&part->channel_mgr_requests, 1); + init_waitqueue_head(&part->channel_mgr_wq); + + sprintf(part->IPI_owner, "xpc%02d", partid); + ret = request_irq(SGI_XPC_NOTIFY, xpc_notify_IRQ_handler, IRQF_SHARED, + part->IPI_owner, (void *) (u64) partid); + if (ret != 0) { + dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " + "errno=%d\n", -ret); + kfree(part->remote_openclose_args_base); + part->remote_openclose_args = NULL; + kfree(part->local_openclose_args_base); + part->local_openclose_args = NULL; + kfree(part->remote_GPs_base); + part->remote_GPs = NULL; + kfree(part->local_GPs_base); + part->local_GPs = NULL; + kfree(part->channels); + part->channels = NULL; + return xpcLackOfResources; + } + + /* Setup a timer to check for dropped IPIs */ + timer = &part->dropped_IPI_timer; + init_timer(timer); + timer->function = (void (*)(unsigned long)) xpc_dropped_IPI_check; + timer->data = (unsigned long) part; + timer->expires = jiffies + XPC_P_DROPPED_IPI_WAIT; + add_timer(timer); + + /* + * With the setting of the partition setup_state to XPC_P_SETUP, we're + * declaring that this partition is ready to go. + */ + part->setup_state = XPC_P_SETUP; + + + /* + * Setup the per partition specific variables required by the + * remote partition to establish channel connections with us. + * + * The setting of the magic # indicates that these per partition + * specific variables are ready to be used. + */ + xpc_vars_part[partid].GPs_pa = __pa(part->local_GPs); + xpc_vars_part[partid].openclose_args_pa = + __pa(part->local_openclose_args); + xpc_vars_part[partid].IPI_amo_pa = __pa(part->local_IPI_amo_va); + cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ + xpc_vars_part[partid].IPI_nasid = cpuid_to_nasid(cpuid); + xpc_vars_part[partid].IPI_phys_cpuid = cpu_physical_id(cpuid); + xpc_vars_part[partid].nchannels = part->nchannels; + xpc_vars_part[partid].magic = XPC_VP_MAGIC1; + + return xpcSuccess; +} + + +/* + * 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. + * dst must be a cacheline aligned virtual address on this partition. + * cnt must be an cacheline sized + */ +static enum xpc_retval +xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst, + const void *src, size_t cnt) +{ + bte_result_t bte_ret; + + + DBUG_ON((u64) src != L1_CACHE_ALIGN((u64) src)); + DBUG_ON((u64) dst != L1_CACHE_ALIGN((u64) dst)); + DBUG_ON(cnt != L1_CACHE_ALIGN(cnt)); + + if (part->act_state == XPC_P_DEACTIVATING) { + return part->reason; + } + + bte_ret = xp_bte_copy((u64) src, (u64) dst, (u64) cnt, + (BTE_NORMAL | BTE_WACQUIRE), NULL); + if (bte_ret == BTE_SUCCESS) { + return xpcSuccess; + } + + dev_dbg(xpc_chan, "xp_bte_copy() from partition %d failed, ret=%d\n", + XPC_PARTID(part), bte_ret); + + return xpc_map_bte_errors(bte_ret); +} + + +/* + * Pull the remote per partition specific variables from the specified + * partition. + */ +enum xpc_retval +xpc_pull_remote_vars_part(struct xpc_partition *part) +{ + u8 buffer[L1_CACHE_BYTES * 2]; + struct xpc_vars_part *pulled_entry_cacheline = + (struct xpc_vars_part *) L1_CACHE_ALIGN((u64) buffer); + struct xpc_vars_part *pulled_entry; + u64 remote_entry_cacheline_pa, remote_entry_pa; + partid_t partid = XPC_PARTID(part); + enum xpc_retval ret; + + + /* pull the cacheline that contains the variables we're interested in */ + + DBUG_ON(part->remote_vars_part_pa != + L1_CACHE_ALIGN(part->remote_vars_part_pa)); + DBUG_ON(sizeof(struct xpc_vars_part) != L1_CACHE_BYTES / 2); + + remote_entry_pa = part->remote_vars_part_pa + + sn_partition_id * sizeof(struct xpc_vars_part); + + remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1)); + + pulled_entry = (struct xpc_vars_part *) ((u64) pulled_entry_cacheline + + (remote_entry_pa & (L1_CACHE_BYTES - 1))); + + ret = xpc_pull_remote_cachelines(part, pulled_entry_cacheline, + (void *) remote_entry_cacheline_pa, + L1_CACHE_BYTES); + if (ret != xpcSuccess) { + dev_dbg(xpc_chan, "failed to pull XPC vars_part from " + "partition %d, ret=%d\n", partid, ret); + return ret; + } + + + /* 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 != 0) { + dev_dbg(xpc_chan, "partition %d's XPC vars_part for " + "partition %d has bad magic value (=0x%lx)\n", + partid, sn_partition_id, pulled_entry->magic); + return xpcBadMagic; + } + + /* they've not been initialized yet */ + return xpcRetry; + } + + if (xpc_vars_part[partid].magic == XPC_VP_MAGIC1) { + + /* validate the variables */ + + if (pulled_entry->GPs_pa == 0 || + pulled_entry->openclose_args_pa == 0 || + pulled_entry->IPI_amo_pa == 0) { + + dev_err(xpc_chan, "partition %d's XPC vars_part for " + "partition %d are not valid\n", partid, + sn_partition_id); + return xpcInvalidAddress; + } + + /* the variables we imported look to be valid */ + + part->remote_GPs_pa = pulled_entry->GPs_pa; + part->remote_openclose_args_pa = + pulled_entry->openclose_args_pa; + part->remote_IPI_amo_va = + (AMO_t *) __va(pulled_entry->IPI_amo_pa); + part->remote_IPI_nasid = pulled_entry->IPI_nasid; + part->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid; + + if (part->nchannels > pulled_entry->nchannels) { + part->nchannels = pulled_entry->nchannels; + } + + /* let the other side know that we've pulled their variables */ + + xpc_vars_part[partid].magic = XPC_VP_MAGIC2; + } + + if (pulled_entry->magic == XPC_VP_MAGIC1) { + return xpcRetry; + } + + return xpcSuccess; +} + + +/* + * Get the IPI flags and pull the openclose args and/or remote GPs as needed. + */ +static u64 +xpc_get_IPI_flags(struct xpc_partition *part) +{ + unsigned long irq_flags; + u64 IPI_amo; + enum xpc_retval ret; + + + /* + * See if there are any IPI flags to be handled. + */ + + spin_lock_irqsave(&part->IPI_lock, irq_flags); + if ((IPI_amo = part->local_IPI_amo) != 0) { + part->local_IPI_amo = 0; + } + spin_unlock_irqrestore(&part->IPI_lock, irq_flags); + + + if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_amo)) { + ret = xpc_pull_remote_cachelines(part, + part->remote_openclose_args, + (void *) part->remote_openclose_args_pa, + XPC_OPENCLOSE_ARGS_SIZE); + if (ret != xpcSuccess) { + XPC_DEACTIVATE_PARTITION(part, ret); + + dev_dbg(xpc_chan, "failed to pull openclose args from " + "partition %d, ret=%d\n", XPC_PARTID(part), + ret); + + /* don't bother processing IPIs anymore */ + IPI_amo = 0; + } + } + + if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_amo)) { + ret = xpc_pull_remote_cachelines(part, part->remote_GPs, + (void *) part->remote_GPs_pa, + XPC_GP_SIZE); + if (ret != xpcSuccess) { + XPC_DEACTIVATE_PARTITION(part, ret); + + dev_dbg(xpc_chan, "failed to pull GPs from partition " + "%d, ret=%d\n", XPC_PARTID(part), ret); + + /* don't bother processing IPIs anymore */ + IPI_amo = 0; + } + } + + return IPI_amo; +} + + +/* + * Allocate the local message queue and the notify queue. + */ +static enum xpc_retval +xpc_allocate_local_msgqueue(struct xpc_channel *ch) +{ + unsigned long irq_flags; + int nentries; + size_t nbytes; + + + // >>> may want to check for ch->flags & XPC_C_DISCONNECTING between + // >>> iterations of the for-loop, bail if set? + + // >>> should we impose a minimum #of entries? like 4 or 8? + for (nentries = ch->local_nentries; nentries > 0; nentries--) { + + nbytes = nentries * ch->msg_size; + ch->local_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, + GFP_KERNEL, + &ch->local_msgqueue_base); + if (ch->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; + continue; + } + + spin_lock_irqsave(&ch->lock, irq_flags); + if (nentries < ch->local_nentries) { + dev_dbg(xpc_chan, "nentries=%d local_nentries=%d, " + "partid=%d, channel=%d\n", nentries, + ch->local_nentries, ch->partid, ch->number); + + ch->local_nentries = nentries; + } + spin_unlock_irqrestore(&ch->lock, irq_flags); + return xpcSuccess; + } + + dev_dbg(xpc_chan, "can't get memory for local message queue and notify " + "queue, partid=%d, channel=%d\n", ch->partid, ch->number); + return xpcNoMemory; +} + + +/* + * Allocate the cached remote message queue. + */ +static enum xpc_retval +xpc_allocate_remote_msgqueue(struct xpc_channel *ch) +{ + unsigned long irq_flags; + int nentries; + size_t nbytes; + + + DBUG_ON(ch->remote_nentries <= 0); + + // >>> may want to check for ch->flags & XPC_C_DISCONNECTING between + // >>> iterations of the for-loop, bail if set? + + // >>> should we impose a minimum #of entries? like 4 or 8? + for (nentries = ch->remote_nentries; nentries > 0; nentries--) { + + nbytes = nentries * ch->msg_size; + ch->remote_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, + GFP_KERNEL, + &ch->remote_msgqueue_base); + if (ch->remote_msgqueue == NULL) { + continue; + } + + spin_lock_irqsave(&ch->lock, irq_flags); + if (nentries < ch->remote_nentries) { + dev_dbg(xpc_chan, "nentries=%d remote_nentries=%d, " + "partid=%d, channel=%d\n", nentries, + ch->remote_nentries, ch->partid, ch->number); + + ch->remote_nentries = nentries; + } + spin_unlock_irqrestore(&ch->lock, irq_flags); + return xpcSuccess; + } + + dev_dbg(xpc_chan, "can't get memory for cached remote message queue, " + "partid=%d, channel=%d\n", ch->partid, ch->number); + return xpcNoMemory; +} + + +/* + * Allocate message queues and other stuff associated with a channel. + * + * Note: Assumes all of the channel sizes are filled in. + */ +static enum xpc_retval +xpc_allocate_msgqueues(struct xpc_channel *ch) +{ + unsigned long irq_flags; + enum xpc_retval ret; + + + DBUG_ON(ch->flags & XPC_C_SETUP); + + if ((ret = xpc_allocate_local_msgqueue(ch)) != xpcSuccess) { + return ret; + } + + if ((ret = xpc_allocate_remote_msgqueue(ch)) != xpcSuccess) { + kfree(ch->local_msgqueue_base); + ch->local_msgqueue = NULL; + kfree(ch->notify_queue); + ch->notify_queue = NULL; + return ret; + } + + spin_lock_irqsave(&ch->lock, irq_flags); + ch->flags |= XPC_C_SETUP; + spin_unlock_irqrestore(&ch->lock, irq_flags); + + return xpcSuccess; +} + + +/* + * Process a connect message from a remote partition. + * + * Note: xpc_process_connect() is expecting to be called with the + * spin_lock_irqsave held and will leave it locked upon return. + */ +static void +xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) +{ + enum xpc_retval ret; + + + DBUG_ON(!spin_is_locked(&ch->lock)); + + if (!(ch->flags & XPC_C_OPENREQUEST) || + !(ch->flags & XPC_C_ROPENREQUEST)) { + /* nothing more to do for now */ + return; + } + DBUG_ON(!(ch->flags & XPC_C_CONNECTING)); + + if (!(ch->flags & XPC_C_SETUP)) { + spin_unlock_irqrestore(&ch->lock, *irq_flags); + ret = xpc_allocate_msgqueues(ch); + spin_lock_irqsave(&ch->lock, *irq_flags); + + if (ret != xpcSuccess) { + XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags); + } + if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING)) { + return; + } + + DBUG_ON(!(ch->flags & XPC_C_SETUP)); + DBUG_ON(ch->local_msgqueue == NULL); + DBUG_ON(ch->remote_msgqueue == NULL); + } + + if (!(ch->flags & XPC_C_OPENREPLY)) { + ch->flags |= XPC_C_OPENREPLY; + xpc_IPI_send_openreply(ch, irq_flags); + } + + 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", + ch->number, ch->partid); + + spin_unlock_irqrestore(&ch->lock, *irq_flags); + xpc_create_kthreads(ch, 1, 0); + spin_lock_irqsave(&ch->lock, *irq_flags); +} + + +/* + * Notify those who wanted to be notified upon delivery of their message. + */ +static void +xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put) +{ + struct xpc_notify *notify; + u8 notify_type; + s64 get = ch->w_remote_GP.get - 1; + + + while (++get < put && atomic_read(&ch->n_to_notify) > 0) { + + notify = &ch->notify_queue[get % ch->local_nentries]; + + /* + * See if the notify entry indicates it was associated with + * a message who's sender wants to be notified. It is possible + * that it is, but someone else is doing or has done the + * notification. + */ + notify_type = notify->type; + if (notify_type == 0 || + cmpxchg(¬ify->type, notify_type, 0) != + notify_type) { + continue; + } + + DBUG_ON(notify_type != XPC_N_CALL); + + 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", + (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); + } + } +} + + +/* + * 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_free_msgqueues(struct xpc_channel *ch) +{ + 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->local_GP->get = 0; + ch->local_GP->put = 0; + ch->remote_GP.get = 0; + ch->remote_GP.put = 0; + ch->w_local_GP.get = 0; + ch->w_local_GP.put = 0; + ch->w_remote_GP.get = 0; + ch->w_remote_GP.put = 0; + ch->next_msg_to_pull = 0; + + if (ch->flags & XPC_C_SETUP) { + ch->flags &= ~XPC_C_SETUP; + + 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; + } +} + + +/* + * spin_lock_irqsave() is expected to be held on entry. + */ +static void +xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_partition *part = &xpc_partitions[ch->partid]; + u32 channel_was_connected = (ch->flags & XPC_C_WASCONNECTED); + + + DBUG_ON(!spin_is_locked(&ch->lock)); + + if (!(ch->flags & XPC_C_DISCONNECTING)) { + return; + } + + DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); + + /* make sure all activity has settled down first */ + + if (atomic_read(&ch->kthreads_assigned) > 0 || + atomic_read(&ch->references) > 0) { + return; + } + DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && + !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE)); + + if (part->act_state == XPC_P_DEACTIVATING) { + /* can't proceed until the other side disengages from us */ + if (xpc_partition_engaged(1UL << ch->partid)) { + return; + } + + } else { + + /* as long as the other side is up do the full protocol */ + + if (!(ch->flags & XPC_C_RCLOSEREQUEST)) { + return; + } + + if (!(ch->flags & XPC_C_CLOSEREPLY)) { + ch->flags |= XPC_C_CLOSEREPLY; + xpc_IPI_send_closereply(ch, irq_flags); + } + + if (!(ch->flags & XPC_C_RCLOSEREPLY)) { + return; + } + } + + /* wake those waiting for notify completion */ + if (atomic_read(&ch->n_to_notify) > 0) { + /* >>> we do callout while holding ch->lock */ + xpc_notify_senders(ch, ch->reason, ch->w_local_GP.put); + } + + /* both sides are disconnected now */ + + if (ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE) { + spin_unlock_irqrestore(&ch->lock, *irq_flags); + xpc_disconnect_callout(ch, xpcDisconnected); + spin_lock_irqsave(&ch->lock, *irq_flags); + } + + /* it's now safe to free the channel's message queues */ + xpc_free_msgqueues(ch); + + /* mark disconnected, clear all other flags except XPC_C_WDISCONNECT */ + ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT)); + + atomic_dec(&part->nchannels_active); + + if (channel_was_connected) { + dev_info(xpc_chan, "channel %d to partition %d disconnected, " + "reason=%d\n", ch->number, ch->partid, ch->reason); + } + + if (ch->flags & XPC_C_WDISCONNECT) { + /* we won't lose the CPU since we're holding ch->lock */ + complete(&ch->wdisconnect_wait); + } else if (ch->delayed_IPI_flags) { + if (part->act_state != XPC_P_DEACTIVATING) { + /* time to take action on any delayed IPI flags */ + spin_lock(&part->IPI_lock); + XPC_SET_IPI_FLAGS(part->local_IPI_amo, ch->number, + ch->delayed_IPI_flags); + spin_unlock(&part->IPI_lock); + } + ch->delayed_IPI_flags = 0; + } +} + + +/* + * Process a change in the channel's remote connection state. + */ +static void +xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, + u8 IPI_flags) +{ + unsigned long irq_flags; + struct xpc_openclose_args *args = + &part->remote_openclose_args[ch_number]; + struct xpc_channel *ch = &part->channels[ch_number]; + enum xpc_retval reason; + + + + spin_lock_irqsave(&ch->lock, irq_flags); + +again: + + if ((ch->flags & XPC_C_DISCONNECTED) && + (ch->flags & XPC_C_WDISCONNECT)) { + /* + * Delay processing IPI flags until thread waiting disconnect + * has had a chance to see that the channel is disconnected. + */ + ch->delayed_IPI_flags |= IPI_flags; + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + + + if (IPI_flags & XPC_IPI_CLOSEREQUEST) { + + dev_dbg(xpc_chan, "XPC_IPI_CLOSEREQUEST (reason=%d) received " + "from partid=%d, channel=%d\n", args->reason, + ch->partid, ch->number); + + /* + * If RCLOSEREQUEST is set, we're probably waiting for + * RCLOSEREPLY. We should find it and a ROPENREQUEST packed + * with this RCLOSEREQUEST in the IPI_flags. + */ + + if (ch->flags & XPC_C_RCLOSEREQUEST) { + DBUG_ON(!(ch->flags & XPC_C_DISCONNECTING)); + DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); + DBUG_ON(!(ch->flags & XPC_C_CLOSEREPLY)); + DBUG_ON(ch->flags & XPC_C_RCLOSEREPLY); + + DBUG_ON(!(IPI_flags & XPC_IPI_CLOSEREPLY)); + IPI_flags &= ~XPC_IPI_CLOSEREPLY; + ch->flags |= XPC_C_RCLOSEREPLY; + + /* both sides have finished disconnecting */ + xpc_process_disconnect(ch, &irq_flags); + DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED)); + goto again; + } + + if (ch->flags & XPC_C_DISCONNECTED) { + if (!(IPI_flags & XPC_IPI_OPENREQUEST)) { + if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, + ch_number) & XPC_IPI_OPENREQUEST)) { + + DBUG_ON(ch->delayed_IPI_flags != 0); + spin_lock(&part->IPI_lock); + XPC_SET_IPI_FLAGS(part->local_IPI_amo, + ch_number, + XPC_IPI_CLOSEREQUEST); + spin_unlock(&part->IPI_lock); + } + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + + XPC_SET_REASON(ch, 0, 0); + ch->flags &= ~XPC_C_DISCONNECTED; + + atomic_inc(&part->nchannels_active); + ch->flags |= (XPC_C_CONNECTING | XPC_C_ROPENREQUEST); + } + + IPI_flags &= ~(XPC_IPI_OPENREQUEST | XPC_IPI_OPENREPLY); + + /* + * The meaningful CLOSEREQUEST connection state fields are: + * reason = reason connection is to be closed + */ + + ch->flags |= XPC_C_RCLOSEREQUEST; + + if (!(ch->flags & XPC_C_DISCONNECTING)) { + reason = args->reason; + if (reason <= xpcSuccess || reason > xpcUnknownReason) { + reason = xpcUnknownReason; + } else if (reason == xpcUnregistering) { + reason = xpcOtherUnregistering; + } + + XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); + + DBUG_ON(IPI_flags & XPC_IPI_CLOSEREPLY); + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + + xpc_process_disconnect(ch, &irq_flags); + } + + + if (IPI_flags & XPC_IPI_CLOSEREPLY) { + + dev_dbg(xpc_chan, "XPC_IPI_CLOSEREPLY received from partid=%d," + " channel=%d\n", ch->partid, ch->number); + + if (ch->flags & XPC_C_DISCONNECTED) { + DBUG_ON(part->act_state != XPC_P_DEACTIVATING); + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + + DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); + + if (!(ch->flags & XPC_C_RCLOSEREQUEST)) { + if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, ch_number) + & XPC_IPI_CLOSEREQUEST)) { + + DBUG_ON(ch->delayed_IPI_flags != 0); + spin_lock(&part->IPI_lock); + XPC_SET_IPI_FLAGS(part->local_IPI_amo, + ch_number, XPC_IPI_CLOSEREPLY); + spin_unlock(&part->IPI_lock); + } + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + + ch->flags |= XPC_C_RCLOSEREPLY; + + if (ch->flags & XPC_C_CLOSEREPLY) { + /* both sides have finished disconnecting */ + xpc_process_disconnect(ch, &irq_flags); + } + } + + + if (IPI_flags & XPC_IPI_OPENREQUEST) { + + dev_dbg(xpc_chan, "XPC_IPI_OPENREQUEST (msg_size=%d, " + "local_nentries=%d) received from partid=%d, " + "channel=%d\n", args->msg_size, args->local_nentries, + ch->partid, ch->number); + + if (part->act_state == XPC_P_DEACTIVATING || + (ch->flags & XPC_C_ROPENREQUEST)) { + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + + if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_WDISCONNECT)) { + ch->delayed_IPI_flags |= XPC_IPI_OPENREQUEST; + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + DBUG_ON(!(ch->flags & (XPC_C_DISCONNECTED | + XPC_C_OPENREQUEST))); + DBUG_ON(ch->flags & (XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | + XPC_C_OPENREPLY | XPC_C_CONNECTED)); + + /* + * The meaningful OPENREQUEST connection state fields are: + * msg_size = size of channel's messages in bytes + * local_nentries = remote partition's local_nentries + */ + if (args->msg_size == 0 || args->local_nentries == 0) { + /* assume OPENREQUEST was delayed by mistake */ + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + + ch->flags |= (XPC_C_ROPENREQUEST | XPC_C_CONNECTING); + ch->remote_nentries = args->local_nentries; + + + if (ch->flags & XPC_C_OPENREQUEST) { + if (args->msg_size != ch->msg_size) { + XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes, + &irq_flags); + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + } else { + ch->msg_size = args->msg_size; + + XPC_SET_REASON(ch, 0, 0); + ch->flags &= ~XPC_C_DISCONNECTED; + + atomic_inc(&part->nchannels_active); + } + + xpc_process_connect(ch, &irq_flags); + } + + + if (IPI_flags & XPC_IPI_OPENREPLY) { + + dev_dbg(xpc_chan, "XPC_IPI_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); + + if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) { + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + if (!(ch->flags & XPC_C_OPENREQUEST)) { + XPC_DISCONNECT_CHANNEL(ch, xpcOpenCloseError, + &irq_flags); + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } + + DBUG_ON(!(ch->flags & XPC_C_ROPENREQUEST)); + DBUG_ON(ch->flags & XPC_C_CONNECTED); + + /* + * The meaningful OPENREPLY connection state fields are: + * local_msgqueue_pa = physical address of remote + * partition's local_msgqueue + * local_nentries = remote partition's local_nentries + * remote_nentries = remote partition's remote_nentries + */ + DBUG_ON(args->local_msgqueue_pa == 0); + DBUG_ON(args->local_nentries == 0); + DBUG_ON(args->remote_nentries == 0); + + ch->flags |= XPC_C_ROPENREPLY; + ch->remote_msgqueue_pa = args->local_msgqueue_pa; + + if (args->local_nentries < ch->remote_nentries) { + dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY: new " + "remote_nentries=%d, old remote_nentries=%d, " + "partid=%d, channel=%d\n", + args->local_nentries, ch->remote_nentries, + ch->partid, ch->number); + + ch->remote_nentries = args->local_nentries; + } + if (args->remote_nentries < ch->local_nentries) { + dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY: new " + "local_nentries=%d, old local_nentries=%d, " + "partid=%d, channel=%d\n", + args->remote_nentries, ch->local_nentries, + ch->partid, ch->number); + + ch->local_nentries = args->remote_nentries; + } + + xpc_process_connect(ch, &irq_flags); + } + + spin_unlock_irqrestore(&ch->lock, irq_flags); +} + + +/* + * Attempt to establish a channel connection to a remote partition. + */ +static enum xpc_retval +xpc_connect_channel(struct xpc_channel *ch) +{ + unsigned long irq_flags; + struct xpc_registration *registration = &xpc_registrations[ch->number]; + + + if (mutex_trylock(®istration->mutex) == 0) { + return xpcRetry; + } + + if (!XPC_CHANNEL_REGISTERED(ch->number)) { + mutex_unlock(®istration->mutex); + return xpcUnregistered; + } + + spin_lock_irqsave(&ch->lock, irq_flags); + + DBUG_ON(ch->flags & XPC_C_CONNECTED); + DBUG_ON(ch->flags & XPC_C_OPENREQUEST); + + if (ch->flags & XPC_C_DISCONNECTING) { + spin_unlock_irqrestore(&ch->lock, irq_flags); + mutex_unlock(®istration->mutex); + return ch->reason; + } + + + /* add info from the channel connect registration to the channel */ + + ch->kthreads_assigned_limit = registration->assigned_limit; + ch->kthreads_idle_limit = registration->idle_limit; + DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0); + DBUG_ON(atomic_read(&ch->kthreads_idle) != 0); + DBUG_ON(atomic_read(&ch->kthreads_active) != 0); + + ch->func = registration->func; + DBUG_ON(registration->func == NULL); + ch->key = registration->key; + + ch->local_nentries = registration->nentries; + + if (ch->flags & XPC_C_ROPENREQUEST) { + if (registration->msg_size != ch->msg_size) { + /* the local and remote sides aren't the same */ + + /* + * Because XPC_DISCONNECT_CHANNEL() can block we're + * forced to up the registration sema before we unlock + * the channel lock. But that's okay here because we're + * done with the part that required the registration + * sema. XPC_DISCONNECT_CHANNEL() requires that the + * channel lock be locked and will unlock and relock + * the channel lock as needed. + */ + mutex_unlock(®istration->mutex); + XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes, + &irq_flags); + spin_unlock_irqrestore(&ch->lock, irq_flags); + return xpcUnequalMsgSizes; + } + } else { + ch->msg_size = registration->msg_size; + + XPC_SET_REASON(ch, 0, 0); + ch->flags &= ~XPC_C_DISCONNECTED; + + atomic_inc(&xpc_partitions[ch->partid].nchannels_active); + } + + mutex_unlock(®istration->mutex); + + + /* initiate the connection */ + + ch->flags |= (XPC_C_OPENREQUEST | XPC_C_CONNECTING); + xpc_IPI_send_openrequest(ch, &irq_flags); + + xpc_process_connect(ch, &irq_flags); + + spin_unlock_irqrestore(&ch->lock, irq_flags); + + return xpcSuccess; +} + + +/* + * Clear some of the msg flags in the local message queue. + */ +static inline void +xpc_clear_local_msgqueue_flags(struct xpc_channel *ch) +{ + struct xpc_msg *msg; + s64 get; + + + get = ch->w_remote_GP.get; + do { + msg = (struct xpc_msg *) ((u64) ch->local_msgqueue + + (get % ch->local_nentries) * ch->msg_size); + msg->flags = 0; + } while (++get < (volatile s64) ch->remote_GP.get); +} + + +/* + * Clear some of the msg flags in the remote message queue. + */ +static inline void +xpc_clear_remote_msgqueue_flags(struct xpc_channel *ch) +{ + struct xpc_msg *msg; + s64 put; + + + put = ch->w_remote_GP.put; + do { + msg = (struct xpc_msg *) ((u64) ch->remote_msgqueue + + (put % ch->remote_nentries) * ch->msg_size); + msg->flags = 0; + } while (++put < (volatile s64) ch->remote_GP.put); +} + + +static void +xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) +{ + struct xpc_channel *ch = &part->channels[ch_number]; + int nmsgs_sent; + + + ch->remote_GP = part->remote_GPs[ch_number]; + + + /* See what, if anything, has changed for each connected channel */ + + xpc_msgqueue_ref(ch); + + if (ch->w_remote_GP.get == ch->remote_GP.get && + ch->w_remote_GP.put == ch->remote_GP.put) { + /* nothing changed since GPs were last pulled */ + xpc_msgqueue_deref(ch); + return; + } + + if (!(ch->flags & XPC_C_CONNECTED)){ + xpc_msgqueue_deref(ch); + return; + } + + + /* + * First check to see if messages recently sent by us have been + * received by the other side. (The remote GET value will have + * changed since we last looked at it.) + */ + + if (ch->w_remote_GP.get != ch->remote_GP.get) { + + /* + * We need to notify any senders that want to be notified + * that their sent messages have been received by their + * intended recipients. We need to do this before updating + * w_remote_GP.get so that we don't allocate the same message + * queue entries prematurely (see xpc_allocate_msg()). + */ + if (atomic_read(&ch->n_to_notify) > 0) { + /* + * Notify senders that messages sent have been + * received and delivered by the other side. + */ + xpc_notify_senders(ch, xpcMsgDelivered, + ch->remote_GP.get); + } + + /* + * Clear msg->flags in previously sent messages, so that + * they're ready for xpc_allocate_msg(). + */ + xpc_clear_local_msgqueue_flags(ch); + + ch->w_remote_GP.get = ch->remote_GP.get; + + dev_dbg(xpc_chan, "w_remote_GP.get changed to %ld, partid=%d, " + "channel=%d\n", ch->w_remote_GP.get, ch->partid, + ch->number); + + /* + * If anyone was waiting for message queue entries to become + * available, wake them up. + */ + if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) { + wake_up(&ch->msg_allocate_wq); + } + } + + + /* + * Now check for newly sent messages by the other side. (The remote + * PUT value will have changed since we last looked at it.) + */ + + if (ch->w_remote_GP.put != ch->remote_GP.put) { + /* + * Clear msg->flags in previously received messages, so that + * they're ready for xpc_get_deliverable_msg(). + */ + xpc_clear_remote_msgqueue_flags(ch); + + ch->w_remote_GP.put = ch->remote_GP.put; + + dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, " + "channel=%d\n", ch->w_remote_GP.put, ch->partid, + ch->number); + + nmsgs_sent = ch->w_remote_GP.put - ch->w_local_GP.get; + if (nmsgs_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); + + if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) { + xpc_activate_kthreads(ch, nmsgs_sent); + } + } + } + + xpc_msgqueue_deref(ch); +} + + +void +xpc_process_channel_activity(struct xpc_partition *part) +{ + unsigned long irq_flags; + u64 IPI_amo, IPI_flags; + struct xpc_channel *ch; + int ch_number; + u32 ch_flags; + + + IPI_amo = xpc_get_IPI_flags(part); + + /* + * Initiate channel connections for registered channels. + * + * For each connected channel that has pending messages activate idle + * kthreads and/or create new kthreads as needed. + */ + + for (ch_number = 0; ch_number < part->nchannels; ch_number++) { + ch = &part->channels[ch_number]; + + + /* + * Process any open or close related IPI flags, and then deal + * with connecting or disconnecting the channel as required. + */ + + IPI_flags = XPC_GET_IPI_FLAGS(IPI_amo, ch_number); + + if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_flags)) { + xpc_process_openclose_IPI(part, ch_number, IPI_flags); + } + + ch_flags = ch->flags; /* need an atomic snapshot of flags */ + + if (ch_flags & XPC_C_DISCONNECTING) { + spin_lock_irqsave(&ch->lock, irq_flags); + xpc_process_disconnect(ch, &irq_flags); + spin_unlock_irqrestore(&ch->lock, irq_flags); + continue; + } + + if (part->act_state == XPC_P_DEACTIVATING) { + continue; + } + + if (!(ch_flags & XPC_C_CONNECTED)) { + if (!(ch_flags & XPC_C_OPENREQUEST)) { + DBUG_ON(ch_flags & XPC_C_SETUP); + (void) xpc_connect_channel(ch); + } else { + spin_lock_irqsave(&ch->lock, irq_flags); + xpc_process_connect(ch, &irq_flags); + spin_unlock_irqrestore(&ch->lock, irq_flags); + } + continue; + } + + + /* + * Process any message related IPI flags, this may involve the + * activation of kthreads to deliver any pending messages sent + * from the other partition. + */ + + if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_flags)) { + xpc_process_msg_IPI(part, ch_number); + } + } +} + + +/* + * XPC's heartbeat code calls this function to inform XPC that a partition is + * going down. XPC responds by tearing down the XPartition Communication + * infrastructure used for the just downed partition. + * + * XPC's heartbeat code will never call this function and xpc_partition_up() + * at the same time. Nor will it ever make multiple calls to either function + * at the same time. + */ +void +xpc_partition_going_down(struct xpc_partition *part, enum xpc_retval reason) +{ + unsigned long irq_flags; + int ch_number; + struct xpc_channel *ch; + + + dev_dbg(xpc_chan, "deactivating partition %d, reason=%d\n", + XPC_PARTID(part), reason); + + if (!xpc_part_ref(part)) { + /* infrastructure for this partition isn't currently set up */ + return; + } + + + /* disconnect channels associated with the partition going down */ + + for (ch_number = 0; ch_number < part->nchannels; ch_number++) { + ch = &part->channels[ch_number]; + + xpc_msgqueue_ref(ch); + spin_lock_irqsave(&ch->lock, irq_flags); + + XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); + + spin_unlock_irqrestore(&ch->lock, irq_flags); + xpc_msgqueue_deref(ch); + } + + xpc_wakeup_channel_mgr(part); + + xpc_part_deref(part); +} + + +/* + * Teardown the infrastructure necessary to support XPartition Communication + * between the specified remote partition and the local one. + */ +void +xpc_teardown_infrastructure(struct xpc_partition *part) +{ + partid_t 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 IPIs sent to + * this partition. + */ + + 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; + + xpc_vars_part[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_TORNDOWN; + + /* in case we've still got outstanding timers registered... */ + del_timer_sync(&part->dropped_IPI_timer); + + kfree(part->remote_openclose_args_base); + part->remote_openclose_args = NULL; + kfree(part->local_openclose_args_base); + part->local_openclose_args = NULL; + kfree(part->remote_GPs_base); + part->remote_GPs = NULL; + kfree(part->local_GPs_base); + part->local_GPs = NULL; + kfree(part->channels); + part->channels = NULL; + part->local_IPI_amo_va = NULL; +} + + +/* + * Called by XP at the time of channel connection registration to cause + * XPC to establish connections to all currently active partitions. + */ +void +xpc_initiate_connect(int ch_number) +{ + partid_t partid; + struct xpc_partition *part; + struct xpc_channel *ch; + + + DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + part = &xpc_partitions[partid]; + + if (xpc_part_ref(part)) { + ch = &part->channels[ch_number]; + + /* + * Initiate the establishment of a connection on the + * newly registered channel to the remote partition. + */ + xpc_wakeup_channel_mgr(part); + xpc_part_deref(part); + } + } +} + + +void +xpc_connected_callout(struct xpc_channel *ch) +{ + /* let the registerer know that a connection has been established */ + + if (ch->func != NULL) { + dev_dbg(xpc_chan, "ch->func() called, reason=xpcConnected, " + "partid=%d, channel=%d\n", ch->partid, ch->number); + + ch->func(xpcConnected, ch->partid, ch->number, + (void *) (u64) ch->local_nentries, ch->key); + + dev_dbg(xpc_chan, "ch->func() returned, reason=xpcConnected, " + "partid=%d, channel=%d\n", ch->partid, ch->number); + } +} + + +/* + * Called by XP at the time of channel connection unregistration to cause + * XPC to teardown all current connections for the specified channel. + * + * Before returning xpc_initiate_disconnect() will wait until all connections + * on the specified channel have been closed/torndown. So the caller can be + * assured that they will not be receiving any more callouts from XPC to the + * function they registered via xpc_connect(). + * + * Arguments: + * + * ch_number - channel # to unregister. + */ +void +xpc_initiate_disconnect(int ch_number) +{ + unsigned long irq_flags; + partid_t partid; + struct xpc_partition *part; + struct xpc_channel *ch; + + + DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + + /* initiate the channel disconnect for every active partition */ + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + part = &xpc_partitions[partid]; + + if (xpc_part_ref(part)) { + ch = &part->channels[ch_number]; + xpc_msgqueue_ref(ch); + + spin_lock_irqsave(&ch->lock, irq_flags); + + if (!(ch->flags & XPC_C_DISCONNECTED)) { + ch->flags |= XPC_C_WDISCONNECT; + + XPC_DISCONNECT_CHANNEL(ch, xpcUnregistering, + &irq_flags); + } + + spin_unlock_irqrestore(&ch->lock, irq_flags); + + xpc_msgqueue_deref(ch); + xpc_part_deref(part); + } + } + + xpc_disconnect_wait(ch_number); +} + + +/* + * To disconnect a channel, and reflect it back to all who may be waiting. + * + * An OPEN is not allowed until XPC_C_DISCONNECTING is cleared by + * xpc_process_disconnect(), and if set, XPC_C_WDISCONNECT is cleared by + * xpc_disconnect_wait(). + * + * THE CHANNEL IS TO BE LOCKED BY THE CALLER AND WILL REMAIN LOCKED UPON RETURN. + */ +void +xpc_disconnect_channel(const int line, struct xpc_channel *ch, + enum xpc_retval reason, unsigned long *irq_flags) +{ + u32 channel_was_connected = (ch->flags & XPC_C_CONNECTED); + + + DBUG_ON(!spin_is_locked(&ch->lock)); + + if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) { + return; + } + DBUG_ON(!(ch->flags & (XPC_C_CONNECTING | XPC_C_CONNECTED))); + + dev_dbg(xpc_chan, "reason=%d, line=%d, partid=%d, channel=%d\n", + reason, line, ch->partid, ch->number); + + XPC_SET_REASON(ch, reason, line); + + ch->flags |= (XPC_C_CLOSEREQUEST | XPC_C_DISCONNECTING); + /* some of these may not have been set */ + ch->flags &= ~(XPC_C_OPENREQUEST | XPC_C_OPENREPLY | + XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | + XPC_C_CONNECTING | XPC_C_CONNECTED); + + xpc_IPI_send_closerequest(ch, irq_flags); + + if (channel_was_connected) { + ch->flags |= XPC_C_WASCONNECTED; + } + + spin_unlock_irqrestore(&ch->lock, *irq_flags); + + /* wake all idle kthreads so they can exit */ + if (atomic_read(&ch->kthreads_idle) > 0) { + wake_up_all(&ch->idle_wq); + + } else if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && + !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) { + /* start a kthread that will do the xpcDisconnecting callout */ + xpc_create_kthreads(ch, 1, 1); + } + + /* wake those waiting to allocate an entry from the local msg queue */ + if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) { + wake_up(&ch->msg_allocate_wq); + } + + spin_lock_irqsave(&ch->lock, *irq_flags); +} + + +void +xpc_disconnect_callout(struct xpc_channel *ch, enum xpc_retval reason) +{ + /* + * Let the channel's registerer know that the channel is being + * disconnected. We don't want to do this if the registerer was never + * informed of a connection being made. + */ + + if (ch->func != NULL) { + dev_dbg(xpc_chan, "ch->func() called, reason=%d, partid=%d, " + "channel=%d\n", reason, ch->partid, ch->number); + + ch->func(reason, ch->partid, ch->number, NULL, ch->key); + + dev_dbg(xpc_chan, "ch->func() returned, reason=%d, partid=%d, " + "channel=%d\n", reason, ch->partid, ch->number); + } +} + + +/* + * Wait for a message entry to become available for the specified channel, + * but don't wait any longer than 1 jiffy. + */ +static enum xpc_retval +xpc_allocate_msg_wait(struct xpc_channel *ch) +{ + enum xpc_retval ret; + + + if (ch->flags & XPC_C_DISCONNECTING) { + DBUG_ON(ch->reason == xpcInterrupted); // >>> Is this true? + return ch->reason; + } + + atomic_inc(&ch->n_on_msg_allocate_wq); + ret = interruptible_sleep_on_timeout(&ch->msg_allocate_wq, 1); + atomic_dec(&ch->n_on_msg_allocate_wq); + + if (ch->flags & XPC_C_DISCONNECTING) { + ret = ch->reason; + DBUG_ON(ch->reason == xpcInterrupted); // >>> Is this true? + } else if (ret == 0) { + ret = xpcTimeout; + } else { + ret = xpcInterrupted; + } + + return ret; +} + + +/* + * Allocate an entry for a message from the message queue associated with the + * specified channel. + */ +static enum xpc_retval +xpc_allocate_msg(struct xpc_channel *ch, u32 flags, + struct xpc_msg **address_of_msg) +{ + struct xpc_msg *msg; + enum xpc_retval ret; + s64 put; + + + /* this reference will be dropped in xpc_send_msg() */ + xpc_msgqueue_ref(ch); + + if (ch->flags & XPC_C_DISCONNECTING) { + xpc_msgqueue_deref(ch); + return ch->reason; + } + if (!(ch->flags & XPC_C_CONNECTED)) { + xpc_msgqueue_deref(ch); + return xpcNotConnected; + } + + + /* + * Get the next available message entry from the local message queue. + * If none are available, we'll make sure that we grab the latest + * GP values. + */ + ret = xpcTimeout; + + while (1) { + + put = (volatile s64) ch->w_local_GP.put; + if (put - (volatile s64) ch->w_remote_GP.get < + ch->local_nentries) { + + /* There are available message entries. We need to try + * to secure one for ourselves. We'll do this by trying + * to increment w_local_GP.put as long as someone else + * doesn't beat us to it. If they do, we'll have to + * try again. + */ + if (cmpxchg(&ch->w_local_GP.put, put, put + 1) == + put) { + /* we got the entry referenced by put */ + break; + } + continue; /* try again */ + } + + + /* + * There aren't any available msg entries at this time. + * + * In waiting for a message entry to become available, + * we set a timeout in case the other side is not + * sending completion IPIs. This lets us fake an IPI + * that will cause the IPI handler to fetch the latest + * GP values as if an IPI was sent by the other side. + */ + if (ret == xpcTimeout) { + xpc_IPI_send_local_msgrequest(ch); + } + + if (flags & XPC_NOWAIT) { + xpc_msgqueue_deref(ch); + return xpcNoWait; + } + + ret = xpc_allocate_msg_wait(ch); + if (ret != xpcInterrupted && ret != xpcTimeout) { + xpc_msgqueue_deref(ch); + return ret; + } + } + + + /* get the message's address and initialize it */ + msg = (struct xpc_msg *) ((u64) ch->local_msgqueue + + (put % ch->local_nentries) * ch->msg_size); + + + DBUG_ON(msg->flags != 0); + msg->number = put; + + dev_dbg(xpc_chan, "w_local_GP.put changed to %ld; msg=0x%p, " + "msg_number=%ld, partid=%d, channel=%d\n", put + 1, + (void *) msg, msg->number, ch->partid, ch->number); + + *address_of_msg = msg; + + return xpcSuccess; +} + + +/* + * Allocate an entry for a message from the message queue associated with the + * specified channel. NOTE that this routine can sleep waiting for a message + * entry to become available. To not sleep, pass in the XPC_NOWAIT flag. + * + * Arguments: + * + * partid - ID of partition to which the channel is connected. + * ch_number - channel #. + * flags - see xpc.h for valid flags. + * payload - address of the allocated payload area pointer (filled in on + * return) in which the user-defined message is constructed. + */ +enum xpc_retval +xpc_initiate_allocate(partid_t partid, int ch_number, u32 flags, void **payload) +{ + struct xpc_partition *part = &xpc_partitions[partid]; + enum xpc_retval ret = xpcUnknownReason; + struct xpc_msg *msg = NULL; + + + DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); + + *payload = NULL; + + if (xpc_part_ref(part)) { + ret = xpc_allocate_msg(&part->channels[ch_number], flags, &msg); + xpc_part_deref(part); + + if (msg != NULL) { + *payload = &msg->payload; + } + } + + return ret; +} + + +/* + * Now we actually send the messages that are ready to be sent by advancing + * the local message queue's Put value and then send an IPI to the recipient + * partition. + */ +static void +xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) +{ + struct xpc_msg *msg; + s64 put = initial_put + 1; + int send_IPI = 0; + + + while (1) { + + while (1) { + if (put == (volatile s64) ch->w_local_GP.put) { + break; + } + + msg = (struct xpc_msg *) ((u64) ch->local_msgqueue + + (put % ch->local_nentries) * ch->msg_size); + + if (!(msg->flags & XPC_M_READY)) { + break; + } + + put++; + } + + if (put == initial_put) { + /* nothing's changed */ + break; + } + + if (cmpxchg_rel(&ch->local_GP->put, initial_put, put) != + initial_put) { + /* someone else beat us to it */ + DBUG_ON((volatile s64) ch->local_GP->put < initial_put); + break; + } + + /* we just set the new value of local_GP->put */ + + dev_dbg(xpc_chan, "local_GP->put changed to %ld, partid=%d, " + "channel=%d\n", put, ch->partid, ch->number); + + send_IPI = 1; + + /* + * We need to ensure that the message referenced by + * local_GP->put is not XPC_M_READY or that local_GP->put + * equals w_local_GP.put, so we'll go have a look. + */ + initial_put = put; + } + + if (send_IPI) { + xpc_IPI_send_msgrequest(ch); + } +} + + +/* + * Common code that does the actual sending of the message by advancing the + * local message queue's Put value and sends an IPI to the partition the + * message is being sent to. + */ +static enum xpc_retval +xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, + xpc_notify_func func, void *key) +{ + enum xpc_retval ret = xpcSuccess; + struct xpc_notify *notify = notify; + s64 put, msg_number = msg->number; + + + DBUG_ON(notify_type == XPC_N_CALL && func == NULL); + DBUG_ON((((u64) msg - (u64) ch->local_msgqueue) / ch->msg_size) != + msg_number % ch->local_nentries); + DBUG_ON(msg->flags & XPC_M_READY); + + if (ch->flags & XPC_C_DISCONNECTING) { + /* drop the reference grabbed in xpc_allocate_msg() */ + xpc_msgqueue_deref(ch); + return ch->reason; + } + + if (notify_type != 0) { + /* + * Tell the remote side to send an ACK interrupt when the + * message has been delivered. + */ + msg->flags |= XPC_M_INTERRUPT; + + atomic_inc(&ch->n_to_notify); + + notify = &ch->notify_queue[msg_number % ch->local_nentries]; + notify->func = func; + notify->key = key; + notify->type = notify_type; + + // >>> is a mb() needed here? + + if (ch->flags & XPC_C_DISCONNECTING) { + /* + * An error occurred between our last error check and + * this one. We will try to clear the type field from + * the notify entry. If we succeed then + * xpc_disconnect_channel() didn't already process + * the notify entry. + */ + if (cmpxchg(¬ify->type, notify_type, 0) == + notify_type) { + atomic_dec(&ch->n_to_notify); + ret = ch->reason; + } + + /* drop the reference grabbed in xpc_allocate_msg() */ + xpc_msgqueue_deref(ch); + return ret; + } + } + + msg->flags |= XPC_M_READY; + + /* + * The preceding store of msg->flags must occur before the following + * load of ch->local_GP->put. + */ + mb(); + + /* see if the message is next in line to be sent, if so send it */ + + put = ch->local_GP->put; + if (put == msg_number) { + xpc_send_msgs(ch, put); + } + + /* drop the reference grabbed in xpc_allocate_msg() */ + xpc_msgqueue_deref(ch); + return ret; +} + + +/* + * Send a message previously allocated using xpc_initiate_allocate() on the + * specified channel connected to the specified partition. + * + * This routine will not wait for the message to be received, nor will + * notification be given when it does happen. Once this routine has returned + * the message entry allocated via xpc_initiate_allocate() is no longer + * accessable to the caller. + * + * This routine, 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_allocate_msg(). + * + * Arguments: + * + * partid - ID of partition to which the channel is connected. + * ch_number - channel # to send message on. + * payload - pointer to the payload area allocated via + * xpc_initiate_allocate(). + */ +enum xpc_retval +xpc_initiate_send(partid_t partid, int ch_number, void *payload) +{ + struct xpc_partition *part = &xpc_partitions[partid]; + struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); + enum xpc_retval ret; + + + dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *) msg, + partid, ch_number); + + DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); + DBUG_ON(msg == NULL); + + ret = xpc_send_msg(&part->channels[ch_number], msg, 0, NULL, NULL); + + return ret; +} + + +/* + * Send a message previously allocated using xpc_initiate_allocate on the + * specified channel connected to the specified partition. + * + * This routine will not wait for the message to be sent. Once this routine + * has returned the message entry allocated via xpc_initiate_allocate() is no + * longer accessable to the caller. + * + * Once the remote end of the channel has received the message, the function + * passed as an argument to xpc_initiate_send_notify() will be called. This + * allows the sender to free up or re-use any buffers referenced by the + * message, but does NOT mean the message has been processed at the remote + * end by a receiver. + * + * If this routine returns an error, the caller's function will NOT be called. + * + * This routine, 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_allocate_msg(). + * + * Arguments: + * + * partid - ID of partition to which the channel is connected. + * ch_number - channel # to send message on. + * payload - pointer to the payload area allocated via + * xpc_initiate_allocate(). + * func - function to call with asynchronous notification of message + * receipt. THIS FUNCTION MUST BE NON-BLOCKING. + * key - user-defined key to be passed to the function when it's called. + */ +enum xpc_retval +xpc_initiate_send_notify(partid_t partid, int ch_number, void *payload, + xpc_notify_func func, void *key) +{ + struct xpc_partition *part = &xpc_partitions[partid]; + struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); + enum xpc_retval ret; + + + dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *) msg, + partid, ch_number); + + DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); + DBUG_ON(msg == NULL); + DBUG_ON(func == NULL); + + ret = xpc_send_msg(&part->channels[ch_number], msg, XPC_N_CALL, + func, key); + return ret; +} + + +static struct xpc_msg * +xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) +{ + struct xpc_partition *part = &xpc_partitions[ch->partid]; + struct xpc_msg *remote_msg, *msg; + u32 msg_index, nmsgs; + u64 msg_offset; + enum xpc_retval ret; + + + if (mutex_lock_interruptible(&ch->msg_to_pull_mutex) != 0) { + /* we were interrupted by a signal */ + return NULL; + } + + while (get >= ch->next_msg_to_pull) { + + /* pull as many messages as are ready and able to be pulled */ + + msg_index = ch->next_msg_to_pull % ch->remote_nentries; + + DBUG_ON(ch->next_msg_to_pull >= + (volatile s64) ch->w_remote_GP.put); + nmsgs = (volatile s64) ch->w_remote_GP.put - + ch->next_msg_to_pull; + if (msg_index + nmsgs > ch->remote_nentries) { + /* ignore the ones that wrap the msg queue for now */ + nmsgs = ch->remote_nentries - msg_index; + } + + 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); + + if ((ret = xpc_pull_remote_cachelines(part, msg, remote_msg, + nmsgs * ch->msg_size)) != xpcSuccess) { + + dev_dbg(xpc_chan, "failed to pull %d msgs starting with" + " msg %ld from partition %d, channel=%d, " + "ret=%d\n", nmsgs, ch->next_msg_to_pull, + ch->partid, ch->number, ret); + + XPC_DEACTIVATE_PARTITION(part, ret); + + mutex_unlock(&ch->msg_to_pull_mutex); + return NULL; + } + + mb(); /* >>> this may not be needed, we're not sure */ + + ch->next_msg_to_pull += nmsgs; + } + + mutex_unlock(&ch->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->remote_msgqueue + msg_offset); + + return msg; +} + + +/* + * Get a message to be delivered. + */ +static struct xpc_msg * +xpc_get_deliverable_msg(struct xpc_channel *ch) +{ + struct xpc_msg *msg = NULL; + s64 get; + + + do { + if ((volatile u32) ch->flags & XPC_C_DISCONNECTING) { + break; + } + + get = (volatile s64) ch->w_local_GP.get; + if (get == (volatile s64) ch->w_remote_GP.put) { + break; + } + + /* There are messages waiting to be pulled and delivered. + * We need to try to secure one for ourselves. We'll do this + * by trying to increment w_local_GP.get and hope that no one + * else beats us to it. If they do, we'll we'll simply have + * to try again for the next one. + */ + + if (cmpxchg(&ch->w_local_GP.get, get, get + 1) == get) { + /* we got the entry referenced by get */ + + dev_dbg(xpc_chan, "w_local_GP.get changed to %ld, " + "partid=%d, channel=%d\n", get + 1, + ch->partid, ch->number); + + /* pull the message from the remote partition */ + + msg = xpc_pull_remote_msg(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)); + + break; + } + + } while (1); + + return msg; +} + + +/* + * Deliver a message to its intended recipient. + */ +void +xpc_deliver_msg(struct xpc_channel *ch) +{ + struct xpc_msg *msg; + + + if ((msg = xpc_get_deliverable_msg(ch)) != NULL) { + + /* + * This ref is taken to protect the payload itself from being + * freed before the user is finished with it, which the user + * indicates by calling xpc_initiate_received(). + */ + xpc_msgqueue_ref(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", + (void *) msg, msg->number, ch->partid, + ch->number); + + /* deliver the message to its intended recipient */ + ch->func(xpcMsgReceived, ch->partid, ch->number, + &msg->payload, ch->key); + + dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, " + "msg_number=%ld, partid=%d, channel=%d\n", + (void *) msg, msg->number, ch->partid, + ch->number); + } + + atomic_dec(&ch->kthreads_active); + } +} + + +/* + * 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 an IPI to the message sender's partition. + */ +static void +xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) +{ + struct xpc_msg *msg; + s64 get = initial_get + 1; + int send_IPI = 0; + + + while (1) { + + while (1) { + if (get == (volatile s64) ch->w_local_GP.get) { + break; + } + + msg = (struct xpc_msg *) ((u64) ch->remote_msgqueue + + (get % ch->remote_nentries) * ch->msg_size); + + if (!(msg->flags & XPC_M_DONE)) { + break; + } + + msg_flags |= msg->flags; + get++; + } + + if (get == initial_get) { + /* nothing's changed */ + break; + } + + if (cmpxchg_rel(&ch->local_GP->get, initial_get, get) != + initial_get) { + /* someone else beat us to it */ + DBUG_ON((volatile s64) ch->local_GP->get <= + initial_get); + break; + } + + /* we just set the new value of local_GP->get */ + + dev_dbg(xpc_chan, "local_GP->get changed to %ld, partid=%d, " + "channel=%d\n", get, ch->partid, ch->number); + + send_IPI = (msg_flags & XPC_M_INTERRUPT); + + /* + * We need to ensure that the message referenced by + * local_GP->get is not XPC_M_DONE or that local_GP->get + * equals w_local_GP.get, so we'll go have a look. + */ + initial_get = get; + } + + if (send_IPI) { + xpc_IPI_send_msgrequest(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. + * + * 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(). + * + * Arguments: + * + * partid - ID of partition to which the channel is connected. + * ch_number - channel # message received on. + * payload - pointer to the payload area allocated via + * xpc_initiate_allocate(). + */ +void +xpc_initiate_received(partid_t partid, int ch_number, void *payload) +{ + struct xpc_partition *part = &xpc_partitions[partid]; + struct xpc_channel *ch; + struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); + s64 get, msg_number = msg->number; + + + DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); + + ch = &part->channels[ch_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) != + msg_number % ch->remote_nentries); + DBUG_ON(msg->flags & XPC_M_DONE); + + msg->flags |= XPC_M_DONE; + + /* + * The preceding store of msg->flags must occur before the following + * load of ch->local_GP->get. + */ + mb(); + + /* + * See if this message is next in line to be acknowledged as having + * been delivered. + */ + get = ch->local_GP->get; + if (get == msg_number) { + xpc_acknowledge_msgs(ch, get, msg->flags); + } + + /* the call to xpc_msgqueue_ref() was done by xpc_deliver_msg() */ + xpc_msgqueue_deref(ch); +} + diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c new file mode 100644 index 00000000000..bdb2cf1fcbc --- /dev/null +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -0,0 +1,1431 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * Cross Partition Communication (XPC) support - standard version. + * + * XPC provides a message passing capability that crosses partition + * boundaries. This module is made up of two parts: + * + * partition This part detects the presence/absence of other + * partitions. It provides a heartbeat and monitors + * the heartbeats of other partitions. + * + * channel This part manages the channels and sends/receives + * messages across them to/from other partitions. + * + * There are a couple of additional functions residing in XP, which + * provide an interface to XPC for its users. + * + * + * Caveats: + * + * . We currently have no way to determine which nasid an IPI came + * from. Thus, xpc_IPI_send() does a remote AMO write followed by + * an IPI. The AMO indicates where data is to be pulled from, so + * after the IPI arrives, the remote partition checks the AMO word. + * The IPI can actually arrive before the AMO however, so other code + * must periodically check for this case. Also, remote AMO operations + * do not reliably time out. Thus we do a remote PIO read solely to + * know whether the remote partition is down and whether we should + * stop sending IPIs to it. This remote PIO read operation is set up + * in a special nofault region so SAL knows to ignore (and cleanup) + * any errors due to the remote AMO write, PIO read, and/or PIO + * write operations. + * + * If/when new hardware solves this IPI problem, we should abandon + * the current approach. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xpc.h" + + +/* define two XPC debug device structures to be used with dev_dbg() et al */ + +struct device_driver xpc_dbg_name = { + .name = "xpc" +}; + +struct device xpc_part_dbg_subname = { + .bus_id = {0}, /* set to "part" at xpc_init() time */ + .driver = &xpc_dbg_name +}; + +struct device xpc_chan_dbg_subname = { + .bus_id = {0}, /* set to "chan" at xpc_init() time */ + .driver = &xpc_dbg_name +}; + +struct device *xpc_part = &xpc_part_dbg_subname; +struct device *xpc_chan = &xpc_chan_dbg_subname; + + +static int xpc_kdebug_ignore; + + +/* systune related variables for /proc/sys directories */ + +static int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL; +static int xpc_hb_min_interval = 1; +static int xpc_hb_max_interval = 10; + +static int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_INTERVAL; +static int xpc_hb_check_min_interval = 10; +static int xpc_hb_check_max_interval = 120; + +int xpc_disengage_request_timelimit = XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT; +static int xpc_disengage_request_min_timelimit = 0; +static int xpc_disengage_request_max_timelimit = 120; + +static ctl_table xpc_sys_xpc_hb_dir[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "hb_interval", + .data = &xpc_hb_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xpc_hb_min_interval, + .extra2 = &xpc_hb_max_interval + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "hb_check_interval", + .data = &xpc_hb_check_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xpc_hb_check_min_interval, + .extra2 = &xpc_hb_check_max_interval + }, + {} +}; +static ctl_table xpc_sys_xpc_dir[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "hb", + .mode = 0555, + .child = xpc_sys_xpc_hb_dir + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "disengage_request_timelimit", + .data = &xpc_disengage_request_timelimit, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xpc_disengage_request_min_timelimit, + .extra2 = &xpc_disengage_request_max_timelimit + }, + {} +}; +static ctl_table xpc_sys_dir[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "xpc", + .mode = 0555, + .child = xpc_sys_xpc_dir + }, + {} +}; +static struct ctl_table_header *xpc_sysctl; + +/* non-zero if any remote partition disengage request was timed out */ +int xpc_disengage_request_timedout; + +/* #of IRQs received */ +static atomic_t xpc_act_IRQ_rcvd; + +/* IRQ handler notifies this wait queue on receipt of an IRQ */ +static DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq); + +static unsigned long xpc_hb_check_timeout; + +/* notification that the xpc_hb_checker thread has exited */ +static DECLARE_COMPLETION(xpc_hb_checker_exited); + +/* notification that the xpc_discovery thread has exited */ +static DECLARE_COMPLETION(xpc_discovery_exited); + + +static struct timer_list xpc_hb_timer; + + +static void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *); + + +static int xpc_system_reboot(struct notifier_block *, unsigned long, void *); +static struct notifier_block xpc_reboot_notifier = { + .notifier_call = xpc_system_reboot, +}; + +static int xpc_system_die(struct notifier_block *, unsigned long, void *); +static struct notifier_block xpc_die_notifier = { + .notifier_call = xpc_system_die, +}; + + +/* + * Timer function to enforce the timelimit on the partition disengage request. + */ +static void +xpc_timeout_partition_disengage_request(unsigned long data) +{ + struct xpc_partition *part = (struct xpc_partition *) data; + + + DBUG_ON(time_before(jiffies, part->disengage_request_timeout)); + + (void) xpc_partition_disengaged(part); + + DBUG_ON(part->disengage_request_timeout != 0); + DBUG_ON(xpc_partition_engaged(1UL << XPC_PARTID(part)) != 0); +} + + +/* + * Notify the heartbeat check thread that an IRQ has been received. + */ +static irqreturn_t +xpc_act_IRQ_handler(int irq, void *dev_id) +{ + atomic_inc(&xpc_act_IRQ_rcvd); + wake_up_interruptible(&xpc_act_IRQ_wq); + return IRQ_HANDLED; +} + + +/* + * Timer to produce the heartbeat. The timer structures function is + * already set when this is initially called. A tunable is used to + * specify when the next timeout should occur. + */ +static void +xpc_hb_beater(unsigned long dummy) +{ + xpc_vars->heartbeat++; + + if (time_after_eq(jiffies, xpc_hb_check_timeout)) { + wake_up_interruptible(&xpc_act_IRQ_wq); + } + + xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ); + add_timer(&xpc_hb_timer); +} + + +/* + * This thread is responsible for nearly all of the partition + * activation/deactivation. + */ +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() */ + + daemonize(XPC_HB_CHECK_THREAD_NAME); + + set_cpus_allowed(current, cpumask_of_cpu(XPC_HB_CHECK_CPU)); + + /* set our heartbeating to other partitions into motion */ + xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); + xpc_hb_beater(0); + + while (!(volatile int) xpc_exiting) { + + 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_act_IRQ_rcvd) - last_IRQ_count); + + + /* checking of remote heartbeats is skewed by IRQ handling */ + if (time_after_eq(jiffies, xpc_hb_check_timeout)) { + dev_dbg(xpc_part, "checking remote heartbeats\n"); + xpc_check_remote_hb(); + + /* + * We need to periodically recheck to ensure no + * IPI/AMO pairs have been missed. That check + * must always reset xpc_hb_check_timeout. + */ + force_IRQ = 1; + } + + + /* check for outstanding IRQs */ + new_IRQ_count = atomic_read(&xpc_act_IRQ_rcvd); + if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) { + force_IRQ = 0; + + dev_dbg(xpc_part, "found an IRQ to process; will be " + "resetting xpc_hb_check_timeout\n"); + + last_IRQ_count += xpc_identify_act_IRQ_sender(); + if (last_IRQ_count < new_IRQ_count) { + /* retry once to help avoid missing AMO */ + (void) xpc_identify_act_IRQ_sender(); + } + last_IRQ_count = new_IRQ_count; + + xpc_hb_check_timeout = jiffies + + (xpc_hb_check_interval * HZ); + } + + /* wait for IRQ or timeout */ + (void) wait_event_interruptible(xpc_act_IRQ_wq, + (last_IRQ_count < atomic_read(&xpc_act_IRQ_rcvd) || + time_after_eq(jiffies, xpc_hb_check_timeout) || + (volatile int) xpc_exiting)); + } + + dev_dbg(xpc_part, "heartbeat checker is exiting\n"); + + + /* mark this thread as having exited */ + complete(&xpc_hb_checker_exited); + return 0; +} + + +/* + * This thread will attempt to discover other partitions to activate + * based on info provided by SAL. This new thread is short lived and + * will exit once discovery is complete. + */ +static int +xpc_initiate_discovery(void *ignore) +{ + daemonize(XPC_DISCOVERY_THREAD_NAME); + + xpc_discovery(); + + dev_dbg(xpc_part, "discovery thread is exiting\n"); + + /* mark this thread as having exited */ + complete(&xpc_discovery_exited); + return 0; +} + + +/* + * Establish first contact with the remote partititon. This involves pulling + * the XPC per partition variables from the remote partition and waiting for + * the remote partition to pull ours. + */ +static enum xpc_retval +xpc_make_first_contact(struct xpc_partition *part) +{ + enum xpc_retval ret; + + + while ((ret = xpc_pull_remote_vars_part(part)) != xpcSuccess) { + if (ret != xpcRetry) { + XPC_DEACTIVATE_PARTITION(part, ret); + return ret; + } + + dev_dbg(xpc_chan, "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_DEACTIVATING) { + return part->reason; + } + } + + return xpc_mark_partition_active(part); +} + + +/* + * The first kthread assigned to a newly activated partition is the one + * created by XPC HB with which it calls xpc_partition_up(). XPC hangs on to + * that kthread until the partition is brought down, at which time that kthread + * returns back to XPC HB. (The return of that kthread will signify to XPC HB + * that XPC has dismantled all communication infrastructure for the associated + * partition.) This kthread becomes the channel manager for that partition. + * + * Each active partition has a channel manager, who, besides connecting and + * disconnecting channels, will ensure that each of the partition's connected + * channels has the required number of assigned kthreads to get the work done. + */ +static void +xpc_channel_mgr(struct xpc_partition *part) +{ + while (part->act_state != XPC_P_DEACTIVATING || + atomic_read(&part->nchannels_active) > 0 || + !xpc_partition_disengaged(part)) { + + xpc_process_channel_activity(part); + + + /* + * Wait until we've been requested to activate kthreads or + * all of the channel's message queues have been torn down or + * a signal is pending. + * + * The channel_mgr_requests is set to 1 after being awakened, + * This is done to prevent the channel mgr from making one pass + * through the loop for each request, since he will + * be servicing all the requests in one pass. The reason it's + * set to 1 instead of 0 is so that other kthreads will know + * that the channel mgr is running and won't bother trying to + * wake him up. + */ + atomic_dec(&part->channel_mgr_requests); + (void) wait_event_interruptible(part->channel_mgr_wq, + (atomic_read(&part->channel_mgr_requests) > 0 || + (volatile u64) part->local_IPI_amo != 0 || + ((volatile u8) part->act_state == + XPC_P_DEACTIVATING && + atomic_read(&part->nchannels_active) == 0 && + xpc_partition_disengaged(part)))); + atomic_set(&part->channel_mgr_requests, 1); + + // >>> Does it need to wakeup periodically as well? In case we + // >>> miscalculated the #of kthreads to wakeup or create? + } +} + + +/* + * 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 + * upped partition. + * + * The kthread that was created by XPC HB and which setup the XPC + * infrastructure will remain assigned to the partition until the partition + * goes down. At which time the kthread will teardown the XPC infrastructure + * and then exit. + * + * XPC HB will put the remote partition's XPC per partition specific variables + * physical address into xpc_partitions[partid].remote_vars_part_pa prior to + * calling xpc_partition_up(). + */ +static void +xpc_partition_up(struct xpc_partition *part) +{ + DBUG_ON(part->channels != NULL); + + dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part)); + + if (xpc_setup_infrastructure(part) != xpcSuccess) { + return; + } + + /* + * The kthread that XPC HB called us with will become the + * channel manager for this partition. It will not return + * back to XPC HB until the partition's XPC infrastructure + * has been dismantled. + */ + + (void) xpc_part_ref(part); /* this will always succeed */ + + if (xpc_make_first_contact(part) == xpcSuccess) { + xpc_channel_mgr(part); + } + + xpc_part_deref(part); + + xpc_teardown_infrastructure(part); +} + + +static int +xpc_activating(void *__partid) +{ + partid_t partid = (u64) __partid; + struct xpc_partition *part = &xpc_partitions[partid]; + unsigned long irq_flags; + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + int ret; + + + DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + + spin_lock_irqsave(&part->act_lock, irq_flags); + + if (part->act_state == XPC_P_DEACTIVATING) { + part->act_state = XPC_P_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; + + XPC_SET_REASON(part, 0, 0); + spin_unlock_irqrestore(&part->act_lock, irq_flags); + + dev_dbg(xpc_part, "bringing partition %d up\n", partid); + + daemonize("xpc%02d", partid); + + /* + * This thread needs to run at a realtime priority to prevent a + * significant performance degradation. + */ + ret = sched_setscheduler(current, SCHED_FIFO, ¶m); + if (ret != 0) { + dev_warn(xpc_part, "unable to set pid %d to a realtime " + "priority, ret=%d\n", current->pid, ret); + } + + /* allow this thread and its children to run on any CPU */ + set_cpus_allowed(current, CPU_MASK_ALL); + + /* + * Register the remote partition's AMOs with SAL so it can handle + * and cleanup errors within that address range should the remote + * partition go down. We don't unregister this range because it is + * difficult to tell when outstanding writes to the remote partition + * are finished and thus when it is safe to unregister. This should + * not result in wasted space in the SAL xp_addr_region table because + * we should get the same page for remote_amos_page_pa after module + * reloads and system reboots. + */ + if (sn_register_xp_addr_region(part->remote_amos_page_pa, + PAGE_SIZE, 1) < 0) { + dev_warn(xpc_part, "xpc_partition_up(%d) failed to register " + "xp_addr region\n", partid); + + spin_lock_irqsave(&part->act_lock, irq_flags); + part->act_state = XPC_P_INACTIVE; + XPC_SET_REASON(part, xpcPhysAddrRegFailed, __LINE__); + spin_unlock_irqrestore(&part->act_lock, irq_flags); + part->remote_rp_pa = 0; + return 0; + } + + xpc_allow_hb(partid, xpc_vars); + xpc_IPI_send_activated(part); + + + /* + * xpc_partition_up() holds this thread and marks this partition as + * XPC_P_ACTIVE by calling xpc_hb_mark_active(). + */ + (void) xpc_partition_up(part); + + xpc_disallow_hb(partid, xpc_vars); + xpc_mark_partition_inactive(part); + + if (part->reason == xpcReactivating) { + /* interrupting ourselves results in activating partition */ + xpc_IPI_send_reactivate(part); + } + + return 0; +} + + +void +xpc_activate_partition(struct xpc_partition *part) +{ + partid_t partid = XPC_PARTID(part); + unsigned long irq_flags; + pid_t pid; + + + spin_lock_irqsave(&part->act_lock, irq_flags); + + DBUG_ON(part->act_state != XPC_P_INACTIVE); + + part->act_state = XPC_P_ACTIVATION_REQ; + XPC_SET_REASON(part, xpcCloneKThread, __LINE__); + + spin_unlock_irqrestore(&part->act_lock, irq_flags); + + pid = kernel_thread(xpc_activating, (void *) ((u64) partid), 0); + + if (unlikely(pid <= 0)) { + spin_lock_irqsave(&part->act_lock, irq_flags); + part->act_state = XPC_P_INACTIVE; + XPC_SET_REASON(part, xpcCloneKThreadFailed, __LINE__); + spin_unlock_irqrestore(&part->act_lock, irq_flags); + } +} + + +/* + * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified + * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more + * than one partition, we use an AMO_t structure per partition to indicate + * whether a partition has sent an IPI or not. >>> If it has, then wake up the + * associated kthread to handle it. + * + * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IPIs sent by XPC + * running on other partitions. + * + * Noteworthy Arguments: + * + * irq - Interrupt ReQuest number. NOT USED. + * + * dev_id - partid of IPI's potential sender. + */ +irqreturn_t +xpc_notify_IRQ_handler(int irq, void *dev_id) +{ + partid_t partid = (partid_t) (u64) dev_id; + struct xpc_partition *part = &xpc_partitions[partid]; + + + DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + + if (xpc_part_ref(part)) { + xpc_check_for_channel_activity(part); + + xpc_part_deref(part); + } + return IRQ_HANDLED; +} + + +/* + * Check to see if xpc_notify_IRQ_handler() dropped any IPIs on the floor + * because the write to their associated IPI amo completed after the IRQ/IPI + * was received. + */ +void +xpc_dropped_IPI_check(struct xpc_partition *part) +{ + if (xpc_part_ref(part)) { + xpc_check_for_channel_activity(part); + + part->dropped_IPI_timer.expires = jiffies + + XPC_P_DROPPED_IPI_WAIT; + add_timer(&part->dropped_IPI_timer); + xpc_part_deref(part); + } +} + + +void +xpc_activate_kthreads(struct xpc_channel *ch, int needed) +{ + int idle = atomic_read(&ch->kthreads_idle); + int assigned = atomic_read(&ch->kthreads_assigned); + int wakeup; + + + DBUG_ON(needed <= 0); + + if (idle > 0) { + wakeup = (needed > idle) ? idle : needed; + needed -= wakeup; + + dev_dbg(xpc_chan, "wakeup %d idle kthreads, partid=%d, " + "channel=%d\n", wakeup, ch->partid, ch->number); + + /* only wakeup the requested number of kthreads */ + wake_up_nr(&ch->idle_wq, wakeup); + } + + if (needed <= 0) { + return; + } + + if (needed + assigned > ch->kthreads_assigned_limit) { + needed = ch->kthreads_assigned_limit - assigned; + // >>>should never be less than 0 + if (needed <= 0) { + return; + } + } + + dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n", + needed, ch->partid, ch->number); + + xpc_create_kthreads(ch, needed, 0); +} + + +/* + * This function is where XPC's kthreads wait for messages to deliver. + */ +static void +xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) +{ + do { + /* deliver messages to their intended recipients */ + + while ((volatile s64) ch->w_local_GP.get < + (volatile s64) ch->w_remote_GP.put && + !((volatile u32) ch->flags & + XPC_C_DISCONNECTING)) { + xpc_deliver_msg(ch); + } + + if (atomic_inc_return(&ch->kthreads_idle) > + ch->kthreads_idle_limit) { + /* too many idle kthreads on this channel */ + atomic_dec(&ch->kthreads_idle); + break; + } + + dev_dbg(xpc_chan, "idle kthread calling " + "wait_event_interruptible_exclusive()\n"); + + (void) wait_event_interruptible_exclusive(ch->idle_wq, + ((volatile s64) ch->w_local_GP.get < + (volatile s64) ch->w_remote_GP.put || + ((volatile u32) ch->flags & + XPC_C_DISCONNECTING))); + + atomic_dec(&ch->kthreads_idle); + + } while (!((volatile u32) ch->flags & XPC_C_DISCONNECTING)); +} + + +static int +xpc_daemonize_kthread(void *args) +{ + partid_t partid = XPC_UNPACK_ARG1(args); + u16 ch_number = XPC_UNPACK_ARG2(args); + struct xpc_partition *part = &xpc_partitions[partid]; + struct xpc_channel *ch; + int n_needed; + unsigned long irq_flags; + + + daemonize("xpc%02dc%d", partid, ch_number); + + dev_dbg(xpc_chan, "kthread starting, partid=%d, channel=%d\n", + partid, ch_number); + + ch = &part->channels[ch_number]; + + if (!(ch->flags & XPC_C_DISCONNECTING)) { + + /* let registerer know that connection has been established */ + + spin_lock_irqsave(&ch->lock, irq_flags); + if (!(ch->flags & XPC_C_CONNECTEDCALLOUT)) { + ch->flags |= XPC_C_CONNECTEDCALLOUT; + spin_unlock_irqrestore(&ch->lock, irq_flags); + + xpc_connected_callout(ch); + + spin_lock_irqsave(&ch->lock, irq_flags); + ch->flags |= XPC_C_CONNECTEDCALLOUT_MADE; + spin_unlock_irqrestore(&ch->lock, irq_flags); + + /* + * It is possible that while the callout was being + * made that the remote partition sent some messages. + * If that is the case, we may need to activate + * additional kthreads to help deliver them. We only + * need one less than total #of messages to deliver. + */ + n_needed = ch->w_remote_GP.put - ch->w_local_GP.get - 1; + if (n_needed > 0 && + !(ch->flags & XPC_C_DISCONNECTING)) { + xpc_activate_kthreads(ch, n_needed); + } + } else { + spin_unlock_irqrestore(&ch->lock, irq_flags); + } + + xpc_kthread_waitmsgs(part, ch); + } + + /* let registerer know that connection is disconnecting */ + + spin_lock_irqsave(&ch->lock, irq_flags); + if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && + !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) { + ch->flags |= XPC_C_DISCONNECTINGCALLOUT; + spin_unlock_irqrestore(&ch->lock, irq_flags); + + xpc_disconnect_callout(ch, xpcDisconnecting); + + spin_lock_irqsave(&ch->lock, irq_flags); + ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE; + } + spin_unlock_irqrestore(&ch->lock, irq_flags); + + if (atomic_dec_return(&ch->kthreads_assigned) == 0) { + if (atomic_dec_return(&part->nchannels_engaged) == 0) { + xpc_mark_partition_disengaged(part); + xpc_IPI_send_disengage(part); + } + } + + xpc_msgqueue_deref(ch); + + dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n", + partid, ch_number); + + xpc_part_deref(part); + return 0; +} + + +/* + * For each partition that XPC has established communications with, there is + * a minimum of one kernel thread assigned to perform any operation that + * may potentially sleep or block (basically the callouts to the asynchronous + * functions registered via xpc_connect()). + * + * Additional kthreads are created and destroyed by XPC as the workload + * demands. + * + * A kthread is assigned to one of the active channels that exists for a given + * partition. + */ +void +xpc_create_kthreads(struct xpc_channel *ch, int needed, + int ignore_disconnecting) +{ + unsigned long irq_flags; + pid_t pid; + u64 args = XPC_PACK_ARGS(ch->partid, ch->number); + struct xpc_partition *part = &xpc_partitions[ch->partid]; + + + while (needed-- > 0) { + + /* + * The following is done on behalf of the newly created + * kthread. That kthread is responsible for doing the + * counterpart to the following before it exits. + */ + if (ignore_disconnecting) { + if (!atomic_inc_not_zero(&ch->kthreads_assigned)) { + /* kthreads assigned had gone to zero */ + BUG_ON(!(ch->flags & + XPC_C_DISCONNECTINGCALLOUT_MADE)); + break; + } + + } else if (ch->flags & XPC_C_DISCONNECTING) { + break; + + } else if (atomic_inc_return(&ch->kthreads_assigned) == 1) { + if (atomic_inc_return(&part->nchannels_engaged) == 1) + xpc_mark_partition_engaged(part); + } + (void) xpc_part_ref(part); + xpc_msgqueue_ref(ch); + + pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0); + if (pid < 0) { + /* the fork failed */ + + /* + * NOTE: if (ignore_disconnecting && + * !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) is true, + * then we'll deadlock if all other kthreads assigned + * to this channel are blocked in the channel's + * registerer, because the only thing that will unblock + * them is the xpcDisconnecting callout that this + * failed kernel_thread would have made. + */ + + if (atomic_dec_return(&ch->kthreads_assigned) == 0 && + atomic_dec_return(&part->nchannels_engaged) == 0) { + xpc_mark_partition_disengaged(part); + xpc_IPI_send_disengage(part); + } + xpc_msgqueue_deref(ch); + xpc_part_deref(part); + + if (atomic_read(&ch->kthreads_assigned) < + ch->kthreads_idle_limit) { + /* + * Flag this as an error only if we have an + * insufficient #of kthreads for the channel + * to function. + */ + spin_lock_irqsave(&ch->lock, irq_flags); + XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources, + &irq_flags); + spin_unlock_irqrestore(&ch->lock, irq_flags); + } + break; + } + + ch->kthreads_created++; // >>> temporary debug only!!! + } +} + + +void +xpc_disconnect_wait(int ch_number) +{ + unsigned long irq_flags; + partid_t partid; + struct xpc_partition *part; + struct xpc_channel *ch; + int wakeup_channel_mgr; + + + /* now wait for all callouts to the caller's function to cease */ + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + part = &xpc_partitions[partid]; + + if (!xpc_part_ref(part)) { + continue; + } + + ch = &part->channels[ch_number]; + + if (!(ch->flags & XPC_C_WDISCONNECT)) { + xpc_part_deref(part); + continue; + } + + wait_for_completion(&ch->wdisconnect_wait); + + spin_lock_irqsave(&ch->lock, irq_flags); + DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED)); + wakeup_channel_mgr = 0; + + if (ch->delayed_IPI_flags) { + if (part->act_state != XPC_P_DEACTIVATING) { + spin_lock(&part->IPI_lock); + XPC_SET_IPI_FLAGS(part->local_IPI_amo, + ch->number, ch->delayed_IPI_flags); + spin_unlock(&part->IPI_lock); + wakeup_channel_mgr = 1; + } + ch->delayed_IPI_flags = 0; + } + + ch->flags &= ~XPC_C_WDISCONNECT; + spin_unlock_irqrestore(&ch->lock, irq_flags); + + if (wakeup_channel_mgr) { + xpc_wakeup_channel_mgr(part); + } + + xpc_part_deref(part); + } +} + + +static void +xpc_do_exit(enum xpc_retval reason) +{ + partid_t partid; + int active_part_count, printed_waiting_msg = 0; + struct xpc_partition *part; + unsigned long printmsg_time, disengage_request_timeout = 0; + + + /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ + DBUG_ON(xpc_exiting == 1); + + /* + * Let the heartbeat checker thread and the discovery thread + * (if one is running) know that they should exit. Also wake up + * the heartbeat checker thread in case it's sleeping. + */ + xpc_exiting = 1; + wake_up_interruptible(&xpc_act_IRQ_wq); + + /* ignore all incoming interrupts */ + free_irq(SGI_XPC_ACTIVATE, NULL); + + /* wait for the discovery thread to exit */ + wait_for_completion(&xpc_discovery_exited); + + /* wait for the heartbeat checker thread to exit */ + wait_for_completion(&xpc_hb_checker_exited); + + + /* sleep for a 1/3 of a second or so */ + (void) msleep_interruptible(300); + + + /* wait for all partitions to become inactive */ + + printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); + xpc_disengage_request_timedout = 0; + + do { + active_part_count = 0; + + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + part = &xpc_partitions[partid]; + + if (xpc_partition_disengaged(part) && + part->act_state == XPC_P_INACTIVE) { + continue; + } + + active_part_count++; + + XPC_DEACTIVATE_PARTITION(part, reason); + + if (part->disengage_request_timeout > + disengage_request_timeout) { + disengage_request_timeout = + part->disengage_request_timeout; + } + } + + if (xpc_partition_engaged(-1UL)) { + if (time_after(jiffies, printmsg_time)) { + dev_info(xpc_part, "waiting for remote " + "partitions to disengage, timeout in " + "%ld seconds\n", + (disengage_request_timeout - jiffies) + / HZ); + printmsg_time = jiffies + + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); + printed_waiting_msg = 1; + } + + } else if (active_part_count > 0) { + if (printed_waiting_msg) { + dev_info(xpc_part, "waiting for local partition" + " to disengage\n"); + printed_waiting_msg = 0; + } + + } else { + if (!xpc_disengage_request_timedout) { + dev_info(xpc_part, "all partitions have " + "disengaged\n"); + } + break; + } + + /* sleep for a 1/3 of a second or so */ + (void) msleep_interruptible(300); + + } while (1); + + DBUG_ON(xpc_partition_engaged(-1UL)); + + + /* indicate to others that our reserved page is uninitialized */ + xpc_rsvd_page->vars_pa = 0; + + /* now it's time to eliminate our heartbeat */ + del_timer_sync(&xpc_hb_timer); + DBUG_ON(xpc_vars->heartbeating_to_mask != 0); + + if (reason == xpcUnloading) { + /* take ourselves off of the reboot_notifier_list */ + (void) unregister_reboot_notifier(&xpc_reboot_notifier); + + /* take ourselves off of the die_notifier list */ + (void) unregister_die_notifier(&xpc_die_notifier); + } + + /* close down protections for IPI operations */ + xpc_restrict_IPI_ops(); + + + /* clear the interface to XPC's functions */ + xpc_clear_interface(); + + if (xpc_sysctl) { + unregister_sysctl_table(xpc_sysctl); + } + + kfree(xpc_remote_copy_buffer_base); +} + + +/* + * This function is called when the system is being rebooted. + */ +static int +xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused) +{ + enum xpc_retval reason; + + + switch (event) { + case SYS_RESTART: + reason = xpcSystemReboot; + break; + case SYS_HALT: + reason = xpcSystemHalt; + break; + case SYS_POWER_OFF: + reason = xpcSystemPoweroff; + break; + default: + reason = xpcSystemGoingDown; + } + + xpc_do_exit(reason); + return NOTIFY_DONE; +} + + +/* + * Notify other partitions to disengage from all references to our memory. + */ +static void +xpc_die_disengage(void) +{ + struct xpc_partition *part; + partid_t partid; + unsigned long engaged; + long time, printmsg_time, disengage_request_timeout; + + + /* keep xpc_hb_checker thread from doing anything (just in case) */ + xpc_exiting = 1; + + xpc_vars->heartbeating_to_mask = 0; /* indicate we're deactivated */ + + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + part = &xpc_partitions[partid]; + + if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part-> + remote_vars_version)) { + + /* just in case it was left set by an earlier XPC */ + xpc_clear_partition_engaged(1UL << partid); + continue; + } + + if (xpc_partition_engaged(1UL << partid) || + part->act_state != XPC_P_INACTIVE) { + xpc_request_partition_disengage(part); + xpc_mark_partition_disengaged(part); + xpc_IPI_send_disengage(part); + } + } + + time = rtc_time(); + printmsg_time = time + + (XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second); + disengage_request_timeout = time + + (xpc_disengage_request_timelimit * sn_rtc_cycles_per_second); + + /* wait for all other partitions to disengage from us */ + + while (1) { + engaged = xpc_partition_engaged(-1UL); + if (!engaged) { + dev_info(xpc_part, "all partitions have disengaged\n"); + break; + } + + time = rtc_time(); + if (time >= disengage_request_timeout) { + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + if (engaged & (1UL << partid)) { + dev_info(xpc_part, "disengage from " + "remote partition %d timed " + "out\n", partid); + } + } + break; + } + + if (time >= printmsg_time) { + dev_info(xpc_part, "waiting for remote partitions to " + "disengage, timeout in %ld seconds\n", + (disengage_request_timeout - time) / + sn_rtc_cycles_per_second); + printmsg_time = time + + (XPC_DISENGAGE_PRINTMSG_INTERVAL * + sn_rtc_cycles_per_second); + } + } +} + + +/* + * This function is called when the system is being restarted or halted due + * to some sort of system failure. If this is the case we need to notify the + * other partitions to disengage from all references to our memory. + * This function can also be called when our heartbeater could be offlined + * for a time. In this case we need to notify other partitions to not worry + * about the lack of a heartbeat. + */ +static int +xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) +{ + switch (event) { + case DIE_MACHINE_RESTART: + case DIE_MACHINE_HALT: + xpc_die_disengage(); + break; + + case DIE_KDEBUG_ENTER: + /* Should lack of heartbeat be ignored by other partitions? */ + if (!xpc_kdebug_ignore) { + break; + } + /* fall through */ + case DIE_MCA_MONARCH_ENTER: + case DIE_INIT_MONARCH_ENTER: + xpc_vars->heartbeat++; + xpc_vars->heartbeat_offline = 1; + break; + + case DIE_KDEBUG_LEAVE: + /* Is lack of heartbeat being ignored by other partitions? */ + if (!xpc_kdebug_ignore) { + break; + } + /* fall through */ + case DIE_MCA_MONARCH_LEAVE: + case DIE_INIT_MONARCH_LEAVE: + xpc_vars->heartbeat++; + xpc_vars->heartbeat_offline = 0; + break; + } + + return NOTIFY_DONE; +} + + +int __init +xpc_init(void) +{ + int ret; + partid_t partid; + struct xpc_partition *part; + pid_t pid; + size_t buf_size; + + + if (!ia64_platform_is("sn2")) { + return -ENODEV; + } + + + buf_size = max(XPC_RP_VARS_SIZE, + XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES); + xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size, + GFP_KERNEL, &xpc_remote_copy_buffer_base); + if (xpc_remote_copy_buffer == NULL) + return -ENOMEM; + + snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); + snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); + + xpc_sysctl = register_sysctl_table(xpc_sys_dir); + + /* + * 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 = 1; partid < XP_MAX_PARTITIONS; partid++) { + part = &xpc_partitions[partid]; + + DBUG_ON((u64) part != L1_CACHE_ALIGN((u64) part)); + + part->act_IRQ_rcvd = 0; + spin_lock_init(&part->act_lock); + part->act_state = XPC_P_INACTIVE; + XPC_SET_REASON(part, 0, 0); + + init_timer(&part->disengage_request_timer); + part->disengage_request_timer.function = + xpc_timeout_partition_disengage_request; + part->disengage_request_timer.data = (unsigned long) part; + + part->setup_state = XPC_P_UNSET; + init_waitqueue_head(&part->teardown_wq); + atomic_set(&part->references, 0); + } + + /* + * Open up protections for IPI operations (and AMO operations on + * Shub 1.1 systems). + */ + xpc_allow_IPI_ops(); + + /* + * Interrupts being processed will increment this atomic variable and + * awaken the heartbeat thread which will process the interrupts. + */ + atomic_set(&xpc_act_IRQ_rcvd, 0); + + /* + * This is safe to do before the xpc_hb_checker thread has started + * because the handler releases a wait queue. If an interrupt is + * received before the thread is waiting, it will not go to sleep, + * but rather immediately process the interrupt. + */ + ret = request_irq(SGI_XPC_ACTIVATE, xpc_act_IRQ_handler, 0, + "xpc hb", NULL); + if (ret != 0) { + dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " + "errno=%d\n", -ret); + + xpc_restrict_IPI_ops(); + + if (xpc_sysctl) { + unregister_sysctl_table(xpc_sysctl); + } + + kfree(xpc_remote_copy_buffer_base); + return -EBUSY; + } + + /* + * Fill the partition reserved page with the information needed by + * other partitions to discover we are alive and establish initial + * communications. + */ + xpc_rsvd_page = xpc_rsvd_page_init(); + if (xpc_rsvd_page == NULL) { + dev_err(xpc_part, "could not setup our reserved page\n"); + + free_irq(SGI_XPC_ACTIVATE, NULL); + xpc_restrict_IPI_ops(); + + if (xpc_sysctl) { + unregister_sysctl_table(xpc_sysctl); + } + + kfree(xpc_remote_copy_buffer_base); + return -EBUSY; + } + + + /* add ourselves to the reboot_notifier_list */ + ret = register_reboot_notifier(&xpc_reboot_notifier); + if (ret != 0) { + dev_warn(xpc_part, "can't register reboot notifier\n"); + } + + /* add ourselves to the die_notifier list */ + ret = register_die_notifier(&xpc_die_notifier); + if (ret != 0) { + dev_warn(xpc_part, "can't register die notifier\n"); + } + + init_timer(&xpc_hb_timer); + xpc_hb_timer.function = xpc_hb_beater; + + /* + * The real work-horse behind xpc. This processes incoming + * interrupts and monitors remote heartbeats. + */ + pid = kernel_thread(xpc_hb_checker, NULL, 0); + if (pid < 0) { + dev_err(xpc_part, "failed while forking hb check thread\n"); + + /* indicate to others that our reserved page is uninitialized */ + xpc_rsvd_page->vars_pa = 0; + + /* take ourselves off of the reboot_notifier_list */ + (void) unregister_reboot_notifier(&xpc_reboot_notifier); + + /* take ourselves off of the die_notifier list */ + (void) unregister_die_notifier(&xpc_die_notifier); + + del_timer_sync(&xpc_hb_timer); + free_irq(SGI_XPC_ACTIVATE, NULL); + xpc_restrict_IPI_ops(); + + if (xpc_sysctl) { + unregister_sysctl_table(xpc_sysctl); + } + + kfree(xpc_remote_copy_buffer_base); + return -EBUSY; + } + + + /* + * Startup a thread that will attempt to discover other partitions to + * activate based on info provided by SAL. This new thread is short + * lived and will exit once discovery is complete. + */ + pid = kernel_thread(xpc_initiate_discovery, NULL, 0); + if (pid < 0) { + dev_err(xpc_part, "failed while forking discovery thread\n"); + + /* mark this new thread as a non-starter */ + complete(&xpc_discovery_exited); + + xpc_do_exit(xpcUnloading); + return -EBUSY; + } + + + /* set the interface to point at XPC's functions */ + xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect, + xpc_initiate_allocate, xpc_initiate_send, + xpc_initiate_send_notify, xpc_initiate_received, + xpc_initiate_partid_to_nasids); + + return 0; +} +module_init(xpc_init); + + +void __exit +xpc_exit(void) +{ + xpc_do_exit(xpcUnloading); +} +module_exit(xpc_exit); + + +MODULE_AUTHOR("Silicon Graphics, Inc."); +MODULE_DESCRIPTION("Cross Partition Communication (XPC) support"); +MODULE_LICENSE("GPL"); + +module_param(xpc_hb_interval, int, 0); +MODULE_PARM_DESC(xpc_hb_interval, "Number of seconds between " + "heartbeat increments."); + +module_param(xpc_hb_check_interval, int, 0); +MODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between " + "heartbeat checks."); + +module_param(xpc_disengage_request_timelimit, int, 0); +MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait " + "for disengage request to complete."); + +module_param(xpc_kdebug_ignore, int, 0); +MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by " + "other partitions when dropping into kdebug."); + diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c new file mode 100644 index 00000000000..7412dc7351c --- /dev/null +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -0,0 +1,1239 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * Cross Partition Communication (XPC) partition support. + * + * This is the part of XPC that detects the presence/absence of + * other partitions. It provides a heartbeat and monitors the + * heartbeats of other partitions. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xpc.h" + + +/* XPC is exiting flag */ +int xpc_exiting; + + +/* SH_IPI_ACCESS shub register value on startup */ +static u64 xpc_sh1_IPI_access; +static u64 xpc_sh2_IPI_access0; +static u64 xpc_sh2_IPI_access1; +static u64 xpc_sh2_IPI_access2; +static u64 xpc_sh2_IPI_access3; + + +/* original protection values for each node */ +u64 xpc_prot_vec[MAX_NUMNODES]; + + +/* this partition's reserved page pointers */ +struct xpc_rsvd_page *xpc_rsvd_page; +static u64 *xpc_part_nasids; +static u64 *xpc_mach_nasids; +struct xpc_vars *xpc_vars; +struct xpc_vars_part *xpc_vars_part; + +static int xp_nasid_mask_bytes; /* actual size in bytes of nasid mask */ +static int xp_nasid_mask_words; /* actual size in words of nasid mask */ + + +/* + * For performance reasons, each entry of xpc_partitions[] is cacheline + * aligned. And xpc_partitions[] is padded with an additional entry at the + * end so that the last legitimate entry doesn't share its cacheline with + * another variable. + */ +struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1]; + + +/* + * Generic 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). + */ +char *xpc_remote_copy_buffer; +void *xpc_remote_copy_buffer_base; + + +/* + * Guarantee that the kmalloc'd memory is cacheline aligned. + */ +void * +xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) +{ + /* see if kmalloc will give us cachline aligned memory by default */ + *base = kmalloc(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 = kmalloc(size + L1_CACHE_BYTES, flags); + if (*base == NULL) { + return NULL; + } + return (void *) L1_CACHE_ALIGN((u64) *base); +} + + +/* + * 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 +xpc_get_rsvd_page_pa(int nasid) +{ + bte_result_t bte_res; + s64 status; + u64 cookie = 0; + u64 rp_pa = nasid; /* seed with nasid */ + u64 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); + + dev_dbg(xpc_part, "SAL returned with status=%li, cookie=" + "0x%016lx, address=0x%016lx, len=0x%016lx\n", + status, cookie, rp_pa, len); + + if (status != SALRET_MORE_PASSES) { + break; + } + + 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); + if (buf_base == NULL) { + dev_err(xpc_part, "unable to kmalloc " + "len=0x%016lx\n", buf_len); + status = SALRET_ERROR; + break; + } + } + + bte_res = xp_bte_copy(rp_pa, buf, buf_len, + (BTE_NOTIFY | BTE_WACQUIRE), NULL); + if (bte_res != BTE_SUCCESS) { + dev_dbg(xpc_part, "xp_bte_copy failed %i\n", bte_res); + status = SALRET_ERROR; + break; + } + } + + kfree(buf_base); + + if (status != SALRET_OK) { + rp_pa = 0; + } + dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa); + return rp_pa; +} + + +/* + * Fill the partition reserved page with the information needed by + * other partitions to discover we are alive and establish initial + * communications. + */ +struct xpc_rsvd_page * +xpc_rsvd_page_init(void) +{ + struct xpc_rsvd_page *rp; + AMO_t *amos_page; + u64 rp_pa, nasid_array = 0; + int i, ret; + + + /* get the local reserved page's address */ + + preempt_disable(); + rp_pa = xpc_get_rsvd_page_pa(cpuid_to_nasid(smp_processor_id())); + preempt_enable(); + if (rp_pa == 0) { + dev_err(xpc_part, "SAL failed to locate the reserved page\n"); + return NULL; + } + rp = (struct xpc_rsvd_page *) __va(rp_pa); + + if (rp->partid != sn_partition_id) { + dev_err(xpc_part, "the reserved page's partid of %d should be " + "%d\n", rp->partid, sn_partition_id); + return NULL; + } + + rp->version = XPC_RP_VERSION; + + /* establish the actual sizes of the nasid masks */ + if (rp->SAL_version == 1) { + /* SAL_version 1 didn't set the nasids_size field */ + rp->nasids_size = 128; + } + xp_nasid_mask_bytes = rp->nasids_size; + xp_nasid_mask_words = xp_nasid_mask_bytes / 8; + + /* setup the pointers to the various items in the reserved page */ + xpc_part_nasids = XPC_RP_PART_NASIDS(rp); + xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); + xpc_vars = XPC_RP_VARS(rp); + xpc_vars_part = XPC_RP_VARS_PART(rp); + + /* + * Before clearing xpc_vars, see if a page of AMOs had been previously + * allocated. If not we'll need to allocate one and set permissions + * so that cross-partition AMOs are allowed. + * + * The allocated AMO page needs MCA reporting to remain disabled after + * XPC has unloaded. To make this work, we keep a copy of the pointer + * to this page (i.e., amos_page) in the struct xpc_vars structure, + * which is pointed to by the reserved page, and re-use that saved copy + * on subsequent loads of XPC. This AMO page is never freed, and its + * memory protections are never restricted. + */ + if ((amos_page = xpc_vars->amos_page) == NULL) { + amos_page = (AMO_t *) TO_AMO(uncached_alloc_page(0)); + if (amos_page == NULL) { + dev_err(xpc_part, "can't allocate page of AMOs\n"); + return NULL; + } + + /* + * Open up AMO-R/W to cpu. This is done for Shub 1.1 systems + * when xpc_allow_IPI_ops() is called via xpc_hb_init(). + */ + if (!enable_shub_wars_1_1()) { + ret = sn_change_memprotect(ia64_tpa((u64) amos_page), + PAGE_SIZE, SN_MEMPROT_ACCESS_CLASS_1, + &nasid_array); + if (ret != 0) { + dev_err(xpc_part, "can't change memory " + "protections\n"); + uncached_free_page(__IA64_UNCACHED_OFFSET | + TO_PHYS((u64) amos_page)); + return NULL; + } + } + } else if (!IS_AMO_ADDRESS((u64) amos_page)) { + /* + * EFI's XPBOOT can also set amos_page in the reserved page, + * but it happens to leave it as an uncached physical address + * and we need it to be an uncached virtual, so we'll have to + * convert it. + */ + if (!IS_AMO_PHYS_ADDRESS((u64) amos_page)) { + dev_err(xpc_part, "previously used amos_page address " + "is bad = 0x%p\n", (void *) amos_page); + return NULL; + } + amos_page = (AMO_t *) TO_AMO((u64) amos_page); + } + + /* clear xpc_vars */ + memset(xpc_vars, 0, sizeof(struct xpc_vars)); + + xpc_vars->version = XPC_V_VERSION; + xpc_vars->act_nasid = cpuid_to_nasid(0); + xpc_vars->act_phys_cpuid = cpu_physical_id(0); + xpc_vars->vars_part_pa = __pa(xpc_vars_part); + xpc_vars->amos_page_pa = ia64_tpa((u64) amos_page); + xpc_vars->amos_page = amos_page; /* save for next load of XPC */ + + + /* clear xpc_vars_part */ + memset((u64 *) xpc_vars_part, 0, sizeof(struct xpc_vars_part) * + XP_MAX_PARTITIONS); + + /* initialize the activate IRQ related AMO variables */ + for (i = 0; i < xp_nasid_mask_words; i++) { + (void) xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); + } + + /* initialize the engaged remote partitions related AMO variables */ + (void) xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); + (void) xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); + + /* timestamp of when reserved page was setup by XPC */ + rp->stamp = CURRENT_TIME; + + /* + * This signifies to the remote partition that our reserved + * page is initialized. + */ + rp->vars_pa = __pa(xpc_vars); + + return rp; +} + + +/* + * Change protections to allow IPI operations (and AMO operations on + * Shub 1.1 systems). + */ +void +xpc_allow_IPI_ops(void) +{ + int node; + int nasid; + + + // >>> Change SH_IPI_ACCESS code to use SAL call once it is available. + + if (is_shub2()) { + xpc_sh2_IPI_access0 = + (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); + xpc_sh2_IPI_access1 = + (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); + xpc_sh2_IPI_access2 = + (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); + xpc_sh2_IPI_access3 = + (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); + + for_each_online_node(node) { + nasid = cnodeid_to_nasid(node); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), + -1UL); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), + -1UL); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), + -1UL); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), + -1UL); + } + + } else { + xpc_sh1_IPI_access = + (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); + + for_each_online_node(node) { + nasid = cnodeid_to_nasid(node); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), + -1UL); + + /* + * Since the BIST collides with memory operations on + * SHUB 1.1 sn_change_memprotect() cannot be used. + */ + if (enable_shub_wars_1_1()) { + /* open up everything */ + xpc_prot_vec[node] = (u64) HUB_L((u64 *) + GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQLP_MMR_DIR_PRIVEC0)); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQLP_MMR_DIR_PRIVEC0), + -1UL); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQRP_MMR_DIR_PRIVEC0), + -1UL); + } + } + } +} + + +/* + * Restrict protections to disallow IPI operations (and AMO operations on + * Shub 1.1 systems). + */ +void +xpc_restrict_IPI_ops(void) +{ + int node; + int nasid; + + + // >>> Change SH_IPI_ACCESS code to use SAL call once it is available. + + if (is_shub2()) { + + for_each_online_node(node) { + nasid = cnodeid_to_nasid(node); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), + xpc_sh2_IPI_access0); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), + xpc_sh2_IPI_access1); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), + xpc_sh2_IPI_access2); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), + xpc_sh2_IPI_access3); + } + + } else { + + for_each_online_node(node) { + nasid = cnodeid_to_nasid(node); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), + xpc_sh1_IPI_access); + + if (enable_shub_wars_1_1()) { + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQLP_MMR_DIR_PRIVEC0), + xpc_prot_vec[node]); + HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQRP_MMR_DIR_PRIVEC0), + xpc_prot_vec[node]); + } + } + } +} + + +/* + * At periodic intervals, scan through all active partitions and ensure + * their heartbeat is still active. If not, the partition is deactivated. + */ +void +xpc_check_remote_hb(void) +{ + struct xpc_vars *remote_vars; + struct xpc_partition *part; + partid_t partid; + bte_result_t bres; + + + remote_vars = (struct xpc_vars *) xpc_remote_copy_buffer; + + for (partid = 1; partid < XP_MAX_PARTITIONS; 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 */ + bres = xp_bte_copy(part->remote_vars_pa, + (u64) remote_vars, + XPC_RP_VARS_SIZE, + (BTE_NOTIFY | BTE_WACQUIRE), NULL); + if (bres != BTE_SUCCESS) { + XPC_DEACTIVATE_PARTITION(part, + xpc_map_bte_errors(bres)); + continue; + } + + dev_dbg(xpc_part, "partid = %d, heartbeat = %ld, last_heartbeat" + " = %ld, heartbeat_offline = %ld, HB_mask = 0x%lx\n", + partid, remote_vars->heartbeat, part->last_heartbeat, + remote_vars->heartbeat_offline, + remote_vars->heartbeating_to_mask); + + if (((remote_vars->heartbeat == part->last_heartbeat) && + (remote_vars->heartbeat_offline == 0)) || + !xpc_hb_allowed(sn_partition_id, remote_vars)) { + + XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat); + continue; + } + + part->last_heartbeat = remote_vars->heartbeat; + } +} + + +/* + * Get a copy of a portion of the remote partition's rsvd page. + * + * remote_rp points to a buffer that is cacheline aligned for BTE copies and + * is large enough to contain a copy of their reserved page header and + * part_nasids mask. + */ +static enum xpc_retval +xpc_get_remote_rp(int nasid, u64 *discovered_nasids, + struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) +{ + int bres, i; + + + /* get the reserved page's physical address */ + + *remote_rp_pa = xpc_get_rsvd_page_pa(nasid); + if (*remote_rp_pa == 0) { + return xpcNoRsvdPageAddr; + } + + + /* pull over the reserved page header and part_nasids mask */ + bres = xp_bte_copy(*remote_rp_pa, (u64) remote_rp, + XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes, + (BTE_NOTIFY | BTE_WACQUIRE), NULL); + if (bres != BTE_SUCCESS) { + return xpc_map_bte_errors(bres); + } + + + if (discovered_nasids != NULL) { + u64 *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); + + + for (i = 0; i < xp_nasid_mask_words; i++) { + discovered_nasids[i] |= remote_part_nasids[i]; + } + } + + + /* check that the partid is for another partition */ + + if (remote_rp->partid < 1 || + remote_rp->partid > (XP_MAX_PARTITIONS - 1)) { + return xpcInvalidPartid; + } + + if (remote_rp->partid == sn_partition_id) { + return xpcLocalPartid; + } + + + if (XPC_VERSION_MAJOR(remote_rp->version) != + XPC_VERSION_MAJOR(XPC_RP_VERSION)) { + return xpcBadVersion; + } + + return xpcSuccess; +} + + +/* + * Get a copy of the remote partition's XPC variables from the reserved page. + * + * remote_vars points to a buffer that is cacheline aligned for BTE copies and + * assumed to be of size XPC_RP_VARS_SIZE. + */ +static enum xpc_retval +xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars) +{ + int bres; + + + if (remote_vars_pa == 0) { + return xpcVarsNotSet; + } + + /* pull over the cross partition variables */ + bres = xp_bte_copy(remote_vars_pa, (u64) remote_vars, XPC_RP_VARS_SIZE, + (BTE_NOTIFY | BTE_WACQUIRE), NULL); + if (bres != BTE_SUCCESS) { + return xpc_map_bte_errors(bres); + } + + if (XPC_VERSION_MAJOR(remote_vars->version) != + XPC_VERSION_MAJOR(XPC_V_VERSION)) { + return xpcBadVersion; + } + + return xpcSuccess; +} + + +/* + * Update the remote partition's info. + */ +static void +xpc_update_partition_info(struct xpc_partition *part, u8 remote_rp_version, + struct timespec *remote_rp_stamp, u64 remote_rp_pa, + u64 remote_vars_pa, struct xpc_vars *remote_vars) +{ + part->remote_rp_version = remote_rp_version; + dev_dbg(xpc_part, " remote_rp_version = 0x%016x\n", + part->remote_rp_version); + + part->remote_rp_stamp = *remote_rp_stamp; + dev_dbg(xpc_part, " remote_rp_stamp (tv_sec = 0x%lx tv_nsec = 0x%lx\n", + part->remote_rp_stamp.tv_sec, part->remote_rp_stamp.tv_nsec); + + part->remote_rp_pa = remote_rp_pa; + dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa); + + part->remote_vars_pa = remote_vars_pa; + dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", + part->remote_vars_pa); + + part->last_heartbeat = remote_vars->heartbeat; + dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", + part->last_heartbeat); + + part->remote_vars_part_pa = remote_vars->vars_part_pa; + dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", + part->remote_vars_part_pa); + + part->remote_act_nasid = remote_vars->act_nasid; + dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n", + part->remote_act_nasid); + + part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid; + dev_dbg(xpc_part, " remote_act_phys_cpuid = 0x%x\n", + part->remote_act_phys_cpuid); + + part->remote_amos_page_pa = remote_vars->amos_page_pa; + dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n", + part->remote_amos_page_pa); + + part->remote_vars_version = remote_vars->version; + dev_dbg(xpc_part, " remote_vars_version = 0x%x\n", + part->remote_vars_version); +} + + +/* + * Prior code has determined the nasid which generated an IPI. Inspect + * that nasid to determine if its partition needs to be activated or + * deactivated. + * + * A partition is consider "awaiting activation" if our partition + * flags indicate it is not active and it has a heartbeat. A + * partition is considered "awaiting deactivation" if our partition + * flags indicate it is active but it has no heartbeat or it is not + * sending its heartbeat to us. + * + * To determine the heartbeat, the remote nasid must have a properly + * initialized reserved page. + */ +static void +xpc_identify_act_IRQ_req(int nasid) +{ + struct xpc_rsvd_page *remote_rp; + struct xpc_vars *remote_vars; + u64 remote_rp_pa; + u64 remote_vars_pa; + int remote_rp_version; + int reactivate = 0; + int stamp_diff; + struct timespec remote_rp_stamp = { 0, 0 }; + partid_t partid; + struct xpc_partition *part; + enum xpc_retval ret; + + + /* pull over the reserved page structure */ + + remote_rp = (struct xpc_rsvd_page *) xpc_remote_copy_buffer; + + ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa); + if (ret != xpcSuccess) { + dev_warn(xpc_part, "unable to get reserved page from nasid %d, " + "which sent interrupt, reason=%d\n", nasid, ret); + return; + } + + remote_vars_pa = remote_rp->vars_pa; + remote_rp_version = remote_rp->version; + if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { + remote_rp_stamp = remote_rp->stamp; + } + partid = remote_rp->partid; + part = &xpc_partitions[partid]; + + + /* pull over the cross partition variables */ + + remote_vars = (struct xpc_vars *) xpc_remote_copy_buffer; + + ret = xpc_get_remote_vars(remote_vars_pa, remote_vars); + if (ret != xpcSuccess) { + + dev_warn(xpc_part, "unable to get XPC variables from nasid %d, " + "which sent interrupt, reason=%d\n", nasid, ret); + + XPC_DEACTIVATE_PARTITION(part, ret); + return; + } + + + part->act_IRQ_rcvd++; + + dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = " + "%ld:0x%lx\n", (int) nasid, (int) partid, part->act_IRQ_rcvd, + remote_vars->heartbeat, remote_vars->heartbeating_to_mask); + + if (xpc_partition_disengaged(part) && + part->act_state == XPC_P_INACTIVE) { + + xpc_update_partition_info(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); + + if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { + if (xpc_partition_disengage_requested(1UL << partid)) { + /* + * Other side is waiting on us to disengage, + * even though we already have. + */ + return; + } + } else { + /* other side doesn't support disengage requests */ + xpc_clear_partition_disengage_request(1UL << partid); + } + + xpc_activate_partition(part); + return; + } + + DBUG_ON(part->remote_rp_version == 0); + DBUG_ON(part->remote_vars_version == 0); + + if (!XPC_SUPPORTS_RP_STAMP(part->remote_rp_version)) { + DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(part-> + remote_vars_version)); + + if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { + DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> + version)); + /* see if the other side rebooted */ + if (part->remote_amos_page_pa == + remote_vars->amos_page_pa && + xpc_hb_allowed(sn_partition_id, + remote_vars)) { + /* doesn't look that way, so ignore the IPI */ + return; + } + } + + /* + * Other side rebooted and previous XPC didn't support the + * disengage request, so we don't need to do anything special. + */ + + xpc_update_partition_info(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); + part->reactivate_nasid = nasid; + XPC_DEACTIVATE_PARTITION(part, xpcReactivating); + return; + } + + DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)); + + if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { + DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); + + /* + * Other side rebooted and previous XPC did support the + * disengage request, but the new one doesn't. + */ + + xpc_clear_partition_engaged(1UL << partid); + xpc_clear_partition_disengage_request(1UL << partid); + + xpc_update_partition_info(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); + reactivate = 1; + + } else { + DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); + + stamp_diff = xpc_compare_stamps(&part->remote_rp_stamp, + &remote_rp_stamp); + if (stamp_diff != 0) { + DBUG_ON(stamp_diff >= 0); + + /* + * Other side rebooted and the previous XPC did support + * the disengage request, as does the new one. + */ + + DBUG_ON(xpc_partition_engaged(1UL << partid)); + DBUG_ON(xpc_partition_disengage_requested(1UL << + partid)); + + xpc_update_partition_info(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); + reactivate = 1; + } + } + + if (part->disengage_request_timeout > 0 && + !xpc_partition_disengaged(part)) { + /* still waiting on other side to disengage from us */ + return; + } + + if (reactivate) { + part->reactivate_nasid = nasid; + XPC_DEACTIVATE_PARTITION(part, xpcReactivating); + + } else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) && + xpc_partition_disengage_requested(1UL << partid)) { + XPC_DEACTIVATE_PARTITION(part, xpcOtherGoingDown); + } +} + + +/* + * Loop through the activation AMO variables and process any bits + * which are set. Each bit indicates a nasid sending a partition + * activation or deactivation request. + * + * Return #of IRQs detected. + */ +int +xpc_identify_act_IRQ_sender(void) +{ + int word, bit; + u64 nasid_mask; + u64 nasid; /* remote nasid */ + int n_IRQs_detected = 0; + AMO_t *act_amos; + + + act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS; + + + /* scan through act AMO variable looking for non-zero entries */ + for (word = 0; word < xp_nasid_mask_words; word++) { + + if (xpc_exiting) { + break; + } + + nasid_mask = xpc_IPI_receive(&act_amos[word]); + if (nasid_mask == 0) { + /* no IRQs from nasids in this variable */ + continue; + } + + dev_dbg(xpc_part, "AMO[%d] gave back 0x%lx\n", word, + nasid_mask); + + + /* + * If this nasid has been added to the machine since + * our partition was reset, this will retain the + * remote nasid in our reserved pages machine mask. + * This is used in the event of module reload. + */ + xpc_mach_nasids[word] |= nasid_mask; + + + /* locate the nasid(s) which sent interrupts */ + + for (bit = 0; bit < (8 * sizeof(u64)); bit++) { + if (nasid_mask & (1UL << bit)) { + n_IRQs_detected++; + nasid = XPC_NASID_FROM_W_B(word, bit); + dev_dbg(xpc_part, "interrupt from nasid %ld\n", + nasid); + xpc_identify_act_IRQ_req(nasid); + } + } + } + return n_IRQs_detected; +} + + +/* + * See if the other side has responded to a partition disengage request + * from us. + */ +int +xpc_partition_disengaged(struct xpc_partition *part) +{ + partid_t partid = XPC_PARTID(part); + int disengaged; + + + disengaged = (xpc_partition_engaged(1UL << partid) == 0); + if (part->disengage_request_timeout) { + if (!disengaged) { + if (time_before(jiffies, part->disengage_request_timeout)) { + /* timelimit hasn't been reached yet */ + return 0; + } + + /* + * Other side hasn't responded to our disengage + * request in a timely fashion, so assume it's dead. + */ + + dev_info(xpc_part, "disengage from remote partition %d " + "timed out\n", partid); + xpc_disengage_request_timedout = 1; + xpc_clear_partition_engaged(1UL << partid); + disengaged = 1; + } + part->disengage_request_timeout = 0; + + /* cancel the timer function, provided it's not us */ + if (!in_interrupt()) { + del_singleshot_timer_sync(&part-> + disengage_request_timer); + } + + DBUG_ON(part->act_state != XPC_P_DEACTIVATING && + part->act_state != XPC_P_INACTIVE); + if (part->act_state != XPC_P_INACTIVE) { + xpc_wakeup_channel_mgr(part); + } + + if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { + xpc_cancel_partition_disengage_request(part); + } + } + return disengaged; +} + + +/* + * Mark specified partition as active. + */ +enum xpc_retval +xpc_mark_partition_active(struct xpc_partition *part) +{ + unsigned long irq_flags; + enum xpc_retval ret; + + + 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; + ret = xpcSuccess; + } else { + DBUG_ON(part->reason == xpcSuccess); + ret = part->reason; + } + spin_unlock_irqrestore(&part->act_lock, irq_flags); + + return ret; +} + + +/* + * Notify XPC that the partition is down. + */ +void +xpc_deactivate_partition(const int line, struct xpc_partition *part, + enum xpc_retval reason) +{ + unsigned long irq_flags; + + + spin_lock_irqsave(&part->act_lock, irq_flags); + + if (part->act_state == XPC_P_INACTIVE) { + XPC_SET_REASON(part, reason, line); + spin_unlock_irqrestore(&part->act_lock, irq_flags); + if (reason == xpcReactivating) { + /* we interrupt ourselves to reactivate partition */ + xpc_IPI_send_reactivate(part); + } + return; + } + if (part->act_state == XPC_P_DEACTIVATING) { + if ((part->reason == xpcUnloading && reason != xpcUnloading) || + reason == xpcReactivating) { + XPC_SET_REASON(part, reason, line); + } + spin_unlock_irqrestore(&part->act_lock, irq_flags); + return; + } + + part->act_state = XPC_P_DEACTIVATING; + XPC_SET_REASON(part, reason, line); + + spin_unlock_irqrestore(&part->act_lock, irq_flags); + + if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { + xpc_request_partition_disengage(part); + xpc_IPI_send_disengage(part); + + /* set a timelimit on the disengage request */ + part->disengage_request_timeout = jiffies + + (xpc_disengage_request_timelimit * HZ); + part->disengage_request_timer.expires = + part->disengage_request_timeout; + add_timer(&part->disengage_request_timer); + } + + dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", + XPC_PARTID(part), reason); + + xpc_partition_going_down(part, reason); +} + + +/* + * Mark specified partition as inactive. + */ +void +xpc_mark_partition_inactive(struct xpc_partition *part) +{ + unsigned long irq_flags; + + + dev_dbg(xpc_part, "setting partition %d to INACTIVE\n", + XPC_PARTID(part)); + + spin_lock_irqsave(&part->act_lock, irq_flags); + part->act_state = XPC_P_INACTIVE; + spin_unlock_irqrestore(&part->act_lock, irq_flags); + part->remote_rp_pa = 0; +} + + +/* + * SAL has provided a partition and machine mask. The partition mask + * contains a bit for each even nasid in our partition. The machine + * mask contains a bit for each even nasid in the entire machine. + * + * Using those two bit arrays, we can determine which nasids are + * known in the machine. Each should also have a reserved page + * initialized if they are available for partitioning. + */ +void +xpc_discovery(void) +{ + void *remote_rp_base; + struct xpc_rsvd_page *remote_rp; + struct xpc_vars *remote_vars; + u64 remote_rp_pa; + u64 remote_vars_pa; + int region; + int region_size; + int max_regions; + int nasid; + struct xpc_rsvd_page *rp; + partid_t partid; + struct xpc_partition *part; + u64 *discovered_nasids; + enum xpc_retval ret; + + + remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + + xp_nasid_mask_bytes, + GFP_KERNEL, &remote_rp_base); + if (remote_rp == NULL) { + return; + } + remote_vars = (struct xpc_vars *) remote_rp; + + + discovered_nasids = kzalloc(sizeof(u64) * xp_nasid_mask_words, + GFP_KERNEL); + if (discovered_nasids == NULL) { + kfree(remote_rp_base); + return; + } + + rp = (struct xpc_rsvd_page *) xpc_rsvd_page; + + /* + * The term 'region' in this context refers to the minimum number of + * nodes that can comprise an access protection grouping. The access + * protection is in regards to memory, IOI and IPI. + */ + max_regions = 64; + region_size = sn_region_size; + + switch (region_size) { + case 128: + max_regions *= 2; + case 64: + max_regions *= 2; + case 32: + max_regions *= 2; + region_size = 16; + DBUG_ON(!is_shub2()); + } + + for (region = 0; region < max_regions; region++) { + + if ((volatile int) xpc_exiting) { + break; + } + + dev_dbg(xpc_part, "searching region %d\n", region); + + for (nasid = (region * region_size * 2); + nasid < ((region + 1) * region_size * 2); + nasid += 2) { + + if ((volatile int) xpc_exiting) { + break; + } + + dev_dbg(xpc_part, "checking nasid %d\n", nasid); + + + if (XPC_NASID_IN_ARRAY(nasid, xpc_part_nasids)) { + dev_dbg(xpc_part, "PROM indicates Nasid %d is " + "part of the local partition; skipping " + "region\n", nasid); + break; + } + + if (!(XPC_NASID_IN_ARRAY(nasid, xpc_mach_nasids))) { + dev_dbg(xpc_part, "PROM indicates Nasid %d was " + "not on Numa-Link network at reset\n", + nasid); + continue; + } + + if (XPC_NASID_IN_ARRAY(nasid, discovered_nasids)) { + dev_dbg(xpc_part, "Nasid %d is part of a " + "partition which was previously " + "discovered\n", nasid); + continue; + } + + + /* pull over the reserved page structure */ + + ret = xpc_get_remote_rp(nasid, discovered_nasids, + remote_rp, &remote_rp_pa); + if (ret != xpcSuccess) { + dev_dbg(xpc_part, "unable to get reserved page " + "from nasid %d, reason=%d\n", nasid, + ret); + + if (ret == xpcLocalPartid) { + break; + } + continue; + } + + remote_vars_pa = remote_rp->vars_pa; + + partid = remote_rp->partid; + part = &xpc_partitions[partid]; + + + /* pull over the cross partition variables */ + + ret = xpc_get_remote_vars(remote_vars_pa, remote_vars); + if (ret != xpcSuccess) { + dev_dbg(xpc_part, "unable to get XPC variables " + "from nasid %d, reason=%d\n", nasid, + ret); + + XPC_DEACTIVATE_PARTITION(part, ret); + continue; + } + + if (part->act_state != XPC_P_INACTIVE) { + dev_dbg(xpc_part, "partition %d on nasid %d is " + "already activating\n", partid, nasid); + break; + } + + /* + * Register the remote partition's AMOs with SAL so it + * can handle and cleanup errors within that address + * range should the remote partition go down. We don't + * unregister this range because it is difficult to + * tell when outstanding writes to the remote partition + * are finished and thus when it is thus safe to + * unregister. This should not result in wasted space + * in the SAL xp_addr_region table because we should + * get the same page for remote_act_amos_pa after + * module reloads and system reboots. + */ + if (sn_register_xp_addr_region( + remote_vars->amos_page_pa, + PAGE_SIZE, 1) < 0) { + dev_dbg(xpc_part, "partition %d failed to " + "register xp_addr region 0x%016lx\n", + partid, remote_vars->amos_page_pa); + + XPC_SET_REASON(part, xpcPhysAddrRegFailed, + __LINE__); + break; + } + + /* + * The remote nasid is valid and available. + * Send an interrupt to that nasid to notify + * it that we are ready to begin activation. + */ + dev_dbg(xpc_part, "sending an interrupt to AMO 0x%lx, " + "nasid %d, phys_cpuid 0x%x\n", + remote_vars->amos_page_pa, + remote_vars->act_nasid, + remote_vars->act_phys_cpuid); + + if (XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> + version)) { + part->remote_amos_page_pa = + remote_vars->amos_page_pa; + xpc_mark_partition_disengaged(part); + xpc_cancel_partition_disengage_request(part); + } + xpc_IPI_send_activate(remote_vars); + } + } + + kfree(discovered_nasids); + kfree(remote_rp_base); +} + + +/* + * Given a partid, get the nasids owned by that partition from the + * remote partition's reserved page. + */ +enum xpc_retval +xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask) +{ + struct xpc_partition *part; + u64 part_nasid_pa; + int bte_res; + + + part = &xpc_partitions[partid]; + if (part->remote_rp_pa == 0) { + return xpcPartitionDown; + } + + memset(nasid_mask, 0, XP_NASID_MASK_BYTES); + + part_nasid_pa = (u64) XPC_RP_PART_NASIDS(part->remote_rp_pa); + + bte_res = xp_bte_copy(part_nasid_pa, (u64) nasid_mask, + xp_nasid_mask_bytes, (BTE_NOTIFY | BTE_WACQUIRE), NULL); + + return xpc_map_bte_errors(bte_res); +} + diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c new file mode 100644 index 00000000000..38552f37e53 --- /dev/null +++ b/drivers/misc/sgi-xp/xpnet.c @@ -0,0 +1,718 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999-2008 Silicon Graphics, Inc. All rights reserved. + */ + + +/* + * Cross Partition Network Interface (XPNET) support + * + * XPNET provides a virtual network layered on top of the Cross + * Partition communication layer. + * + * XPNET provides direct point-to-point and broadcast-like support + * for an ethernet-like device. The ethernet broadcast medium is + * replaced with a point-to-point message structure which passes + * pointers to a DMA-capable block that a remote partition should + * retrieve and pass to the upper level networking layer. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xp.h" + + +/* + * The message payload transferred by XPC. + * + * buf_pa is the physical address where the DMA should pull from. + * + * NOTE: for performance reasons, buf_pa should _ALWAYS_ begin on a + * cacheline boundary. To accomplish this, we record the number of + * bytes from the beginning of the first cacheline to the first useful + * byte of the skb (leadin_ignore) and the number of bytes from the + * last useful byte of the skb to the end of the last cacheline + * (tailout_ignore). + * + * size is the number of bytes to transfer which includes the skb->len + * (useful bytes of the senders skb) plus the leadin and tailout + */ +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 */ + 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 */ + unsigned char data; /* body of small packets */ +}; + +/* + * Determine the size of our message, the cacheline aligned size, + * and then the number of message will request from XPC. + * + * XPC expects each message to exist in an individual cacheline. + */ +#define XPNET_MSG_SIZE (L1_CACHE_BYTES - XPC_MSG_PAYLOAD_OFFSET) +#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) + + +#define XPNET_MAX_KTHREADS (XPNET_MSG_NENTRIES + 1) +#define XPNET_MAX_IDLE_KTHREADS (XPNET_MSG_NENTRIES + 1) + +/* + * Version number of XPNET implementation. XPNET can always talk to versions + * with same major #, and never talk to versions with a different version. + */ +#define _XPNET_VERSION(_major, _minor) (((_major) << 4) | (_minor)) +#define XPNET_VERSION_MAJOR(_v) ((_v) >> 4) +#define XPNET_VERSION_MINOR(_v) ((_v) & 0xf) + +#define XPNET_VERSION _XPNET_VERSION(1,0) /* version 1.0 */ +#define XPNET_VERSION_EMBED _XPNET_VERSION(1,1) /* version 1.1 */ +#define XPNET_MAGIC 0x88786984 /* "XNET" */ + +#define XPNET_VALID_MSG(_m) \ + ((XPNET_VERSION_MAJOR(_m->version) == XPNET_VERSION_MAJOR(XPNET_VERSION)) \ + && (msg->magic == XPNET_MAGIC)) + +#define XPNET_DEVICE_NAME "xp0" + + +/* + * When messages are queued with xpc_send_notify, a kmalloc'd buffer + * of the following type is passed as a notification cookie. When the + * notification function is called, we use the cookie to decide + * whether all outstanding message sends have completed. The skb can + * then be released. + */ +struct xpnet_pending_msg { + struct list_head free_list; + struct sk_buff *skb; + atomic_t use_count; +}; + +/* driver specific structure pointed to by the device structure */ +struct xpnet_dev_private { + struct net_device_stats stats; +}; + +struct net_device *xpnet_device; + +/* + * When we are notified of other partitions activating, we add them to + * our bitmask of partitions to which we broadcast. + */ +static u64 xpnet_broadcast_partitions; +/* protect above */ +static DEFINE_SPINLOCK(xpnet_broadcast_lock); + +/* + * Since the Block Transfer Engine (BTE) is being used for the transfer + * and it relies upon cache-line size transfers, we need to reserve at + * least one cache-line for head and tail alignment. The BTE is + * limited to 8MB transfers. + * + * Testing has shown that changing MTU to greater than 64KB has no effect + * on TCP as the two sides negotiate a Max Segment Size that is limited + * to 64K. Other protocols May use packets greater than this, but for + * now, the default is 64KB. + */ +#define XPNET_MAX_MTU (0x800000UL - L1_CACHE_BYTES) +/* 32KB has been determined to be the ideal */ +#define XPNET_DEF_MTU (0x8000UL) + + +/* + * The partition id is encapsulated in the MAC address. The following + * define locates the octet the partid is in. + */ +#define XPNET_PARTID_OCTET 1 +#define XPNET_LICENSE_OCTET 2 + + +/* + * Define the XPNET debug device structure that is to be used with dev_dbg(), + * dev_err(), dev_warn(), and dev_info(). + */ +struct device_driver xpnet_dbg_name = { + .name = "xpnet" +}; + +struct device xpnet_dbg_subname = { + .bus_id = {0}, /* set to "" */ + .driver = &xpnet_dbg_name +}; + +struct device *xpnet = &xpnet_dbg_subname; + +/* + * Packet was recevied by XPC and forwarded to us. + */ +static void +xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) +{ + struct sk_buff *skb; + bte_result_t bret; + struct xpnet_dev_private *priv = + (struct xpnet_dev_private *) xpnet_device->priv; + + + if (!XPNET_VALID_MSG(msg)) { + /* + * Packet with a different XPC version. Ignore. + */ + xpc_received(partid, channel, (void *) msg); + + priv->stats.rx_errors++; + + return; + } + 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); + if (!skb) { + dev_err(xpnet, "failed on dev_alloc_skb(%d)\n", + msg->size + L1_CACHE_BYTES); + + xpc_received(partid, channel, (void *) msg); + + priv->stats.rx_errors++; + + return; + } + + /* + * The allocated skb has some reserved space. + * In order to use bte_copy, we need to get the + * skb->data pointer moved forward. + */ + skb_reserve(skb, (L1_CACHE_BYTES - ((u64)skb->data & + (L1_CACHE_BYTES - 1)) + + msg->leadin_ignore)); + + /* + * Update the tail pointer to indicate data actually + * transferred. + */ + skb_put(skb, (msg->size - msg->leadin_ignore - msg->tailout_ignore)); + + /* + * Move the data over from the other side. + */ + if ((XPNET_VERSION_MINOR(msg->version) == 1) && + (msg->embedded_bytes != 0)) { + dev_dbg(xpnet, "copying embedded message. memcpy(0x%p, 0x%p, " + "%lu)\n", skb->data, &msg->data, + (size_t) msg->embedded_bytes); + + skb_copy_to_linear_data(skb, &msg->data, (size_t)msg->embedded_bytes); + } else { + dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t" + "bte_copy(0x%p, 0x%p, %hu)\n", (void *)msg->buf_pa, + (void *)__pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)), + msg->size); + + bret = bte_copy(msg->buf_pa, + __pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)), + msg->size, (BTE_NOTIFY | BTE_WACQUIRE), NULL); + + if (bret != BTE_SUCCESS) { + // >>> Need better way of cleaning skb. Currently skb + // >>> appears in_use and we can't just call + // >>> dev_kfree_skb. + dev_err(xpnet, "bte_copy(0x%p, 0x%p, 0x%hx) returned " + "error=0x%x\n", (void *)msg->buf_pa, + (void *)__pa((u64)skb->data & + ~(L1_CACHE_BYTES - 1)), + msg->size, bret); + + xpc_received(partid, channel, (void *) msg); + + priv->stats.rx_errors++; + + return; + } + } + + dev_dbg(xpnet, "head=0x%p skb->data=0x%p skb->tail=0x%p " + "skb->end=0x%p skb->len=%d\n", (void *) skb->head, + (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), + skb->len); + + skb->protocol = eth_type_trans(skb, xpnet_device); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + dev_dbg(xpnet, "passing skb to network layer\n" + KERN_DEBUG "\tskb->head=0x%p skb->data=0x%p skb->tail=0x%p " + "skb->end=0x%p skb->len=%d\n", + (void *)skb->head, (void *)skb->data, skb_tail_pointer(skb), + skb_end_pointer(skb), skb->len); + + + xpnet_device->last_rx = jiffies; + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len + ETH_HLEN; + + netif_rx_ni(skb); + xpc_received(partid, channel, (void *) msg); +} + + +/* + * This is the handler which XPC calls during any sort of change in + * state or message reception on a connection. + */ +static void +xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel, + void *data, void *key) +{ + long bp; + + + DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(channel != XPC_NET_CHANNEL); + + switch(reason) { + case xpcMsgReceived: /* message received */ + DBUG_ON(data == NULL); + + xpnet_receive(partid, channel, (struct xpnet_message *) data); + break; + + case xpcConnected: /* connection completed to a partition */ + spin_lock_bh(&xpnet_broadcast_lock); + xpnet_broadcast_partitions |= 1UL << (partid -1 ); + bp = xpnet_broadcast_partitions; + spin_unlock_bh(&xpnet_broadcast_lock); + + netif_carrier_on(xpnet_device); + + dev_dbg(xpnet, "%s connection created to partition %d; " + "xpnet_broadcast_partitions=0x%lx\n", + xpnet_device->name, partid, bp); + break; + + default: + spin_lock_bh(&xpnet_broadcast_lock); + xpnet_broadcast_partitions &= ~(1UL << (partid -1 )); + bp = xpnet_broadcast_partitions; + spin_unlock_bh(&xpnet_broadcast_lock); + + if (bp == 0) { + netif_carrier_off(xpnet_device); + } + + dev_dbg(xpnet, "%s disconnected from partition %d; " + "xpnet_broadcast_partitions=0x%lx\n", + xpnet_device->name, partid, bp); + break; + + } +} + + +static int +xpnet_dev_open(struct net_device *dev) +{ + enum xpc_retval ret; + + + 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); + + ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL, + XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, + XPNET_MAX_KTHREADS, XPNET_MAX_IDLE_KTHREADS); + if (ret != xpcSuccess) { + dev_err(xpnet, "ifconfig up of %s failed on XPC connect, " + "ret=%d\n", dev->name, ret); + + return -ENOMEM; + } + + dev_dbg(xpnet, "ifconfig up of %s; XPC connected\n", dev->name); + + return 0; +} + + +static int +xpnet_dev_stop(struct net_device *dev) +{ + xpc_disconnect(XPC_NET_CHANNEL); + + dev_dbg(xpnet, "ifconfig down of %s; XPC disconnected\n", dev->name); + + return 0; +} + + +static int +xpnet_dev_change_mtu(struct net_device *dev, int new_mtu) +{ + /* 68 comes from min TCP+IP+MAC header */ + if ((new_mtu < 68) || (new_mtu > XPNET_MAX_MTU)) { + dev_err(xpnet, "ifconfig %s mtu %d failed; value must be " + "between 68 and %ld\n", dev->name, new_mtu, + XPNET_MAX_MTU); + return -EINVAL; + } + + dev->mtu = new_mtu; + dev_dbg(xpnet, "ifconfig %s mtu set to %d\n", dev->name, new_mtu); + return 0; +} + + +/* + * Required for the net_device structure. + */ +static int +xpnet_dev_set_config(struct net_device *dev, struct ifmap *new_map) +{ + return 0; +} + + +/* + * Return statistics to the caller. + */ +static struct net_device_stats * +xpnet_dev_get_stats(struct net_device *dev) +{ + struct xpnet_dev_private *priv; + + + priv = (struct xpnet_dev_private *) dev->priv; + + return &priv->stats; +} + + +/* + * Notification that the other end has received the message and + * DMA'd the skb information. At this point, they are done with + * our side. When all recipients are done processing, we + * release the skb and then release our pending message structure. + */ +static void +xpnet_send_completed(enum xpc_retval reason, partid_t partid, int channel, + void *__qm) +{ + struct xpnet_pending_msg *queued_msg = + (struct xpnet_pending_msg *) __qm; + + + DBUG_ON(queued_msg == NULL); + + dev_dbg(xpnet, "message to %d notified with reason %d\n", + partid, reason); + + if (atomic_dec_return(&queued_msg->use_count) == 0) { + dev_dbg(xpnet, "all acks for skb->head=-x%p\n", + (void *) queued_msg->skb->head); + + dev_kfree_skb_any(queued_msg->skb); + kfree(queued_msg); + } +} + + +/* + * Network layer has formatted a packet (skb) and is ready to place it + * "on the wire". Prepare and send an xpnet_message to all partitions + * which have connected with us and are targets of this packet. + * + * MAC-NOTE: For the XPNET driver, the MAC address contains the + * destination partition_id. If the destination partition id word + * is 0xff, this packet is to broadcast to all partitions. + */ +static int +xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct xpnet_pending_msg *queued_msg; + enum xpc_retval ret; + struct xpnet_message *msg; + u64 start_addr, end_addr; + long dp; + u8 second_mac_octet; + partid_t dest_partid; + struct xpnet_dev_private *priv; + u16 embedded_bytes; + + + priv = (struct xpnet_dev_private *) dev->priv; + + + dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " + "skb->end=0x%p skb->len=%d\n", (void *) skb->head, + (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), + skb->len); + + + /* + * The xpnet_pending_msg tracks how many outstanding + * xpc_send_notifies are relying on this skb. When none + * remain, release the skb. + */ + queued_msg = kmalloc(sizeof(struct xpnet_pending_msg), GFP_ATOMIC); + if (queued_msg == NULL) { + dev_warn(xpnet, "failed to kmalloc %ld bytes; dropping " + "packet\n", sizeof(struct xpnet_pending_msg)); + + priv->stats.tx_errors++; + + return -ENOMEM; + } + + + /* get the beginning of the first cacheline and end of last */ + start_addr = ((u64) skb->data & ~(L1_CACHE_BYTES - 1)); + end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb)); + + /* calculate how many bytes to embed in the XPC message */ + embedded_bytes = 0; + if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) { + /* skb->data does fit so embed */ + embedded_bytes = skb->len; + } + + + /* + * Since the send occurs asynchronously, we set the count to one + * and begin sending. Any sends that happen to complete before + * we are done sending will not free the skb. We will be left + * with that task during exit. This also handles the case of + * a packet destined for a partition which is no longer up. + */ + atomic_set(&queued_msg->use_count, 1); + queued_msg->skb = skb; + + + second_mac_octet = skb->data[XPNET_PARTID_OCTET]; + if (second_mac_octet == 0xff) { + /* we are being asked to broadcast to all partitions */ + dp = xpnet_broadcast_partitions; + } else if (second_mac_octet != 0) { + dp = xpnet_broadcast_partitions & + (1UL << (second_mac_octet - 1)); + } else { + /* 0 is an invalid partid. Ignore */ + dp = 0; + } + dev_dbg(xpnet, "destination Partitions mask (dp) = 0x%lx\n", dp); + + /* + * If we wanted to allow promiscuous mode to work like an + * unswitched network, this would be a good point to OR in a + * mask of partitions which should be receiving all packets. + */ + + /* + * Main send loop. + */ + for (dest_partid = 1; dp && dest_partid < XP_MAX_PARTITIONS; + dest_partid++) { + + + if (!(dp & (1UL << (dest_partid - 1)))) { + /* not destined for this partition */ + continue; + } + + /* remove this partition from the destinations mask */ + dp &= ~(1UL << (dest_partid - 1)); + + + /* found a partition to send to */ + + ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL, + XPC_NOWAIT, (void **)&msg); + if (unlikely(ret != xpcSuccess)) { + continue; + } + + msg->embedded_bytes = embedded_bytes; + if (unlikely(embedded_bytes != 0)) { + msg->version = XPNET_VERSION_EMBED; + dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n", + &msg->data, skb->data, (size_t) embedded_bytes); + skb_copy_from_linear_data(skb, &msg->data, + (size_t)embedded_bytes); + } else { + msg->version = XPNET_VERSION; + } + msg->magic = XPNET_MAGIC; + 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); + + 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); + + + atomic_inc(&queued_msg->use_count); + + ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, msg, + xpnet_send_completed, queued_msg); + if (unlikely(ret != xpcSuccess)) { + atomic_dec(&queued_msg->use_count); + continue; + } + + } + + if (atomic_dec_return(&queued_msg->use_count) == 0) { + dev_dbg(xpnet, "no partitions to receive packet destined for " + "%d\n", dest_partid); + + + dev_kfree_skb(skb); + kfree(queued_msg); + } + + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + + return 0; +} + + +/* + * Deal with transmit timeouts coming from the network layer. + */ +static void +xpnet_dev_tx_timeout (struct net_device *dev) +{ + struct xpnet_dev_private *priv; + + + priv = (struct xpnet_dev_private *) dev->priv; + + priv->stats.tx_errors++; + return; +} + + +static int __init +xpnet_init(void) +{ + int i; + u32 license_num; + int result = -ENOMEM; + + + if (!ia64_platform_is("sn2")) { + return -ENODEV; + } + + dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME); + + /* + * use ether_setup() to init the majority of our device + * structure and then override the necessary pieces. + */ + xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private), + XPNET_DEVICE_NAME, ether_setup); + if (xpnet_device == NULL) { + return -ENOMEM; + } + + netif_carrier_off(xpnet_device); + + xpnet_device->mtu = XPNET_DEF_MTU; + xpnet_device->change_mtu = xpnet_dev_change_mtu; + xpnet_device->open = xpnet_dev_open; + xpnet_device->get_stats = xpnet_dev_get_stats; + xpnet_device->stop = xpnet_dev_stop; + xpnet_device->hard_start_xmit = xpnet_dev_hard_start_xmit; + xpnet_device->tx_timeout = xpnet_dev_tx_timeout; + xpnet_device->set_config = xpnet_dev_set_config; + + /* + * Multicast assumes the LSB of the first octet is set for multicast + * MAC addresses. We chose the first octet of the MAC to be unlikely + * to collide with any vendor's officially issued MAC. + */ + xpnet_device->dev_addr[0] = 0xfe; + xpnet_device->dev_addr[XPNET_PARTID_OCTET] = sn_partition_id; + license_num = sn_partition_serial_number_val(); + for (i = 3; i >= 0; i--) { + xpnet_device->dev_addr[XPNET_LICENSE_OCTET + i] = + license_num & 0xff; + license_num = license_num >> 8; + } + + /* + * ether_setup() sets this to a multicast device. We are + * really not supporting multicast at this time. + */ + xpnet_device->flags &= ~IFF_MULTICAST; + + /* + * No need to checksum as it is a DMA transfer. The BTE will + * report an error if the data is not retrievable and the + * packet will be dropped. + */ + xpnet_device->features = NETIF_F_NO_CSUM; + + result = register_netdev(xpnet_device); + if (result != 0) { + free_netdev(xpnet_device); + } + + return result; +} +module_init(xpnet_init); + + +static void __exit +xpnet_exit(void) +{ + dev_info(xpnet, "unregistering network device %s\n", + xpnet_device[0].name); + + unregister_netdev(xpnet_device); + + free_netdev(xpnet_device); +} +module_exit(xpnet_exit); + + +MODULE_AUTHOR("Silicon Graphics, Inc."); +MODULE_DESCRIPTION("Cross Partition Network adapter (XPNET)"); +MODULE_LICENSE("GPL"); + -- cgit v1.2.3 From 4a3ad2ddc0b920cd3ead84b0c67599be02d689ca Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 22 Apr 2008 14:48:01 -0500 Subject: [IA64] run some drivers/misc/sgi-xp through scripts/Lindent Ran patches through scripts/Lindent (part 1). Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- drivers/misc/sgi-xp/xp.h | 80 +++---- drivers/misc/sgi-xp/xp_main.c | 98 ++++---- drivers/misc/sgi-xp/xp_nofault.S | 1 - drivers/misc/sgi-xp/xpc.h | 442 +++++++++++++++--------------------- drivers/misc/sgi-xp/xpc_partition.c | 328 +++++++++++--------------- 5 files changed, 396 insertions(+), 553 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index fb65981754c..87171682664 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -6,30 +6,25 @@ * Copyright (C) 2004-2008 Silicon Graphics, Inc. All rights reserved. */ - /* * External Cross Partition (XP) structures and defines. */ - #ifndef _DRIVERS_MISC_SGIXP_XP_H #define _DRIVERS_MISC_SGIXP_XP_H - #include #include #include #include #include - #ifdef USE_DBUG_ON #define DBUG_ON(condition) BUG_ON(condition) #else #define DBUG_ON(condition) #endif - /* * Define the maximum number of logically defined partitions the system * can support. It is constrained by the maximum number of hardware @@ -43,7 +38,6 @@ */ #define XP_MAX_PARTITIONS 64 - /* * Define the number of u64s required to represent all the C-brick nasids * as a bitmap. The cross-partition kernel modules deal only with @@ -54,7 +48,6 @@ #define XP_NASID_MASK_BYTES ((XP_MAX_PHYSNODE_ID + 7) / 8) #define XP_NASID_MASK_WORDS ((XP_MAX_PHYSNODE_ID + 63) / 64) - /* * Wrapper for bte_copy() that should it return a failure status will retry * the bte_copy() once in the hope that the failure was due to a temporary @@ -74,7 +67,6 @@ xp_bte_copy(u64 src, u64 vdst, u64 len, u64 mode, void *notification) bte_result_t ret; u64 pdst = ia64_tpa(vdst); - /* * Ensure that the physically mapped memory is contiguous. * @@ -96,7 +88,6 @@ xp_bte_copy(u64 src, u64 vdst, u64 len, u64 mode, void *notification) return ret; } - /* * XPC establishes channel connections between the local partition and any * other partition that is currently up. Over these channels, kernel-level @@ -122,7 +113,6 @@ xp_bte_copy(u64 src, u64 vdst, u64 len, u64 mode, void *notification) #error XPC_NCHANNELS exceeds MAXIMUM allowed. #endif - /* * The format of an XPC message is as follows: * @@ -160,12 +150,10 @@ struct xpc_msg { u64 payload; /* user defined portion of message */ }; - #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)) - /* * Define the return values and values passed to user's callout functions. * (It is important to add new value codes at the end just preceding @@ -270,7 +258,6 @@ enum xpc_retval { xpcUnknownReason /* 116: unknown reason -- must be last in list */ }; - /* * Define the callout function types used by XPC to update the user on * connection activity and state changes (via the user function registered by @@ -375,12 +362,11 @@ enum xpc_retval { * =====================+================================+===================== */ -typedef void (*xpc_channel_func)(enum xpc_retval reason, partid_t partid, - int ch_number, void *data, void *key); - -typedef void (*xpc_notify_func)(enum xpc_retval reason, partid_t partid, - int ch_number, void *key); +typedef void (*xpc_channel_func) (enum xpc_retval reason, partid_t partid, + int ch_number, void *data, void *key); +typedef void (*xpc_notify_func) (enum xpc_retval reason, partid_t partid, + int ch_number, void *key); /* * The following is a registration entry. There is a global array of these, @@ -398,50 +384,45 @@ typedef void (*xpc_notify_func)(enum xpc_retval reason, partid_t partid, */ struct xpc_registration { struct mutex mutex; - 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 */ - u32 assigned_limit; /* limit on #of assigned kthreads */ - u32 idle_limit; /* limit on #of idle kthreads */ + 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 */ + u32 assigned_limit; /* limit on #of assigned kthreads */ + u32 idle_limit; /* limit on #of idle kthreads */ } ____cacheline_aligned; - #define XPC_CHANNEL_REGISTERED(_c) (xpc_registrations[_c].func != NULL) - /* the following are valid xpc_allocate() flags */ -#define XPC_WAIT 0 /* wait flag */ -#define XPC_NOWAIT 1 /* no wait flag */ - +#define XPC_WAIT 0 /* wait flag */ +#define XPC_NOWAIT 1 /* no wait flag */ struct xpc_interface { - void (*connect)(int); - void (*disconnect)(int); - enum xpc_retval (*allocate)(partid_t, int, u32, void **); - enum xpc_retval (*send)(partid_t, int, void *); - enum xpc_retval (*send_notify)(partid_t, int, void *, - xpc_notify_func, void *); - void (*received)(partid_t, int, void *); - enum xpc_retval (*partid_to_nasids)(partid_t, void *); + void (*connect) (int); + void (*disconnect) (int); + enum xpc_retval (*allocate) (partid_t, int, u32, void **); + enum xpc_retval (*send) (partid_t, int, void *); + enum xpc_retval (*send_notify) (partid_t, int, void *, + xpc_notify_func, void *); + void (*received) (partid_t, int, void *); + enum xpc_retval (*partid_to_nasids) (partid_t, void *); }; - extern struct xpc_interface xpc_interface; extern void xpc_set_interface(void (*)(int), - void (*)(int), - enum xpc_retval (*)(partid_t, int, u32, void **), - enum xpc_retval (*)(partid_t, int, void *), - enum xpc_retval (*)(partid_t, int, void *, xpc_notify_func, - void *), - void (*)(partid_t, int, void *), - enum xpc_retval (*)(partid_t, void *)); + void (*)(int), + enum xpc_retval (*)(partid_t, int, u32, void **), + enum xpc_retval (*)(partid_t, int, void *), + enum xpc_retval (*)(partid_t, int, void *, + xpc_notify_func, void *), + void (*)(partid_t, int, void *), + enum xpc_retval (*)(partid_t, void *)); extern void xpc_clear_interface(void); - extern enum xpc_retval xpc_connect(int, xpc_channel_func, void *, u16, - u16, u32, u32); + u16, u32, u32); extern void xpc_disconnect(int); static inline enum xpc_retval @@ -458,7 +439,7 @@ xpc_send(partid_t partid, int ch_number, void *payload) static inline enum xpc_retval xpc_send_notify(partid_t partid, int ch_number, void *payload, - xpc_notify_func func, void *key) + xpc_notify_func func, void *key) { return xpc_interface.send_notify(partid, ch_number, payload, func, key); } @@ -475,11 +456,8 @@ xpc_partid_to_nasids(partid_t partid, void *nasids) return xpc_interface.partid_to_nasids(partid, nasids); } - extern u64 xp_nofault_PIOR_target; extern int xp_nofault_PIOR(void *); extern int xp_error_PIOR(void); - #endif /* _DRIVERS_MISC_SGIXP_XP_H */ - diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index 5f9f9c2e929..bb9257642fc 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -6,7 +6,6 @@ * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. */ - /* * Cross Partition (XP) base. * @@ -15,7 +14,6 @@ * */ - #include #include #include @@ -24,49 +22,49 @@ #include #include "xp.h" - /* * Target of nofault PIO read. */ u64 xp_nofault_PIOR_target; - /* * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level * users of XPC. */ struct xpc_registration xpc_registrations[XPC_NCHANNELS]; - /* * Initialize the XPC interface to indicate that XPC isn't loaded. */ -static enum xpc_retval xpc_notloaded(void) { return xpcNotLoaded; } +static enum xpc_retval +xpc_notloaded(void) +{ + return xpcNotLoaded; +} struct xpc_interface xpc_interface = { - (void (*)(int)) xpc_notloaded, - (void (*)(int)) xpc_notloaded, - (enum xpc_retval (*)(partid_t, int, u32, void **)) xpc_notloaded, - (enum xpc_retval (*)(partid_t, int, void *)) xpc_notloaded, - (enum xpc_retval (*)(partid_t, int, void *, xpc_notify_func, void *)) - xpc_notloaded, - (void (*)(partid_t, int, void *)) xpc_notloaded, - (enum xpc_retval (*)(partid_t, void *)) xpc_notloaded + (void (*)(int))xpc_notloaded, + (void (*)(int))xpc_notloaded, + (enum xpc_retval(*)(partid_t, int, u32, void **))xpc_notloaded, + (enum xpc_retval(*)(partid_t, int, void *))xpc_notloaded, + (enum xpc_retval(*)(partid_t, int, void *, xpc_notify_func, void *)) + xpc_notloaded, + (void (*)(partid_t, int, void *))xpc_notloaded, + (enum xpc_retval(*)(partid_t, void *))xpc_notloaded }; - /* * XPC calls this when it (the XPC module) has been loaded. */ void -xpc_set_interface(void (*connect)(int), - void (*disconnect)(int), - enum xpc_retval (*allocate)(partid_t, int, u32, void **), - enum xpc_retval (*send)(partid_t, int, void *), - enum xpc_retval (*send_notify)(partid_t, int, void *, - xpc_notify_func, void *), - void (*received)(partid_t, int, void *), - enum xpc_retval (*partid_to_nasids)(partid_t, void *)) +xpc_set_interface(void (*connect) (int), + void (*disconnect) (int), + enum xpc_retval (*allocate) (partid_t, int, u32, void **), + enum xpc_retval (*send) (partid_t, int, void *), + enum xpc_retval (*send_notify) (partid_t, int, void *, + xpc_notify_func, void *), + void (*received) (partid_t, int, void *), + enum xpc_retval (*partid_to_nasids) (partid_t, void *)) { xpc_interface.connect = connect; xpc_interface.disconnect = disconnect; @@ -77,28 +75,27 @@ xpc_set_interface(void (*connect)(int), xpc_interface.partid_to_nasids = partid_to_nasids; } - /* * XPC calls this when it (the XPC module) is being unloaded. */ void xpc_clear_interface(void) { - xpc_interface.connect = (void (*)(int)) xpc_notloaded; - xpc_interface.disconnect = (void (*)(int)) xpc_notloaded; - xpc_interface.allocate = (enum xpc_retval (*)(partid_t, int, u32, - void **)) xpc_notloaded; - xpc_interface.send = (enum xpc_retval (*)(partid_t, int, void *)) - xpc_notloaded; - xpc_interface.send_notify = (enum xpc_retval (*)(partid_t, int, void *, - xpc_notify_func, void *)) xpc_notloaded; + xpc_interface.connect = (void (*)(int))xpc_notloaded; + xpc_interface.disconnect = (void (*)(int))xpc_notloaded; + xpc_interface.allocate = (enum xpc_retval(*)(partid_t, int, u32, + void **))xpc_notloaded; + xpc_interface.send = (enum xpc_retval(*)(partid_t, int, void *)) + xpc_notloaded; + xpc_interface.send_notify = (enum xpc_retval(*)(partid_t, int, void *, + xpc_notify_func, + void *))xpc_notloaded; xpc_interface.received = (void (*)(partid_t, int, void *)) - xpc_notloaded; - xpc_interface.partid_to_nasids = (enum xpc_retval (*)(partid_t, void *)) - xpc_notloaded; + xpc_notloaded; + xpc_interface.partid_to_nasids = (enum xpc_retval(*)(partid_t, void *)) + xpc_notloaded; } - /* * Register for automatic establishment of a channel connection whenever * a partition comes up. @@ -125,11 +122,10 @@ xpc_clear_interface(void) */ enum xpc_retval xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, - u16 nentries, u32 assigned_limit, u32 idle_limit) + u16 nentries, u32 assigned_limit, u32 idle_limit) { struct xpc_registration *registration; - DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); DBUG_ON(payload_size == 0 || nentries == 0); DBUG_ON(func == NULL); @@ -162,7 +158,6 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, return xpcSuccess; } - /* * Remove the registration for automatic connection of the specified channel * when a partition comes up. @@ -181,7 +176,6 @@ xpc_disconnect(int ch_number) { struct xpc_registration *registration; - DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); registration = &xpc_registrations[ch_number]; @@ -214,14 +208,12 @@ xpc_disconnect(int ch_number) return; } - int __init xp_init(void) { int ret, ch_number; - u64 func_addr = *(u64 *) xp_nofault_PIOR; - u64 err_func_addr = *(u64 *) xp_error_PIOR; - + u64 func_addr = *(u64 *)xp_nofault_PIOR; + u64 err_func_addr = *(u64 *)xp_error_PIOR; if (!ia64_platform_is("sn2")) { return -ENODEV; @@ -237,9 +229,9 @@ xp_init(void) * work around). */ if ((ret = sn_register_nofault_code(func_addr, err_func_addr, - err_func_addr, 1, 1)) != 0) { + err_func_addr, 1, 1)) != 0) { printk(KERN_ERR "XP: can't register nofault code, error=%d\n", - ret); + ret); } /* * Setup the nofault PIO read target. (There is no special reason why @@ -258,22 +250,21 @@ xp_init(void) return 0; } -module_init(xp_init); +module_init(xp_init); void __exit xp_exit(void) { - u64 func_addr = *(u64 *) xp_nofault_PIOR; - u64 err_func_addr = *(u64 *) xp_error_PIOR; - + u64 func_addr = *(u64 *)xp_nofault_PIOR; + u64 err_func_addr = *(u64 *)xp_error_PIOR; /* unregister the PIO read nofault code region */ - (void) sn_register_nofault_code(func_addr, err_func_addr, - err_func_addr, 1, 0); + (void)sn_register_nofault_code(func_addr, err_func_addr, + err_func_addr, 1, 0); } -module_exit(xp_exit); +module_exit(xp_exit); MODULE_AUTHOR("Silicon Graphics, Inc."); MODULE_DESCRIPTION("Cross Partition (XP) base"); @@ -287,4 +278,3 @@ EXPORT_SYMBOL(xpc_clear_interface); EXPORT_SYMBOL(xpc_set_interface); EXPORT_SYMBOL(xpc_connect); EXPORT_SYMBOL(xpc_disconnect); - diff --git a/drivers/misc/sgi-xp/xp_nofault.S b/drivers/misc/sgi-xp/xp_nofault.S index c13a709c4db..e38d4331942 100644 --- a/drivers/misc/sgi-xp/xp_nofault.S +++ b/drivers/misc/sgi-xp/xp_nofault.S @@ -6,7 +6,6 @@ * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. */ - /* * The xp_nofault_PIOR function takes a pointer to a remote PIO register * and attempts to load and consume a value from it. This function diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 14e70ee53eb..64368bb8889 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -6,7 +6,6 @@ * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. */ - /* * Cross Partition Communication (XPC) structures and macros. */ @@ -14,7 +13,6 @@ #ifndef _DRIVERS_MISC_SGIXP_XPC_H #define _DRIVERS_MISC_SGIXP_XPC_H - #include #include #include @@ -29,7 +27,6 @@ #include #include "xp.h" - /* * XPC Version numbers consist of a major and minor number. XPC can always * talk to versions with same major #, and never talk to versions with a @@ -39,7 +36,6 @@ #define XPC_VERSION_MAJOR(_v) ((_v) >> 4) #define XPC_VERSION_MINOR(_v) ((_v) & 0xf) - /* * The next macros define word or bit representations for given * C-brick nasid in either the SAL provided bit array representing @@ -67,7 +63,6 @@ /* define the process name of the discovery thread */ #define XPC_DISCOVERY_THREAD_NAME "xpc_discovery" - /* * the reserved page * @@ -121,7 +116,7 @@ struct xpc_rsvd_page { u64 nasids_size; /* SAL: size of each nasid mask in bytes */ }; -#define XPC_RP_VERSION _XPC_VERSION(1,1) /* version 1.1 of the reserved page */ +#define XPC_RP_VERSION _XPC_VERSION(1,1) /* version 1.1 of the reserved page */ #define XPC_SUPPORTS_RP_STAMP(_version) \ (_version >= _XPC_VERSION(1,1)) @@ -138,14 +133,12 @@ xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2) { int ret; - if ((ret = stamp1->tv_sec - stamp2->tv_sec) == 0) { ret = stamp1->tv_nsec - stamp2->tv_nsec; } return ret; } - /* * Define the structures by which XPC variables can be exported to other * partitions. (There are two: struct xpc_vars and struct xpc_vars_part) @@ -172,12 +165,11 @@ struct xpc_vars { AMO_t *amos_page; /* vaddr of page of AMOs from MSPEC driver */ }; -#define XPC_V_VERSION _XPC_VERSION(3,1) /* version 3.1 of the cross vars */ +#define XPC_V_VERSION _XPC_VERSION(3,1) /* version 3.1 of the cross vars */ #define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \ (_version >= _XPC_VERSION(3,1)) - static inline int xpc_hb_allowed(partid_t partid, struct xpc_vars *vars) { @@ -193,7 +185,7 @@ xpc_allow_hb(partid_t partid, struct xpc_vars *vars) old_mask = vars->heartbeating_to_mask; new_mask = (old_mask | (1UL << partid)); } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != - old_mask); + old_mask); } static inline void @@ -205,10 +197,9 @@ xpc_disallow_hb(partid_t partid, struct xpc_vars *vars) old_mask = vars->heartbeating_to_mask; new_mask = (old_mask & ~(1UL << partid)); } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != - old_mask); + old_mask); } - /* * The AMOs page consists of a number of AMO variables which are divided into * four groups, The first two groups are used to identify an IRQ's sender. @@ -222,7 +213,6 @@ xpc_disallow_hb(partid_t partid, struct xpc_vars *vars) #define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS) #define XPC_DISENGAGE_REQUEST_AMO (XPC_ENGAGED_PARTITIONS_AMO + 1) - /* * The following structure describes the per partition specific variables. * @@ -257,9 +247,8 @@ struct xpc_vars_part { * 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 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */ +#define XPC_VP_MAGIC2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */ /* the reserved page sizes and offsets */ @@ -271,7 +260,6 @@ struct xpc_vars_part { #define XPC_RP_VARS(_rp) ((struct xpc_vars *) XPC_RP_MACH_NASIDS(_rp) + xp_nasid_mask_words) #define XPC_RP_VARS_PART(_rp) (struct xpc_vars_part *) ((u8 *) XPC_RP_VARS(rp) + XPC_RP_VARS_SIZE) - /* * 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 @@ -285,8 +273,6 @@ struct xpc_vars_part { #define XPC_UNPACK_ARG1(_args) (((u64) _args) & 0xffffffff) #define XPC_UNPACK_ARG2(_args) ((((u64) _args) >> 32) & 0xffffffff) - - /* * Define a Get/Put value pair (pointers) used with a message queue. */ @@ -298,8 +284,6 @@ struct xpc_gp { #define XPC_GP_SIZE \ L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_NCHANNELS) - - /* * Define a structure that contains arguments associated with opening and * closing a channel. @@ -315,20 +299,15 @@ struct xpc_openclose_args { #define XPC_OPENCLOSE_ARGS_SIZE \ L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * XPC_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 */ - #define XPC_MSG_ADDRESS(_payload) \ ((struct xpc_msg *)((u8 *)(_payload) - XPC_MSG_PAYLOAD_OFFSET)) - - /* * Defines notify entry. * @@ -336,19 +315,17 @@ struct xpc_openclose_args { * and consumed by the intended recipient. */ struct xpc_notify { - volatile u8 type; /* type of notification */ + volatile u8 type; /* type of notification */ /* the following two fields are only used if type == XPC_N_CALL */ - xpc_notify_func func; /* user's notify function */ - void *key; /* pointer to user's key */ + xpc_notify_func func; /* user's notify function */ + void *key; /* pointer to user's key */ }; /* struct xpc_notify type of notification */ #define XPC_N_CALL 0x01 /* notify function provided by user */ - - /* * Define the structure that manages all the stuff required by a channel. In * particular, they are used to manage the messages sent across the channel. @@ -428,48 +405,48 @@ struct xpc_notify { * messages. */ struct xpc_channel { - partid_t partid; /* ID of remote partition connected */ - spinlock_t lock; /* lock for updating this structure */ - u32 flags; /* general flags */ + partid_t partid; /* ID of remote partition connected */ + spinlock_t lock; /* lock for updating this structure */ + u32 flags; /* general flags */ - enum xpc_retval reason; /* reason why channel is disconnect'g */ - int reason_line; /* line# disconnect initiated from */ + enum xpc_retval reason; /* reason why channel is disconnect'g */ + int reason_line; /* line# disconnect initiated from */ - u16 number; /* channel # */ + u16 number; /* channel # */ - u16 msg_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*/ + u16 msg_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 */ 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 */ - u64 remote_msgqueue_pa; /* phys addr of remote partition's */ - /* local message queue */ + 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 */ - atomic_t references; /* #of external references to queues */ + atomic_t references; /* #of external references to queues */ - atomic_t n_on_msg_allocate_wq; /* #on msg allocation wait queue */ - wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */ + atomic_t n_on_msg_allocate_wq; /* #on msg allocation wait queue */ + wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */ - u8 delayed_IPI_flags; /* IPI flags received, but delayed */ - /* action until channel disconnected */ + u8 delayed_IPI_flags; /* IPI 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 */ + 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 */ + xpc_channel_func func; /* user's channel function */ + void *key; /* pointer to user's key */ struct mutex msg_to_pull_mutex; /* next msg to pull serialization */ - struct completion wdisconnect_wait; /* wait for channel disconnect */ + struct completion wdisconnect_wait; /* wait for channel disconnect */ - struct xpc_openclose_args *local_openclose_args; /* args passed on */ - /* opening or closing of channel */ + struct xpc_openclose_args *local_openclose_args; /* args passed on */ + /* opening or closing of channel */ /* various flavors of local and remote Get/Put values */ @@ -477,7 +454,7 @@ struct xpc_channel { 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 */ - s64 next_msg_to_pull; /* Put value of next msg to pull */ + s64 next_msg_to_pull; /* Put value of next msg to pull */ /* kthread management related fields */ @@ -485,48 +462,45 @@ struct xpc_channel { // >>> allow the assigned limit be unbounded and let the idle limit be dynamic // >>> dependent on activity over the last interval of time atomic_t kthreads_assigned; /* #of kthreads assigned to channel */ - u32 kthreads_assigned_limit; /* limit on #of kthreads assigned */ - atomic_t kthreads_idle; /* #of kthreads idle waiting for work */ + u32 kthreads_assigned_limit; /* limit on #of kthreads assigned */ + atomic_t kthreads_idle; /* #of kthreads idle waiting for work */ u32 kthreads_idle_limit; /* limit on #of kthreads idle */ atomic_t kthreads_active; /* #of kthreads actively working */ // >>> following field is temporary - u32 kthreads_created; /* total #of kthreads created */ + u32 kthreads_created; /* total #of kthreads created */ wait_queue_head_t idle_wq; /* idle kthread wait queue */ } ____cacheline_aligned; - /* struct xpc_channel flags */ -#define XPC_C_WASCONNECTED 0x00000001 /* channel was connected */ +#define XPC_C_WASCONNECTED 0x00000001 /* channel was connected */ -#define XPC_C_ROPENREPLY 0x00000002 /* remote open channel reply */ -#define XPC_C_OPENREPLY 0x00000004 /* local open channel reply */ -#define XPC_C_ROPENREQUEST 0x00000008 /* remote open channel request */ -#define XPC_C_OPENREQUEST 0x00000010 /* local open channel request */ +#define XPC_C_ROPENREPLY 0x00000002 /* remote open channel reply */ +#define XPC_C_OPENREPLY 0x00000004 /* local open channel reply */ +#define XPC_C_ROPENREQUEST 0x00000008 /* remote open channel request */ +#define XPC_C_OPENREQUEST 0x00000010 /* local open channel request */ -#define XPC_C_SETUP 0x00000020 /* channel's msgqueues are alloc'd */ -#define XPC_C_CONNECTEDCALLOUT 0x00000040 /* connected callout initiated */ +#define XPC_C_SETUP 0x00000020 /* channel's msgqueues are alloc'd */ +#define XPC_C_CONNECTEDCALLOUT 0x00000040 /* connected callout initiated */ #define XPC_C_CONNECTEDCALLOUT_MADE \ - 0x00000080 /* connected callout completed */ -#define XPC_C_CONNECTED 0x00000100 /* local channel is connected */ -#define XPC_C_CONNECTING 0x00000200 /* channel is being connected */ + 0x00000080 /* connected callout completed */ +#define XPC_C_CONNECTED 0x00000100 /* local channel is connected */ +#define XPC_C_CONNECTING 0x00000200 /* channel is being connected */ -#define XPC_C_RCLOSEREPLY 0x00000400 /* remote close channel reply */ -#define XPC_C_CLOSEREPLY 0x00000800 /* local close channel reply */ -#define XPC_C_RCLOSEREQUEST 0x00001000 /* remote close channel request */ -#define XPC_C_CLOSEREQUEST 0x00002000 /* local close channel request */ +#define XPC_C_RCLOSEREPLY 0x00000400 /* remote close channel reply */ +#define XPC_C_CLOSEREPLY 0x00000800 /* local close channel reply */ +#define XPC_C_RCLOSEREQUEST 0x00001000 /* remote close channel request */ +#define XPC_C_CLOSEREQUEST 0x00002000 /* local close channel request */ -#define XPC_C_DISCONNECTED 0x00004000 /* channel is disconnected */ -#define XPC_C_DISCONNECTING 0x00008000 /* channel is being disconnected */ +#define XPC_C_DISCONNECTED 0x00004000 /* channel is disconnected */ +#define XPC_C_DISCONNECTING 0x00008000 /* channel is being disconnected */ #define XPC_C_DISCONNECTINGCALLOUT \ - 0x00010000 /* disconnecting callout initiated */ + 0x00010000 /* disconnecting callout initiated */ #define XPC_C_DISCONNECTINGCALLOUT_MADE \ - 0x00020000 /* disconnecting callout completed */ -#define XPC_C_WDISCONNECT 0x00040000 /* waiting for channel disconnect */ - - + 0x00020000 /* disconnecting callout completed */ +#define XPC_C_WDISCONNECT 0x00040000 /* waiting for channel disconnect */ /* * Manages channels on a partition basis. There is one of these structures @@ -537,33 +511,31 @@ struct xpc_partition { /* XPC HB infrastructure */ - u8 remote_rp_version; /* version# of partition's rsvd pg */ - struct timespec remote_rp_stamp;/* time when rsvd pg was initialized */ - u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ - u64 remote_vars_pa; /* phys addr of partition's vars */ + u8 remote_rp_version; /* version# of partition's rsvd pg */ + struct timespec remote_rp_stamp; /* time when rsvd pg was initialized */ + u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ + u64 remote_vars_pa; /* phys addr of partition's vars */ u64 remote_vars_part_pa; /* phys addr of partition's vars part */ - u64 last_heartbeat; /* HB at last read */ + u64 last_heartbeat; /* HB at last read */ u64 remote_amos_page_pa; /* phys addr of partition's amos page */ - int remote_act_nasid; /* active part's act/deact nasid */ + int remote_act_nasid; /* active part's act/deact nasid */ int remote_act_phys_cpuid; /* active part's act/deact phys cpuid */ - u32 act_IRQ_rcvd; /* IRQs since activation */ - spinlock_t act_lock; /* protect updating of act_state */ - u8 act_state; /* from XPC HB viewpoint */ - u8 remote_vars_version; /* version# of partition's vars */ - enum xpc_retval reason; /* reason partition is deactivating */ - int reason_line; /* line# deactivation initiated from */ - int reactivate_nasid; /* nasid in partition to reactivate */ - - unsigned long disengage_request_timeout; /* timeout in jiffies */ + u32 act_IRQ_rcvd; /* IRQs since activation */ + spinlock_t act_lock; /* protect updating of act_state */ + u8 act_state; /* from XPC HB viewpoint */ + u8 remote_vars_version; /* version# of partition's vars */ + enum xpc_retval reason; /* reason partition is deactivating */ + int reason_line; /* line# deactivation initiated from */ + int reactivate_nasid; /* nasid in partition to reactivate */ + + unsigned long disengage_request_timeout; /* timeout in jiffies */ struct timer_list disengage_request_timer; - /* XPC infrastructure referencing and teardown control */ volatile u8 setup_state; /* infrastructure setup state */ wait_queue_head_t teardown_wq; /* kthread waiting to teardown infra */ - atomic_t references; /* #of references to infrastructure */ - + atomic_t references; /* #of references to infrastructure */ /* * NONE OF THE PRECEDING FIELDS OF THIS STRUCTURE WILL BE CLEARED WHEN @@ -572,53 +544,48 @@ struct xpc_partition { * 'nchannels' FIELD MUST BE THE FIRST OF THE FIELDS TO BE CLEARED.) */ - - u8 nchannels; /* #of defined channels supported */ - atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */ - atomic_t nchannels_engaged;/* #of channels engaged with remote part */ - struct xpc_channel *channels;/* array of channel structures */ - - void *local_GPs_base; /* base address of kmalloc'd space */ - struct xpc_gp *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 Get/Put */ - /* values */ - u64 remote_GPs_pa; /* phys address of remote partition's local */ - /* Get/Put values */ - + u8 nchannels; /* #of defined channels supported */ + atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */ + atomic_t nchannels_engaged; /* #of channels engaged with remote part */ + struct xpc_channel *channels; /* array of channel structures */ + + void *local_GPs_base; /* base address of kmalloc'd space */ + struct xpc_gp *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 Get/Put */ + /* values */ + u64 remote_GPs_pa; /* phys address of remote partition's local */ + /* Get/Put values */ /* fields used to pass args when opening or closing a channel */ - 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 */ - u64 remote_openclose_args_pa; /* phys addr of remote's args */ - + 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 */ + u64 remote_openclose_args_pa; /* phys addr of remote's args */ /* IPI sending, receiving and handling related fields */ - int remote_IPI_nasid; /* nasid of where to send IPIs */ - int remote_IPI_phys_cpuid; /* phys CPU ID of where to send IPIs */ - AMO_t *remote_IPI_amo_va; /* address of remote IPI AMO_t structure */ + int remote_IPI_nasid; /* nasid of where to send IPIs */ + int remote_IPI_phys_cpuid; /* phys CPU ID of where to send IPIs */ + AMO_t *remote_IPI_amo_va; /* address of remote IPI AMO_t structure */ - AMO_t *local_IPI_amo_va; /* address of IPI AMO_t structure */ - u64 local_IPI_amo; /* IPI amo flags yet to be handled */ - char IPI_owner[8]; /* IPI owner's name */ - struct timer_list dropped_IPI_timer; /* dropped IPI timer */ - - spinlock_t IPI_lock; /* IPI handler lock */ + AMO_t *local_IPI_amo_va; /* address of IPI AMO_t structure */ + u64 local_IPI_amo; /* IPI amo flags yet to be handled */ + char IPI_owner[8]; /* IPI owner's name */ + struct timer_list dropped_IPI_timer; /* dropped IPI timer */ + spinlock_t IPI_lock; /* IPI handler lock */ /* channel manager related fields */ atomic_t channel_mgr_requests; /* #of requests to activate chan mgr */ - wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */ + wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */ } ____cacheline_aligned; - /* struct xpc_partition act_state values (for XPC HB) */ #define XPC_P_INACTIVE 0x00 /* partition is not active */ @@ -627,11 +594,9 @@ struct xpc_partition { #define XPC_P_ACTIVE 0x03 /* xpc_partition_up() was called */ #define XPC_P_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 */ @@ -639,8 +604,6 @@ struct xpc_partition { #define XPC_P_WTEARDOWN 0x02 /* waiting to teardown infrastructure */ #define XPC_P_TORNDOWN 0x03 /* infrastructure is torndown */ - - /* * struct xpc_partition IPI_timer #of seconds to wait before checking for * dropped IPIs. These occur whenever an IPI amo write doesn't complete until @@ -648,22 +611,17 @@ struct xpc_partition { */ #define XPC_P_DROPPED_IPI_WAIT (0.25 * HZ) - /* number of seconds to wait for other partitions to disengage */ #define XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT 90 /* interval in seconds to print 'waiting disengagement' messages */ #define XPC_DISENGAGE_PRINTMSG_INTERVAL 10 - #define XPC_PARTID(_p) ((partid_t) ((_p) - &xpc_partitions[0])) - - /* found in xp_main.c */ extern struct xpc_registration xpc_registrations[]; - /* found in xpc_main.c */ extern struct device *xpc_part; extern struct device *xpc_chan; @@ -676,7 +634,6 @@ 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); - /* found in xpc_partition.c */ extern int xpc_exiting; extern struct xpc_vars *xpc_vars; @@ -696,10 +653,9 @@ extern void xpc_mark_partition_inactive(struct xpc_partition *); extern void xpc_discovery(void); extern void xpc_check_remote_hb(void); extern void xpc_deactivate_partition(const int, struct xpc_partition *, - enum xpc_retval); + enum xpc_retval); extern enum xpc_retval xpc_initiate_partid_to_nasids(partid_t, void *); - /* found in xpc_channel.c */ extern void xpc_initiate_connect(int); extern void xpc_initiate_disconnect(int); @@ -714,13 +670,11 @@ extern void xpc_process_channel_activity(struct xpc_partition *); extern void xpc_connected_callout(struct xpc_channel *); extern void xpc_deliver_msg(struct xpc_channel *); extern void xpc_disconnect_channel(const int, struct xpc_channel *, - enum xpc_retval, unsigned long *); + enum xpc_retval, unsigned long *); extern void xpc_disconnect_callout(struct xpc_channel *, enum xpc_retval); extern void xpc_partition_going_down(struct xpc_partition *, enum xpc_retval); extern void xpc_teardown_infrastructure(struct xpc_partition *); - - static inline void xpc_wakeup_channel_mgr(struct xpc_partition *part) { @@ -729,8 +683,6 @@ xpc_wakeup_channel_mgr(struct xpc_partition *part) } } - - /* * These next two inlines are used to keep us from tearing down a channel's * msg queues while a thread may be referencing them. @@ -752,12 +704,9 @@ xpc_msgqueue_deref(struct xpc_channel *ch) } } - - #define XPC_DISCONNECT_CHANNEL(_ch, _reason, _irqflgs) \ xpc_disconnect_channel(__LINE__, _ch, _reason, _irqflgs) - /* * These two inlines are used to keep us from tearing down a partition's * setup infrastructure while a thread may be referencing it. @@ -767,7 +716,6 @@ xpc_part_deref(struct xpc_partition *part) { s32 refs = atomic_dec_return(&part->references); - DBUG_ON(refs < 0); if (refs == 0 && part->setup_state == XPC_P_WTEARDOWN) { wake_up(&part->teardown_wq); @@ -779,7 +727,6 @@ xpc_part_ref(struct xpc_partition *part) { int setup; - atomic_inc(&part->references); setup = (part->setup_state == XPC_P_SETUP); if (!setup) { @@ -788,8 +735,6 @@ xpc_part_ref(struct xpc_partition *part) return setup; } - - /* * The following macro is to be used for the setting of the reason and * reason_line fields in both the struct xpc_channel and struct xpc_partition @@ -801,8 +746,6 @@ xpc_part_ref(struct xpc_partition *part) (_p)->reason_line = _line; \ } - - /* * This next set of inlines are used to keep track of when a partition is * potentially engaged in accessing memory belonging to another partition. @@ -812,23 +755,24 @@ static inline void xpc_mark_partition_engaged(struct xpc_partition *part) { unsigned long irq_flags; - AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + - (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t))); - + AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * + sizeof(AMO_t))); local_irq_save(irq_flags); /* set bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, - (1UL << sn_partition_id)); + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, + (1UL << sn_partition_id)); /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would * keep sending IPIs and AMOs to it until the heartbeat times out. */ - (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), xp_nofault_PIOR_target)); + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); local_irq_restore(irq_flags); } @@ -837,23 +781,24 @@ static inline void xpc_mark_partition_disengaged(struct xpc_partition *part) { unsigned long irq_flags; - AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + - (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t))); - + AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * + sizeof(AMO_t))); local_irq_save(irq_flags); /* clear bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, - ~(1UL << sn_partition_id)); + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~(1UL << sn_partition_id)); /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would * keep sending IPIs and AMOs to it until the heartbeat times out. */ - (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), xp_nofault_PIOR_target)); + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); local_irq_restore(irq_flags); } @@ -862,23 +807,23 @@ static inline void xpc_request_partition_disengage(struct xpc_partition *part) { unsigned long irq_flags; - AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + - (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); - + AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); local_irq_save(irq_flags); /* set bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, - (1UL << sn_partition_id)); + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, + (1UL << sn_partition_id)); /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would * keep sending IPIs and AMOs to it until the heartbeat times out. */ - (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), xp_nofault_PIOR_target)); + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); local_irq_restore(irq_flags); } @@ -887,23 +832,23 @@ static inline void xpc_cancel_partition_disengage_request(struct xpc_partition *part) { unsigned long irq_flags; - AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa + - (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); - + AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); local_irq_save(irq_flags); /* clear bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, - ~(1UL << sn_partition_id)); + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~(1UL << sn_partition_id)); /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would * keep sending IPIs and AMOs to it until the heartbeat times out. */ - (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), xp_nofault_PIOR_target)); + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); local_irq_restore(irq_flags); } @@ -913,10 +858,9 @@ xpc_partition_engaged(u64 partid_mask) { AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - /* return our partition's AMO variable ANDed with partid_mask */ - return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) & - partid_mask); + return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & + partid_mask); } static inline u64 @@ -924,10 +868,9 @@ xpc_partition_disengage_requested(u64 partid_mask) { AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; - /* return our partition's AMO variable ANDed with partid_mask */ - return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) & - partid_mask); + return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & + partid_mask); } static inline void @@ -935,10 +878,9 @@ xpc_clear_partition_engaged(u64 partid_mask) { AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - /* clear bit(s) based on partid_mask in our partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, - ~partid_mask); + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~partid_mask); } static inline void @@ -946,14 +888,11 @@ xpc_clear_partition_disengage_request(u64 partid_mask) { AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; - /* clear bit(s) based on partid_mask in our partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND, - ~partid_mask); + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~partid_mask); } - - /* * The following set of macros and inlines are used for the sending and * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, @@ -964,20 +903,18 @@ xpc_clear_partition_disengage_request(u64 partid_mask) static inline u64 xpc_IPI_receive(AMO_t *amo) { - return FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_CLEAR); + return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR); } - static inline enum xpc_retval xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) { int ret = 0; unsigned long irq_flags; - local_irq_save(irq_flags); - FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, flag); + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, flag); sn_send_IPI_phys(nasid, phys_cpuid, vector, 0); /* @@ -986,15 +923,14 @@ xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) * didn't, we'd never know that the other partition is down and would * keep sending IPIs and AMOs to it until the heartbeat times out. */ - ret = xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->variable), - xp_nofault_PIOR_target)); + ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable), + xp_nofault_PIOR_target)); local_irq_restore(irq_flags); return ((ret == 0) ? xpcSuccess : xpcPioReadError); } - /* * IPIs associated with SGI_XPC_ACTIVATE IRQ. */ @@ -1004,47 +940,47 @@ xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) */ static inline void xpc_activate_IRQ_send(u64 amos_page_pa, int from_nasid, int to_nasid, - int to_phys_cpuid) + int to_phys_cpuid) { int w_index = XPC_NASID_W_INDEX(from_nasid); int b_index = XPC_NASID_B_INDEX(from_nasid); - AMO_t *amos = (AMO_t *) __va(amos_page_pa + - (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); - + AMO_t *amos = (AMO_t *)__va(amos_page_pa + + (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); - (void) xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid, - to_phys_cpuid, SGI_XPC_ACTIVATE); + (void)xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid, + to_phys_cpuid, SGI_XPC_ACTIVATE); } static inline void xpc_IPI_send_activate(struct xpc_vars *vars) { xpc_activate_IRQ_send(vars->amos_page_pa, cnodeid_to_nasid(0), - vars->act_nasid, vars->act_phys_cpuid); + vars->act_nasid, vars->act_phys_cpuid); } static inline void xpc_IPI_send_activated(struct xpc_partition *part) { xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0), - part->remote_act_nasid, part->remote_act_phys_cpuid); + part->remote_act_nasid, + part->remote_act_phys_cpuid); } static inline void xpc_IPI_send_reactivate(struct xpc_partition *part) { xpc_activate_IRQ_send(xpc_vars->amos_page_pa, part->reactivate_nasid, - xpc_vars->act_nasid, xpc_vars->act_phys_cpuid); + xpc_vars->act_nasid, xpc_vars->act_phys_cpuid); } static inline void xpc_IPI_send_disengage(struct xpc_partition *part) { xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0), - part->remote_act_nasid, part->remote_act_phys_cpuid); + part->remote_act_nasid, + part->remote_act_phys_cpuid); } - /* * IPIs associated with SGI_XPC_NOTIFY IRQ. */ @@ -1058,18 +994,16 @@ xpc_IPI_send_disengage(struct xpc_partition *part) static inline void xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string, - unsigned long *irq_flags) + unsigned long *irq_flags) { struct xpc_partition *part = &xpc_partitions[ch->partid]; enum xpc_retval ret; - if (likely(part->act_state != XPC_P_DEACTIVATING)) { ret = xpc_IPI_send(part->remote_IPI_amo_va, - (u64) ipi_flag << (ch->number * 8), - part->remote_IPI_nasid, - part->remote_IPI_phys_cpuid, - SGI_XPC_NOTIFY); + (u64)ipi_flag << (ch->number * 8), + part->remote_IPI_nasid, + part->remote_IPI_phys_cpuid, SGI_XPC_NOTIFY); dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n", ipi_flag_string, ch->partid, ch->number, ret); if (unlikely(ret != xpcSuccess)) { @@ -1084,7 +1018,6 @@ xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string, } } - /* * Make it look like the remote partition, which is associated with the * specified channel, sent us an IPI. This faked IPI will be handled @@ -1095,18 +1028,16 @@ xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string, static inline void xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag, - char *ipi_flag_string) + char *ipi_flag_string) { struct xpc_partition *part = &xpc_partitions[ch->partid]; - - FETCHOP_STORE_OP(TO_AMO((u64) &part->local_IPI_amo_va->variable), - FETCHOP_OR, ((u64) ipi_flag << (ch->number * 8))); + FETCHOP_STORE_OP(TO_AMO((u64)&part->local_IPI_amo_va->variable), + FETCHOP_OR, ((u64)ipi_flag << (ch->number * 8))); dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n", ipi_flag_string, ch->partid, ch->number); } - /* * The sending and receiving of IPIs includes the setting of an AMO variable * to indicate the reason the IPI was sent. The 64-bit variable is divided @@ -1121,7 +1052,6 @@ xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag, #define XPC_IPI_OPENREPLY 0x08 #define XPC_IPI_MSGREQUEST 0x10 - /* given an AMO variable and a channel#, get its associated IPI flags */ #define XPC_GET_IPI_FLAGS(_amo, _c) ((u8) (((_amo) >> ((_c) * 8)) & 0xff)) #define XPC_SET_IPI_FLAGS(_amo, _c, _f) (_amo) |= ((u64) (_f) << ((_c) * 8)) @@ -1129,13 +1059,11 @@ xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag, #define XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & __IA64_UL_CONST(0x0f0f0f0f0f0f0f0f)) #define XPC_ANY_MSG_IPI_FLAGS_SET(_amo) ((_amo) & __IA64_UL_CONST(0x1010101010101010)) - static inline void xpc_IPI_send_closerequest(struct xpc_channel *ch, unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->local_openclose_args; - args->reason = ch->reason; XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREQUEST, irq_flags); @@ -1152,7 +1080,6 @@ xpc_IPI_send_openrequest(struct xpc_channel *ch, unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->local_openclose_args; - args->msg_size = ch->msg_size; args->local_nentries = ch->local_nentries; @@ -1164,7 +1091,6 @@ xpc_IPI_send_openreply(struct xpc_channel *ch, unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->local_openclose_args; - args->remote_nentries = ch->remote_nentries; args->local_nentries = ch->local_nentries; args->local_msgqueue_pa = __pa(ch->local_msgqueue); @@ -1184,7 +1110,6 @@ xpc_IPI_send_local_msgrequest(struct xpc_channel *ch) XPC_NOTIFY_IRQ_SEND_LOCAL(ch, XPC_IPI_MSGREQUEST); } - /* * Memory for XPC's AMO variables is allocated by the MSPEC driver. These * pages are located in the lowest granule. The lowest granule uses 4k pages @@ -1201,13 +1126,10 @@ xpc_IPI_init(int index) { AMO_t *amo = xpc_vars->amos_page + index; - - (void) xpc_IPI_receive(amo); /* clear AMO variable */ + (void)xpc_IPI_receive(amo); /* clear AMO variable */ return amo; } - - static inline enum xpc_retval xpc_map_bte_errors(bte_result_t error) { @@ -1220,22 +1142,31 @@ xpc_map_bte_errors(bte_result_t error) return xpcBteUnmappedError; } switch (error) { - case BTE_SUCCESS: return xpcSuccess; - case BTEFAIL_DIR: return xpcBteDirectoryError; - case BTEFAIL_POISON: return xpcBtePoisonError; - case BTEFAIL_WERR: return xpcBteWriteError; - case BTEFAIL_ACCESS: return xpcBteAccessError; - case BTEFAIL_PWERR: return xpcBtePWriteError; - case BTEFAIL_PRERR: return xpcBtePReadError; - case BTEFAIL_TOUT: return xpcBteTimeOutError; - case BTEFAIL_XTERR: return xpcBteXtalkError; - case BTEFAIL_NOTAVAIL: return xpcBteNotAvailable; - default: return xpcBteUnmappedError; + case BTE_SUCCESS: + return xpcSuccess; + case BTEFAIL_DIR: + return xpcBteDirectoryError; + case BTEFAIL_POISON: + return xpcBtePoisonError; + case BTEFAIL_WERR: + return xpcBteWriteError; + case BTEFAIL_ACCESS: + return xpcBteAccessError; + case BTEFAIL_PWERR: + return xpcBtePWriteError; + case BTEFAIL_PRERR: + return xpcBtePReadError; + case BTEFAIL_TOUT: + return xpcBteTimeOutError; + case BTEFAIL_XTERR: + return xpcBteXtalkError; + case BTEFAIL_NOTAVAIL: + return xpcBteNotAvailable; + default: + return xpcBteUnmappedError; } } - - /* * Check to see if there is any channel activity to/from the specified * partition. @@ -1246,7 +1177,6 @@ xpc_check_for_channel_activity(struct xpc_partition *part) u64 IPI_amo; unsigned long irq_flags; - IPI_amo = xpc_IPI_receive(part->local_IPI_amo_va); if (IPI_amo == 0) { return; @@ -1262,6 +1192,4 @@ xpc_check_for_channel_activity(struct xpc_partition *part) xpc_wakeup_channel_mgr(part); } - #endif /* _DRIVERS_MISC_SGIXP_XPC_H */ - diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 7412dc7351c..57f1d0b3ac2 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -6,7 +6,6 @@ * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. */ - /* * Cross Partition Communication (XPC) partition support. * @@ -16,7 +15,6 @@ * */ - #include #include #include @@ -30,11 +28,9 @@ #include #include "xpc.h" - /* XPC is exiting flag */ int xpc_exiting; - /* SH_IPI_ACCESS shub register value on startup */ static u64 xpc_sh1_IPI_access; static u64 xpc_sh2_IPI_access0; @@ -42,11 +38,9 @@ static u64 xpc_sh2_IPI_access1; static u64 xpc_sh2_IPI_access2; static u64 xpc_sh2_IPI_access3; - /* original protection values for each node */ u64 xpc_prot_vec[MAX_NUMNODES]; - /* this partition's reserved page pointers */ struct xpc_rsvd_page *xpc_rsvd_page; static u64 *xpc_part_nasids; @@ -57,7 +51,6 @@ struct xpc_vars_part *xpc_vars_part; static int xp_nasid_mask_bytes; /* actual size in bytes of nasid mask */ static int xp_nasid_mask_words; /* actual size in words of nasid mask */ - /* * For performance reasons, each entry of xpc_partitions[] is cacheline * aligned. And xpc_partitions[] is padded with an additional entry at the @@ -66,7 +59,6 @@ static int xp_nasid_mask_words; /* actual size in words of nasid mask */ */ struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1]; - /* * Generic buffer used to store a local copy of portions of a remote * partition's reserved page (either its header and part_nasids mask, @@ -75,7 +67,6 @@ struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1]; char *xpc_remote_copy_buffer; void *xpc_remote_copy_buffer_base; - /* * Guarantee that the kmalloc'd memory is cacheline aligned. */ @@ -87,7 +78,7 @@ xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) if (*base == NULL) { return NULL; } - if ((u64) *base == L1_CACHE_ALIGN((u64) *base)) { + if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) { return *base; } kfree(*base); @@ -97,10 +88,9 @@ xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) if (*base == NULL) { return NULL; } - return (void *) L1_CACHE_ALIGN((u64) *base); + return (void *)L1_CACHE_ALIGN((u64)*base); } - /* * Given a nasid, get the physical address of the partition's reserved page * for that nasid. This function returns 0 on any error. @@ -117,11 +107,10 @@ xpc_get_rsvd_page_pa(int nasid) u64 buf_len = 0; void *buf_base = NULL; - while (1) { status = sn_partition_reserved_page_pa(buf, &cookie, &rp_pa, - &len); + &len); dev_dbg(xpc_part, "SAL returned with status=%li, cookie=" "0x%016lx, address=0x%016lx, len=0x%016lx\n", @@ -134,8 +123,9 @@ 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 = (u64)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", buf_len); @@ -145,7 +135,7 @@ xpc_get_rsvd_page_pa(int nasid) } bte_res = xp_bte_copy(rp_pa, buf, buf_len, - (BTE_NOTIFY | BTE_WACQUIRE), NULL); + (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bte_res != BTE_SUCCESS) { dev_dbg(xpc_part, "xp_bte_copy failed %i\n", bte_res); status = SALRET_ERROR; @@ -162,7 +152,6 @@ xpc_get_rsvd_page_pa(int nasid) return rp_pa; } - /* * Fill the partition reserved page with the information needed by * other partitions to discover we are alive and establish initial @@ -176,7 +165,6 @@ xpc_rsvd_page_init(void) u64 rp_pa, nasid_array = 0; int i, ret; - /* get the local reserved page's address */ preempt_disable(); @@ -186,7 +174,7 @@ xpc_rsvd_page_init(void) dev_err(xpc_part, "SAL failed to locate the reserved page\n"); return NULL; } - rp = (struct xpc_rsvd_page *) __va(rp_pa); + rp = (struct xpc_rsvd_page *)__va(rp_pa); if (rp->partid != sn_partition_id) { dev_err(xpc_part, "the reserved page's partid of %d should be " @@ -223,7 +211,7 @@ xpc_rsvd_page_init(void) * memory protections are never restricted. */ if ((amos_page = xpc_vars->amos_page) == NULL) { - amos_page = (AMO_t *) TO_AMO(uncached_alloc_page(0)); + amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0)); if (amos_page == NULL) { dev_err(xpc_part, "can't allocate page of AMOs\n"); return NULL; @@ -234,30 +222,31 @@ xpc_rsvd_page_init(void) * when xpc_allow_IPI_ops() is called via xpc_hb_init(). */ if (!enable_shub_wars_1_1()) { - ret = sn_change_memprotect(ia64_tpa((u64) amos_page), - PAGE_SIZE, SN_MEMPROT_ACCESS_CLASS_1, - &nasid_array); + ret = sn_change_memprotect(ia64_tpa((u64)amos_page), + PAGE_SIZE, + SN_MEMPROT_ACCESS_CLASS_1, + &nasid_array); if (ret != 0) { dev_err(xpc_part, "can't change memory " "protections\n"); uncached_free_page(__IA64_UNCACHED_OFFSET | - TO_PHYS((u64) amos_page)); + TO_PHYS((u64)amos_page)); return NULL; } } - } else if (!IS_AMO_ADDRESS((u64) amos_page)) { + } else if (!IS_AMO_ADDRESS((u64)amos_page)) { /* * EFI's XPBOOT can also set amos_page in the reserved page, * but it happens to leave it as an uncached physical address * and we need it to be an uncached virtual, so we'll have to * convert it. */ - if (!IS_AMO_PHYS_ADDRESS((u64) amos_page)) { + if (!IS_AMO_PHYS_ADDRESS((u64)amos_page)) { dev_err(xpc_part, "previously used amos_page address " - "is bad = 0x%p\n", (void *) amos_page); + "is bad = 0x%p\n", (void *)amos_page); return NULL; } - amos_page = (AMO_t *) TO_AMO((u64) amos_page); + amos_page = (AMO_t *)TO_AMO((u64)amos_page); } /* clear xpc_vars */ @@ -267,22 +256,21 @@ xpc_rsvd_page_init(void) xpc_vars->act_nasid = cpuid_to_nasid(0); xpc_vars->act_phys_cpuid = cpu_physical_id(0); xpc_vars->vars_part_pa = __pa(xpc_vars_part); - xpc_vars->amos_page_pa = ia64_tpa((u64) amos_page); - xpc_vars->amos_page = amos_page; /* save for next load of XPC */ - + xpc_vars->amos_page_pa = ia64_tpa((u64)amos_page); + xpc_vars->amos_page = amos_page; /* save for next load of XPC */ /* clear xpc_vars_part */ - memset((u64 *) xpc_vars_part, 0, sizeof(struct xpc_vars_part) * - XP_MAX_PARTITIONS); + memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part) * + XP_MAX_PARTITIONS); /* initialize the activate IRQ related AMO variables */ for (i = 0; i < xp_nasid_mask_words; i++) { - (void) xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); + (void)xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); } /* initialize the engaged remote partitions related AMO variables */ - (void) xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); - (void) xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); + (void)xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); + (void)xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); /* timestamp of when reserved page was setup by XPC */ rp->stamp = CURRENT_TIME; @@ -296,7 +284,6 @@ xpc_rsvd_page_init(void) return rp; } - /* * Change protections to allow IPI operations (and AMO operations on * Shub 1.1 systems). @@ -307,39 +294,38 @@ xpc_allow_IPI_ops(void) int node; int nasid; - // >>> Change SH_IPI_ACCESS code to use SAL call once it is available. if (is_shub2()) { xpc_sh2_IPI_access0 = - (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); xpc_sh2_IPI_access1 = - (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); xpc_sh2_IPI_access2 = - (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); xpc_sh2_IPI_access3 = - (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); for_each_online_node(node) { nasid = cnodeid_to_nasid(node); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), - -1UL); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), - -1UL); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), - -1UL); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), - -1UL); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), + -1UL); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), + -1UL); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), + -1UL); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), + -1UL); } } else { xpc_sh1_IPI_access = - (u64) HUB_L((u64 *) LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); for_each_online_node(node) { nasid = cnodeid_to_nasid(node); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), - -1UL); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), + -1UL); /* * Since the BIST collides with memory operations on @@ -347,21 +333,23 @@ xpc_allow_IPI_ops(void) */ if (enable_shub_wars_1_1()) { /* open up everything */ - xpc_prot_vec[node] = (u64) HUB_L((u64 *) - GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQLP_MMR_DIR_PRIVEC0)); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQLP_MMR_DIR_PRIVEC0), - -1UL); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQRP_MMR_DIR_PRIVEC0), - -1UL); + xpc_prot_vec[node] = (u64)HUB_L((u64 *) + GLOBAL_MMR_ADDR + (nasid, + SH1_MD_DQLP_MMR_DIR_PRIVEC0)); + HUB_S((u64 *) + GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQLP_MMR_DIR_PRIVEC0), + -1UL); + HUB_S((u64 *) + GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQRP_MMR_DIR_PRIVEC0), + -1UL); } } } } - /* * Restrict protections to disallow IPI operations (and AMO operations on * Shub 1.1 systems). @@ -372,43 +360,41 @@ xpc_restrict_IPI_ops(void) int node; int nasid; - // >>> Change SH_IPI_ACCESS code to use SAL call once it is available. if (is_shub2()) { for_each_online_node(node) { nasid = cnodeid_to_nasid(node); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), - xpc_sh2_IPI_access0); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), - xpc_sh2_IPI_access1); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), - xpc_sh2_IPI_access2); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), - xpc_sh2_IPI_access3); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), + xpc_sh2_IPI_access0); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), + xpc_sh2_IPI_access1); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), + xpc_sh2_IPI_access2); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), + xpc_sh2_IPI_access3); } } else { for_each_online_node(node) { nasid = cnodeid_to_nasid(node); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), - xpc_sh1_IPI_access); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), + xpc_sh1_IPI_access); if (enable_shub_wars_1_1()) { - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQLP_MMR_DIR_PRIVEC0), - xpc_prot_vec[node]); - HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQRP_MMR_DIR_PRIVEC0), - xpc_prot_vec[node]); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQLP_MMR_DIR_PRIVEC0), + xpc_prot_vec[node]); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQRP_MMR_DIR_PRIVEC0), + xpc_prot_vec[node]); } } } } - /* * At periodic intervals, scan through all active partitions and ensure * their heartbeat is still active. If not, the partition is deactivated. @@ -421,8 +407,7 @@ xpc_check_remote_hb(void) partid_t partid; bte_result_t bres; - - remote_vars = (struct xpc_vars *) xpc_remote_copy_buffer; + remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer; for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { @@ -437,18 +422,18 @@ xpc_check_remote_hb(void) part = &xpc_partitions[partid]; if (part->act_state == XPC_P_INACTIVE || - part->act_state == XPC_P_DEACTIVATING) { + part->act_state == XPC_P_DEACTIVATING) { continue; } /* pull the remote_hb cache line */ bres = xp_bte_copy(part->remote_vars_pa, - (u64) remote_vars, - XPC_RP_VARS_SIZE, - (BTE_NOTIFY | BTE_WACQUIRE), NULL); + (u64)remote_vars, + XPC_RP_VARS_SIZE, + (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bres != BTE_SUCCESS) { XPC_DEACTIVATE_PARTITION(part, - xpc_map_bte_errors(bres)); + xpc_map_bte_errors(bres)); continue; } @@ -459,8 +444,8 @@ xpc_check_remote_hb(void) remote_vars->heartbeating_to_mask); if (((remote_vars->heartbeat == part->last_heartbeat) && - (remote_vars->heartbeat_offline == 0)) || - !xpc_hb_allowed(sn_partition_id, remote_vars)) { + (remote_vars->heartbeat_offline == 0)) || + !xpc_hb_allowed(sn_partition_id, remote_vars)) { XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat); continue; @@ -470,7 +455,6 @@ xpc_check_remote_hb(void) } } - /* * Get a copy of a portion of the remote partition's rsvd page. * @@ -480,11 +464,10 @@ xpc_check_remote_hb(void) */ static enum xpc_retval xpc_get_remote_rp(int nasid, u64 *discovered_nasids, - struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) + struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) { int bres, i; - /* get the reserved page's physical address */ *remote_rp_pa = xpc_get_rsvd_page_pa(nasid); @@ -492,30 +475,26 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, return xpcNoRsvdPageAddr; } - /* pull over the reserved page header and part_nasids mask */ - bres = xp_bte_copy(*remote_rp_pa, (u64) remote_rp, - XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes, - (BTE_NOTIFY | BTE_WACQUIRE), NULL); + bres = xp_bte_copy(*remote_rp_pa, (u64)remote_rp, + XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes, + (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bres != BTE_SUCCESS) { return xpc_map_bte_errors(bres); } - if (discovered_nasids != NULL) { u64 *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); - for (i = 0; i < xp_nasid_mask_words; i++) { discovered_nasids[i] |= remote_part_nasids[i]; } } - /* check that the partid is for another partition */ if (remote_rp->partid < 1 || - remote_rp->partid > (XP_MAX_PARTITIONS - 1)) { + remote_rp->partid > (XP_MAX_PARTITIONS - 1)) { return xpcInvalidPartid; } @@ -523,16 +502,14 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, return xpcLocalPartid; } - if (XPC_VERSION_MAJOR(remote_rp->version) != - XPC_VERSION_MAJOR(XPC_RP_VERSION)) { + XPC_VERSION_MAJOR(XPC_RP_VERSION)) { return xpcBadVersion; } return xpcSuccess; } - /* * Get a copy of the remote partition's XPC variables from the reserved page. * @@ -544,34 +521,32 @@ xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars) { int bres; - if (remote_vars_pa == 0) { return xpcVarsNotSet; } /* pull over the cross partition variables */ - bres = xp_bte_copy(remote_vars_pa, (u64) remote_vars, XPC_RP_VARS_SIZE, - (BTE_NOTIFY | BTE_WACQUIRE), NULL); + bres = xp_bte_copy(remote_vars_pa, (u64)remote_vars, XPC_RP_VARS_SIZE, + (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bres != BTE_SUCCESS) { return xpc_map_bte_errors(bres); } if (XPC_VERSION_MAJOR(remote_vars->version) != - XPC_VERSION_MAJOR(XPC_V_VERSION)) { + XPC_VERSION_MAJOR(XPC_V_VERSION)) { return xpcBadVersion; } return xpcSuccess; } - /* * Update the remote partition's info. */ static void xpc_update_partition_info(struct xpc_partition *part, u8 remote_rp_version, - struct timespec *remote_rp_stamp, u64 remote_rp_pa, - u64 remote_vars_pa, struct xpc_vars *remote_vars) + struct timespec *remote_rp_stamp, u64 remote_rp_pa, + u64 remote_vars_pa, struct xpc_vars *remote_vars) { part->remote_rp_version = remote_rp_version; dev_dbg(xpc_part, " remote_rp_version = 0x%016x\n", @@ -613,7 +588,6 @@ xpc_update_partition_info(struct xpc_partition *part, u8 remote_rp_version, part->remote_vars_version); } - /* * Prior code has determined the nasid which generated an IPI. Inspect * that nasid to determine if its partition needs to be activated or @@ -643,15 +617,14 @@ xpc_identify_act_IRQ_req(int nasid) struct xpc_partition *part; enum xpc_retval ret; - /* pull over the reserved page structure */ - remote_rp = (struct xpc_rsvd_page *) xpc_remote_copy_buffer; + remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer; ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa); if (ret != xpcSuccess) { dev_warn(xpc_part, "unable to get reserved page from nasid %d, " - "which sent interrupt, reason=%d\n", nasid, ret); + "which sent interrupt, reason=%d\n", nasid, ret); return; } @@ -663,34 +636,31 @@ xpc_identify_act_IRQ_req(int nasid) partid = remote_rp->partid; part = &xpc_partitions[partid]; - /* pull over the cross partition variables */ - remote_vars = (struct xpc_vars *) xpc_remote_copy_buffer; + remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer; ret = xpc_get_remote_vars(remote_vars_pa, remote_vars); if (ret != xpcSuccess) { dev_warn(xpc_part, "unable to get XPC variables from nasid %d, " - "which sent interrupt, reason=%d\n", nasid, ret); + "which sent interrupt, reason=%d\n", nasid, ret); XPC_DEACTIVATE_PARTITION(part, ret); return; } - part->act_IRQ_rcvd++; dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = " - "%ld:0x%lx\n", (int) nasid, (int) partid, part->act_IRQ_rcvd, + "%ld:0x%lx\n", (int)nasid, (int)partid, part->act_IRQ_rcvd, remote_vars->heartbeat, remote_vars->heartbeating_to_mask); - if (xpc_partition_disengaged(part) && - part->act_state == XPC_P_INACTIVE) { + if (xpc_partition_disengaged(part) && part->act_state == XPC_P_INACTIVE) { xpc_update_partition_info(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { if (xpc_partition_disengage_requested(1UL << partid)) { @@ -714,16 +684,15 @@ xpc_identify_act_IRQ_req(int nasid) if (!XPC_SUPPORTS_RP_STAMP(part->remote_rp_version)) { DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(part-> - remote_vars_version)); + remote_vars_version)); if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> - version)); + version)); /* see if the other side rebooted */ if (part->remote_amos_page_pa == - remote_vars->amos_page_pa && - xpc_hb_allowed(sn_partition_id, - remote_vars)) { + remote_vars->amos_page_pa && + xpc_hb_allowed(sn_partition_id, remote_vars)) { /* doesn't look that way, so ignore the IPI */ return; } @@ -735,8 +704,8 @@ xpc_identify_act_IRQ_req(int nasid) */ xpc_update_partition_info(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); part->reactivate_nasid = nasid; XPC_DEACTIVATE_PARTITION(part, xpcReactivating); return; @@ -756,15 +725,15 @@ xpc_identify_act_IRQ_req(int nasid) xpc_clear_partition_disengage_request(1UL << partid); xpc_update_partition_info(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); reactivate = 1; } else { DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); stamp_diff = xpc_compare_stamps(&part->remote_rp_stamp, - &remote_rp_stamp); + &remote_rp_stamp); if (stamp_diff != 0) { DBUG_ON(stamp_diff >= 0); @@ -775,17 +744,18 @@ xpc_identify_act_IRQ_req(int nasid) DBUG_ON(xpc_partition_engaged(1UL << partid)); DBUG_ON(xpc_partition_disengage_requested(1UL << - partid)); + partid)); xpc_update_partition_info(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); + &remote_rp_stamp, + remote_rp_pa, remote_vars_pa, + remote_vars); reactivate = 1; } } if (part->disengage_request_timeout > 0 && - !xpc_partition_disengaged(part)) { + !xpc_partition_disengaged(part)) { /* still waiting on other side to disengage from us */ return; } @@ -795,12 +765,11 @@ xpc_identify_act_IRQ_req(int nasid) XPC_DEACTIVATE_PARTITION(part, xpcReactivating); } else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) && - xpc_partition_disengage_requested(1UL << partid)) { + xpc_partition_disengage_requested(1UL << partid)) { XPC_DEACTIVATE_PARTITION(part, xpcOtherGoingDown); } } - /* * Loop through the activation AMO variables and process any bits * which are set. Each bit indicates a nasid sending a partition @@ -813,14 +782,12 @@ xpc_identify_act_IRQ_sender(void) { int word, bit; u64 nasid_mask; - u64 nasid; /* remote nasid */ + u64 nasid; /* remote nasid */ int n_IRQs_detected = 0; AMO_t *act_amos; - act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS; - /* scan through act AMO variable looking for non-zero entries */ for (word = 0; word < xp_nasid_mask_words; word++) { @@ -837,7 +804,6 @@ xpc_identify_act_IRQ_sender(void) dev_dbg(xpc_part, "AMO[%d] gave back 0x%lx\n", word, nasid_mask); - /* * If this nasid has been added to the machine since * our partition was reset, this will retain the @@ -846,7 +812,6 @@ xpc_identify_act_IRQ_sender(void) */ xpc_mach_nasids[word] |= nasid_mask; - /* locate the nasid(s) which sent interrupts */ for (bit = 0; bit < (8 * sizeof(u64)); bit++) { @@ -862,7 +827,6 @@ xpc_identify_act_IRQ_sender(void) return n_IRQs_detected; } - /* * See if the other side has responded to a partition disengage request * from us. @@ -873,7 +837,6 @@ xpc_partition_disengaged(struct xpc_partition *part) partid_t partid = XPC_PARTID(part); int disengaged; - disengaged = (xpc_partition_engaged(1UL << partid) == 0); if (part->disengage_request_timeout) { if (!disengaged) { @@ -888,7 +851,7 @@ xpc_partition_disengaged(struct xpc_partition *part) */ dev_info(xpc_part, "disengage from remote partition %d " - "timed out\n", partid); + "timed out\n", partid); xpc_disengage_request_timedout = 1; xpc_clear_partition_engaged(1UL << partid); disengaged = 1; @@ -898,11 +861,11 @@ xpc_partition_disengaged(struct xpc_partition *part) /* cancel the timer function, provided it's not us */ if (!in_interrupt()) { del_singleshot_timer_sync(&part-> - disengage_request_timer); + disengage_request_timer); } DBUG_ON(part->act_state != XPC_P_DEACTIVATING && - part->act_state != XPC_P_INACTIVE); + part->act_state != XPC_P_INACTIVE); if (part->act_state != XPC_P_INACTIVE) { xpc_wakeup_channel_mgr(part); } @@ -914,7 +877,6 @@ xpc_partition_disengaged(struct xpc_partition *part) return disengaged; } - /* * Mark specified partition as active. */ @@ -924,7 +886,6 @@ xpc_mark_partition_active(struct xpc_partition *part) unsigned long irq_flags; enum xpc_retval ret; - dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part)); spin_lock_irqsave(&part->act_lock, irq_flags); @@ -940,17 +901,15 @@ xpc_mark_partition_active(struct xpc_partition *part) return ret; } - /* * Notify XPC that the partition is down. */ void xpc_deactivate_partition(const int line, struct xpc_partition *part, - enum xpc_retval reason) + enum xpc_retval reason) { unsigned long irq_flags; - spin_lock_irqsave(&part->act_lock, irq_flags); if (part->act_state == XPC_P_INACTIVE) { @@ -964,7 +923,7 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, } if (part->act_state == XPC_P_DEACTIVATING) { if ((part->reason == xpcUnloading && reason != xpcUnloading) || - reason == xpcReactivating) { + reason == xpcReactivating) { XPC_SET_REASON(part, reason, line); } spin_unlock_irqrestore(&part->act_lock, irq_flags); @@ -982,9 +941,9 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, /* set a timelimit on the disengage request */ part->disengage_request_timeout = jiffies + - (xpc_disengage_request_timelimit * HZ); + (xpc_disengage_request_timelimit * HZ); part->disengage_request_timer.expires = - part->disengage_request_timeout; + part->disengage_request_timeout; add_timer(&part->disengage_request_timer); } @@ -994,7 +953,6 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, xpc_partition_going_down(part, reason); } - /* * Mark specified partition as inactive. */ @@ -1003,7 +961,6 @@ xpc_mark_partition_inactive(struct xpc_partition *part) { unsigned long irq_flags; - dev_dbg(xpc_part, "setting partition %d to INACTIVE\n", XPC_PARTID(part)); @@ -1013,7 +970,6 @@ xpc_mark_partition_inactive(struct xpc_partition *part) part->remote_rp_pa = 0; } - /* * SAL has provided a partition and machine mask. The partition mask * contains a bit for each even nasid in our partition. The machine @@ -1041,24 +997,22 @@ xpc_discovery(void) u64 *discovered_nasids; enum xpc_retval ret; - remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + - xp_nasid_mask_bytes, - GFP_KERNEL, &remote_rp_base); + xp_nasid_mask_bytes, + GFP_KERNEL, &remote_rp_base); if (remote_rp == NULL) { return; } - remote_vars = (struct xpc_vars *) remote_rp; - + remote_vars = (struct xpc_vars *)remote_rp; discovered_nasids = kzalloc(sizeof(u64) * xp_nasid_mask_words, - GFP_KERNEL); + GFP_KERNEL); if (discovered_nasids == NULL) { kfree(remote_rp_base); return; } - rp = (struct xpc_rsvd_page *) xpc_rsvd_page; + rp = (struct xpc_rsvd_page *)xpc_rsvd_page; /* * The term 'region' in this context refers to the minimum number of @@ -1081,23 +1035,21 @@ xpc_discovery(void) for (region = 0; region < max_regions; region++) { - if ((volatile int) xpc_exiting) { + if ((volatile int)xpc_exiting) { break; } dev_dbg(xpc_part, "searching region %d\n", region); for (nasid = (region * region_size * 2); - nasid < ((region + 1) * region_size * 2); - nasid += 2) { + nasid < ((region + 1) * region_size * 2); nasid += 2) { - if ((volatile int) xpc_exiting) { + if ((volatile int)xpc_exiting) { break; } dev_dbg(xpc_part, "checking nasid %d\n", nasid); - if (XPC_NASID_IN_ARRAY(nasid, xpc_part_nasids)) { dev_dbg(xpc_part, "PROM indicates Nasid %d is " "part of the local partition; skipping " @@ -1119,11 +1071,10 @@ xpc_discovery(void) continue; } - /* pull over the reserved page structure */ ret = xpc_get_remote_rp(nasid, discovered_nasids, - remote_rp, &remote_rp_pa); + remote_rp, &remote_rp_pa); if (ret != xpcSuccess) { dev_dbg(xpc_part, "unable to get reserved page " "from nasid %d, reason=%d\n", nasid, @@ -1140,7 +1091,6 @@ xpc_discovery(void) partid = remote_rp->partid; part = &xpc_partitions[partid]; - /* pull over the cross partition variables */ ret = xpc_get_remote_vars(remote_vars_pa, remote_vars); @@ -1171,15 +1121,15 @@ xpc_discovery(void) * get the same page for remote_act_amos_pa after * module reloads and system reboots. */ - if (sn_register_xp_addr_region( - remote_vars->amos_page_pa, - PAGE_SIZE, 1) < 0) { - dev_dbg(xpc_part, "partition %d failed to " + if (sn_register_xp_addr_region + (remote_vars->amos_page_pa, PAGE_SIZE, 1) < 0) { + dev_dbg(xpc_part, + "partition %d failed to " "register xp_addr region 0x%016lx\n", partid, remote_vars->amos_page_pa); XPC_SET_REASON(part, xpcPhysAddrRegFailed, - __LINE__); + __LINE__); break; } @@ -1195,9 +1145,9 @@ xpc_discovery(void) remote_vars->act_phys_cpuid); if (XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> - version)) { + version)) { part->remote_amos_page_pa = - remote_vars->amos_page_pa; + remote_vars->amos_page_pa; xpc_mark_partition_disengaged(part); xpc_cancel_partition_disengage_request(part); } @@ -1209,7 +1159,6 @@ xpc_discovery(void) kfree(remote_rp_base); } - /* * Given a partid, get the nasids owned by that partition from the * remote partition's reserved page. @@ -1221,7 +1170,6 @@ xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask) u64 part_nasid_pa; int bte_res; - part = &xpc_partitions[partid]; if (part->remote_rp_pa == 0) { return xpcPartitionDown; @@ -1229,11 +1177,11 @@ xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask) memset(nasid_mask, 0, XP_NASID_MASK_BYTES); - part_nasid_pa = (u64) XPC_RP_PART_NASIDS(part->remote_rp_pa); + part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); - bte_res = xp_bte_copy(part_nasid_pa, (u64) nasid_mask, - xp_nasid_mask_bytes, (BTE_NOTIFY | BTE_WACQUIRE), NULL); + bte_res = xp_bte_copy(part_nasid_pa, (u64)nasid_mask, + xp_nasid_mask_bytes, (BTE_NOTIFY | BTE_WACQUIRE), + NULL); return xpc_map_bte_errors(bte_res); } - -- cgit v1.2.3 From 35190506b1a18eda7df24b285fdcd94dec7800ef Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 22 Apr 2008 14:48:55 -0500 Subject: [IA64] run rest drivers/misc/sgi-xp through scripts/Lindent Ran patches through scripts/Lindent (part 2). Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- drivers/misc/sgi-xp/xpc_channel.c | 390 +++++++++++++++----------------------- drivers/misc/sgi-xp/xpc_main.c | 329 ++++++++++++++------------------ drivers/misc/sgi-xp/xpnet.c | 109 ++++------- 3 files changed, 322 insertions(+), 506 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index d7a215eeaaf..15cb91a8210 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -6,7 +6,6 @@ * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. */ - /* * Cross Partition Communication (XPC) channel support. * @@ -15,7 +14,6 @@ * */ - #include #include #include @@ -27,7 +25,6 @@ #include #include "xpc.h" - /* * Guarantee that the kzalloc'd memory is cacheline aligned. */ @@ -39,7 +36,7 @@ xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) if (*base == NULL) { return NULL; } - if ((u64) *base == L1_CACHE_ALIGN((u64) *base)) { + if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) { return *base; } kfree(*base); @@ -49,10 +46,9 @@ xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) if (*base == NULL) { return NULL; } - return (void *) L1_CACHE_ALIGN((u64) *base); + return (void *)L1_CACHE_ALIGN((u64)*base); } - /* * Set up the initial values for the XPartition Communication channels. */ @@ -62,7 +58,6 @@ xpc_initialize_channels(struct xpc_partition *part, partid_t partid) int ch_number; struct xpc_channel *ch; - for (ch_number = 0; ch_number < part->nchannels; ch_number++) { ch = &part->channels[ch_number]; @@ -72,7 +67,7 @@ xpc_initialize_channels(struct xpc_partition *part, partid_t partid) ch->local_GP = &part->local_GPs[ch_number]; ch->local_openclose_args = - &part->local_openclose_args[ch_number]; + &part->local_openclose_args[ch_number]; atomic_set(&ch->kthreads_assigned, 0); atomic_set(&ch->kthreads_idle, 0); @@ -91,7 +86,6 @@ xpc_initialize_channels(struct xpc_partition *part, partid_t partid) } } - /* * Setup the infrastructure necessary to support XPartition Communication * between the specified remote partition and the local one. @@ -103,7 +97,6 @@ xpc_setup_infrastructure(struct xpc_partition *part) struct timer_list *timer; partid_t partid = XPC_PARTID(part); - /* * Zero out MOST of the entry for this partition. Only the fields * starting with `nchannels' will be zeroed. The preceding fields must @@ -111,14 +104,14 @@ xpc_setup_infrastructure(struct xpc_partition *part) * referenced during this memset() operation. */ memset(&part->nchannels, 0, sizeof(struct xpc_partition) - - offsetof(struct xpc_partition, nchannels)); + offsetof(struct xpc_partition, nchannels)); /* * Allocate all of the channel structures as a contiguous chunk of * memory. */ part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_NCHANNELS, - GFP_KERNEL); + GFP_KERNEL); if (part->channels == NULL) { dev_err(xpc_chan, "can't get memory for channels\n"); return xpcNoMemory; @@ -126,11 +119,11 @@ xpc_setup_infrastructure(struct xpc_partition *part) part->nchannels = XPC_NCHANNELS; - /* allocate all the required GET/PUT values */ part->local_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, - GFP_KERNEL, &part->local_GPs_base); + GFP_KERNEL, + &part->local_GPs_base); if (part->local_GPs == NULL) { kfree(part->channels); part->channels = NULL; @@ -140,7 +133,9 @@ xpc_setup_infrastructure(struct xpc_partition *part) } part->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, - GFP_KERNEL, &part->remote_GPs_base); + GFP_KERNEL, + &part-> + remote_GPs_base); if (part->remote_GPs == NULL) { dev_err(xpc_chan, "can't get memory for remote get/put " "values\n"); @@ -151,12 +146,11 @@ xpc_setup_infrastructure(struct xpc_partition *part) return xpcNoMemory; } - /* allocate all the required open and close args */ - part->local_openclose_args = xpc_kzalloc_cacheline_aligned( - XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, - &part->local_openclose_args_base); + part->local_openclose_args = + xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, + &part->local_openclose_args_base); if (part->local_openclose_args == NULL) { dev_err(xpc_chan, "can't get memory for local connect args\n"); kfree(part->remote_GPs_base); @@ -168,9 +162,9 @@ xpc_setup_infrastructure(struct xpc_partition *part) return xpcNoMemory; } - part->remote_openclose_args = xpc_kzalloc_cacheline_aligned( - XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, - &part->remote_openclose_args_base); + 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"); kfree(part->local_openclose_args_base); @@ -184,13 +178,11 @@ xpc_setup_infrastructure(struct xpc_partition *part) return xpcNoMemory; } - xpc_initialize_channels(part, partid); atomic_set(&part->nchannels_active, 0); atomic_set(&part->nchannels_engaged, 0); - /* local_IPI_amo were set to 0 by an earlier memset() */ /* Initialize this partitions AMO_t structure */ @@ -203,7 +195,7 @@ xpc_setup_infrastructure(struct xpc_partition *part) sprintf(part->IPI_owner, "xpc%02d", partid); ret = request_irq(SGI_XPC_NOTIFY, xpc_notify_IRQ_handler, IRQF_SHARED, - part->IPI_owner, (void *) (u64) partid); + part->IPI_owner, (void *)(u64)partid); if (ret != 0) { dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " "errno=%d\n", -ret); @@ -223,8 +215,8 @@ xpc_setup_infrastructure(struct xpc_partition *part) /* Setup a timer to check for dropped IPIs */ timer = &part->dropped_IPI_timer; init_timer(timer); - timer->function = (void (*)(unsigned long)) xpc_dropped_IPI_check; - timer->data = (unsigned long) part; + timer->function = (void (*)(unsigned long))xpc_dropped_IPI_check; + timer->data = (unsigned long)part; timer->expires = jiffies + XPC_P_DROPPED_IPI_WAIT; add_timer(timer); @@ -234,7 +226,6 @@ xpc_setup_infrastructure(struct xpc_partition *part) */ part->setup_state = XPC_P_SETUP; - /* * Setup the per partition specific variables required by the * remote partition to establish channel connections with us. @@ -244,7 +235,7 @@ xpc_setup_infrastructure(struct xpc_partition *part) */ xpc_vars_part[partid].GPs_pa = __pa(part->local_GPs); xpc_vars_part[partid].openclose_args_pa = - __pa(part->local_openclose_args); + __pa(part->local_openclose_args); xpc_vars_part[partid].IPI_amo_pa = __pa(part->local_IPI_amo_va); cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ xpc_vars_part[partid].IPI_nasid = cpuid_to_nasid(cpuid); @@ -255,7 +246,6 @@ xpc_setup_infrastructure(struct xpc_partition *part) return xpcSuccess; } - /* * Create a wrapper that hides the underlying mechanism for pulling a cacheline * (or multiple cachelines) from a remote partition. @@ -266,21 +256,20 @@ xpc_setup_infrastructure(struct xpc_partition *part) */ static enum xpc_retval xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst, - const void *src, size_t cnt) + const void *src, size_t cnt) { bte_result_t bte_ret; - - DBUG_ON((u64) src != L1_CACHE_ALIGN((u64) src)); - DBUG_ON((u64) dst != L1_CACHE_ALIGN((u64) dst)); + DBUG_ON((u64)src != L1_CACHE_ALIGN((u64)src)); + DBUG_ON((u64)dst != L1_CACHE_ALIGN((u64)dst)); DBUG_ON(cnt != L1_CACHE_ALIGN(cnt)); if (part->act_state == XPC_P_DEACTIVATING) { return part->reason; } - bte_ret = xp_bte_copy((u64) src, (u64) dst, (u64) cnt, - (BTE_NORMAL | BTE_WACQUIRE), NULL); + bte_ret = xp_bte_copy((u64)src, (u64)dst, (u64)cnt, + (BTE_NORMAL | BTE_WACQUIRE), NULL); if (bte_ret == BTE_SUCCESS) { return xpcSuccess; } @@ -291,7 +280,6 @@ xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst, return xpc_map_bte_errors(bte_ret); } - /* * Pull the remote per partition specific variables from the specified * partition. @@ -301,41 +289,40 @@ xpc_pull_remote_vars_part(struct xpc_partition *part) { u8 buffer[L1_CACHE_BYTES * 2]; struct xpc_vars_part *pulled_entry_cacheline = - (struct xpc_vars_part *) L1_CACHE_ALIGN((u64) buffer); + (struct xpc_vars_part *)L1_CACHE_ALIGN((u64)buffer); struct xpc_vars_part *pulled_entry; u64 remote_entry_cacheline_pa, remote_entry_pa; partid_t partid = XPC_PARTID(part); enum xpc_retval ret; - /* pull the cacheline that contains the variables we're interested in */ DBUG_ON(part->remote_vars_part_pa != - L1_CACHE_ALIGN(part->remote_vars_part_pa)); + L1_CACHE_ALIGN(part->remote_vars_part_pa)); DBUG_ON(sizeof(struct xpc_vars_part) != L1_CACHE_BYTES / 2); remote_entry_pa = part->remote_vars_part_pa + - sn_partition_id * sizeof(struct xpc_vars_part); + sn_partition_id * sizeof(struct xpc_vars_part); remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1)); - pulled_entry = (struct xpc_vars_part *) ((u64) pulled_entry_cacheline + - (remote_entry_pa & (L1_CACHE_BYTES - 1))); + pulled_entry = (struct xpc_vars_part *)((u64)pulled_entry_cacheline + + (remote_entry_pa & + (L1_CACHE_BYTES - 1))); ret = xpc_pull_remote_cachelines(part, pulled_entry_cacheline, - (void *) remote_entry_cacheline_pa, - L1_CACHE_BYTES); + (void *)remote_entry_cacheline_pa, + L1_CACHE_BYTES); if (ret != xpcSuccess) { dev_dbg(xpc_chan, "failed to pull XPC vars_part from " "partition %d, ret=%d\n", partid, ret); return ret; } - /* see if they've been set up yet */ if (pulled_entry->magic != XPC_VP_MAGIC1 && - pulled_entry->magic != XPC_VP_MAGIC2) { + pulled_entry->magic != XPC_VP_MAGIC2) { if (pulled_entry->magic != 0) { dev_dbg(xpc_chan, "partition %d's XPC vars_part for " @@ -353,8 +340,8 @@ xpc_pull_remote_vars_part(struct xpc_partition *part) /* validate the variables */ if (pulled_entry->GPs_pa == 0 || - pulled_entry->openclose_args_pa == 0 || - pulled_entry->IPI_amo_pa == 0) { + pulled_entry->openclose_args_pa == 0 || + pulled_entry->IPI_amo_pa == 0) { dev_err(xpc_chan, "partition %d's XPC vars_part for " "partition %d are not valid\n", partid, @@ -366,9 +353,9 @@ xpc_pull_remote_vars_part(struct xpc_partition *part) part->remote_GPs_pa = pulled_entry->GPs_pa; part->remote_openclose_args_pa = - pulled_entry->openclose_args_pa; + pulled_entry->openclose_args_pa; part->remote_IPI_amo_va = - (AMO_t *) __va(pulled_entry->IPI_amo_pa); + (AMO_t *)__va(pulled_entry->IPI_amo_pa); part->remote_IPI_nasid = pulled_entry->IPI_nasid; part->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid; @@ -388,7 +375,6 @@ xpc_pull_remote_vars_part(struct xpc_partition *part) return xpcSuccess; } - /* * Get the IPI flags and pull the openclose args and/or remote GPs as needed. */ @@ -399,7 +385,6 @@ xpc_get_IPI_flags(struct xpc_partition *part) u64 IPI_amo; enum xpc_retval ret; - /* * See if there are any IPI flags to be handled. */ @@ -410,12 +395,12 @@ xpc_get_IPI_flags(struct xpc_partition *part) } spin_unlock_irqrestore(&part->IPI_lock, irq_flags); - if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_amo)) { ret = xpc_pull_remote_cachelines(part, - part->remote_openclose_args, - (void *) part->remote_openclose_args_pa, - XPC_OPENCLOSE_ARGS_SIZE); + part->remote_openclose_args, + (void *)part-> + remote_openclose_args_pa, + XPC_OPENCLOSE_ARGS_SIZE); if (ret != xpcSuccess) { XPC_DEACTIVATE_PARTITION(part, ret); @@ -430,8 +415,8 @@ xpc_get_IPI_flags(struct xpc_partition *part) if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_amo)) { ret = xpc_pull_remote_cachelines(part, part->remote_GPs, - (void *) part->remote_GPs_pa, - XPC_GP_SIZE); + (void *)part->remote_GPs_pa, + XPC_GP_SIZE); if (ret != xpcSuccess) { XPC_DEACTIVATE_PARTITION(part, ret); @@ -446,7 +431,6 @@ xpc_get_IPI_flags(struct xpc_partition *part) return IPI_amo; } - /* * Allocate the local message queue and the notify queue. */ @@ -457,7 +441,6 @@ xpc_allocate_local_msgqueue(struct xpc_channel *ch) int nentries; size_t nbytes; - // >>> may want to check for ch->flags & XPC_C_DISCONNECTING between // >>> iterations of the for-loop, bail if set? @@ -466,8 +449,9 @@ xpc_allocate_local_msgqueue(struct xpc_channel *ch) nbytes = nentries * ch->msg_size; ch->local_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, - GFP_KERNEL, - &ch->local_msgqueue_base); + GFP_KERNEL, + &ch-> + local_msgqueue_base); if (ch->local_msgqueue == NULL) { continue; } @@ -497,7 +481,6 @@ xpc_allocate_local_msgqueue(struct xpc_channel *ch) return xpcNoMemory; } - /* * Allocate the cached remote message queue. */ @@ -508,7 +491,6 @@ xpc_allocate_remote_msgqueue(struct xpc_channel *ch) int nentries; size_t nbytes; - DBUG_ON(ch->remote_nentries <= 0); // >>> may want to check for ch->flags & XPC_C_DISCONNECTING between @@ -519,8 +501,9 @@ xpc_allocate_remote_msgqueue(struct xpc_channel *ch) nbytes = nentries * ch->msg_size; ch->remote_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, - GFP_KERNEL, - &ch->remote_msgqueue_base); + GFP_KERNEL, + &ch-> + remote_msgqueue_base); if (ch->remote_msgqueue == NULL) { continue; } @@ -542,7 +525,6 @@ xpc_allocate_remote_msgqueue(struct xpc_channel *ch) return xpcNoMemory; } - /* * Allocate message queues and other stuff associated with a channel. * @@ -554,7 +536,6 @@ xpc_allocate_msgqueues(struct xpc_channel *ch) unsigned long irq_flags; enum xpc_retval ret; - DBUG_ON(ch->flags & XPC_C_SETUP); if ((ret = xpc_allocate_local_msgqueue(ch)) != xpcSuccess) { @@ -576,7 +557,6 @@ xpc_allocate_msgqueues(struct xpc_channel *ch) return xpcSuccess; } - /* * Process a connect message from a remote partition. * @@ -588,11 +568,10 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) { enum xpc_retval ret; - DBUG_ON(!spin_is_locked(&ch->lock)); if (!(ch->flags & XPC_C_OPENREQUEST) || - !(ch->flags & XPC_C_ROPENREQUEST)) { + !(ch->flags & XPC_C_ROPENREQUEST)) { /* nothing more to do for now */ return; } @@ -629,14 +608,13 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) ch->flags = (XPC_C_CONNECTED | XPC_C_SETUP); /* clear all else */ dev_info(xpc_chan, "channel %d to partition %d connected\n", - ch->number, ch->partid); + ch->number, ch->partid); spin_unlock_irqrestore(&ch->lock, *irq_flags); xpc_create_kthreads(ch, 1, 0); spin_lock_irqsave(&ch->lock, *irq_flags); } - /* * Notify those who wanted to be notified upon delivery of their message. */ @@ -647,7 +625,6 @@ xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put) u8 notify_type; s64 get = ch->w_remote_GP.get - 1; - while (++get < put && atomic_read(&ch->n_to_notify) > 0) { notify = &ch->notify_queue[get % ch->local_nentries]; @@ -660,8 +637,7 @@ xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put) */ notify_type = notify->type; if (notify_type == 0 || - cmpxchg(¬ify->type, notify_type, 0) != - notify_type) { + cmpxchg(¬ify->type, notify_type, 0) != notify_type) { continue; } @@ -672,20 +648,19 @@ xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put) if (notify->func != NULL) { 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); + (void *)notify, get, ch->partid, ch->number); notify->func(reason, ch->partid, ch->number, - notify->key); + notify->key); dev_dbg(xpc_chan, "notify->func() returned, " "notify=0x%p, msg_number=%ld, partid=%d, " - "channel=%d\n", (void *) notify, get, + "channel=%d\n", (void *)notify, get, ch->partid, ch->number); } } } - /* * Free up message queues and other stuff that were allocated for the specified * channel. @@ -733,7 +708,6 @@ xpc_free_msgqueues(struct xpc_channel *ch) } } - /* * spin_lock_irqsave() is expected to be held on entry. */ @@ -743,7 +717,6 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) struct xpc_partition *part = &xpc_partitions[ch->partid]; u32 channel_was_connected = (ch->flags & XPC_C_WASCONNECTED); - DBUG_ON(!spin_is_locked(&ch->lock)); if (!(ch->flags & XPC_C_DISCONNECTING)) { @@ -755,11 +728,11 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) /* make sure all activity has settled down first */ if (atomic_read(&ch->kthreads_assigned) > 0 || - atomic_read(&ch->references) > 0) { + atomic_read(&ch->references) > 0) { return; } DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && - !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE)); + !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE)); if (part->act_state == XPC_P_DEACTIVATING) { /* can't proceed until the other side disengages from us */ @@ -809,7 +782,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) if (channel_was_connected) { dev_info(xpc_chan, "channel %d to partition %d disconnected, " - "reason=%d\n", ch->number, ch->partid, ch->reason); + "reason=%d\n", ch->number, ch->partid, ch->reason); } if (ch->flags & XPC_C_WDISCONNECT) { @@ -820,35 +793,31 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) /* time to take action on any delayed IPI flags */ spin_lock(&part->IPI_lock); XPC_SET_IPI_FLAGS(part->local_IPI_amo, ch->number, - ch->delayed_IPI_flags); + ch->delayed_IPI_flags); spin_unlock(&part->IPI_lock); } ch->delayed_IPI_flags = 0; } } - /* * Process a change in the channel's remote connection state. */ static void xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, - u8 IPI_flags) + u8 IPI_flags) { unsigned long irq_flags; struct xpc_openclose_args *args = - &part->remote_openclose_args[ch_number]; + &part->remote_openclose_args[ch_number]; struct xpc_channel *ch = &part->channels[ch_number]; enum xpc_retval reason; - - spin_lock_irqsave(&ch->lock, irq_flags); -again: + again: - if ((ch->flags & XPC_C_DISCONNECTED) && - (ch->flags & XPC_C_WDISCONNECT)) { + if ((ch->flags & XPC_C_DISCONNECTED) && (ch->flags & XPC_C_WDISCONNECT)) { /* * Delay processing IPI flags until thread waiting disconnect * has had a chance to see that the channel is disconnected. @@ -858,7 +827,6 @@ again: return; } - if (IPI_flags & XPC_IPI_CLOSEREQUEST) { dev_dbg(xpc_chan, "XPC_IPI_CLOSEREQUEST (reason=%d) received " @@ -890,13 +858,14 @@ again: if (ch->flags & XPC_C_DISCONNECTED) { if (!(IPI_flags & XPC_IPI_OPENREQUEST)) { if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, - ch_number) & XPC_IPI_OPENREQUEST)) { + ch_number) & + XPC_IPI_OPENREQUEST)) { DBUG_ON(ch->delayed_IPI_flags != 0); spin_lock(&part->IPI_lock); XPC_SET_IPI_FLAGS(part->local_IPI_amo, - ch_number, - XPC_IPI_CLOSEREQUEST); + ch_number, + XPC_IPI_CLOSEREQUEST); spin_unlock(&part->IPI_lock); } spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -937,7 +906,6 @@ again: xpc_process_disconnect(ch, &irq_flags); } - if (IPI_flags & XPC_IPI_CLOSEREPLY) { dev_dbg(xpc_chan, "XPC_IPI_CLOSEREPLY received from partid=%d," @@ -953,12 +921,13 @@ again: if (!(ch->flags & XPC_C_RCLOSEREQUEST)) { if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, ch_number) - & XPC_IPI_CLOSEREQUEST)) { + & XPC_IPI_CLOSEREQUEST)) { DBUG_ON(ch->delayed_IPI_flags != 0); spin_lock(&part->IPI_lock); XPC_SET_IPI_FLAGS(part->local_IPI_amo, - ch_number, XPC_IPI_CLOSEREPLY); + ch_number, + XPC_IPI_CLOSEREPLY); spin_unlock(&part->IPI_lock); } spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -973,7 +942,6 @@ again: } } - if (IPI_flags & XPC_IPI_OPENREQUEST) { dev_dbg(xpc_chan, "XPC_IPI_OPENREQUEST (msg_size=%d, " @@ -982,7 +950,7 @@ again: ch->partid, ch->number); if (part->act_state == XPC_P_DEACTIVATING || - (ch->flags & XPC_C_ROPENREQUEST)) { + (ch->flags & XPC_C_ROPENREQUEST)) { spin_unlock_irqrestore(&ch->lock, irq_flags); return; } @@ -993,9 +961,9 @@ again: return; } DBUG_ON(!(ch->flags & (XPC_C_DISCONNECTED | - XPC_C_OPENREQUEST))); + XPC_C_OPENREQUEST))); DBUG_ON(ch->flags & (XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | - XPC_C_OPENREPLY | XPC_C_CONNECTED)); + XPC_C_OPENREPLY | XPC_C_CONNECTED)); /* * The meaningful OPENREQUEST connection state fields are: @@ -1011,11 +979,10 @@ again: ch->flags |= (XPC_C_ROPENREQUEST | XPC_C_CONNECTING); ch->remote_nentries = args->local_nentries; - if (ch->flags & XPC_C_OPENREQUEST) { if (args->msg_size != ch->msg_size) { XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes, - &irq_flags); + &irq_flags); spin_unlock_irqrestore(&ch->lock, irq_flags); return; } @@ -1031,7 +998,6 @@ again: xpc_process_connect(ch, &irq_flags); } - if (IPI_flags & XPC_IPI_OPENREPLY) { dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY (local_msgqueue_pa=0x%lx, " @@ -1046,7 +1012,7 @@ again: } if (!(ch->flags & XPC_C_OPENREQUEST)) { XPC_DISCONNECT_CHANNEL(ch, xpcOpenCloseError, - &irq_flags); + &irq_flags); spin_unlock_irqrestore(&ch->lock, irq_flags); return; } @@ -1057,7 +1023,7 @@ again: /* * The meaningful OPENREPLY connection state fields are: * local_msgqueue_pa = physical address of remote - * partition's local_msgqueue + * partition's local_msgqueue * local_nentries = remote partition's local_nentries * remote_nentries = remote partition's remote_nentries */ @@ -1093,7 +1059,6 @@ again: spin_unlock_irqrestore(&ch->lock, irq_flags); } - /* * Attempt to establish a channel connection to a remote partition. */ @@ -1103,7 +1068,6 @@ xpc_connect_channel(struct xpc_channel *ch) unsigned long irq_flags; struct xpc_registration *registration = &xpc_registrations[ch->number]; - if (mutex_trylock(®istration->mutex) == 0) { return xpcRetry; } @@ -1124,7 +1088,6 @@ xpc_connect_channel(struct xpc_channel *ch) return ch->reason; } - /* add info from the channel connect registration to the channel */ ch->kthreads_assigned_limit = registration->assigned_limit; @@ -1154,7 +1117,7 @@ xpc_connect_channel(struct xpc_channel *ch) */ mutex_unlock(®istration->mutex); XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes, - &irq_flags); + &irq_flags); spin_unlock_irqrestore(&ch->lock, irq_flags); return xpcUnequalMsgSizes; } @@ -1169,7 +1132,6 @@ xpc_connect_channel(struct xpc_channel *ch) mutex_unlock(®istration->mutex); - /* initiate the connection */ ch->flags |= (XPC_C_OPENREQUEST | XPC_C_CONNECTING); @@ -1182,7 +1144,6 @@ xpc_connect_channel(struct xpc_channel *ch) return xpcSuccess; } - /* * Clear some of the msg flags in the local message queue. */ @@ -1192,16 +1153,15 @@ xpc_clear_local_msgqueue_flags(struct xpc_channel *ch) struct xpc_msg *msg; s64 get; - get = ch->w_remote_GP.get; do { - msg = (struct xpc_msg *) ((u64) ch->local_msgqueue + - (get % ch->local_nentries) * ch->msg_size); + msg = (struct xpc_msg *)((u64)ch->local_msgqueue + + (get % ch->local_nentries) * + ch->msg_size); msg->flags = 0; - } while (++get < (volatile s64) ch->remote_GP.get); + } while (++get < (volatile s64)ch->remote_GP.get); } - /* * Clear some of the msg flags in the remote message queue. */ @@ -1211,43 +1171,39 @@ xpc_clear_remote_msgqueue_flags(struct xpc_channel *ch) struct xpc_msg *msg; s64 put; - put = ch->w_remote_GP.put; do { - msg = (struct xpc_msg *) ((u64) ch->remote_msgqueue + - (put % ch->remote_nentries) * ch->msg_size); + msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + + (put % ch->remote_nentries) * + ch->msg_size); msg->flags = 0; - } while (++put < (volatile s64) ch->remote_GP.put); + } while (++put < (volatile s64)ch->remote_GP.put); } - static void xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) { struct xpc_channel *ch = &part->channels[ch_number]; int nmsgs_sent; - ch->remote_GP = part->remote_GPs[ch_number]; - /* See what, if anything, has changed for each connected channel */ xpc_msgqueue_ref(ch); if (ch->w_remote_GP.get == ch->remote_GP.get && - ch->w_remote_GP.put == ch->remote_GP.put) { + ch->w_remote_GP.put == ch->remote_GP.put) { /* nothing changed since GPs were last pulled */ xpc_msgqueue_deref(ch); return; } - if (!(ch->flags & XPC_C_CONNECTED)){ + if (!(ch->flags & XPC_C_CONNECTED)) { xpc_msgqueue_deref(ch); return; } - /* * First check to see if messages recently sent by us have been * received by the other side. (The remote GET value will have @@ -1269,7 +1225,7 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) * received and delivered by the other side. */ xpc_notify_senders(ch, xpcMsgDelivered, - ch->remote_GP.get); + ch->remote_GP.get); } /* @@ -1293,7 +1249,6 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) } } - /* * Now check for newly sent messages by the other side. (The remote * PUT value will have changed since we last looked at it.) @@ -1327,7 +1282,6 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) xpc_msgqueue_deref(ch); } - void xpc_process_channel_activity(struct xpc_partition *part) { @@ -1337,7 +1291,6 @@ xpc_process_channel_activity(struct xpc_partition *part) int ch_number; u32 ch_flags; - IPI_amo = xpc_get_IPI_flags(part); /* @@ -1350,7 +1303,6 @@ xpc_process_channel_activity(struct xpc_partition *part) for (ch_number = 0; ch_number < part->nchannels; ch_number++) { ch = &part->channels[ch_number]; - /* * Process any open or close related IPI flags, and then deal * with connecting or disconnecting the channel as required. @@ -1378,7 +1330,7 @@ xpc_process_channel_activity(struct xpc_partition *part) if (!(ch_flags & XPC_C_CONNECTED)) { if (!(ch_flags & XPC_C_OPENREQUEST)) { DBUG_ON(ch_flags & XPC_C_SETUP); - (void) xpc_connect_channel(ch); + (void)xpc_connect_channel(ch); } else { spin_lock_irqsave(&ch->lock, irq_flags); xpc_process_connect(ch, &irq_flags); @@ -1387,7 +1339,6 @@ xpc_process_channel_activity(struct xpc_partition *part) continue; } - /* * Process any message related IPI flags, this may involve the * activation of kthreads to deliver any pending messages sent @@ -1400,7 +1351,6 @@ xpc_process_channel_activity(struct xpc_partition *part) } } - /* * XPC's heartbeat code calls this function to inform XPC that a partition is * going down. XPC responds by tearing down the XPartition Communication @@ -1417,7 +1367,6 @@ xpc_partition_going_down(struct xpc_partition *part, enum xpc_retval reason) int ch_number; struct xpc_channel *ch; - dev_dbg(xpc_chan, "deactivating partition %d, reason=%d\n", XPC_PARTID(part), reason); @@ -1426,7 +1375,6 @@ xpc_partition_going_down(struct xpc_partition *part, enum xpc_retval reason) return; } - /* disconnect channels associated with the partition going down */ for (ch_number = 0; ch_number < part->nchannels; ch_number++) { @@ -1446,7 +1394,6 @@ xpc_partition_going_down(struct xpc_partition *part, enum xpc_retval reason) xpc_part_deref(part); } - /* * Teardown the infrastructure necessary to support XPartition Communication * between the specified remote partition and the local one. @@ -1456,7 +1403,6 @@ xpc_teardown_infrastructure(struct xpc_partition *part) { partid_t 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 @@ -1473,9 +1419,7 @@ xpc_teardown_infrastructure(struct xpc_partition *part) xpc_vars_part[partid].magic = 0; - - free_irq(SGI_XPC_NOTIFY, (void *) (u64) partid); - + free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid); /* * Before proceeding with the teardown we have to wait until all @@ -1483,7 +1427,6 @@ xpc_teardown_infrastructure(struct xpc_partition *part) */ wait_event(part->teardown_wq, (atomic_read(&part->references) == 0)); - /* now we can begin tearing down the infrastructure */ part->setup_state = XPC_P_TORNDOWN; @@ -1504,7 +1447,6 @@ xpc_teardown_infrastructure(struct xpc_partition *part) part->local_IPI_amo_va = NULL; } - /* * Called by XP at the time of channel connection registration to cause * XPC to establish connections to all currently active partitions. @@ -1516,7 +1458,6 @@ xpc_initiate_connect(int ch_number) struct xpc_partition *part; struct xpc_channel *ch; - DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { @@ -1535,7 +1476,6 @@ xpc_initiate_connect(int ch_number) } } - void xpc_connected_callout(struct xpc_channel *ch) { @@ -1546,14 +1486,13 @@ xpc_connected_callout(struct xpc_channel *ch) "partid=%d, channel=%d\n", ch->partid, ch->number); ch->func(xpcConnected, ch->partid, ch->number, - (void *) (u64) ch->local_nentries, ch->key); + (void *)(u64)ch->local_nentries, ch->key); dev_dbg(xpc_chan, "ch->func() returned, reason=xpcConnected, " "partid=%d, channel=%d\n", ch->partid, ch->number); } } - /* * Called by XP at the time of channel connection unregistration to cause * XPC to teardown all current connections for the specified channel. @@ -1575,7 +1514,6 @@ xpc_initiate_disconnect(int ch_number) struct xpc_partition *part; struct xpc_channel *ch; - DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); /* initiate the channel disconnect for every active partition */ @@ -1592,7 +1530,7 @@ xpc_initiate_disconnect(int ch_number) ch->flags |= XPC_C_WDISCONNECT; XPC_DISCONNECT_CHANNEL(ch, xpcUnregistering, - &irq_flags); + &irq_flags); } spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -1605,7 +1543,6 @@ xpc_initiate_disconnect(int ch_number) xpc_disconnect_wait(ch_number); } - /* * To disconnect a channel, and reflect it back to all who may be waiting. * @@ -1617,11 +1554,10 @@ xpc_initiate_disconnect(int ch_number) */ void xpc_disconnect_channel(const int line, struct xpc_channel *ch, - enum xpc_retval reason, unsigned long *irq_flags) + enum xpc_retval reason, unsigned long *irq_flags) { u32 channel_was_connected = (ch->flags & XPC_C_CONNECTED); - DBUG_ON(!spin_is_locked(&ch->lock)); if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) { @@ -1637,8 +1573,8 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, ch->flags |= (XPC_C_CLOSEREQUEST | XPC_C_DISCONNECTING); /* some of these may not have been set */ ch->flags &= ~(XPC_C_OPENREQUEST | XPC_C_OPENREPLY | - XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | - XPC_C_CONNECTING | XPC_C_CONNECTED); + XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | + XPC_C_CONNECTING | XPC_C_CONNECTED); xpc_IPI_send_closerequest(ch, irq_flags); @@ -1653,7 +1589,7 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, wake_up_all(&ch->idle_wq); } else if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && - !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) { + !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) { /* start a kthread that will do the xpcDisconnecting callout */ xpc_create_kthreads(ch, 1, 1); } @@ -1666,7 +1602,6 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, spin_lock_irqsave(&ch->lock, *irq_flags); } - void xpc_disconnect_callout(struct xpc_channel *ch, enum xpc_retval reason) { @@ -1687,7 +1622,6 @@ xpc_disconnect_callout(struct xpc_channel *ch, enum xpc_retval reason) } } - /* * Wait for a message entry to become available for the specified channel, * but don't wait any longer than 1 jiffy. @@ -1697,9 +1631,8 @@ xpc_allocate_msg_wait(struct xpc_channel *ch) { enum xpc_retval ret; - if (ch->flags & XPC_C_DISCONNECTING) { - DBUG_ON(ch->reason == xpcInterrupted); // >>> Is this true? + DBUG_ON(ch->reason == xpcInterrupted); // >>> Is this true? return ch->reason; } @@ -1709,7 +1642,7 @@ xpc_allocate_msg_wait(struct xpc_channel *ch) if (ch->flags & XPC_C_DISCONNECTING) { ret = ch->reason; - DBUG_ON(ch->reason == xpcInterrupted); // >>> Is this true? + DBUG_ON(ch->reason == xpcInterrupted); // >>> Is this true? } else if (ret == 0) { ret = xpcTimeout; } else { @@ -1719,20 +1652,18 @@ xpc_allocate_msg_wait(struct xpc_channel *ch) return ret; } - /* * Allocate an entry for a message from the message queue associated with the * specified channel. */ static enum xpc_retval xpc_allocate_msg(struct xpc_channel *ch, u32 flags, - struct xpc_msg **address_of_msg) + struct xpc_msg **address_of_msg) { struct xpc_msg *msg; enum xpc_retval ret; s64 put; - /* this reference will be dropped in xpc_send_msg() */ xpc_msgqueue_ref(ch); @@ -1745,7 +1676,6 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags, return xpcNotConnected; } - /* * Get the next available message entry from the local message queue. * If none are available, we'll make sure that we grab the latest @@ -1755,25 +1685,23 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags, while (1) { - put = (volatile s64) ch->w_local_GP.put; - if (put - (volatile s64) ch->w_remote_GP.get < - ch->local_nentries) { + put = (volatile s64)ch->w_local_GP.put; + if (put - (volatile s64)ch->w_remote_GP.get < + ch->local_nentries) { /* There are available message entries. We need to try * to secure one for ourselves. We'll do this by trying * to increment w_local_GP.put as long as someone else * doesn't beat us to it. If they do, we'll have to * try again. - */ - if (cmpxchg(&ch->w_local_GP.put, put, put + 1) == - put) { + */ + if (cmpxchg(&ch->w_local_GP.put, put, put + 1) == put) { /* we got the entry referenced by put */ break; } continue; /* try again */ } - /* * There aren't any available msg entries at this time. * @@ -1799,25 +1727,22 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags, } } - /* get the message's address and initialize it */ - msg = (struct xpc_msg *) ((u64) ch->local_msgqueue + - (put % ch->local_nentries) * ch->msg_size); - + msg = (struct xpc_msg *)((u64)ch->local_msgqueue + + (put % ch->local_nentries) * ch->msg_size); DBUG_ON(msg->flags != 0); msg->number = put; dev_dbg(xpc_chan, "w_local_GP.put changed to %ld; msg=0x%p, " "msg_number=%ld, partid=%d, channel=%d\n", put + 1, - (void *) msg, msg->number, ch->partid, ch->number); + (void *)msg, msg->number, ch->partid, ch->number); *address_of_msg = msg; return xpcSuccess; } - /* * Allocate an entry for a message from the message queue associated with the * specified channel. NOTE that this routine can sleep waiting for a message @@ -1838,7 +1763,6 @@ xpc_initiate_allocate(partid_t partid, int ch_number, u32 flags, void **payload) enum xpc_retval ret = xpcUnknownReason; struct xpc_msg *msg = NULL; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); @@ -1856,7 +1780,6 @@ xpc_initiate_allocate(partid_t partid, int ch_number, u32 flags, void **payload) return ret; } - /* * Now we actually send the messages that are ready to be sent by advancing * the local message queue's Put value and then send an IPI to the recipient @@ -1869,16 +1792,16 @@ xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) s64 put = initial_put + 1; int send_IPI = 0; - while (1) { while (1) { - if (put == (volatile s64) ch->w_local_GP.put) { + if (put == (volatile s64)ch->w_local_GP.put) { break; } - msg = (struct xpc_msg *) ((u64) ch->local_msgqueue + - (put % ch->local_nentries) * ch->msg_size); + msg = (struct xpc_msg *)((u64)ch->local_msgqueue + + (put % ch->local_nentries) * + ch->msg_size); if (!(msg->flags & XPC_M_READY)) { break; @@ -1893,9 +1816,9 @@ xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) } if (cmpxchg_rel(&ch->local_GP->put, initial_put, put) != - initial_put) { + initial_put) { /* someone else beat us to it */ - DBUG_ON((volatile s64) ch->local_GP->put < initial_put); + DBUG_ON((volatile s64)ch->local_GP->put < initial_put); break; } @@ -1919,7 +1842,6 @@ xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) } } - /* * Common code that does the actual sending of the message by advancing the * local message queue's Put value and sends an IPI to the partition the @@ -1927,16 +1849,15 @@ xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) */ static enum xpc_retval xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, - xpc_notify_func func, void *key) + xpc_notify_func func, void *key) { enum xpc_retval ret = xpcSuccess; struct xpc_notify *notify = notify; s64 put, msg_number = msg->number; - DBUG_ON(notify_type == XPC_N_CALL && func == NULL); - DBUG_ON((((u64) msg - (u64) ch->local_msgqueue) / ch->msg_size) != - msg_number % ch->local_nentries); + DBUG_ON((((u64)msg - (u64)ch->local_msgqueue) / ch->msg_size) != + msg_number % ch->local_nentries); DBUG_ON(msg->flags & XPC_M_READY); if (ch->flags & XPC_C_DISCONNECTING) { @@ -1970,7 +1891,7 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, * the notify entry. */ if (cmpxchg(¬ify->type, notify_type, 0) == - notify_type) { + notify_type) { atomic_dec(&ch->n_to_notify); ret = ch->reason; } @@ -2001,7 +1922,6 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, return ret; } - /* * Send a message previously allocated using xpc_initiate_allocate() on the * specified channel connected to the specified partition. @@ -2029,8 +1949,7 @@ xpc_initiate_send(partid_t partid, int ch_number, void *payload) struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); enum xpc_retval ret; - - dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *) msg, + dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg, partid, ch_number); DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); @@ -2042,7 +1961,6 @@ xpc_initiate_send(partid_t partid, int ch_number, void *payload) return ret; } - /* * Send a message previously allocated using xpc_initiate_allocate on the * specified channel connected to the specified partition. @@ -2075,14 +1993,13 @@ xpc_initiate_send(partid_t partid, int ch_number, void *payload) */ enum xpc_retval xpc_initiate_send_notify(partid_t partid, int ch_number, void *payload, - xpc_notify_func func, void *key) + xpc_notify_func func, void *key) { struct xpc_partition *part = &xpc_partitions[partid]; struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); enum xpc_retval ret; - - dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *) msg, + dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg, partid, ch_number); DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); @@ -2091,11 +2008,10 @@ xpc_initiate_send_notify(partid_t partid, int ch_number, void *payload, DBUG_ON(func == NULL); ret = xpc_send_msg(&part->channels[ch_number], msg, XPC_N_CALL, - func, key); + func, key); return ret; } - static struct xpc_msg * xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) { @@ -2105,7 +2021,6 @@ xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) u64 msg_offset; enum xpc_retval ret; - if (mutex_lock_interruptible(&ch->msg_to_pull_mutex) != 0) { /* we were interrupted by a signal */ return NULL; @@ -2118,22 +2033,22 @@ xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) msg_index = ch->next_msg_to_pull % ch->remote_nentries; DBUG_ON(ch->next_msg_to_pull >= - (volatile s64) ch->w_remote_GP.put); - nmsgs = (volatile s64) ch->w_remote_GP.put - - ch->next_msg_to_pull; + (volatile s64)ch->w_remote_GP.put); + nmsgs = (volatile s64)ch->w_remote_GP.put - + ch->next_msg_to_pull; if (msg_index + nmsgs > ch->remote_nentries) { /* ignore the ones that wrap the msg queue for now */ nmsgs = ch->remote_nentries - msg_index; } 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); + msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); + remote_msg = (struct xpc_msg *)(ch->remote_msgqueue_pa + + msg_offset); if ((ret = xpc_pull_remote_cachelines(part, msg, remote_msg, - nmsgs * ch->msg_size)) != xpcSuccess) { + nmsgs * ch->msg_size)) != + xpcSuccess) { dev_dbg(xpc_chan, "failed to pull %d msgs starting with" " msg %ld from partition %d, channel=%d, " @@ -2146,7 +2061,7 @@ xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) return NULL; } - mb(); /* >>> this may not be needed, we're not sure */ + mb(); /* >>> this may not be needed, we're not sure */ ch->next_msg_to_pull += nmsgs; } @@ -2155,12 +2070,11 @@ xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) /* 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->remote_msgqueue + msg_offset); return msg; } - /* * Get a message to be delivered. */ @@ -2170,14 +2084,13 @@ xpc_get_deliverable_msg(struct xpc_channel *ch) struct xpc_msg *msg = NULL; s64 get; - do { - if ((volatile u32) ch->flags & XPC_C_DISCONNECTING) { + if ((volatile u32)ch->flags & XPC_C_DISCONNECTING) { break; } - get = (volatile s64) ch->w_local_GP.get; - if (get == (volatile s64) ch->w_remote_GP.put) { + get = (volatile s64)ch->w_local_GP.get; + if (get == (volatile s64)ch->w_remote_GP.put) { break; } @@ -2186,7 +2099,7 @@ xpc_get_deliverable_msg(struct xpc_channel *ch) * by trying to increment w_local_GP.get and hope that no one * else beats us to it. If they do, we'll we'll simply have * to try again for the next one. - */ + */ if (cmpxchg(&ch->w_local_GP.get, get, get + 1) == get) { /* we got the entry referenced by get */ @@ -2211,7 +2124,6 @@ xpc_get_deliverable_msg(struct xpc_channel *ch) return msg; } - /* * Deliver a message to its intended recipient. */ @@ -2220,7 +2132,6 @@ xpc_deliver_msg(struct xpc_channel *ch) { struct xpc_msg *msg; - if ((msg = xpc_get_deliverable_msg(ch)) != NULL) { /* @@ -2235,16 +2146,16 @@ 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, + (void *)msg, msg->number, ch->partid, ch->number); /* deliver the message to its intended recipient */ ch->func(xpcMsgReceived, ch->partid, ch->number, - &msg->payload, ch->key); + &msg->payload, ch->key); dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, " "msg_number=%ld, partid=%d, channel=%d\n", - (void *) msg, msg->number, ch->partid, + (void *)msg, msg->number, ch->partid, ch->number); } @@ -2252,7 +2163,6 @@ xpc_deliver_msg(struct xpc_channel *ch) } } - /* * 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 @@ -2265,16 +2175,16 @@ xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) s64 get = initial_get + 1; int send_IPI = 0; - while (1) { while (1) { - if (get == (volatile s64) ch->w_local_GP.get) { + if (get == (volatile s64)ch->w_local_GP.get) { break; } - msg = (struct xpc_msg *) ((u64) ch->remote_msgqueue + - (get % ch->remote_nentries) * ch->msg_size); + msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + + (get % ch->remote_nentries) * + ch->msg_size); if (!(msg->flags & XPC_M_DONE)) { break; @@ -2290,10 +2200,9 @@ xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) } if (cmpxchg_rel(&ch->local_GP->get, initial_get, get) != - initial_get) { + initial_get) { /* someone else beat us to it */ - DBUG_ON((volatile s64) ch->local_GP->get <= - initial_get); + DBUG_ON((volatile s64)ch->local_GP->get <= initial_get); break; } @@ -2317,7 +2226,6 @@ xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) } } - /* * Acknowledge receipt of a delivered message. * @@ -2343,17 +2251,16 @@ xpc_initiate_received(partid_t partid, int ch_number, void *payload) struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); s64 get, msg_number = msg->number; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); ch = &part->channels[ch_number]; dev_dbg(xpc_chan, "msg=0x%p, msg_number=%ld, partid=%d, channel=%d\n", - (void *) msg, msg_number, ch->partid, ch->number); + (void *)msg, msg_number, ch->partid, ch->number); - DBUG_ON((((u64) msg - (u64) ch->remote_msgqueue) / ch->msg_size) != - msg_number % ch->remote_nentries); + DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->msg_size) != + msg_number % ch->remote_nentries); DBUG_ON(msg->flags & XPC_M_DONE); msg->flags |= XPC_M_DONE; @@ -2376,4 +2283,3 @@ xpc_initiate_received(partid_t partid, int ch_number, void *payload) /* the call to xpc_msgqueue_ref() was done by xpc_deliver_msg() */ xpc_msgqueue_deref(ch); } - diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index bdb2cf1fcbc..d81a2dd787a 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -6,7 +6,6 @@ * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. */ - /* * Cross Partition Communication (XPC) support - standard version. * @@ -44,7 +43,6 @@ * */ - #include #include #include @@ -61,7 +59,6 @@ #include #include "xpc.h" - /* define two XPC debug device structures to be used with dev_dbg() et al */ struct device_driver xpc_dbg_name = { @@ -81,10 +78,8 @@ struct device xpc_chan_dbg_subname = { struct device *xpc_part = &xpc_part_dbg_subname; struct device *xpc_chan = &xpc_chan_dbg_subname; - static int xpc_kdebug_ignore; - /* systune related variables for /proc/sys directories */ static int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL; @@ -101,56 +96,51 @@ static int xpc_disengage_request_max_timelimit = 120; static ctl_table xpc_sys_xpc_hb_dir[] = { { - .ctl_name = CTL_UNNUMBERED, - .procname = "hb_interval", - .data = &xpc_hb_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &xpc_hb_min_interval, - .extra2 = &xpc_hb_max_interval - }, + .ctl_name = CTL_UNNUMBERED, + .procname = "hb_interval", + .data = &xpc_hb_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xpc_hb_min_interval, + .extra2 = &xpc_hb_max_interval}, { - .ctl_name = CTL_UNNUMBERED, - .procname = "hb_check_interval", - .data = &xpc_hb_check_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &xpc_hb_check_min_interval, - .extra2 = &xpc_hb_check_max_interval - }, + .ctl_name = CTL_UNNUMBERED, + .procname = "hb_check_interval", + .data = &xpc_hb_check_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xpc_hb_check_min_interval, + .extra2 = &xpc_hb_check_max_interval}, {} }; static ctl_table xpc_sys_xpc_dir[] = { { - .ctl_name = CTL_UNNUMBERED, - .procname = "hb", - .mode = 0555, - .child = xpc_sys_xpc_hb_dir - }, + .ctl_name = CTL_UNNUMBERED, + .procname = "hb", + .mode = 0555, + .child = xpc_sys_xpc_hb_dir}, { - .ctl_name = CTL_UNNUMBERED, - .procname = "disengage_request_timelimit", - .data = &xpc_disengage_request_timelimit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &xpc_disengage_request_min_timelimit, - .extra2 = &xpc_disengage_request_max_timelimit - }, + .ctl_name = CTL_UNNUMBERED, + .procname = "disengage_request_timelimit", + .data = &xpc_disengage_request_timelimit, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xpc_disengage_request_min_timelimit, + .extra2 = &xpc_disengage_request_max_timelimit}, {} }; static ctl_table xpc_sys_dir[] = { { - .ctl_name = CTL_UNNUMBERED, - .procname = "xpc", - .mode = 0555, - .child = xpc_sys_xpc_dir - }, + .ctl_name = CTL_UNNUMBERED, + .procname = "xpc", + .mode = 0555, + .child = xpc_sys_xpc_dir}, {} }; static struct ctl_table_header *xpc_sysctl; @@ -172,13 +162,10 @@ static DECLARE_COMPLETION(xpc_hb_checker_exited); /* notification that the xpc_discovery thread has exited */ static DECLARE_COMPLETION(xpc_discovery_exited); - static struct timer_list xpc_hb_timer; - static void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *); - static int xpc_system_reboot(struct notifier_block *, unsigned long, void *); static struct notifier_block xpc_reboot_notifier = { .notifier_call = xpc_system_reboot, @@ -189,25 +176,22 @@ static struct notifier_block xpc_die_notifier = { .notifier_call = xpc_system_die, }; - /* * Timer function to enforce the timelimit on the partition disengage request. */ static void xpc_timeout_partition_disengage_request(unsigned long data) { - struct xpc_partition *part = (struct xpc_partition *) data; - + struct xpc_partition *part = (struct xpc_partition *)data; DBUG_ON(time_before(jiffies, part->disengage_request_timeout)); - (void) xpc_partition_disengaged(part); + (void)xpc_partition_disengaged(part); DBUG_ON(part->disengage_request_timeout != 0); DBUG_ON(xpc_partition_engaged(1UL << XPC_PARTID(part)) != 0); } - /* * Notify the heartbeat check thread that an IRQ has been received. */ @@ -219,7 +203,6 @@ xpc_act_IRQ_handler(int irq, void *dev_id) return IRQ_HANDLED; } - /* * Timer to produce the heartbeat. The timer structures function is * already set when this is initially called. A tunable is used to @@ -238,7 +221,6 @@ xpc_hb_beater(unsigned long dummy) add_timer(&xpc_hb_timer); } - /* * This thread is responsible for nearly all of the partition * activation/deactivation. @@ -248,8 +230,7 @@ xpc_hb_checker(void *ignore) { int last_IRQ_count = 0; int new_IRQ_count; - int force_IRQ=0; - + int force_IRQ = 0; /* this thread was marked active by xpc_hb_init() */ @@ -261,14 +242,13 @@ xpc_hb_checker(void *ignore) xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); xpc_hb_beater(0); - while (!(volatile int) xpc_exiting) { + while (!(volatile int)xpc_exiting) { dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " "been received\n", - (int) (xpc_hb_check_timeout - jiffies), + (int)(xpc_hb_check_timeout - jiffies), atomic_read(&xpc_act_IRQ_rcvd) - last_IRQ_count); - /* checking of remote heartbeats is skewed by IRQ handling */ if (time_after_eq(jiffies, xpc_hb_check_timeout)) { dev_dbg(xpc_part, "checking remote heartbeats\n"); @@ -282,7 +262,6 @@ xpc_hb_checker(void *ignore) force_IRQ = 1; } - /* check for outstanding IRQs */ new_IRQ_count = atomic_read(&xpc_act_IRQ_rcvd); if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) { @@ -294,30 +273,30 @@ xpc_hb_checker(void *ignore) last_IRQ_count += xpc_identify_act_IRQ_sender(); if (last_IRQ_count < new_IRQ_count) { /* retry once to help avoid missing AMO */ - (void) xpc_identify_act_IRQ_sender(); + (void)xpc_identify_act_IRQ_sender(); } last_IRQ_count = new_IRQ_count; xpc_hb_check_timeout = jiffies + - (xpc_hb_check_interval * HZ); + (xpc_hb_check_interval * HZ); } /* wait for IRQ or timeout */ - (void) wait_event_interruptible(xpc_act_IRQ_wq, - (last_IRQ_count < atomic_read(&xpc_act_IRQ_rcvd) || - time_after_eq(jiffies, xpc_hb_check_timeout) || - (volatile int) xpc_exiting)); + (void)wait_event_interruptible(xpc_act_IRQ_wq, + (last_IRQ_count < + atomic_read(&xpc_act_IRQ_rcvd) + || time_after_eq(jiffies, + xpc_hb_check_timeout) || + (volatile int)xpc_exiting)); } dev_dbg(xpc_part, "heartbeat checker is exiting\n"); - /* mark this thread as having exited */ complete(&xpc_hb_checker_exited); return 0; } - /* * This thread will attempt to discover other partitions to activate * based on info provided by SAL. This new thread is short lived and @@ -337,7 +316,6 @@ xpc_initiate_discovery(void *ignore) return 0; } - /* * Establish first contact with the remote partititon. This involves pulling * the XPC per partition variables from the remote partition and waiting for @@ -348,7 +326,6 @@ xpc_make_first_contact(struct xpc_partition *part) { enum xpc_retval ret; - while ((ret = xpc_pull_remote_vars_part(part)) != xpcSuccess) { if (ret != xpcRetry) { XPC_DEACTIVATE_PARTITION(part, ret); @@ -359,7 +336,7 @@ xpc_make_first_contact(struct xpc_partition *part) "partition %d\n", XPC_PARTID(part)); /* wait a 1/4 of a second or so */ - (void) msleep_interruptible(250); + (void)msleep_interruptible(250); if (part->act_state == XPC_P_DEACTIVATING) { return part->reason; @@ -369,7 +346,6 @@ xpc_make_first_contact(struct xpc_partition *part) return xpc_mark_partition_active(part); } - /* * The first kthread assigned to a newly activated partition is the one * created by XPC HB with which it calls xpc_partition_up(). XPC hangs on to @@ -386,12 +362,11 @@ static void xpc_channel_mgr(struct xpc_partition *part) { while (part->act_state != XPC_P_DEACTIVATING || - atomic_read(&part->nchannels_active) > 0 || - !xpc_partition_disengaged(part)) { + atomic_read(&part->nchannels_active) > 0 || + !xpc_partition_disengaged(part)) { xpc_process_channel_activity(part); - /* * Wait until we've been requested to activate kthreads or * all of the channel's message queues have been torn down or @@ -406,13 +381,19 @@ xpc_channel_mgr(struct xpc_partition *part) * wake him up. */ atomic_dec(&part->channel_mgr_requests); - (void) wait_event_interruptible(part->channel_mgr_wq, - (atomic_read(&part->channel_mgr_requests) > 0 || - (volatile u64) part->local_IPI_amo != 0 || - ((volatile u8) part->act_state == - XPC_P_DEACTIVATING && - atomic_read(&part->nchannels_active) == 0 && - xpc_partition_disengaged(part)))); + (void)wait_event_interruptible(part->channel_mgr_wq, + (atomic_read + (&part->channel_mgr_requests) > + 0 || + (volatile u64)part-> + local_IPI_amo != 0 || + ((volatile u8)part->act_state == + XPC_P_DEACTIVATING && + atomic_read(&part-> + nchannels_active) + == 0 && + xpc_partition_disengaged + (part)))); atomic_set(&part->channel_mgr_requests, 1); // >>> Does it need to wakeup periodically as well? In case we @@ -420,7 +401,6 @@ xpc_channel_mgr(struct xpc_partition *part) } } - /* * 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 @@ -454,7 +434,7 @@ xpc_partition_up(struct xpc_partition *part) * has been dismantled. */ - (void) xpc_part_ref(part); /* this will always succeed */ + (void)xpc_part_ref(part); /* this will always succeed */ if (xpc_make_first_contact(part) == xpcSuccess) { xpc_channel_mgr(part); @@ -465,17 +445,15 @@ xpc_partition_up(struct xpc_partition *part) xpc_teardown_infrastructure(part); } - static int xpc_activating(void *__partid) { - partid_t partid = (u64) __partid; + partid_t partid = (u64)__partid; struct xpc_partition *part = &xpc_partitions[partid]; unsigned long irq_flags; - struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; int ret; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); spin_lock_irqsave(&part->act_lock, irq_flags); @@ -505,7 +483,7 @@ xpc_activating(void *__partid) ret = sched_setscheduler(current, SCHED_FIFO, ¶m); if (ret != 0) { dev_warn(xpc_part, "unable to set pid %d to a realtime " - "priority, ret=%d\n", current->pid, ret); + "priority, ret=%d\n", current->pid, ret); } /* allow this thread and its children to run on any CPU */ @@ -522,9 +500,9 @@ xpc_activating(void *__partid) * reloads and system reboots. */ if (sn_register_xp_addr_region(part->remote_amos_page_pa, - PAGE_SIZE, 1) < 0) { + PAGE_SIZE, 1) < 0) { dev_warn(xpc_part, "xpc_partition_up(%d) failed to register " - "xp_addr region\n", partid); + "xp_addr region\n", partid); spin_lock_irqsave(&part->act_lock, irq_flags); part->act_state = XPC_P_INACTIVE; @@ -537,12 +515,11 @@ xpc_activating(void *__partid) xpc_allow_hb(partid, xpc_vars); xpc_IPI_send_activated(part); - /* * xpc_partition_up() holds this thread and marks this partition as * XPC_P_ACTIVE by calling xpc_hb_mark_active(). */ - (void) xpc_partition_up(part); + (void)xpc_partition_up(part); xpc_disallow_hb(partid, xpc_vars); xpc_mark_partition_inactive(part); @@ -555,7 +532,6 @@ xpc_activating(void *__partid) return 0; } - void xpc_activate_partition(struct xpc_partition *part) { @@ -563,7 +539,6 @@ xpc_activate_partition(struct xpc_partition *part) unsigned long irq_flags; pid_t pid; - spin_lock_irqsave(&part->act_lock, irq_flags); DBUG_ON(part->act_state != XPC_P_INACTIVE); @@ -573,7 +548,7 @@ xpc_activate_partition(struct xpc_partition *part) spin_unlock_irqrestore(&part->act_lock, irq_flags); - pid = kernel_thread(xpc_activating, (void *) ((u64) partid), 0); + pid = kernel_thread(xpc_activating, (void *)((u64)partid), 0); if (unlikely(pid <= 0)) { spin_lock_irqsave(&part->act_lock, irq_flags); @@ -583,7 +558,6 @@ xpc_activate_partition(struct xpc_partition *part) } } - /* * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more @@ -603,10 +577,9 @@ xpc_activate_partition(struct xpc_partition *part) irqreturn_t xpc_notify_IRQ_handler(int irq, void *dev_id) { - partid_t partid = (partid_t) (u64) dev_id; + partid_t partid = (partid_t) (u64)dev_id; struct xpc_partition *part = &xpc_partitions[partid]; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); if (xpc_part_ref(part)) { @@ -617,7 +590,6 @@ xpc_notify_IRQ_handler(int irq, void *dev_id) return IRQ_HANDLED; } - /* * Check to see if xpc_notify_IRQ_handler() dropped any IPIs on the floor * because the write to their associated IPI amo completed after the IRQ/IPI @@ -630,13 +602,12 @@ xpc_dropped_IPI_check(struct xpc_partition *part) xpc_check_for_channel_activity(part); part->dropped_IPI_timer.expires = jiffies + - XPC_P_DROPPED_IPI_WAIT; + XPC_P_DROPPED_IPI_WAIT; add_timer(&part->dropped_IPI_timer); xpc_part_deref(part); } } - void xpc_activate_kthreads(struct xpc_channel *ch, int needed) { @@ -644,7 +615,6 @@ xpc_activate_kthreads(struct xpc_channel *ch, int needed) int assigned = atomic_read(&ch->kthreads_assigned); int wakeup; - DBUG_ON(needed <= 0); if (idle > 0) { @@ -676,7 +646,6 @@ xpc_activate_kthreads(struct xpc_channel *ch, int needed) xpc_create_kthreads(ch, needed, 0); } - /* * This function is where XPC's kthreads wait for messages to deliver. */ @@ -686,15 +655,14 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) do { /* deliver messages to their intended recipients */ - while ((volatile s64) ch->w_local_GP.get < - (volatile s64) ch->w_remote_GP.put && - !((volatile u32) ch->flags & - XPC_C_DISCONNECTING)) { + while ((volatile s64)ch->w_local_GP.get < + (volatile s64)ch->w_remote_GP.put && + !((volatile u32)ch->flags & XPC_C_DISCONNECTING)) { xpc_deliver_msg(ch); } if (atomic_inc_return(&ch->kthreads_idle) > - ch->kthreads_idle_limit) { + ch->kthreads_idle_limit) { /* too many idle kthreads on this channel */ atomic_dec(&ch->kthreads_idle); break; @@ -703,18 +671,20 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) dev_dbg(xpc_chan, "idle kthread calling " "wait_event_interruptible_exclusive()\n"); - (void) wait_event_interruptible_exclusive(ch->idle_wq, - ((volatile s64) ch->w_local_GP.get < - (volatile s64) ch->w_remote_GP.put || - ((volatile u32) ch->flags & - XPC_C_DISCONNECTING))); + (void)wait_event_interruptible_exclusive(ch->idle_wq, + ((volatile s64)ch-> + w_local_GP.get < + (volatile s64)ch-> + w_remote_GP.put || + ((volatile u32)ch-> + flags & + XPC_C_DISCONNECTING))); atomic_dec(&ch->kthreads_idle); - } while (!((volatile u32) ch->flags & XPC_C_DISCONNECTING)); + } while (!((volatile u32)ch->flags & XPC_C_DISCONNECTING)); } - static int xpc_daemonize_kthread(void *args) { @@ -725,7 +695,6 @@ xpc_daemonize_kthread(void *args) int n_needed; unsigned long irq_flags; - daemonize("xpc%02dc%d", partid, ch_number); dev_dbg(xpc_chan, "kthread starting, partid=%d, channel=%d\n", @@ -756,8 +725,7 @@ xpc_daemonize_kthread(void *args) * need one less than total #of messages to deliver. */ n_needed = ch->w_remote_GP.put - ch->w_local_GP.get - 1; - if (n_needed > 0 && - !(ch->flags & XPC_C_DISCONNECTING)) { + if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING)) { xpc_activate_kthreads(ch, n_needed); } } else { @@ -771,7 +739,7 @@ xpc_daemonize_kthread(void *args) spin_lock_irqsave(&ch->lock, irq_flags); if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && - !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) { + !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) { ch->flags |= XPC_C_DISCONNECTINGCALLOUT; spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -798,7 +766,6 @@ xpc_daemonize_kthread(void *args) return 0; } - /* * For each partition that XPC has established communications with, there is * a minimum of one kernel thread assigned to perform any operation that @@ -813,14 +780,13 @@ xpc_daemonize_kthread(void *args) */ void xpc_create_kthreads(struct xpc_channel *ch, int needed, - int ignore_disconnecting) + int ignore_disconnecting) { unsigned long irq_flags; pid_t pid; u64 args = XPC_PACK_ARGS(ch->partid, ch->number); struct xpc_partition *part = &xpc_partitions[ch->partid]; - while (needed-- > 0) { /* @@ -832,7 +798,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, if (!atomic_inc_not_zero(&ch->kthreads_assigned)) { /* kthreads assigned had gone to zero */ BUG_ON(!(ch->flags & - XPC_C_DISCONNECTINGCALLOUT_MADE)); + XPC_C_DISCONNECTINGCALLOUT_MADE)); break; } @@ -843,10 +809,10 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, if (atomic_inc_return(&part->nchannels_engaged) == 1) xpc_mark_partition_engaged(part); } - (void) xpc_part_ref(part); + (void)xpc_part_ref(part); xpc_msgqueue_ref(ch); - pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0); + pid = kernel_thread(xpc_daemonize_kthread, (void *)args, 0); if (pid < 0) { /* the fork failed */ @@ -869,7 +835,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, xpc_part_deref(part); if (atomic_read(&ch->kthreads_assigned) < - ch->kthreads_idle_limit) { + ch->kthreads_idle_limit) { /* * Flag this as an error only if we have an * insufficient #of kthreads for the channel @@ -877,7 +843,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, */ spin_lock_irqsave(&ch->lock, irq_flags); XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources, - &irq_flags); + &irq_flags); spin_unlock_irqrestore(&ch->lock, irq_flags); } break; @@ -887,7 +853,6 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, } } - void xpc_disconnect_wait(int ch_number) { @@ -897,7 +862,6 @@ xpc_disconnect_wait(int ch_number) struct xpc_channel *ch; int wakeup_channel_mgr; - /* now wait for all callouts to the caller's function to cease */ for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; @@ -923,7 +887,8 @@ xpc_disconnect_wait(int ch_number) if (part->act_state != XPC_P_DEACTIVATING) { spin_lock(&part->IPI_lock); XPC_SET_IPI_FLAGS(part->local_IPI_amo, - ch->number, ch->delayed_IPI_flags); + ch->number, + ch->delayed_IPI_flags); spin_unlock(&part->IPI_lock); wakeup_channel_mgr = 1; } @@ -941,7 +906,6 @@ xpc_disconnect_wait(int ch_number) } } - static void xpc_do_exit(enum xpc_retval reason) { @@ -950,7 +914,6 @@ xpc_do_exit(enum xpc_retval reason) struct xpc_partition *part; unsigned long printmsg_time, disengage_request_timeout = 0; - /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ DBUG_ON(xpc_exiting == 1); @@ -971,10 +934,8 @@ xpc_do_exit(enum xpc_retval reason) /* wait for the heartbeat checker thread to exit */ wait_for_completion(&xpc_hb_checker_exited); - /* sleep for a 1/3 of a second or so */ - (void) msleep_interruptible(300); - + (void)msleep_interruptible(300); /* wait for all partitions to become inactive */ @@ -988,7 +949,7 @@ xpc_do_exit(enum xpc_retval reason) part = &xpc_partitions[partid]; if (xpc_partition_disengaged(part) && - part->act_state == XPC_P_INACTIVE) { + part->act_state == XPC_P_INACTIVE) { continue; } @@ -997,47 +958,46 @@ xpc_do_exit(enum xpc_retval reason) XPC_DEACTIVATE_PARTITION(part, reason); if (part->disengage_request_timeout > - disengage_request_timeout) { + disengage_request_timeout) { disengage_request_timeout = - part->disengage_request_timeout; + part->disengage_request_timeout; } } if (xpc_partition_engaged(-1UL)) { if (time_after(jiffies, printmsg_time)) { dev_info(xpc_part, "waiting for remote " - "partitions to disengage, timeout in " - "%ld seconds\n", - (disengage_request_timeout - jiffies) - / HZ); + "partitions to disengage, timeout in " + "%ld seconds\n", + (disengage_request_timeout - jiffies) + / HZ); printmsg_time = jiffies + - (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); printed_waiting_msg = 1; } } else if (active_part_count > 0) { if (printed_waiting_msg) { dev_info(xpc_part, "waiting for local partition" - " to disengage\n"); + " to disengage\n"); printed_waiting_msg = 0; } } else { if (!xpc_disengage_request_timedout) { dev_info(xpc_part, "all partitions have " - "disengaged\n"); + "disengaged\n"); } break; } /* sleep for a 1/3 of a second or so */ - (void) msleep_interruptible(300); + (void)msleep_interruptible(300); } while (1); DBUG_ON(xpc_partition_engaged(-1UL)); - /* indicate to others that our reserved page is uninitialized */ xpc_rsvd_page->vars_pa = 0; @@ -1047,16 +1007,15 @@ xpc_do_exit(enum xpc_retval reason) if (reason == xpcUnloading) { /* take ourselves off of the reboot_notifier_list */ - (void) unregister_reboot_notifier(&xpc_reboot_notifier); + (void)unregister_reboot_notifier(&xpc_reboot_notifier); /* take ourselves off of the die_notifier list */ - (void) unregister_die_notifier(&xpc_die_notifier); + (void)unregister_die_notifier(&xpc_die_notifier); } /* close down protections for IPI operations */ xpc_restrict_IPI_ops(); - /* clear the interface to XPC's functions */ xpc_clear_interface(); @@ -1067,7 +1026,6 @@ xpc_do_exit(enum xpc_retval reason) kfree(xpc_remote_copy_buffer_base); } - /* * This function is called when the system is being rebooted. */ @@ -1076,7 +1034,6 @@ xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused) { enum xpc_retval reason; - switch (event) { case SYS_RESTART: reason = xpcSystemReboot; @@ -1095,7 +1052,6 @@ xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused) return NOTIFY_DONE; } - /* * Notify other partitions to disengage from all references to our memory. */ @@ -1107,17 +1063,15 @@ xpc_die_disengage(void) unsigned long engaged; long time, printmsg_time, disengage_request_timeout; - /* keep xpc_hb_checker thread from doing anything (just in case) */ xpc_exiting = 1; - xpc_vars->heartbeating_to_mask = 0; /* indicate we're deactivated */ + xpc_vars->heartbeating_to_mask = 0; /* indicate we're deactivated */ for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; - if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part-> - remote_vars_version)) { + if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { /* just in case it was left set by an earlier XPC */ xpc_clear_partition_engaged(1UL << partid); @@ -1125,7 +1079,7 @@ xpc_die_disengage(void) } if (xpc_partition_engaged(1UL << partid) || - part->act_state != XPC_P_INACTIVE) { + part->act_state != XPC_P_INACTIVE) { xpc_request_partition_disengage(part); xpc_mark_partition_disengaged(part); xpc_IPI_send_disengage(part); @@ -1134,9 +1088,9 @@ xpc_die_disengage(void) time = rtc_time(); printmsg_time = time + - (XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second); + (XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second); disengage_request_timeout = time + - (xpc_disengage_request_timelimit * sn_rtc_cycles_per_second); + (xpc_disengage_request_timelimit * sn_rtc_cycles_per_second); /* wait for all other partitions to disengage from us */ @@ -1152,8 +1106,8 @@ xpc_die_disengage(void) for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { if (engaged & (1UL << partid)) { dev_info(xpc_part, "disengage from " - "remote partition %d timed " - "out\n", partid); + "remote partition %d timed " + "out\n", partid); } } break; @@ -1161,17 +1115,16 @@ xpc_die_disengage(void) if (time >= printmsg_time) { dev_info(xpc_part, "waiting for remote partitions to " - "disengage, timeout in %ld seconds\n", - (disengage_request_timeout - time) / - sn_rtc_cycles_per_second); + "disengage, timeout in %ld seconds\n", + (disengage_request_timeout - time) / + sn_rtc_cycles_per_second); printmsg_time = time + - (XPC_DISENGAGE_PRINTMSG_INTERVAL * - sn_rtc_cycles_per_second); + (XPC_DISENGAGE_PRINTMSG_INTERVAL * + sn_rtc_cycles_per_second); } } } - /* * This function is called when the system is being restarted or halted due * to some sort of system failure. If this is the case we need to notify the @@ -1217,7 +1170,6 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) return NOTIFY_DONE; } - int __init xpc_init(void) { @@ -1227,16 +1179,15 @@ xpc_init(void) pid_t pid; size_t buf_size; - if (!ia64_platform_is("sn2")) { return -ENODEV; } - buf_size = max(XPC_RP_VARS_SIZE, - XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES); + XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES); xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size, - GFP_KERNEL, &xpc_remote_copy_buffer_base); + GFP_KERNEL, + &xpc_remote_copy_buffer_base); if (xpc_remote_copy_buffer == NULL) return -ENOMEM; @@ -1256,7 +1207,7 @@ xpc_init(void) for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; - DBUG_ON((u64) part != L1_CACHE_ALIGN((u64) part)); + DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); part->act_IRQ_rcvd = 0; spin_lock_init(&part->act_lock); @@ -1265,8 +1216,8 @@ xpc_init(void) init_timer(&part->disengage_request_timer); part->disengage_request_timer.function = - xpc_timeout_partition_disengage_request; - part->disengage_request_timer.data = (unsigned long) part; + xpc_timeout_partition_disengage_request; + part->disengage_request_timer.data = (unsigned long)part; part->setup_state = XPC_P_UNSET; init_waitqueue_head(&part->teardown_wq); @@ -1292,7 +1243,7 @@ xpc_init(void) * but rather immediately process the interrupt. */ ret = request_irq(SGI_XPC_ACTIVATE, xpc_act_IRQ_handler, 0, - "xpc hb", NULL); + "xpc hb", NULL); if (ret != 0) { dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " "errno=%d\n", -ret); @@ -1327,7 +1278,6 @@ xpc_init(void) return -EBUSY; } - /* add ourselves to the reboot_notifier_list */ ret = register_reboot_notifier(&xpc_reboot_notifier); if (ret != 0) { @@ -1355,10 +1305,10 @@ xpc_init(void) xpc_rsvd_page->vars_pa = 0; /* take ourselves off of the reboot_notifier_list */ - (void) unregister_reboot_notifier(&xpc_reboot_notifier); + (void)unregister_reboot_notifier(&xpc_reboot_notifier); /* take ourselves off of the die_notifier list */ - (void) unregister_die_notifier(&xpc_die_notifier); + (void)unregister_die_notifier(&xpc_die_notifier); del_timer_sync(&xpc_hb_timer); free_irq(SGI_XPC_ACTIVATE, NULL); @@ -1372,7 +1322,6 @@ xpc_init(void) return -EBUSY; } - /* * Startup a thread that will attempt to discover other partitions to * activate based on info provided by SAL. This new thread is short @@ -1389,7 +1338,6 @@ xpc_init(void) return -EBUSY; } - /* set the interface to point at XPC's functions */ xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect, xpc_initiate_allocate, xpc_initiate_send, @@ -1398,16 +1346,16 @@ xpc_init(void) return 0; } -module_init(xpc_init); +module_init(xpc_init); void __exit xpc_exit(void) { xpc_do_exit(xpcUnloading); } -module_exit(xpc_exit); +module_exit(xpc_exit); MODULE_AUTHOR("Silicon Graphics, Inc."); MODULE_DESCRIPTION("Cross Partition Communication (XPC) support"); @@ -1415,17 +1363,16 @@ MODULE_LICENSE("GPL"); module_param(xpc_hb_interval, int, 0); MODULE_PARM_DESC(xpc_hb_interval, "Number of seconds between " - "heartbeat increments."); + "heartbeat increments."); module_param(xpc_hb_check_interval, int, 0); MODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between " - "heartbeat checks."); + "heartbeat checks."); module_param(xpc_disengage_request_timelimit, int, 0); MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait " - "for disengage request to complete."); + "for disengage request to complete."); module_param(xpc_kdebug_ignore, int, 0); MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by " - "other partitions when dropping into kdebug."); - + "other partitions when dropping into kdebug."); diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 38552f37e53..e41cb93b8c8 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -6,7 +6,6 @@ * Copyright (C) 1999-2008 Silicon Graphics, Inc. All rights reserved. */ - /* * Cross Partition Network Interface (XPNET) support * @@ -21,7 +20,6 @@ * */ - #include #include #include @@ -40,7 +38,6 @@ #include #include "xp.h" - /* * The message payload transferred by XPC. * @@ -79,7 +76,6 @@ struct xpnet_message { #define XPNET_MSG_ALIGNED_SIZE (L1_CACHE_ALIGN(XPNET_MSG_SIZE)) #define XPNET_MSG_NENTRIES (PAGE_SIZE / XPNET_MSG_ALIGNED_SIZE) - #define XPNET_MAX_KTHREADS (XPNET_MSG_NENTRIES + 1) #define XPNET_MAX_IDLE_KTHREADS (XPNET_MSG_NENTRIES + 1) @@ -91,9 +87,9 @@ struct xpnet_message { #define XPNET_VERSION_MAJOR(_v) ((_v) >> 4) #define XPNET_VERSION_MINOR(_v) ((_v) & 0xf) -#define XPNET_VERSION _XPNET_VERSION(1,0) /* version 1.0 */ -#define XPNET_VERSION_EMBED _XPNET_VERSION(1,1) /* version 1.1 */ -#define XPNET_MAGIC 0x88786984 /* "XNET" */ +#define XPNET_VERSION _XPNET_VERSION(1,0) /* version 1.0 */ +#define XPNET_VERSION_EMBED _XPNET_VERSION(1,1) /* version 1.1 */ +#define XPNET_MAGIC 0x88786984 /* "XNET" */ #define XPNET_VALID_MSG(_m) \ ((XPNET_VERSION_MAJOR(_m->version) == XPNET_VERSION_MAJOR(XPNET_VERSION)) \ @@ -101,7 +97,6 @@ struct xpnet_message { #define XPNET_DEVICE_NAME "xp0" - /* * When messages are queued with xpc_send_notify, a kmalloc'd buffer * of the following type is passed as a notification cookie. When the @@ -145,7 +140,6 @@ static DEFINE_SPINLOCK(xpnet_broadcast_lock); /* 32KB has been determined to be the ideal */ #define XPNET_DEF_MTU (0x8000UL) - /* * The partition id is encapsulated in the MAC address. The following * define locates the octet the partid is in. @@ -153,7 +147,6 @@ static DEFINE_SPINLOCK(xpnet_broadcast_lock); #define XPNET_PARTID_OCTET 1 #define XPNET_LICENSE_OCTET 2 - /* * Define the XPNET debug device structure that is to be used with dev_dbg(), * dev_err(), dev_warn(), and dev_info(). @@ -163,7 +156,7 @@ struct device_driver xpnet_dbg_name = { }; struct device xpnet_dbg_subname = { - .bus_id = {0}, /* set to "" */ + .bus_id = {0}, /* set to "" */ .driver = &xpnet_dbg_name }; @@ -178,14 +171,13 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) struct sk_buff *skb; bte_result_t bret; struct xpnet_dev_private *priv = - (struct xpnet_dev_private *) xpnet_device->priv; - + (struct xpnet_dev_private *)xpnet_device->priv; if (!XPNET_VALID_MSG(msg)) { /* * Packet with a different XPC version. Ignore. */ - xpc_received(partid, channel, (void *) msg); + xpc_received(partid, channel, (void *)msg); priv->stats.rx_errors++; @@ -194,14 +186,13 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) 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); if (!skb) { dev_err(xpnet, "failed on dev_alloc_skb(%d)\n", msg->size + L1_CACHE_BYTES); - xpc_received(partid, channel, (void *) msg); + xpc_received(partid, channel, (void *)msg); priv->stats.rx_errors++; @@ -227,12 +218,13 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) * Move the data over from the other side. */ if ((XPNET_VERSION_MINOR(msg->version) == 1) && - (msg->embedded_bytes != 0)) { + (msg->embedded_bytes != 0)) { dev_dbg(xpnet, "copying embedded message. memcpy(0x%p, 0x%p, " "%lu)\n", skb->data, &msg->data, - (size_t) msg->embedded_bytes); + (size_t)msg->embedded_bytes); - skb_copy_to_linear_data(skb, &msg->data, (size_t)msg->embedded_bytes); + skb_copy_to_linear_data(skb, &msg->data, + (size_t)msg->embedded_bytes); } else { dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t" "bte_copy(0x%p, 0x%p, %hu)\n", (void *)msg->buf_pa, @@ -250,10 +242,10 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) dev_err(xpnet, "bte_copy(0x%p, 0x%p, 0x%hx) returned " "error=0x%x\n", (void *)msg->buf_pa, (void *)__pa((u64)skb->data & - ~(L1_CACHE_BYTES - 1)), + ~(L1_CACHE_BYTES - 1)), msg->size, bret); - xpc_received(partid, channel, (void *) msg); + xpc_received(partid, channel, (void *)msg); priv->stats.rx_errors++; @@ -262,7 +254,7 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) } dev_dbg(xpnet, "head=0x%p skb->data=0x%p skb->tail=0x%p " - "skb->end=0x%p skb->len=%d\n", (void *) skb->head, + "skb->end=0x%p skb->len=%d\n", (void *)skb->head, (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len); @@ -275,16 +267,14 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) (void *)skb->head, (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len); - xpnet_device->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += skb->len + ETH_HLEN; netif_rx_ni(skb); - xpc_received(partid, channel, (void *) msg); + xpc_received(partid, channel, (void *)msg); } - /* * This is the handler which XPC calls during any sort of change in * state or message reception on a connection. @@ -295,20 +285,19 @@ xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel, { long bp; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); DBUG_ON(channel != XPC_NET_CHANNEL); - switch(reason) { + switch (reason) { case xpcMsgReceived: /* message received */ DBUG_ON(data == NULL); - xpnet_receive(partid, channel, (struct xpnet_message *) data); + xpnet_receive(partid, channel, (struct xpnet_message *)data); break; case xpcConnected: /* connection completed to a partition */ spin_lock_bh(&xpnet_broadcast_lock); - xpnet_broadcast_partitions |= 1UL << (partid -1 ); + xpnet_broadcast_partitions |= 1UL << (partid - 1); bp = xpnet_broadcast_partitions; spin_unlock_bh(&xpnet_broadcast_lock); @@ -321,7 +310,7 @@ xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel, default: spin_lock_bh(&xpnet_broadcast_lock); - xpnet_broadcast_partitions &= ~(1UL << (partid -1 )); + xpnet_broadcast_partitions &= ~(1UL << (partid - 1)); bp = xpnet_broadcast_partitions; spin_unlock_bh(&xpnet_broadcast_lock); @@ -337,13 +326,11 @@ xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel, } } - static int xpnet_dev_open(struct net_device *dev) { enum xpc_retval ret; - 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, @@ -364,7 +351,6 @@ xpnet_dev_open(struct net_device *dev) return 0; } - static int xpnet_dev_stop(struct net_device *dev) { @@ -375,7 +361,6 @@ xpnet_dev_stop(struct net_device *dev) return 0; } - static int xpnet_dev_change_mtu(struct net_device *dev, int new_mtu) { @@ -392,7 +377,6 @@ xpnet_dev_change_mtu(struct net_device *dev, int new_mtu) return 0; } - /* * Required for the net_device structure. */ @@ -402,7 +386,6 @@ xpnet_dev_set_config(struct net_device *dev, struct ifmap *new_map) return 0; } - /* * Return statistics to the caller. */ @@ -411,13 +394,11 @@ xpnet_dev_get_stats(struct net_device *dev) { struct xpnet_dev_private *priv; - - priv = (struct xpnet_dev_private *) dev->priv; + priv = (struct xpnet_dev_private *)dev->priv; return &priv->stats; } - /* * Notification that the other end has received the message and * DMA'd the skb information. At this point, they are done with @@ -426,11 +407,9 @@ xpnet_dev_get_stats(struct net_device *dev) */ static void xpnet_send_completed(enum xpc_retval reason, partid_t partid, int channel, - void *__qm) + void *__qm) { - struct xpnet_pending_msg *queued_msg = - (struct xpnet_pending_msg *) __qm; - + struct xpnet_pending_msg *queued_msg = (struct xpnet_pending_msg *)__qm; DBUG_ON(queued_msg == NULL); @@ -439,14 +418,13 @@ xpnet_send_completed(enum xpc_retval reason, partid_t partid, int channel, if (atomic_dec_return(&queued_msg->use_count) == 0) { dev_dbg(xpnet, "all acks for skb->head=-x%p\n", - (void *) queued_msg->skb->head); + (void *)queued_msg->skb->head); dev_kfree_skb_any(queued_msg->skb); kfree(queued_msg); } } - /* * Network layer has formatted a packet (skb) and is ready to place it * "on the wire". Prepare and send an xpnet_message to all partitions @@ -469,16 +447,13 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct xpnet_dev_private *priv; u16 embedded_bytes; - - priv = (struct xpnet_dev_private *) dev->priv; - + priv = (struct xpnet_dev_private *)dev->priv; dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " - "skb->end=0x%p skb->len=%d\n", (void *) skb->head, + "skb->end=0x%p skb->len=%d\n", (void *)skb->head, (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len); - /* * The xpnet_pending_msg tracks how many outstanding * xpc_send_notifies are relying on this skb. When none @@ -487,16 +462,15 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) queued_msg = kmalloc(sizeof(struct xpnet_pending_msg), GFP_ATOMIC); if (queued_msg == NULL) { dev_warn(xpnet, "failed to kmalloc %ld bytes; dropping " - "packet\n", sizeof(struct xpnet_pending_msg)); + "packet\n", sizeof(struct xpnet_pending_msg)); priv->stats.tx_errors++; return -ENOMEM; } - /* get the beginning of the first cacheline and end of last */ - start_addr = ((u64) skb->data & ~(L1_CACHE_BYTES - 1)); + start_addr = ((u64)skb->data & ~(L1_CACHE_BYTES - 1)); end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb)); /* calculate how many bytes to embed in the XPC message */ @@ -506,7 +480,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) embedded_bytes = skb->len; } - /* * Since the send occurs asynchronously, we set the count to one * and begin sending. Any sends that happen to complete before @@ -517,14 +490,13 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) atomic_set(&queued_msg->use_count, 1); queued_msg->skb = skb; - second_mac_octet = skb->data[XPNET_PARTID_OCTET]; if (second_mac_octet == 0xff) { /* we are being asked to broadcast to all partitions */ dp = xpnet_broadcast_partitions; } else if (second_mac_octet != 0) { dp = xpnet_broadcast_partitions & - (1UL << (second_mac_octet - 1)); + (1UL << (second_mac_octet - 1)); } else { /* 0 is an invalid partid. Ignore */ dp = 0; @@ -543,7 +515,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) for (dest_partid = 1; dp && dest_partid < XP_MAX_PARTITIONS; dest_partid++) { - if (!(dp & (1UL << (dest_partid - 1)))) { /* not destined for this partition */ continue; @@ -552,7 +523,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) /* remove this partition from the destinations mask */ dp &= ~(1UL << (dest_partid - 1)); - /* found a partition to send to */ ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL, @@ -565,7 +535,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(embedded_bytes != 0)) { msg->version = XPNET_VERSION_EMBED; dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n", - &msg->data, skb->data, (size_t) embedded_bytes); + &msg->data, skb->data, (size_t)embedded_bytes); skb_copy_from_linear_data(skb, &msg->data, (size_t)embedded_bytes); } else { @@ -573,7 +543,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } msg->magic = XPNET_MAGIC; msg->size = end_addr - start_addr; - msg->leadin_ignore = (u64) skb->data - 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); @@ -583,7 +553,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size, msg->leadin_ignore, msg->tailout_ignore); - atomic_inc(&queued_msg->use_count); ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, msg, @@ -599,7 +568,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_dbg(xpnet, "no partitions to receive packet destined for " "%d\n", dest_partid); - dev_kfree_skb(skb); kfree(queued_msg); } @@ -610,23 +578,20 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } - /* * Deal with transmit timeouts coming from the network layer. */ static void -xpnet_dev_tx_timeout (struct net_device *dev) +xpnet_dev_tx_timeout(struct net_device *dev) { struct xpnet_dev_private *priv; - - priv = (struct xpnet_dev_private *) dev->priv; + priv = (struct xpnet_dev_private *)dev->priv; priv->stats.tx_errors++; return; } - static int __init xpnet_init(void) { @@ -634,7 +599,6 @@ xpnet_init(void) u32 license_num; int result = -ENOMEM; - if (!ia64_platform_is("sn2")) { return -ENODEV; } @@ -672,7 +636,7 @@ xpnet_init(void) license_num = sn_partition_serial_number_val(); for (i = 3; i >= 0; i--) { xpnet_device->dev_addr[XPNET_LICENSE_OCTET + i] = - license_num & 0xff; + license_num & 0xff; license_num = license_num >> 8; } @@ -696,23 +660,22 @@ xpnet_init(void) return result; } -module_init(xpnet_init); +module_init(xpnet_init); static void __exit xpnet_exit(void) { dev_info(xpnet, "unregistering network device %s\n", - xpnet_device[0].name); + xpnet_device[0].name); unregister_netdev(xpnet_device); free_netdev(xpnet_device); } -module_exit(xpnet_exit); +module_exit(xpnet_exit); MODULE_AUTHOR("Silicon Graphics, Inc."); MODULE_DESCRIPTION("Cross Partition Network adapter (XPNET)"); MODULE_LICENSE("GPL"); - -- cgit v1.2.3 From 2c2b94f93f4732c3b9703ce62627e6187e7d6128 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 22 Apr 2008 14:50:17 -0500 Subject: [IA64] run drivers/misc/sgi-xp through scripts/checkpatch.pl Addressed issues raised by scripts/checkpatch.pl. Removed unnecessary curly braces. Eliminated uses of volatiles and use of kernel_thread() and daemonize(). Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- drivers/misc/sgi-xp/xp.h | 6 +- drivers/misc/sgi-xp/xp_main.c | 41 ++++---- drivers/misc/sgi-xp/xpc.h | 124 +++++++++++------------ drivers/misc/sgi-xp/xpc_channel.c | 192 ++++++++++++++---------------------- drivers/misc/sgi-xp/xpc_main.c | 167 +++++++++++-------------------- drivers/misc/sgi-xp/xpc_partition.c | 99 ++++++++----------- drivers/misc/sgi-xp/xpnet.c | 30 +++--- 7 files changed, 268 insertions(+), 391 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 87171682664..5515234be86 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -79,9 +79,9 @@ xp_bte_copy(u64 src, u64 vdst, u64 len, u64 mode, void *notification) ret = bte_copy(src, pdst, len, mode, notification); if ((ret != BTE_SUCCESS) && BTE_ERROR_RETRY(ret)) { - if (!in_interrupt()) { + if (!in_interrupt()) cond_resched(); - } + ret = bte_copy(src, pdst, len, mode, notification); } @@ -255,7 +255,7 @@ enum xpc_retval { /* 115: BTE end */ xpcBteSh2End = xpcBteSh2Start + BTEFAIL_SH2_ALL, - xpcUnknownReason /* 116: unknown reason -- must be last in list */ + xpcUnknownReason /* 116: unknown reason - must be last in enum */ }; /* diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index bb9257642fc..1fbf99bae96 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -23,15 +23,21 @@ #include "xp.h" /* - * Target of nofault PIO read. + * The export of xp_nofault_PIOR needs to happen here since it is defined + * in drivers/misc/sgi-xp/xp_nofault.S. The target of the nofault read is + * defined here. */ +EXPORT_SYMBOL_GPL(xp_nofault_PIOR); + u64 xp_nofault_PIOR_target; +EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target); /* * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level * users of XPC. */ struct xpc_registration xpc_registrations[XPC_NCHANNELS]; +EXPORT_SYMBOL_GPL(xpc_registrations); /* * Initialize the XPC interface to indicate that XPC isn't loaded. @@ -52,6 +58,7 @@ struct xpc_interface xpc_interface = { (void (*)(partid_t, int, void *))xpc_notloaded, (enum xpc_retval(*)(partid_t, void *))xpc_notloaded }; +EXPORT_SYMBOL_GPL(xpc_interface); /* * XPC calls this when it (the XPC module) has been loaded. @@ -74,6 +81,7 @@ xpc_set_interface(void (*connect) (int), xpc_interface.received = received; xpc_interface.partid_to_nasids = partid_to_nasids; } +EXPORT_SYMBOL_GPL(xpc_set_interface); /* * XPC calls this when it (the XPC module) is being unloaded. @@ -95,6 +103,7 @@ xpc_clear_interface(void) xpc_interface.partid_to_nasids = (enum xpc_retval(*)(partid_t, void *)) xpc_notloaded; } +EXPORT_SYMBOL_GPL(xpc_clear_interface); /* * Register for automatic establishment of a channel connection whenever @@ -133,9 +142,8 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, registration = &xpc_registrations[ch_number]; - if (mutex_lock_interruptible(®istration->mutex) != 0) { + if (mutex_lock_interruptible(®istration->mutex) != 0) return xpcInterrupted; - } /* if XPC_CHANNEL_REGISTERED(ch_number) */ if (registration->func != NULL) { @@ -157,6 +165,7 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, return xpcSuccess; } +EXPORT_SYMBOL_GPL(xpc_connect); /* * Remove the registration for automatic connection of the specified channel @@ -207,6 +216,7 @@ xpc_disconnect(int ch_number) return; } +EXPORT_SYMBOL_GPL(xpc_disconnect); int __init xp_init(void) @@ -215,9 +225,8 @@ xp_init(void) u64 func_addr = *(u64 *)xp_nofault_PIOR; u64 err_func_addr = *(u64 *)xp_error_PIOR; - if (!ia64_platform_is("sn2")) { + if (!ia64_platform_is("sn2")) return -ENODEV; - } /* * Register a nofault code region which performs a cross-partition @@ -228,8 +237,9 @@ xp_init(void) * least some CPUs on Shubs <= v1.2, which unfortunately we have to * work around). */ - if ((ret = sn_register_nofault_code(func_addr, err_func_addr, - err_func_addr, 1, 1)) != 0) { + ret = sn_register_nofault_code(func_addr, err_func_addr, err_func_addr, + 1, 1); + if (ret != 0) { printk(KERN_ERR "XP: can't register nofault code, error=%d\n", ret); } @@ -237,16 +247,14 @@ xp_init(void) * Setup the nofault PIO read target. (There is no special reason why * SH_IPI_ACCESS was selected.) */ - if (is_shub2()) { + if (is_shub2()) xp_nofault_PIOR_target = SH2_IPI_ACCESS0; - } else { + else xp_nofault_PIOR_target = SH1_IPI_ACCESS; - } /* initialize the connection registration mutex */ - for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) { + for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) mutex_init(&xpc_registrations[ch_number].mutex); - } return 0; } @@ -269,12 +277,3 @@ module_exit(xp_exit); MODULE_AUTHOR("Silicon Graphics, Inc."); MODULE_DESCRIPTION("Cross Partition (XP) base"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(xp_nofault_PIOR); -EXPORT_SYMBOL(xp_nofault_PIOR_target); -EXPORT_SYMBOL(xpc_registrations); -EXPORT_SYMBOL(xpc_interface); -EXPORT_SYMBOL(xpc_clear_interface); -EXPORT_SYMBOL(xpc_set_interface); -EXPORT_SYMBOL(xpc_connect); -EXPORT_SYMBOL(xpc_disconnect); diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 64368bb8889..9eb6d4a3269 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -110,16 +110,16 @@ struct xpc_rsvd_page { u8 partid; /* SAL: partition ID */ u8 version; u8 pad1[6]; /* align to next u64 in cacheline */ - volatile u64 vars_pa; + u64 vars_pa; /* physical address of struct xpc_vars */ struct timespec stamp; /* time when reserved page was setup by XPC */ u64 pad2[9]; /* align to last u64 in cacheline */ u64 nasids_size; /* SAL: size of each nasid mask in bytes */ }; -#define XPC_RP_VERSION _XPC_VERSION(1,1) /* version 1.1 of the reserved page */ +#define XPC_RP_VERSION _XPC_VERSION(1, 1) /* version 1.1 of the reserved page */ #define XPC_SUPPORTS_RP_STAMP(_version) \ - (_version >= _XPC_VERSION(1,1)) + (_version >= _XPC_VERSION(1, 1)) /* * compare stamps - the return value is: @@ -133,9 +133,10 @@ xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2) { int ret; - if ((ret = stamp1->tv_sec - stamp2->tv_sec) == 0) { + ret = stamp1->tv_sec - stamp2->tv_sec; + if (ret == 0) ret = stamp1->tv_nsec - stamp2->tv_nsec; - } + return ret; } @@ -165,10 +166,10 @@ struct xpc_vars { AMO_t *amos_page; /* vaddr of page of AMOs from MSPEC driver */ }; -#define XPC_V_VERSION _XPC_VERSION(3,1) /* version 3.1 of the cross vars */ +#define XPC_V_VERSION _XPC_VERSION(3, 1) /* version 3.1 of the cross vars */ #define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \ - (_version >= _XPC_VERSION(3,1)) + (_version >= _XPC_VERSION(3, 1)) static inline int xpc_hb_allowed(partid_t partid, struct xpc_vars *vars) @@ -224,7 +225,7 @@ xpc_disallow_hb(partid_t partid, struct xpc_vars *vars) * occupies half a cacheline. */ struct xpc_vars_part { - volatile u64 magic; + u64 magic; u64 openclose_args_pa; /* physical address of open and close args */ u64 GPs_pa; /* physical address of Get/Put values */ @@ -247,18 +248,20 @@ struct xpc_vars_part { * 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 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */ +#define XPC_VP_MAGIC2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */ /* the reserved page sizes and offsets */ #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)) +#define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars)) -#define XPC_RP_PART_NASIDS(_rp) (u64 *) ((u8 *) _rp + XPC_RP_HEADER_SIZE) +#define XPC_RP_PART_NASIDS(_rp) ((u64 *)((u8 *)(_rp) + XPC_RP_HEADER_SIZE)) #define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words) -#define XPC_RP_VARS(_rp) ((struct xpc_vars *) XPC_RP_MACH_NASIDS(_rp) + xp_nasid_mask_words) -#define XPC_RP_VARS_PART(_rp) (struct xpc_vars_part *) ((u8 *) XPC_RP_VARS(rp) + XPC_RP_VARS_SIZE) +#define XPC_RP_VARS(_rp) ((struct xpc_vars *)(XPC_RP_MACH_NASIDS(_rp) + \ + xp_nasid_mask_words)) +#define XPC_RP_VARS_PART(_rp) ((struct xpc_vars_part *) \ + ((u8 *)XPC_RP_VARS(_rp) + XPC_RP_VARS_SIZE)) /* * Functions registered by add_timer() or called by kernel_thread() only @@ -277,8 +280,8 @@ struct xpc_vars_part { * Define a Get/Put value pair (pointers) used with a message queue. */ struct xpc_gp { - volatile s64 get; /* Get value */ - volatile s64 put; /* Put value */ + s64 get; /* Get value */ + s64 put; /* Put value */ }; #define XPC_GP_SIZE \ @@ -315,7 +318,7 @@ struct xpc_openclose_args { * and consumed by the intended recipient. */ struct xpc_notify { - volatile u8 type; /* type of notification */ + u8 type; /* type of notification */ /* the following two fields are only used if type == XPC_N_CALL */ xpc_notify_func func; /* user's notify function */ @@ -421,8 +424,8 @@ struct xpc_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 */ + 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 */ @@ -437,16 +440,16 @@ struct xpc_channel { /* 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 */ + 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 mutex msg_to_pull_mutex; /* next msg to pull serialization */ - struct completion wdisconnect_wait; /* wait for channel disconnect */ + struct completion wdisconnect_wait; /* wait for channel disconnect */ - struct xpc_openclose_args *local_openclose_args; /* args passed on */ - /* opening or closing of channel */ + struct xpc_openclose_args *local_openclose_args; /* args passed on */ + /* opening or closing of channel */ /* various flavors of local and remote Get/Put values */ @@ -458,16 +461,11 @@ struct xpc_channel { /* kthread management related fields */ -// >>> rethink having kthreads_assigned_limit and kthreads_idle_limit; perhaps -// >>> allow the assigned limit be unbounded and let the idle limit be dynamic -// >>> dependent on activity over the last interval of time atomic_t kthreads_assigned; /* #of kthreads assigned to channel */ u32 kthreads_assigned_limit; /* limit on #of kthreads assigned */ atomic_t kthreads_idle; /* #of kthreads idle waiting for work */ u32 kthreads_idle_limit; /* limit on #of kthreads idle */ atomic_t kthreads_active; /* #of kthreads actively working */ - // >>> following field is temporary - u32 kthreads_created; /* total #of kthreads created */ wait_queue_head_t idle_wq; /* idle kthread wait queue */ @@ -479,28 +477,28 @@ struct xpc_channel { #define XPC_C_ROPENREPLY 0x00000002 /* remote open channel reply */ #define XPC_C_OPENREPLY 0x00000004 /* local open channel reply */ -#define XPC_C_ROPENREQUEST 0x00000008 /* remote open channel request */ +#define XPC_C_ROPENREQUEST 0x00000008 /* remote open channel request */ #define XPC_C_OPENREQUEST 0x00000010 /* local open channel request */ -#define XPC_C_SETUP 0x00000020 /* channel's msgqueues are alloc'd */ -#define XPC_C_CONNECTEDCALLOUT 0x00000040 /* connected callout initiated */ +#define XPC_C_SETUP 0x00000020 /* channel's msgqueues are alloc'd */ +#define XPC_C_CONNECTEDCALLOUT 0x00000040 /* connected callout initiated */ #define XPC_C_CONNECTEDCALLOUT_MADE \ - 0x00000080 /* connected callout completed */ + 0x00000080 /* connected callout completed */ #define XPC_C_CONNECTED 0x00000100 /* local channel is connected */ #define XPC_C_CONNECTING 0x00000200 /* channel is being connected */ #define XPC_C_RCLOSEREPLY 0x00000400 /* remote close channel reply */ #define XPC_C_CLOSEREPLY 0x00000800 /* local close channel reply */ -#define XPC_C_RCLOSEREQUEST 0x00001000 /* remote close channel request */ -#define XPC_C_CLOSEREQUEST 0x00002000 /* local close channel request */ +#define XPC_C_RCLOSEREQUEST 0x00001000 /* remote close channel request */ +#define XPC_C_CLOSEREQUEST 0x00002000 /* local close channel request */ #define XPC_C_DISCONNECTED 0x00004000 /* channel is disconnected */ -#define XPC_C_DISCONNECTING 0x00008000 /* channel is being disconnected */ +#define XPC_C_DISCONNECTING 0x00008000 /* channel is being disconnected */ #define XPC_C_DISCONNECTINGCALLOUT \ - 0x00010000 /* disconnecting callout initiated */ + 0x00010000 /* disconnecting callout initiated */ #define XPC_C_DISCONNECTINGCALLOUT_MADE \ - 0x00020000 /* disconnecting callout completed */ -#define XPC_C_WDISCONNECT 0x00040000 /* waiting for channel disconnect */ + 0x00020000 /* disconnecting callout completed */ +#define XPC_C_WDISCONNECT 0x00040000 /* waiting for channel disconnect */ /* * Manages channels on a partition basis. There is one of these structures @@ -512,7 +510,7 @@ struct xpc_partition { /* XPC HB infrastructure */ u8 remote_rp_version; /* version# of partition's rsvd pg */ - struct timespec remote_rp_stamp; /* time when rsvd pg was initialized */ + struct timespec remote_rp_stamp; /* time when rsvd pg was initialized */ u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ u64 remote_vars_pa; /* phys addr of partition's vars */ u64 remote_vars_part_pa; /* phys addr of partition's vars part */ @@ -533,7 +531,7 @@ struct xpc_partition { /* XPC infrastructure referencing and teardown control */ - volatile u8 setup_state; /* infrastructure setup state */ + u8 setup_state; /* infrastructure setup state */ wait_queue_head_t teardown_wq; /* kthread waiting to teardown infra */ atomic_t references; /* #of references to infrastructure */ @@ -545,32 +543,32 @@ struct xpc_partition { */ u8 nchannels; /* #of defined channels supported */ - atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */ - atomic_t nchannels_engaged; /* #of channels engaged with remote part */ + atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */ + atomic_t nchannels_engaged; /* #of channels engaged with remote part */ struct xpc_channel *channels; /* array of channel structures */ void *local_GPs_base; /* base address of kmalloc'd space */ struct xpc_gp *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 Get/Put */ - /* values */ + struct xpc_gp *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 */ /* fields used to pass args when opening or closing a channel */ - 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 */ + 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 */ u64 remote_openclose_args_pa; /* phys addr of remote's args */ /* IPI sending, receiving and handling related fields */ int remote_IPI_nasid; /* nasid of where to send IPIs */ int remote_IPI_phys_cpuid; /* phys CPU ID of where to send IPIs */ - AMO_t *remote_IPI_amo_va; /* address of remote IPI AMO_t structure */ + AMO_t *remote_IPI_amo_va; /* address of remote IPI AMO_t structure */ AMO_t *local_IPI_amo_va; /* address of IPI AMO_t structure */ u64 local_IPI_amo; /* IPI amo flags yet to be handled */ @@ -678,9 +676,8 @@ extern void xpc_teardown_infrastructure(struct xpc_partition *); static inline void xpc_wakeup_channel_mgr(struct xpc_partition *part) { - if (atomic_inc_return(&part->channel_mgr_requests) == 1) { + if (atomic_inc_return(&part->channel_mgr_requests) == 1) wake_up(&part->channel_mgr_wq); - } } /* @@ -699,9 +696,8 @@ xpc_msgqueue_deref(struct xpc_channel *ch) s32 refs = atomic_dec_return(&ch->references); DBUG_ON(refs < 0); - if (refs == 0) { + if (refs == 0) xpc_wakeup_channel_mgr(&xpc_partitions[ch->partid]); - } } #define XPC_DISCONNECT_CHANNEL(_ch, _reason, _irqflgs) \ @@ -717,9 +713,8 @@ xpc_part_deref(struct xpc_partition *part) 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_WTEARDOWN) wake_up(&part->teardown_wq); - } } static inline int @@ -729,9 +724,9 @@ xpc_part_ref(struct xpc_partition *part) atomic_inc(&part->references); setup = (part->setup_state == XPC_P_SETUP); - if (!setup) { + if (!setup) xpc_part_deref(part); - } + return setup; } @@ -1007,13 +1002,11 @@ xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string, dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n", ipi_flag_string, ch->partid, ch->number, ret); if (unlikely(ret != xpcSuccess)) { - if (irq_flags != NULL) { + if (irq_flags != NULL) spin_unlock_irqrestore(&ch->lock, *irq_flags); - } XPC_DEACTIVATE_PARTITION(part, ret); - if (irq_flags != NULL) { + if (irq_flags != NULL) spin_lock_irqsave(&ch->lock, *irq_flags); - } } } } @@ -1056,8 +1049,8 @@ xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag, #define XPC_GET_IPI_FLAGS(_amo, _c) ((u8) (((_amo) >> ((_c) * 8)) & 0xff)) #define XPC_SET_IPI_FLAGS(_amo, _c, _f) (_amo) |= ((u64) (_f) << ((_c) * 8)) -#define XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & __IA64_UL_CONST(0x0f0f0f0f0f0f0f0f)) -#define XPC_ANY_MSG_IPI_FLAGS_SET(_amo) ((_amo) & __IA64_UL_CONST(0x1010101010101010)) +#define XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & 0x0f0f0f0f0f0f0f0fUL) +#define XPC_ANY_MSG_IPI_FLAGS_SET(_amo) ((_amo) & 0x1010101010101010UL) static inline void xpc_IPI_send_closerequest(struct xpc_channel *ch, unsigned long *irq_flags) @@ -1178,9 +1171,8 @@ xpc_check_for_channel_activity(struct xpc_partition *part) unsigned long irq_flags; IPI_amo = xpc_IPI_receive(part->local_IPI_amo_va); - if (IPI_amo == 0) { + if (IPI_amo == 0) return; - } spin_lock_irqsave(&part->IPI_lock, irq_flags); part->local_IPI_amo |= IPI_amo; diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 15cb91a8210..bfcb9ea968e 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -33,19 +33,19 @@ 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) { + if (*base == NULL) return NULL; - } - if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) { + + 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) { + if (*base == NULL) return NULL; - } + return (void *)L1_CACHE_ALIGN((u64)*base); } @@ -264,15 +264,13 @@ xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst, DBUG_ON((u64)dst != L1_CACHE_ALIGN((u64)dst)); DBUG_ON(cnt != L1_CACHE_ALIGN(cnt)); - if (part->act_state == XPC_P_DEACTIVATING) { + if (part->act_state == XPC_P_DEACTIVATING) return part->reason; - } bte_ret = xp_bte_copy((u64)src, (u64)dst, (u64)cnt, (BTE_NORMAL | BTE_WACQUIRE), NULL); - if (bte_ret == BTE_SUCCESS) { + if (bte_ret == BTE_SUCCESS) return xpcSuccess; - } dev_dbg(xpc_chan, "xp_bte_copy() from partition %d failed, ret=%d\n", XPC_PARTID(part), bte_ret); @@ -359,18 +357,16 @@ xpc_pull_remote_vars_part(struct xpc_partition *part) part->remote_IPI_nasid = pulled_entry->IPI_nasid; part->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid; - if (part->nchannels > pulled_entry->nchannels) { + if (part->nchannels > pulled_entry->nchannels) part->nchannels = pulled_entry->nchannels; - } /* let the other side know that we've pulled their variables */ xpc_vars_part[partid].magic = XPC_VP_MAGIC2; } - if (pulled_entry->magic == XPC_VP_MAGIC1) { + if (pulled_entry->magic == XPC_VP_MAGIC1) return xpcRetry; - } return xpcSuccess; } @@ -390,9 +386,10 @@ xpc_get_IPI_flags(struct xpc_partition *part) */ spin_lock_irqsave(&part->IPI_lock, irq_flags); - if ((IPI_amo = part->local_IPI_amo) != 0) { + IPI_amo = part->local_IPI_amo; + if (IPI_amo != 0) part->local_IPI_amo = 0; - } + spin_unlock_irqrestore(&part->IPI_lock, irq_flags); if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_amo)) { @@ -441,20 +438,14 @@ xpc_allocate_local_msgqueue(struct xpc_channel *ch) int nentries; size_t nbytes; - // >>> may want to check for ch->flags & XPC_C_DISCONNECTING between - // >>> iterations of the for-loop, bail if set? - - // >>> should we impose a minimum #of entries? like 4 or 8? for (nentries = ch->local_nentries; nentries > 0; nentries--) { nbytes = nentries * ch->msg_size; ch->local_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, - &ch-> - local_msgqueue_base); - if (ch->local_msgqueue == NULL) { + &ch->local_msgqueue_base); + if (ch->local_msgqueue == NULL) continue; - } nbytes = nentries * sizeof(struct xpc_notify); ch->notify_queue = kzalloc(nbytes, GFP_KERNEL); @@ -493,20 +484,14 @@ xpc_allocate_remote_msgqueue(struct xpc_channel *ch) DBUG_ON(ch->remote_nentries <= 0); - // >>> may want to check for ch->flags & XPC_C_DISCONNECTING between - // >>> iterations of the for-loop, bail if set? - - // >>> should we impose a minimum #of entries? like 4 or 8? for (nentries = ch->remote_nentries; nentries > 0; nentries--) { nbytes = nentries * ch->msg_size; ch->remote_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, - &ch-> - remote_msgqueue_base); - if (ch->remote_msgqueue == NULL) { + &ch->remote_msgqueue_base); + if (ch->remote_msgqueue == NULL) continue; - } spin_lock_irqsave(&ch->lock, irq_flags); if (nentries < ch->remote_nentries) { @@ -538,11 +523,12 @@ xpc_allocate_msgqueues(struct xpc_channel *ch) DBUG_ON(ch->flags & XPC_C_SETUP); - if ((ret = xpc_allocate_local_msgqueue(ch)) != xpcSuccess) { + ret = xpc_allocate_local_msgqueue(ch); + if (ret != xpcSuccess) return ret; - } - if ((ret = xpc_allocate_remote_msgqueue(ch)) != xpcSuccess) { + ret = xpc_allocate_remote_msgqueue(ch); + if (ret != xpcSuccess) { kfree(ch->local_msgqueue_base); ch->local_msgqueue = NULL; kfree(ch->notify_queue); @@ -582,12 +568,11 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) ret = xpc_allocate_msgqueues(ch); spin_lock_irqsave(&ch->lock, *irq_flags); - if (ret != xpcSuccess) { + if (ret != xpcSuccess) XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags); - } - if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING)) { + + if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING)) return; - } DBUG_ON(!(ch->flags & XPC_C_SETUP)); DBUG_ON(ch->local_msgqueue == NULL); @@ -599,9 +584,8 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) xpc_IPI_send_openreply(ch, irq_flags); } - if (!(ch->flags & XPC_C_ROPENREPLY)) { + if (!(ch->flags & XPC_C_ROPENREPLY)) return; - } DBUG_ON(ch->remote_msgqueue_pa == 0); @@ -719,9 +703,8 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) DBUG_ON(!spin_is_locked(&ch->lock)); - if (!(ch->flags & XPC_C_DISCONNECTING)) { + if (!(ch->flags & XPC_C_DISCONNECTING)) return; - } DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); @@ -736,26 +719,23 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) if (part->act_state == XPC_P_DEACTIVATING) { /* can't proceed until the other side disengages from us */ - if (xpc_partition_engaged(1UL << ch->partid)) { + if (xpc_partition_engaged(1UL << ch->partid)) return; - } } else { /* as long as the other side is up do the full protocol */ - if (!(ch->flags & XPC_C_RCLOSEREQUEST)) { + if (!(ch->flags & XPC_C_RCLOSEREQUEST)) return; - } if (!(ch->flags & XPC_C_CLOSEREPLY)) { ch->flags |= XPC_C_CLOSEREPLY; xpc_IPI_send_closereply(ch, irq_flags); } - if (!(ch->flags & XPC_C_RCLOSEREPLY)) { + if (!(ch->flags & XPC_C_RCLOSEREPLY)) return; - } } /* wake those waiting for notify completion */ @@ -815,9 +795,10 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, spin_lock_irqsave(&ch->lock, irq_flags); - again: +again: - if ((ch->flags & XPC_C_DISCONNECTED) && (ch->flags & XPC_C_WDISCONNECT)) { + if ((ch->flags & XPC_C_DISCONNECTED) && + (ch->flags & XPC_C_WDISCONNECT)) { /* * Delay processing IPI flags until thread waiting disconnect * has had a chance to see that the channel is disconnected. @@ -890,11 +871,10 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, if (!(ch->flags & XPC_C_DISCONNECTING)) { reason = args->reason; - if (reason <= xpcSuccess || reason > xpcUnknownReason) { + if (reason <= xpcSuccess || reason > xpcUnknownReason) reason = xpcUnknownReason; - } else if (reason == xpcUnregistering) { + else if (reason == xpcUnregistering) reason = xpcOtherUnregistering; - } XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); @@ -1068,9 +1048,8 @@ xpc_connect_channel(struct xpc_channel *ch) unsigned long irq_flags; struct xpc_registration *registration = &xpc_registrations[ch->number]; - if (mutex_trylock(®istration->mutex) == 0) { + if (mutex_trylock(®istration->mutex) == 0) return xpcRetry; - } if (!XPC_CHANNEL_REGISTERED(ch->number)) { mutex_unlock(®istration->mutex); @@ -1159,7 +1138,7 @@ xpc_clear_local_msgqueue_flags(struct xpc_channel *ch) (get % ch->local_nentries) * ch->msg_size); msg->flags = 0; - } while (++get < (volatile s64)ch->remote_GP.get); + } while (++get < ch->remote_GP.get); } /* @@ -1177,7 +1156,7 @@ xpc_clear_remote_msgqueue_flags(struct xpc_channel *ch) (put % ch->remote_nentries) * ch->msg_size); msg->flags = 0; - } while (++put < (volatile s64)ch->remote_GP.put); + } while (++put < ch->remote_GP.put); } static void @@ -1244,9 +1223,8 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) * If anyone was waiting for message queue entries to become * available, wake them up. */ - if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) { + if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) wake_up(&ch->msg_allocate_wq); - } } /* @@ -1273,9 +1251,8 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) "delivered=%d, partid=%d, channel=%d\n", nmsgs_sent, ch->partid, ch->number); - if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) { + if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) xpc_activate_kthreads(ch, nmsgs_sent); - } } } @@ -1310,9 +1287,8 @@ xpc_process_channel_activity(struct xpc_partition *part) IPI_flags = XPC_GET_IPI_FLAGS(IPI_amo, ch_number); - if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_flags)) { + if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_flags)) xpc_process_openclose_IPI(part, ch_number, IPI_flags); - } ch_flags = ch->flags; /* need an atomic snapshot of flags */ @@ -1323,9 +1299,8 @@ xpc_process_channel_activity(struct xpc_partition *part) continue; } - if (part->act_state == XPC_P_DEACTIVATING) { + if (part->act_state == XPC_P_DEACTIVATING) continue; - } if (!(ch_flags & XPC_C_CONNECTED)) { if (!(ch_flags & XPC_C_OPENREQUEST)) { @@ -1345,9 +1320,8 @@ xpc_process_channel_activity(struct xpc_partition *part) * from the other partition. */ - if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_flags)) { + if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_flags)) xpc_process_msg_IPI(part, ch_number); - } } } @@ -1560,9 +1534,9 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, DBUG_ON(!spin_is_locked(&ch->lock)); - if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) { + if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) return; - } + DBUG_ON(!(ch->flags & (XPC_C_CONNECTING | XPC_C_CONNECTED))); dev_dbg(xpc_chan, "reason=%d, line=%d, partid=%d, channel=%d\n", @@ -1578,9 +1552,8 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, xpc_IPI_send_closerequest(ch, irq_flags); - if (channel_was_connected) { + if (channel_was_connected) ch->flags |= XPC_C_WASCONNECTED; - } spin_unlock_irqrestore(&ch->lock, *irq_flags); @@ -1595,9 +1568,8 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, } /* wake those waiting to allocate an entry from the local msg queue */ - if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) { + if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) wake_up(&ch->msg_allocate_wq); - } spin_lock_irqsave(&ch->lock, *irq_flags); } @@ -1632,7 +1604,7 @@ xpc_allocate_msg_wait(struct xpc_channel *ch) enum xpc_retval ret; if (ch->flags & XPC_C_DISCONNECTING) { - DBUG_ON(ch->reason == xpcInterrupted); // >>> Is this true? + DBUG_ON(ch->reason == xpcInterrupted); return ch->reason; } @@ -1642,7 +1614,7 @@ xpc_allocate_msg_wait(struct xpc_channel *ch) if (ch->flags & XPC_C_DISCONNECTING) { ret = ch->reason; - DBUG_ON(ch->reason == xpcInterrupted); // >>> Is this true? + DBUG_ON(ch->reason == xpcInterrupted); } else if (ret == 0) { ret = xpcTimeout; } else { @@ -1685,9 +1657,9 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags, while (1) { - put = (volatile s64)ch->w_local_GP.put; - if (put - (volatile s64)ch->w_remote_GP.get < - ch->local_nentries) { + put = ch->w_local_GP.put; + rmb(); /* guarantee that .put loads before .get */ + if (put - ch->w_remote_GP.get < ch->local_nentries) { /* There are available message entries. We need to try * to secure one for ourselves. We'll do this by trying @@ -1711,9 +1683,8 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags, * that will cause the IPI handler to fetch the latest * GP values as if an IPI was sent by the other side. */ - if (ret == xpcTimeout) { + if (ret == xpcTimeout) xpc_IPI_send_local_msgrequest(ch); - } if (flags & XPC_NOWAIT) { xpc_msgqueue_deref(ch); @@ -1772,9 +1743,8 @@ xpc_initiate_allocate(partid_t partid, int ch_number, u32 flags, void **payload) ret = xpc_allocate_msg(&part->channels[ch_number], flags, &msg); xpc_part_deref(part); - if (msg != NULL) { + if (msg != NULL) *payload = &msg->payload; - } } return ret; @@ -1795,17 +1765,15 @@ xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) while (1) { while (1) { - if (put == (volatile s64)ch->w_local_GP.put) { + if (put == ch->w_local_GP.put) break; - } msg = (struct xpc_msg *)((u64)ch->local_msgqueue + (put % ch->local_nentries) * ch->msg_size); - if (!(msg->flags & XPC_M_READY)) { + if (!(msg->flags & XPC_M_READY)) break; - } put++; } @@ -1818,7 +1786,7 @@ xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) if (cmpxchg_rel(&ch->local_GP->put, initial_put, put) != initial_put) { /* someone else beat us to it */ - DBUG_ON((volatile s64)ch->local_GP->put < initial_put); + DBUG_ON(ch->local_GP->put < initial_put); break; } @@ -1837,9 +1805,8 @@ xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) initial_put = put; } - if (send_IPI) { + if (send_IPI) xpc_IPI_send_msgrequest(ch); - } } /* @@ -1880,7 +1847,7 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, notify->key = key; notify->type = notify_type; - // >>> is a mb() needed here? + /* >>> is a mb() needed here? */ if (ch->flags & XPC_C_DISCONNECTING) { /* @@ -1913,9 +1880,8 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, /* see if the message is next in line to be sent, if so send it */ put = ch->local_GP->put; - if (put == msg_number) { + if (put == msg_number) xpc_send_msgs(ch, put); - } /* drop the reference grabbed in xpc_allocate_msg() */ xpc_msgqueue_deref(ch); @@ -2032,10 +1998,8 @@ xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) msg_index = ch->next_msg_to_pull % ch->remote_nentries; - DBUG_ON(ch->next_msg_to_pull >= - (volatile s64)ch->w_remote_GP.put); - nmsgs = (volatile s64)ch->w_remote_GP.put - - ch->next_msg_to_pull; + DBUG_ON(ch->next_msg_to_pull >= ch->w_remote_GP.put); + nmsgs = ch->w_remote_GP.put - ch->next_msg_to_pull; if (msg_index + nmsgs > ch->remote_nentries) { /* ignore the ones that wrap the msg queue for now */ nmsgs = ch->remote_nentries - msg_index; @@ -2046,9 +2010,9 @@ xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) remote_msg = (struct xpc_msg *)(ch->remote_msgqueue_pa + msg_offset); - if ((ret = xpc_pull_remote_cachelines(part, msg, remote_msg, - nmsgs * ch->msg_size)) != - xpcSuccess) { + ret = xpc_pull_remote_cachelines(part, msg, remote_msg, + nmsgs * ch->msg_size); + if (ret != xpcSuccess) { dev_dbg(xpc_chan, "failed to pull %d msgs starting with" " msg %ld from partition %d, channel=%d, " @@ -2061,8 +2025,6 @@ xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) return NULL; } - mb(); /* >>> this may not be needed, we're not sure */ - ch->next_msg_to_pull += nmsgs; } @@ -2085,14 +2047,13 @@ xpc_get_deliverable_msg(struct xpc_channel *ch) s64 get; do { - if ((volatile u32)ch->flags & XPC_C_DISCONNECTING) { + if (ch->flags & XPC_C_DISCONNECTING) break; - } - get = (volatile s64)ch->w_local_GP.get; - if (get == (volatile s64)ch->w_remote_GP.put) { + get = ch->w_local_GP.get; + rmb(); /* guarantee that .get loads before .put */ + if (get == ch->w_remote_GP.put) break; - } /* There are messages waiting to be pulled and delivered. * We need to try to secure one for ourselves. We'll do this @@ -2132,7 +2093,8 @@ xpc_deliver_msg(struct xpc_channel *ch) { struct xpc_msg *msg; - if ((msg = xpc_get_deliverable_msg(ch)) != NULL) { + msg = xpc_get_deliverable_msg(ch); + if (msg != NULL) { /* * This ref is taken to protect the payload itself from being @@ -2178,17 +2140,15 @@ xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) while (1) { while (1) { - if (get == (volatile s64)ch->w_local_GP.get) { + if (get == ch->w_local_GP.get) break; - } msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + (get % ch->remote_nentries) * ch->msg_size); - if (!(msg->flags & XPC_M_DONE)) { + if (!(msg->flags & XPC_M_DONE)) break; - } msg_flags |= msg->flags; get++; @@ -2202,7 +2162,7 @@ xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) if (cmpxchg_rel(&ch->local_GP->get, initial_get, get) != initial_get) { /* someone else beat us to it */ - DBUG_ON((volatile s64)ch->local_GP->get <= initial_get); + DBUG_ON(ch->local_GP->get <= initial_get); break; } @@ -2221,9 +2181,8 @@ xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) initial_get = get; } - if (send_IPI) { + if (send_IPI) xpc_IPI_send_msgrequest(ch); - } } /* @@ -2276,9 +2235,8 @@ xpc_initiate_received(partid_t partid, int ch_number, void *payload) * been delivered. */ get = ch->local_GP->get; - if (get == msg_number) { + if (get == msg_number) xpc_acknowledge_msgs(ch, get, msg->flags); - } /* the call to xpc_msgqueue_ref() was done by xpc_deliver_msg() */ xpc_msgqueue_deref(ch); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index d81a2dd787a..f673ba90eb0 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -46,17 +46,16 @@ #include #include #include -#include -#include #include #include #include #include #include #include +#include +#include #include #include -#include #include "xpc.h" /* define two XPC debug device structures to be used with dev_dbg() et al */ @@ -91,7 +90,7 @@ static int xpc_hb_check_min_interval = 10; static int xpc_hb_check_max_interval = 120; int xpc_disengage_request_timelimit = XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT; -static int xpc_disengage_request_min_timelimit = 0; +static int xpc_disengage_request_min_timelimit; /* = 0 */ static int xpc_disengage_request_max_timelimit = 120; static ctl_table xpc_sys_xpc_hb_dir[] = { @@ -213,9 +212,8 @@ xpc_hb_beater(unsigned long dummy) { xpc_vars->heartbeat++; - if (time_after_eq(jiffies, xpc_hb_check_timeout)) { + if (time_after_eq(jiffies, xpc_hb_check_timeout)) wake_up_interruptible(&xpc_act_IRQ_wq); - } xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ); add_timer(&xpc_hb_timer); @@ -234,15 +232,13 @@ xpc_hb_checker(void *ignore) /* this thread was marked active by xpc_hb_init() */ - daemonize(XPC_HB_CHECK_THREAD_NAME); - set_cpus_allowed(current, cpumask_of_cpu(XPC_HB_CHECK_CPU)); /* set our heartbeating to other partitions into motion */ xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); xpc_hb_beater(0); - while (!(volatile int)xpc_exiting) { + while (!xpc_exiting) { dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " "been received\n", @@ -287,7 +283,7 @@ xpc_hb_checker(void *ignore) atomic_read(&xpc_act_IRQ_rcvd) || time_after_eq(jiffies, xpc_hb_check_timeout) || - (volatile int)xpc_exiting)); + xpc_exiting)); } dev_dbg(xpc_part, "heartbeat checker is exiting\n"); @@ -305,8 +301,6 @@ xpc_hb_checker(void *ignore) static int xpc_initiate_discovery(void *ignore) { - daemonize(XPC_DISCOVERY_THREAD_NAME); - xpc_discovery(); dev_dbg(xpc_part, "discovery thread is exiting\n"); @@ -338,9 +332,8 @@ xpc_make_first_contact(struct xpc_partition *part) /* 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_DEACTIVATING) return part->reason; - } } return xpc_mark_partition_active(part); @@ -382,22 +375,12 @@ xpc_channel_mgr(struct xpc_partition *part) */ atomic_dec(&part->channel_mgr_requests); (void)wait_event_interruptible(part->channel_mgr_wq, - (atomic_read - (&part->channel_mgr_requests) > - 0 || - (volatile u64)part-> - local_IPI_amo != 0 || - ((volatile u8)part->act_state == - XPC_P_DEACTIVATING && - atomic_read(&part-> - nchannels_active) - == 0 && - xpc_partition_disengaged - (part)))); + (atomic_read(&part->channel_mgr_requests) > 0 || + part->local_IPI_amo != 0 || + (part->act_state == XPC_P_DEACTIVATING && + atomic_read(&part->nchannels_active) == 0 && + xpc_partition_disengaged(part)))); atomic_set(&part->channel_mgr_requests, 1); - - // >>> Does it need to wakeup periodically as well? In case we - // >>> miscalculated the #of kthreads to wakeup or create? } } @@ -423,9 +406,8 @@ xpc_partition_up(struct xpc_partition *part) dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part)); - if (xpc_setup_infrastructure(part) != xpcSuccess) { + if (xpc_setup_infrastructure(part) != xpcSuccess) return; - } /* * The kthread that XPC HB called us with will become the @@ -436,9 +418,8 @@ xpc_partition_up(struct xpc_partition *part) (void)xpc_part_ref(part); /* this will always succeed */ - if (xpc_make_first_contact(part) == xpcSuccess) { + if (xpc_make_first_contact(part) == xpcSuccess) xpc_channel_mgr(part); - } xpc_part_deref(part); @@ -451,8 +432,6 @@ xpc_activating(void *__partid) partid_t partid = (u64)__partid; struct xpc_partition *part = &xpc_partitions[partid]; unsigned long irq_flags; - struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; - int ret; DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); @@ -474,21 +453,6 @@ xpc_activating(void *__partid) dev_dbg(xpc_part, "bringing partition %d up\n", partid); - daemonize("xpc%02d", partid); - - /* - * This thread needs to run at a realtime priority to prevent a - * significant performance degradation. - */ - ret = sched_setscheduler(current, SCHED_FIFO, ¶m); - if (ret != 0) { - dev_warn(xpc_part, "unable to set pid %d to a realtime " - "priority, ret=%d\n", current->pid, ret); - } - - /* allow this thread and its children to run on any CPU */ - set_cpus_allowed(current, CPU_MASK_ALL); - /* * Register the remote partition's AMOs with SAL so it can handle * and cleanup errors within that address range should the remote @@ -537,7 +501,7 @@ xpc_activate_partition(struct xpc_partition *part) { partid_t partid = XPC_PARTID(part); unsigned long irq_flags; - pid_t pid; + struct task_struct *kthread; spin_lock_irqsave(&part->act_lock, irq_flags); @@ -548,9 +512,9 @@ xpc_activate_partition(struct xpc_partition *part) spin_unlock_irqrestore(&part->act_lock, irq_flags); - pid = kernel_thread(xpc_activating, (void *)((u64)partid), 0); - - if (unlikely(pid <= 0)) { + kthread = kthread_run(xpc_activating, (void *)((u64)partid), "xpc%02d", + partid); + if (IS_ERR(kthread)) { spin_lock_irqsave(&part->act_lock, irq_flags); part->act_state = XPC_P_INACTIVE; XPC_SET_REASON(part, xpcCloneKThreadFailed, __LINE__); @@ -562,7 +526,7 @@ xpc_activate_partition(struct xpc_partition *part) * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more * than one partition, we use an AMO_t structure per partition to indicate - * whether a partition has sent an IPI or not. >>> If it has, then wake up the + * whether a partition has sent an IPI or not. If it has, then wake up the * associated kthread to handle it. * * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IPIs sent by XPC @@ -628,16 +592,13 @@ xpc_activate_kthreads(struct xpc_channel *ch, int needed) wake_up_nr(&ch->idle_wq, wakeup); } - if (needed <= 0) { + if (needed <= 0) return; - } if (needed + assigned > ch->kthreads_assigned_limit) { needed = ch->kthreads_assigned_limit - assigned; - // >>>should never be less than 0 - if (needed <= 0) { + if (needed <= 0) return; - } } dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n", @@ -655,9 +616,8 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) do { /* deliver messages to their intended recipients */ - while ((volatile s64)ch->w_local_GP.get < - (volatile s64)ch->w_remote_GP.put && - !((volatile u32)ch->flags & XPC_C_DISCONNECTING)) { + while (ch->w_local_GP.get < ch->w_remote_GP.put && + !(ch->flags & XPC_C_DISCONNECTING)) { xpc_deliver_msg(ch); } @@ -672,21 +632,16 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) "wait_event_interruptible_exclusive()\n"); (void)wait_event_interruptible_exclusive(ch->idle_wq, - ((volatile s64)ch-> - w_local_GP.get < - (volatile s64)ch-> - w_remote_GP.put || - ((volatile u32)ch-> - flags & - XPC_C_DISCONNECTING))); + (ch->w_local_GP.get < ch->w_remote_GP.put || + (ch->flags & XPC_C_DISCONNECTING))); atomic_dec(&ch->kthreads_idle); - } while (!((volatile u32)ch->flags & XPC_C_DISCONNECTING)); + } while (!(ch->flags & XPC_C_DISCONNECTING)); } static int -xpc_daemonize_kthread(void *args) +xpc_kthread_start(void *args) { partid_t partid = XPC_UNPACK_ARG1(args); u16 ch_number = XPC_UNPACK_ARG2(args); @@ -695,8 +650,6 @@ xpc_daemonize_kthread(void *args) int n_needed; unsigned long irq_flags; - daemonize("xpc%02dc%d", partid, ch_number); - dev_dbg(xpc_chan, "kthread starting, partid=%d, channel=%d\n", partid, ch_number); @@ -725,9 +678,9 @@ xpc_daemonize_kthread(void *args) * need one less than total #of messages to deliver. */ n_needed = ch->w_remote_GP.put - ch->w_local_GP.get - 1; - if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING)) { + if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING)) xpc_activate_kthreads(ch, n_needed); - } + } else { spin_unlock_irqrestore(&ch->lock, irq_flags); } @@ -783,9 +736,9 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, int ignore_disconnecting) { unsigned long irq_flags; - pid_t pid; u64 args = XPC_PACK_ARGS(ch->partid, ch->number); struct xpc_partition *part = &xpc_partitions[ch->partid]; + struct task_struct *kthread; while (needed-- > 0) { @@ -812,8 +765,9 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, (void)xpc_part_ref(part); xpc_msgqueue_ref(ch); - pid = kernel_thread(xpc_daemonize_kthread, (void *)args, 0); - if (pid < 0) { + kthread = kthread_run(xpc_kthread_start, (void *)args, + "xpc%02dc%d", ch->partid, ch->number); + if (IS_ERR(kthread)) { /* the fork failed */ /* @@ -823,7 +777,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, * to this channel are blocked in the channel's * registerer, because the only thing that will unblock * them is the xpcDisconnecting callout that this - * failed kernel_thread would have made. + * failed kthread_run() would have made. */ if (atomic_dec_return(&ch->kthreads_assigned) == 0 && @@ -848,8 +802,6 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, } break; } - - ch->kthreads_created++; // >>> temporary debug only!!! } } @@ -866,9 +818,8 @@ xpc_disconnect_wait(int ch_number) for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; - if (!xpc_part_ref(part)) { + if (!xpc_part_ref(part)) continue; - } ch = &part->channels[ch_number]; @@ -898,9 +849,8 @@ xpc_disconnect_wait(int ch_number) ch->flags &= ~XPC_C_WDISCONNECT; spin_unlock_irqrestore(&ch->lock, irq_flags); - if (wakeup_channel_mgr) { + if (wakeup_channel_mgr) xpc_wakeup_channel_mgr(part); - } xpc_part_deref(part); } @@ -1019,9 +969,8 @@ xpc_do_exit(enum xpc_retval reason) /* clear the interface to XPC's functions */ xpc_clear_interface(); - if (xpc_sysctl) { + if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); - } kfree(xpc_remote_copy_buffer_base); } @@ -1071,7 +1020,8 @@ xpc_die_disengage(void) for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; - if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { + if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part-> + remote_vars_version)) { /* just in case it was left set by an earlier XPC */ xpc_clear_partition_engaged(1UL << partid); @@ -1144,9 +1094,9 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) case DIE_KDEBUG_ENTER: /* Should lack of heartbeat be ignored by other partitions? */ - if (!xpc_kdebug_ignore) { + if (!xpc_kdebug_ignore) break; - } + /* fall through */ case DIE_MCA_MONARCH_ENTER: case DIE_INIT_MONARCH_ENTER: @@ -1156,9 +1106,9 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) case DIE_KDEBUG_LEAVE: /* Is lack of heartbeat being ignored by other partitions? */ - if (!xpc_kdebug_ignore) { + if (!xpc_kdebug_ignore) break; - } + /* fall through */ case DIE_MCA_MONARCH_LEAVE: case DIE_INIT_MONARCH_LEAVE: @@ -1176,18 +1126,17 @@ xpc_init(void) int ret; partid_t partid; struct xpc_partition *part; - pid_t pid; + struct task_struct *kthread; size_t buf_size; - if (!ia64_platform_is("sn2")) { + if (!ia64_platform_is("sn2")) return -ENODEV; - } buf_size = max(XPC_RP_VARS_SIZE, XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES); xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size, GFP_KERNEL, - &xpc_remote_copy_buffer_base); + &xpc_remote_copy_buffer_base); if (xpc_remote_copy_buffer == NULL) return -ENOMEM; @@ -1250,9 +1199,8 @@ xpc_init(void) xpc_restrict_IPI_ops(); - if (xpc_sysctl) { + if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); - } kfree(xpc_remote_copy_buffer_base); return -EBUSY; @@ -1270,9 +1218,8 @@ xpc_init(void) free_irq(SGI_XPC_ACTIVATE, NULL); xpc_restrict_IPI_ops(); - if (xpc_sysctl) { + if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); - } kfree(xpc_remote_copy_buffer_base); return -EBUSY; @@ -1280,15 +1227,13 @@ xpc_init(void) /* add ourselves to the reboot_notifier_list */ ret = register_reboot_notifier(&xpc_reboot_notifier); - if (ret != 0) { + if (ret != 0) dev_warn(xpc_part, "can't register reboot notifier\n"); - } /* add ourselves to the die_notifier list */ ret = register_die_notifier(&xpc_die_notifier); - if (ret != 0) { + if (ret != 0) dev_warn(xpc_part, "can't register die notifier\n"); - } init_timer(&xpc_hb_timer); xpc_hb_timer.function = xpc_hb_beater; @@ -1297,8 +1242,8 @@ xpc_init(void) * The real work-horse behind xpc. This processes incoming * interrupts and monitors remote heartbeats. */ - pid = kernel_thread(xpc_hb_checker, NULL, 0); - if (pid < 0) { + kthread = kthread_run(xpc_hb_checker, NULL, XPC_HB_CHECK_THREAD_NAME); + if (IS_ERR(kthread)) { dev_err(xpc_part, "failed while forking hb check thread\n"); /* indicate to others that our reserved page is uninitialized */ @@ -1314,9 +1259,8 @@ xpc_init(void) free_irq(SGI_XPC_ACTIVATE, NULL); xpc_restrict_IPI_ops(); - if (xpc_sysctl) { + if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); - } kfree(xpc_remote_copy_buffer_base); return -EBUSY; @@ -1327,8 +1271,9 @@ xpc_init(void) * activate based on info provided by SAL. This new thread is short * lived and will exit once discovery is complete. */ - pid = kernel_thread(xpc_initiate_discovery, NULL, 0); - if (pid < 0) { + kthread = kthread_run(xpc_initiate_discovery, NULL, + XPC_DISCOVERY_THREAD_NAME); + if (IS_ERR(kthread)) { dev_err(xpc_part, "failed while forking discovery thread\n"); /* mark this new thread as a non-starter */ diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 57f1d0b3ac2..27e200ec582 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -75,19 +75,19 @@ xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) { /* see if kmalloc will give us cachline aligned memory by default */ *base = kmalloc(size, flags); - if (*base == NULL) { + if (*base == NULL) return NULL; - } - if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) { + + if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) return *base; - } + kfree(*base); /* nope, we'll have to do it ourselves */ *base = kmalloc(size + L1_CACHE_BYTES, flags); - if (*base == NULL) { + if (*base == NULL) return NULL; - } + return (void *)L1_CACHE_ALIGN((u64)*base); } @@ -116,9 +116,8 @@ xpc_get_rsvd_page_pa(int nasid) "0x%016lx, address=0x%016lx, len=0x%016lx\n", status, cookie, rp_pa, len); - if (status != SALRET_MORE_PASSES) { + if (status != SALRET_MORE_PASSES) break; - } if (L1_CACHE_ALIGN(len) > buf_len) { kfree(buf_base); @@ -145,9 +144,9 @@ xpc_get_rsvd_page_pa(int nasid) kfree(buf_base); - if (status != SALRET_OK) { + if (status != SALRET_OK) rp_pa = 0; - } + dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa); return rp_pa; } @@ -210,7 +209,8 @@ xpc_rsvd_page_init(void) * on subsequent loads of XPC. This AMO page is never freed, and its * memory protections are never restricted. */ - if ((amos_page = xpc_vars->amos_page) == NULL) { + amos_page = xpc_vars->amos_page; + if (amos_page == NULL) { amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0)); if (amos_page == NULL) { dev_err(xpc_part, "can't allocate page of AMOs\n"); @@ -264,9 +264,8 @@ xpc_rsvd_page_init(void) XP_MAX_PARTITIONS); /* initialize the activate IRQ related AMO variables */ - for (i = 0; i < xp_nasid_mask_words; i++) { + for (i = 0; i < xp_nasid_mask_words; i++) (void)xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); - } /* initialize the engaged remote partitions related AMO variables */ (void)xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); @@ -294,7 +293,7 @@ xpc_allow_IPI_ops(void) int node; int nasid; - // >>> Change SH_IPI_ACCESS code to use SAL call once it is available. + /* >>> Change SH_IPI_ACCESS code to use SAL call once it is available */ if (is_shub2()) { xpc_sh2_IPI_access0 = @@ -336,14 +335,14 @@ xpc_allow_IPI_ops(void) xpc_prot_vec[node] = (u64)HUB_L((u64 *) GLOBAL_MMR_ADDR (nasid, - SH1_MD_DQLP_MMR_DIR_PRIVEC0)); + SH1_MD_DQLP_MMR_DIR_PRIVEC0)); HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQLP_MMR_DIR_PRIVEC0), + SH1_MD_DQLP_MMR_DIR_PRIVEC0), -1UL); HUB_S((u64 *) GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQRP_MMR_DIR_PRIVEC0), + SH1_MD_DQRP_MMR_DIR_PRIVEC0), -1UL); } } @@ -360,7 +359,7 @@ xpc_restrict_IPI_ops(void) int node; int nasid; - // >>> Change SH_IPI_ACCESS code to use SAL call once it is available. + /* >>> Change SH_IPI_ACCESS code to use SAL call once it is available */ if (is_shub2()) { @@ -385,10 +384,10 @@ xpc_restrict_IPI_ops(void) if (enable_shub_wars_1_1()) { HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQLP_MMR_DIR_PRIVEC0), + SH1_MD_DQLP_MMR_DIR_PRIVEC0), xpc_prot_vec[node]); HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQRP_MMR_DIR_PRIVEC0), + SH1_MD_DQRP_MMR_DIR_PRIVEC0), xpc_prot_vec[node]); } } @@ -411,13 +410,11 @@ xpc_check_remote_hb(void) for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { - if (xpc_exiting) { + if (xpc_exiting) break; - } - if (partid == sn_partition_id) { + if (partid == sn_partition_id) continue; - } part = &xpc_partitions[partid]; @@ -471,24 +468,21 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, /* get the reserved page's physical address */ *remote_rp_pa = xpc_get_rsvd_page_pa(nasid); - if (*remote_rp_pa == 0) { + if (*remote_rp_pa == 0) return xpcNoRsvdPageAddr; - } /* pull over the reserved page header and part_nasids mask */ bres = xp_bte_copy(*remote_rp_pa, (u64)remote_rp, XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes, (BTE_NOTIFY | BTE_WACQUIRE), NULL); - if (bres != BTE_SUCCESS) { + if (bres != BTE_SUCCESS) return xpc_map_bte_errors(bres); - } if (discovered_nasids != NULL) { u64 *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); - for (i = 0; i < xp_nasid_mask_words; i++) { + for (i = 0; i < xp_nasid_mask_words; i++) discovered_nasids[i] |= remote_part_nasids[i]; - } } /* check that the partid is for another partition */ @@ -498,9 +492,8 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, return xpcInvalidPartid; } - if (remote_rp->partid == sn_partition_id) { + if (remote_rp->partid == sn_partition_id) return xpcLocalPartid; - } if (XPC_VERSION_MAJOR(remote_rp->version) != XPC_VERSION_MAJOR(XPC_RP_VERSION)) { @@ -521,16 +514,14 @@ xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars) { int bres; - if (remote_vars_pa == 0) { + if (remote_vars_pa == 0) return xpcVarsNotSet; - } /* pull over the cross partition variables */ bres = xp_bte_copy(remote_vars_pa, (u64)remote_vars, XPC_RP_VARS_SIZE, (BTE_NOTIFY | BTE_WACQUIRE), NULL); - if (bres != BTE_SUCCESS) { + if (bres != BTE_SUCCESS) return xpc_map_bte_errors(bres); - } if (XPC_VERSION_MAJOR(remote_vars->version) != XPC_VERSION_MAJOR(XPC_V_VERSION)) { @@ -630,9 +621,9 @@ xpc_identify_act_IRQ_req(int nasid) remote_vars_pa = remote_rp->vars_pa; remote_rp_version = remote_rp->version; - if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { + if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) remote_rp_stamp = remote_rp->stamp; - } + partid = remote_rp->partid; part = &xpc_partitions[partid]; @@ -656,7 +647,8 @@ xpc_identify_act_IRQ_req(int nasid) "%ld:0x%lx\n", (int)nasid, (int)partid, part->act_IRQ_rcvd, remote_vars->heartbeat, remote_vars->heartbeating_to_mask); - if (xpc_partition_disengaged(part) && part->act_state == XPC_P_INACTIVE) { + if (xpc_partition_disengaged(part) && + part->act_state == XPC_P_INACTIVE) { xpc_update_partition_info(part, remote_rp_version, &remote_rp_stamp, remote_rp_pa, @@ -791,9 +783,8 @@ xpc_identify_act_IRQ_sender(void) /* scan through act AMO variable looking for non-zero entries */ for (word = 0; word < xp_nasid_mask_words; word++) { - if (xpc_exiting) { + if (xpc_exiting) break; - } nasid_mask = xpc_IPI_receive(&act_amos[word]); if (nasid_mask == 0) { @@ -840,7 +831,8 @@ xpc_partition_disengaged(struct xpc_partition *part) disengaged = (xpc_partition_engaged(1UL << partid) == 0); if (part->disengage_request_timeout) { if (!disengaged) { - if (time_before(jiffies, part->disengage_request_timeout)) { + if (time_before(jiffies, + part->disengage_request_timeout)) { /* timelimit hasn't been reached yet */ return 0; } @@ -866,13 +858,11 @@ xpc_partition_disengaged(struct xpc_partition *part) DBUG_ON(part->act_state != XPC_P_DEACTIVATING && part->act_state != XPC_P_INACTIVE); - if (part->act_state != XPC_P_INACTIVE) { + if (part->act_state != XPC_P_INACTIVE) xpc_wakeup_channel_mgr(part); - } - if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { + if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) xpc_cancel_partition_disengage_request(part); - } } return disengaged; } @@ -1000,9 +990,9 @@ xpc_discovery(void) remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes, GFP_KERNEL, &remote_rp_base); - if (remote_rp == NULL) { + if (remote_rp == NULL) return; - } + remote_vars = (struct xpc_vars *)remote_rp; discovered_nasids = kzalloc(sizeof(u64) * xp_nasid_mask_words, @@ -1035,18 +1025,16 @@ xpc_discovery(void) for (region = 0; region < max_regions; region++) { - if ((volatile int)xpc_exiting) { + if (xpc_exiting) break; - } dev_dbg(xpc_part, "searching region %d\n", region); for (nasid = (region * region_size * 2); nasid < ((region + 1) * region_size * 2); nasid += 2) { - if ((volatile int)xpc_exiting) { + if (xpc_exiting) break; - } dev_dbg(xpc_part, "checking nasid %d\n", nasid); @@ -1080,9 +1068,9 @@ xpc_discovery(void) "from nasid %d, reason=%d\n", nasid, ret); - if (ret == xpcLocalPartid) { + if (ret == xpcLocalPartid) break; - } + continue; } @@ -1171,9 +1159,8 @@ xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask) int bte_res; part = &xpc_partitions[partid]; - if (part->remote_rp_pa == 0) { + if (part->remote_rp_pa == 0) return xpcPartitionDown; - } memset(nasid_mask, 0, XP_NASID_MASK_BYTES); diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index e41cb93b8c8..a9543c65814 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include #include #include "xp.h" @@ -87,8 +87,8 @@ struct xpnet_message { #define XPNET_VERSION_MAJOR(_v) ((_v) >> 4) #define XPNET_VERSION_MINOR(_v) ((_v) & 0xf) -#define XPNET_VERSION _XPNET_VERSION(1,0) /* version 1.0 */ -#define XPNET_VERSION_EMBED _XPNET_VERSION(1,1) /* version 1.1 */ +#define XPNET_VERSION _XPNET_VERSION(1, 0) /* version 1.0 */ +#define XPNET_VERSION_EMBED _XPNET_VERSION(1, 1) /* version 1.1 */ #define XPNET_MAGIC 0x88786984 /* "XNET" */ #define XPNET_VALID_MSG(_m) \ @@ -236,9 +236,11 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) msg->size, (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (bret != BTE_SUCCESS) { - // >>> Need better way of cleaning skb. Currently skb - // >>> appears in_use and we can't just call - // >>> dev_kfree_skb. + /* + * >>> Need better way of cleaning skb. Currently skb + * >>> appears in_use and we can't just call + * >>> dev_kfree_skb. + */ dev_err(xpnet, "bte_copy(0x%p, 0x%p, 0x%hx) returned " "error=0x%x\n", (void *)msg->buf_pa, (void *)__pa((u64)skb->data & @@ -314,9 +316,8 @@ xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel, bp = xpnet_broadcast_partitions; spin_unlock_bh(&xpnet_broadcast_lock); - if (bp == 0) { + if (bp == 0) netif_carrier_off(xpnet_device); - } dev_dbg(xpnet, "%s disconnected from partition %d; " "xpnet_broadcast_partitions=0x%lx\n", @@ -527,9 +528,8 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT, (void **)&msg); - if (unlikely(ret != xpcSuccess)) { + if (unlikely(ret != xpcSuccess)) continue; - } msg->embedded_bytes = embedded_bytes; if (unlikely(embedded_bytes != 0)) { @@ -561,7 +561,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) atomic_dec(&queued_msg->use_count); continue; } - } if (atomic_dec_return(&queued_msg->use_count) == 0) { @@ -599,9 +598,8 @@ xpnet_init(void) u32 license_num; int result = -ENOMEM; - if (!ia64_platform_is("sn2")) { + if (!ia64_platform_is("sn2")) return -ENODEV; - } dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME); @@ -611,9 +609,8 @@ xpnet_init(void) */ xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private), XPNET_DEVICE_NAME, ether_setup); - if (xpnet_device == NULL) { + if (xpnet_device == NULL) return -ENOMEM; - } netif_carrier_off(xpnet_device); @@ -654,9 +651,8 @@ xpnet_init(void) xpnet_device->features = NETIF_F_NO_CSUM; result = register_netdev(xpnet_device); - if (result != 0) { + if (result != 0) free_netdev(xpnet_device); - } return result; } -- cgit v1.2.3