/* * 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; unsigned long remote_rp_pa; int region; int region_size; int max_regions; int nasid; struct xpc_rsvd_page *rp; unsigned long *discovered_nasids; enum xp_retval ret; remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes, GFP_KERNEL, &remote_rp_base); if (remote_rp == NULL) return; discovered_nasids = kzalloc(sizeof(long) * xpc_nasid_mask_nlongs, 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. */ region_size = xp_region_size; if (is_uv()) max_regions = 256; else { max_regions = 64; 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 (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 (xpc_exiting) break; dev_dbg(xpc_part, "checking nasid %d\n", nasid); if (test_bit(nasid / 2, xpc_part_nasids)) { dev_dbg(xpc_part, "PROM indicates Nasid %d is " "part of the local partition; skipping " "region\n", nasid); break; } if (!(test_bit(nasid / 2, xpc_mach_nasids))) { dev_dbg(xpc_part, "PROM indicates Nasid %d was " "not on Numa-Link network at reset\n", nasid); continue; } if (test_bit(nasid / 2, discovered_nasids)) { dev_dbg(xpc_part, "Nasid %d is part of a " "partition which was previously " "discovered\n", nasid); continue; } /* pull over the rsvd page header & part_nasids mask */ ret = xpc_get_remote_rp(nasid, discovered_nasids, remote_rp, &remote_rp_pa); if (ret != xpSuccess) { dev_dbg(xpc_part, "unable to get reserved page " "from nasid %d, reason=%d\n", nasid, ret); if (ret == xpLocalPartid) break; continue; } xpc_arch_ops.request_partition_activation(remote_rp, remote_rp_pa, nasid); } } kfree(discovered_nasids); kfree(remote_rp_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 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 (is_shub()) len = L1_CACHE_ALIGN(len); if (len > buf_len) { if (buf_base != NULL) 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, 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; }