|
@@ -47,13 +47,16 @@ static u64 xpc_sh2_IPI_access3;
|
|
|
u64 xpc_prot_vec[MAX_NUMNODES];
|
|
|
|
|
|
|
|
|
-/* this partition's reserved page */
|
|
|
+/* this partition's reserved page pointers */
|
|
|
struct xpc_rsvd_page *xpc_rsvd_page;
|
|
|
-
|
|
|
-/* this partition's XPC variables (within the reserved 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
|
|
@@ -65,20 +68,16 @@ struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1];
|
|
|
|
|
|
|
|
|
/*
|
|
|
- * Generic buffer used to store a local copy of the remote partitions
|
|
|
- * reserved page or XPC variables.
|
|
|
+ * 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).
|
|
|
*
|
|
|
* xpc_discovery runs only once and is a seperate thread that is
|
|
|
* very likely going to be processing in parallel with receiving
|
|
|
* interrupts.
|
|
|
*/
|
|
|
-char ____cacheline_aligned
|
|
|
- xpc_remote_copy_buffer[XPC_RSVD_PAGE_ALIGNED_SIZE];
|
|
|
-
|
|
|
-
|
|
|
-/* systune related variables */
|
|
|
-int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL;
|
|
|
-int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_TIMEOUT;
|
|
|
+char ____cacheline_aligned xpc_remote_copy_buffer[XPC_RP_HEADER_SIZE +
|
|
|
+ XP_NASID_MASK_BYTES];
|
|
|
|
|
|
|
|
|
/*
|
|
@@ -86,13 +85,16 @@ int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_TIMEOUT;
|
|
|
* for that nasid. This function returns 0 on any error.
|
|
|
*/
|
|
|
static u64
|
|
|
-xpc_get_rsvd_page_pa(int nasid, u64 buf, u64 buf_size)
|
|
|
+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) {
|
|
@@ -108,13 +110,22 @@ xpc_get_rsvd_page_pa(int nasid, u64 buf, u64 buf_size)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (len > buf_size) {
|
|
|
- dev_err(xpc_part, "len (=0x%016lx) > buf_size\n", len);
|
|
|
- status = SALRET_ERROR;
|
|
|
- break;
|
|
|
+ if (L1_CACHE_ALIGN(len) > buf_len) {
|
|
|
+ if (buf_base != NULL) {
|
|
|
+ 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, ia64_tpa(buf), buf_size,
|
|
|
+ bte_res = xp_bte_copy(rp_pa, ia64_tpa(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);
|
|
@@ -123,6 +134,10 @@ xpc_get_rsvd_page_pa(int nasid, u64 buf, u64 buf_size)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (buf_base != NULL) {
|
|
|
+ kfree(buf_base);
|
|
|
+ }
|
|
|
+
|
|
|
if (status != SALRET_OK) {
|
|
|
rp_pa = 0;
|
|
|
}
|
|
@@ -141,15 +156,15 @@ xpc_rsvd_page_init(void)
|
|
|
{
|
|
|
struct xpc_rsvd_page *rp;
|
|
|
AMO_t *amos_page;
|
|
|
- u64 rp_pa, next_cl, nasid_array = 0;
|
|
|
+ u64 rp_pa, nasid_array = 0;
|
|
|
int i, ret;
|
|
|
|
|
|
|
|
|
/* get the local reserved page's address */
|
|
|
|
|
|
- rp_pa = xpc_get_rsvd_page_pa(cnodeid_to_nasid(0),
|
|
|
- (u64) xpc_remote_copy_buffer,
|
|
|
- XPC_RSVD_PAGE_ALIGNED_SIZE);
|
|
|
+ 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;
|
|
@@ -164,12 +179,19 @@ xpc_rsvd_page_init(void)
|
|
|
|
|
|
rp->version = XPC_RP_VERSION;
|
|
|
|
|
|
- /*
|
|
|
- * Place the XPC variables on the cache line following the
|
|
|
- * reserved page structure.
|
|
|
- */
|
|
|
- next_cl = (u64) rp + XPC_RSVD_PAGE_ALIGNED_SIZE;
|
|
|
- xpc_vars = (struct xpc_vars *) next_cl;
|
|
|
+ /* 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
|
|
@@ -221,33 +243,32 @@ xpc_rsvd_page_init(void)
|
|
|
amos_page = (AMO_t *) TO_AMO((u64) amos_page);
|
|
|
}
|
|
|
|
|
|
+ /* clear xpc_vars */
|
|
|
memset(xpc_vars, 0, sizeof(struct xpc_vars));
|
|
|
|
|
|
- /*
|
|
|
- * Place the XPC per partition specific variables on the cache line
|
|
|
- * following the XPC variables structure.
|
|
|
- */
|
|
|
- next_cl += XPC_VARS_ALIGNED_SIZE;
|
|
|
- memset((u64 *) next_cl, 0, sizeof(struct xpc_vars_part) *
|
|
|
- XP_MAX_PARTITIONS);
|
|
|
- xpc_vars_part = (struct xpc_vars_part *) next_cl;
|
|
|
- xpc_vars->vars_part_pa = __pa(next_cl);
|
|
|
-
|
|
|
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 */
|
|
|
|
|
|
|
|
|
- /*
|
|
|
- * Initialize the activation related AMO variables.
|
|
|
- */
|
|
|
- xpc_vars->act_amos = xpc_IPI_init(XP_MAX_PARTITIONS);
|
|
|
- for (i = 1; i < XP_NASID_MASK_WORDS; i++) {
|
|
|
- xpc_IPI_init(i + XP_MAX_PARTITIONS);
|
|
|
+ /* 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);
|
|
|
}
|
|
|
- /* export AMO page's physical address to other partitions */
|
|
|
- xpc_vars->amos_page_pa = ia64_tpa((u64) xpc_vars->amos_page);
|
|
|
+
|
|
|
+ /* 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
|
|
@@ -387,6 +408,11 @@ xpc_check_remote_hb(void)
|
|
|
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;
|
|
|
}
|
|
@@ -401,7 +427,7 @@ xpc_check_remote_hb(void)
|
|
|
/* pull the remote_hb cache line */
|
|
|
bres = xp_bte_copy(part->remote_vars_pa,
|
|
|
ia64_tpa((u64) remote_vars),
|
|
|
- XPC_VARS_ALIGNED_SIZE,
|
|
|
+ XPC_RP_VARS_SIZE,
|
|
|
(BTE_NOTIFY | BTE_WACQUIRE), NULL);
|
|
|
if (bres != BTE_SUCCESS) {
|
|
|
XPC_DEACTIVATE_PARTITION(part,
|
|
@@ -417,7 +443,7 @@ xpc_check_remote_hb(void)
|
|
|
|
|
|
if (((remote_vars->heartbeat == part->last_heartbeat) &&
|
|
|
(remote_vars->kdb_status == 0)) ||
|
|
|
- !XPC_HB_ALLOWED(sn_partition_id, remote_vars)) {
|
|
|
+ !xpc_hb_allowed(sn_partition_id, remote_vars)) {
|
|
|
|
|
|
XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat);
|
|
|
continue;
|
|
@@ -429,31 +455,31 @@ xpc_check_remote_hb(void)
|
|
|
|
|
|
|
|
|
/*
|
|
|
- * Get a copy of the remote partition's rsvd page.
|
|
|
+ * 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
|
|
|
- * assumed to be of size XPC_RSVD_PAGE_ALIGNED_SIZE.
|
|
|
+ * 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_rsvd_page_pa)
|
|
|
+ struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa)
|
|
|
{
|
|
|
int bres, i;
|
|
|
|
|
|
|
|
|
/* get the reserved page's physical address */
|
|
|
|
|
|
- *remote_rsvd_page_pa = xpc_get_rsvd_page_pa(nasid, (u64) remote_rp,
|
|
|
- XPC_RSVD_PAGE_ALIGNED_SIZE);
|
|
|
- if (*remote_rsvd_page_pa == 0) {
|
|
|
+ *remote_rp_pa = xpc_get_rsvd_page_pa(nasid);
|
|
|
+ if (*remote_rp_pa == 0) {
|
|
|
return xpcNoRsvdPageAddr;
|
|
|
}
|
|
|
|
|
|
|
|
|
- /* pull over the reserved page structure */
|
|
|
+ /* pull over the reserved page header and part_nasids mask */
|
|
|
|
|
|
- bres = xp_bte_copy(*remote_rsvd_page_pa, ia64_tpa((u64) remote_rp),
|
|
|
- XPC_RSVD_PAGE_ALIGNED_SIZE,
|
|
|
+ bres = xp_bte_copy(*remote_rp_pa, ia64_tpa((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);
|
|
@@ -461,8 +487,11 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids,
|
|
|
|
|
|
|
|
|
if (discovered_nasids != NULL) {
|
|
|
- for (i = 0; i < XP_NASID_MASK_WORDS; i++) {
|
|
|
- discovered_nasids[i] |= remote_rp->part_nasids[i];
|
|
|
+ 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];
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -489,10 +518,10 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids,
|
|
|
|
|
|
|
|
|
/*
|
|
|
- * Get a copy of the remote partition's XPC variables.
|
|
|
+ * 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_VARS_ALIGNED_SIZE.
|
|
|
+ * 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)
|
|
@@ -508,7 +537,7 @@ xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars)
|
|
|
/* pull over the cross partition variables */
|
|
|
|
|
|
bres = xp_bte_copy(remote_vars_pa, ia64_tpa((u64) remote_vars),
|
|
|
- XPC_VARS_ALIGNED_SIZE,
|
|
|
+ XPC_RP_VARS_SIZE,
|
|
|
(BTE_NOTIFY | BTE_WACQUIRE), NULL);
|
|
|
if (bres != BTE_SUCCESS) {
|
|
|
return xpc_map_bte_errors(bres);
|
|
@@ -524,7 +553,56 @@ xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars)
|
|
|
|
|
|
|
|
|
/*
|
|
|
- * Prior code has determine the nasid which generated an IPI. Inspect
|
|
|
+ * 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%016lx\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.
|
|
|
*
|
|
@@ -542,8 +620,12 @@ xpc_identify_act_IRQ_req(int nasid)
|
|
|
{
|
|
|
struct xpc_rsvd_page *remote_rp;
|
|
|
struct xpc_vars *remote_vars;
|
|
|
- u64 remote_rsvd_page_pa;
|
|
|
+ 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;
|
|
@@ -553,7 +635,7 @@ xpc_identify_act_IRQ_req(int nasid)
|
|
|
|
|
|
remote_rp = (struct xpc_rsvd_page *) xpc_remote_copy_buffer;
|
|
|
|
|
|
- ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rsvd_page_pa);
|
|
|
+ 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);
|
|
@@ -561,6 +643,10 @@ 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)) {
|
|
|
+ remote_rp_stamp = remote_rp->stamp;
|
|
|
+ }
|
|
|
partid = remote_rp->partid;
|
|
|
part = &xpc_partitions[partid];
|
|
|
|
|
@@ -586,44 +672,117 @@ 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 (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);
|
|
|
|
|
|
- part->remote_rp_pa = remote_rsvd_page_pa;
|
|
|
- dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n",
|
|
|
- part->remote_rp_pa);
|
|
|
+ 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);
|
|
|
+ }
|
|
|
|
|
|
- part->remote_vars_pa = remote_vars_pa;
|
|
|
- dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n",
|
|
|
- part->remote_vars_pa);
|
|
|
+ xpc_activate_partition(part);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- part->last_heartbeat = remote_vars->heartbeat;
|
|
|
- dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n",
|
|
|
- part->last_heartbeat);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- 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);
|
|
|
+ /*
|
|
|
+ * Other side rebooted and previous XPC didn't support the
|
|
|
+ * disengage request, so we don't need to do anything special.
|
|
|
+ */
|
|
|
|
|
|
- part->remote_act_nasid = remote_vars->act_nasid;
|
|
|
- dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n",
|
|
|
- part->remote_act_nasid);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
|
|
|
- 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);
|
|
|
+ DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version));
|
|
|
|
|
|
- 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);
|
|
|
+ if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) {
|
|
|
+ DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version));
|
|
|
|
|
|
- xpc_activate_partition(part);
|
|
|
+ /*
|
|
|
+ * 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);
|
|
|
|
|
|
- } else if (part->remote_amos_page_pa != remote_vars->amos_page_pa ||
|
|
|
- !XPC_HB_ALLOWED(sn_partition_id, remote_vars)) {
|
|
|
+ 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 (!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);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -643,14 +802,17 @@ xpc_identify_act_IRQ_sender(void)
|
|
|
u64 nasid; /* remote nasid */
|
|
|
int n_IRQs_detected = 0;
|
|
|
AMO_t *act_amos;
|
|
|
- struct xpc_rsvd_page *rp = (struct xpc_rsvd_page *) xpc_rsvd_page;
|
|
|
|
|
|
|
|
|
- act_amos = xpc_vars->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++) {
|
|
|
+ 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) {
|
|
@@ -668,7 +830,7 @@ xpc_identify_act_IRQ_sender(void)
|
|
|
* remote nasid in our reserved pages machine mask.
|
|
|
* This is used in the event of module reload.
|
|
|
*/
|
|
|
- rp->mach_nasids[word] |= nasid_mask;
|
|
|
+ xpc_mach_nasids[word] |= nasid_mask;
|
|
|
|
|
|
|
|
|
/* locate the nasid(s) which sent interrupts */
|
|
@@ -687,6 +849,55 @@ xpc_identify_act_IRQ_sender(void)
|
|
|
}
|
|
|
|
|
|
|
|
|
+/*
|
|
|
+ * 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 (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.
|
|
|
+ */
|
|
|
+
|
|
|
+ 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.
|
|
|
*/
|
|
@@ -721,7 +932,6 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part,
|
|
|
enum xpc_retval reason)
|
|
|
{
|
|
|
unsigned long irq_flags;
|
|
|
- partid_t partid = XPC_PARTID(part);
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&part->act_lock, irq_flags);
|
|
@@ -749,17 +959,27 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part,
|
|
|
|
|
|
spin_unlock_irqrestore(&part->act_lock, irq_flags);
|
|
|
|
|
|
- XPC_DISALLOW_HB(partid, xpc_vars);
|
|
|
+ if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) {
|
|
|
+ xpc_request_partition_disengage(part);
|
|
|
+ xpc_IPI_send_disengage(part);
|
|
|
|
|
|
- dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", partid,
|
|
|
- reason);
|
|
|
+ /* 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_down(part, reason);
|
|
|
+ xpc_partition_going_down(part, reason);
|
|
|
}
|
|
|
|
|
|
|
|
|
/*
|
|
|
- * Mark specified partition as active.
|
|
|
+ * Mark specified partition as inactive.
|
|
|
*/
|
|
|
void
|
|
|
xpc_mark_partition_inactive(struct xpc_partition *part)
|
|
@@ -792,9 +1012,10 @@ xpc_discovery(void)
|
|
|
void *remote_rp_base;
|
|
|
struct xpc_rsvd_page *remote_rp;
|
|
|
struct xpc_vars *remote_vars;
|
|
|
- u64 remote_rsvd_page_pa;
|
|
|
+ u64 remote_rp_pa;
|
|
|
u64 remote_vars_pa;
|
|
|
int region;
|
|
|
+ int region_size;
|
|
|
int max_regions;
|
|
|
int nasid;
|
|
|
struct xpc_rsvd_page *rp;
|
|
@@ -804,7 +1025,8 @@ xpc_discovery(void)
|
|
|
enum xpc_retval ret;
|
|
|
|
|
|
|
|
|
- remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RSVD_PAGE_ALIGNED_SIZE,
|
|
|
+ remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE +
|
|
|
+ xp_nasid_mask_bytes,
|
|
|
GFP_KERNEL, &remote_rp_base);
|
|
|
if (remote_rp == NULL) {
|
|
|
return;
|
|
@@ -812,13 +1034,13 @@ xpc_discovery(void)
|
|
|
remote_vars = (struct xpc_vars *) remote_rp;
|
|
|
|
|
|
|
|
|
- discovered_nasids = kmalloc(sizeof(u64) * XP_NASID_MASK_WORDS,
|
|
|
+ discovered_nasids = kmalloc(sizeof(u64) * xp_nasid_mask_words,
|
|
|
GFP_KERNEL);
|
|
|
if (discovered_nasids == NULL) {
|
|
|
kfree(remote_rp_base);
|
|
|
return;
|
|
|
}
|
|
|
- memset(discovered_nasids, 0, sizeof(u64) * XP_NASID_MASK_WORDS);
|
|
|
+ memset(discovered_nasids, 0, sizeof(u64) * xp_nasid_mask_words);
|
|
|
|
|
|
rp = (struct xpc_rsvd_page *) xpc_rsvd_page;
|
|
|
|
|
@@ -827,11 +1049,19 @@ xpc_discovery(void)
|
|
|
* nodes that can comprise an access protection grouping. The access
|
|
|
* protection is in regards to memory, IOI and IPI.
|
|
|
*/
|
|
|
-//>>> move the next two #defines into either include/asm-ia64/sn/arch.h or
|
|
|
-//>>> include/asm-ia64/sn/addrs.h
|
|
|
-#define SH1_MAX_REGIONS 64
|
|
|
-#define SH2_MAX_REGIONS 256
|
|
|
- max_regions = is_shub2() ? SH2_MAX_REGIONS : SH1_MAX_REGIONS;
|
|
|
+ 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++) {
|
|
|
|
|
@@ -841,8 +1071,8 @@ xpc_discovery(void)
|
|
|
|
|
|
dev_dbg(xpc_part, "searching region %d\n", region);
|
|
|
|
|
|
- for (nasid = (region * sn_region_size * 2);
|
|
|
- nasid < ((region + 1) * sn_region_size * 2);
|
|
|
+ for (nasid = (region * region_size * 2);
|
|
|
+ nasid < ((region + 1) * region_size * 2);
|
|
|
nasid += 2) {
|
|
|
|
|
|
if ((volatile int) xpc_exiting) {
|
|
@@ -852,14 +1082,14 @@ xpc_discovery(void)
|
|
|
dev_dbg(xpc_part, "checking nasid %d\n", nasid);
|
|
|
|
|
|
|
|
|
- if (XPC_NASID_IN_ARRAY(nasid, rp->part_nasids)) {
|
|
|
+ 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, rp->mach_nasids))) {
|
|
|
+ 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);
|
|
@@ -877,7 +1107,7 @@ xpc_discovery(void)
|
|
|
/* pull over the reserved page structure */
|
|
|
|
|
|
ret = xpc_get_remote_rp(nasid, discovered_nasids,
|
|
|
- remote_rp, &remote_rsvd_page_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,
|
|
@@ -948,6 +1178,13 @@ xpc_discovery(void)
|
|
|
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);
|
|
|
}
|
|
|
}
|
|
@@ -974,12 +1211,12 @@ xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask)
|
|
|
return xpcPartitionDown;
|
|
|
}
|
|
|
|
|
|
- part_nasid_pa = part->remote_rp_pa +
|
|
|
- (u64) &((struct xpc_rsvd_page *) 0)->part_nasids;
|
|
|
+ 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, ia64_tpa((u64) nasid_mask),
|
|
|
- L1_CACHE_ALIGN(XP_NASID_MASK_BYTES),
|
|
|
- (BTE_NOTIFY | BTE_WACQUIRE), NULL);
|
|
|
+ xp_nasid_mask_bytes, (BTE_NOTIFY | BTE_WACQUIRE), NULL);
|
|
|
|
|
|
return xpc_map_bte_errors(bte_res);
|
|
|
}
|