/* * Given a nasid, get the physical address of the partition's reserved page * for that nasid. This function returns 0 on any error. */ static unsigned long xpc_get_rsvd_page_pa(int nasid) { enum xp_retval ret; u64 cookie = 0; unsigned long rp_pa = nasid; /* seed with nasid */ size_t len = 0; size_t buf_len = 0; void *buf = buf; void *buf_base = NULL; enum xp_retval (*get_partition_rsvd_page_pa) (void *, u64 *, unsigned long *, size_t *) = xpc_arch_ops.get_partition_rsvd_page_pa; while (1) { /* !!! rp_pa will need to be _gpa on UV. * ??? So do we save it into the architecture specific parts * ??? of the xpc_partition structure? Do we rename this * ??? function or have two versions? Rename rp_pa for UV to * ??? rp_gpa? */ ret = get_partition_rsvd_page_pa(buf, &cookie, &rp_pa, &len); dev_dbg(xpc_part, "SAL returned with ret=%d, cookie=0x%016lx, " "address=0x%016lx, len=0x%016lx\n", ret, (unsigned long)cookie, rp_pa, len); if (ret != xpNeedMoreInfo) break; /* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ if (L1_CACHE_ALIGN(len) > buf_len) { kfree(buf_base); buf_len = L1_CACHE_ALIGN(len); buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL, &buf_base); if (buf_base == NULL) { dev_err(xpc_part, "unable to kmalloc " "len=0x%016lx\n", buf_len); ret = xpNoMemory; break; } } ret = xp_remote_memcpy(xp_pa(buf), rp_pa, buf_len); if (ret != xpSuccess) { dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); break; } } kfree(buf_base); if (ret != xpSuccess) rp_pa = 0; dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa); return rp_pa; }
static enum xp_retval xpc_cache_remote_gru_mq_desc_uv(struct gru_message_queue_desc *gru_mq_desc, unsigned long gru_mq_desc_gpa) { enum xp_retval ret; ret = xp_remote_memcpy(uv_gpa(gru_mq_desc), gru_mq_desc_gpa, sizeof(struct gru_message_queue_desc)); if (ret == xpSuccess) gru_mq_desc->mq = NULL; return ret; }
/* * 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. */ enum xp_retval xpc_get_remote_rp(int nasid, unsigned long *discovered_nasids, struct xpc_rsvd_page *remote_rp, unsigned long *remote_rp_pa) { int l; enum xp_retval ret; /* get the reserved page's physical address */ *remote_rp_pa = xpc_get_rsvd_page_pa(nasid); if (*remote_rp_pa == 0) return xpNoRsvdPageAddr; /* pull over the reserved page header and part_nasids mask */ ret = xp_remote_memcpy(xp_pa(remote_rp), *remote_rp_pa, XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes); if (ret != xpSuccess) return ret; if (discovered_nasids != NULL) { unsigned long *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); for (l = 0; l < xpc_nasid_mask_nlongs; l++) discovered_nasids[l] |= remote_part_nasids[l]; } /* zero timestamp indicates the reserved page has not been setup */ if (remote_rp->ts_jiffies == 0) return xpRsvdPageNotSet; if (XPC_VERSION_MAJOR(remote_rp->version) != XPC_VERSION_MAJOR(XPC_RP_VERSION)) { return xpBadVersion; } /* check that both remote and local partids are valid for each side */ if (remote_rp->SAL_partid < 0 || remote_rp->SAL_partid >= xp_max_npartitions || remote_rp->max_npartitions <= xp_partition_id) { return xpInvalidPartid; } if (remote_rp->SAL_partid == xp_partition_id) return xpLocalPartid; return xpSuccess; }
/* * Given a partid, get the nasids owned by that partition from the * remote partition's reserved page. */ enum xp_retval xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) { struct xpc_partition *part; unsigned long part_nasid_pa; part = &xpc_partitions[partid]; if (part->remote_rp_pa == 0) return xpPartitionDown; memset(nasid_mask, 0, xpc_nasid_mask_nbytes); part_nasid_pa = (unsigned long)XPC_RP_PART_NASIDS(part->remote_rp_pa); return xp_remote_memcpy(xp_pa(nasid_mask), part_nasid_pa, xpc_nasid_mask_nbytes); }
static enum xp_retval xpc_get_remote_heartbeat_uv(struct xpc_partition *part) { struct xpc_partition_uv *part_uv = &part->sn.uv; enum xp_retval ret; ret = xp_remote_memcpy(uv_gpa(&part_uv->cached_heartbeat), part_uv->heartbeat_gpa, sizeof(struct xpc_heartbeat_uv)); if (ret != xpSuccess) return ret; if (part_uv->cached_heartbeat.value == part->last_heartbeat && !part_uv->cached_heartbeat.offline) { ret = xpNoHeartbeat; } else { part->last_heartbeat = part_uv->cached_heartbeat.value; } return ret; }