18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * (C) Copyright 2020 Hewlett Packard Enterprise Development LP 78c2ecf20Sopenharmony_ci * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * Cross Partition Communication (XPC) partition support. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This is the part of XPC that detects the presence/absence of 148c2ecf20Sopenharmony_ci * other partitions. It provides a heartbeat and monitors the 158c2ecf20Sopenharmony_ci * heartbeats of other partitions. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/device.h> 208c2ecf20Sopenharmony_ci#include <linux/hardirq.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include "xpc.h" 238c2ecf20Sopenharmony_ci#include <asm/uv/uv_hub.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* XPC is exiting flag */ 268c2ecf20Sopenharmony_ciint xpc_exiting; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* this partition's reserved page pointers */ 298c2ecf20Sopenharmony_cistruct xpc_rsvd_page *xpc_rsvd_page; 308c2ecf20Sopenharmony_cistatic unsigned long *xpc_part_nasids; 318c2ecf20Sopenharmony_ciunsigned long *xpc_mach_nasids; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int xpc_nasid_mask_nbytes; /* #of bytes in nasid mask */ 348c2ecf20Sopenharmony_ciint xpc_nasid_mask_nlongs; /* #of longs in nasid mask */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct xpc_partition *xpc_partitions; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * Guarantee that the kmalloc'd memory is cacheline aligned. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_civoid * 428c2ecf20Sopenharmony_cixpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci /* see if kmalloc will give us cachline aligned memory by default */ 458c2ecf20Sopenharmony_ci *base = kmalloc(size, flags); 468c2ecf20Sopenharmony_ci if (*base == NULL) 478c2ecf20Sopenharmony_ci return NULL; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) 508c2ecf20Sopenharmony_ci return *base; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci kfree(*base); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* nope, we'll have to do it ourselves */ 558c2ecf20Sopenharmony_ci *base = kmalloc(size + L1_CACHE_BYTES, flags); 568c2ecf20Sopenharmony_ci if (*base == NULL) 578c2ecf20Sopenharmony_ci return NULL; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return (void *)L1_CACHE_ALIGN((u64)*base); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* 638c2ecf20Sopenharmony_ci * Given a nasid, get the physical address of the partition's reserved page 648c2ecf20Sopenharmony_ci * for that nasid. This function returns 0 on any error. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_cistatic unsigned long 678c2ecf20Sopenharmony_cixpc_get_rsvd_page_pa(int nasid) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci enum xp_retval ret; 708c2ecf20Sopenharmony_ci u64 cookie = 0; 718c2ecf20Sopenharmony_ci unsigned long rp_pa = nasid; /* seed with nasid */ 728c2ecf20Sopenharmony_ci size_t len = 0; 738c2ecf20Sopenharmony_ci size_t buf_len = 0; 748c2ecf20Sopenharmony_ci void *buf = NULL; 758c2ecf20Sopenharmony_ci void *buf_base = NULL; 768c2ecf20Sopenharmony_ci enum xp_retval (*get_partition_rsvd_page_pa) 778c2ecf20Sopenharmony_ci (void *, u64 *, unsigned long *, size_t *) = 788c2ecf20Sopenharmony_ci xpc_arch_ops.get_partition_rsvd_page_pa; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci while (1) { 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* !!! rp_pa will need to be _gpa on UV. 838c2ecf20Sopenharmony_ci * ??? So do we save it into the architecture specific parts 848c2ecf20Sopenharmony_ci * ??? of the xpc_partition structure? Do we rename this 858c2ecf20Sopenharmony_ci * ??? function or have two versions? Rename rp_pa for UV to 868c2ecf20Sopenharmony_ci * ??? rp_gpa? 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ci ret = get_partition_rsvd_page_pa(buf, &cookie, &rp_pa, &len); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "SAL returned with ret=%d, cookie=0x%016lx, " 918c2ecf20Sopenharmony_ci "address=0x%016lx, len=0x%016lx\n", ret, 928c2ecf20Sopenharmony_ci (unsigned long)cookie, rp_pa, len); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (ret != xpNeedMoreInfo) 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (len > buf_len) { 988c2ecf20Sopenharmony_ci kfree(buf_base); 998c2ecf20Sopenharmony_ci buf_len = L1_CACHE_ALIGN(len); 1008c2ecf20Sopenharmony_ci buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL, 1018c2ecf20Sopenharmony_ci &buf_base); 1028c2ecf20Sopenharmony_ci if (buf_base == NULL) { 1038c2ecf20Sopenharmony_ci dev_err(xpc_part, "unable to kmalloc " 1048c2ecf20Sopenharmony_ci "len=0x%016lx\n", buf_len); 1058c2ecf20Sopenharmony_ci ret = xpNoMemory; 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci ret = xp_remote_memcpy(xp_pa(buf), rp_pa, len); 1118c2ecf20Sopenharmony_ci if (ret != xpSuccess) { 1128c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci kfree(buf_base); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (ret != xpSuccess) 1208c2ecf20Sopenharmony_ci rp_pa = 0; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa); 1238c2ecf20Sopenharmony_ci return rp_pa; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* 1278c2ecf20Sopenharmony_ci * Fill the partition reserved page with the information needed by 1288c2ecf20Sopenharmony_ci * other partitions to discover we are alive and establish initial 1298c2ecf20Sopenharmony_ci * communications. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ciint 1328c2ecf20Sopenharmony_cixpc_setup_rsvd_page(void) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci int ret; 1358c2ecf20Sopenharmony_ci struct xpc_rsvd_page *rp; 1368c2ecf20Sopenharmony_ci unsigned long rp_pa; 1378c2ecf20Sopenharmony_ci unsigned long new_ts_jiffies; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* get the local reserved page's address */ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci preempt_disable(); 1428c2ecf20Sopenharmony_ci rp_pa = xpc_get_rsvd_page_pa(xp_cpu_to_nasid(smp_processor_id())); 1438c2ecf20Sopenharmony_ci preempt_enable(); 1448c2ecf20Sopenharmony_ci if (rp_pa == 0) { 1458c2ecf20Sopenharmony_ci dev_err(xpc_part, "SAL failed to locate the reserved page\n"); 1468c2ecf20Sopenharmony_ci return -ESRCH; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci rp = (struct xpc_rsvd_page *)__va(xp_socket_pa(rp_pa)); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (rp->SAL_version < 3) { 1518c2ecf20Sopenharmony_ci /* SAL_versions < 3 had a SAL_partid defined as a u8 */ 1528c2ecf20Sopenharmony_ci rp->SAL_partid &= 0xff; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci BUG_ON(rp->SAL_partid != xp_partition_id); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (rp->SAL_partid < 0 || rp->SAL_partid >= xp_max_npartitions) { 1578c2ecf20Sopenharmony_ci dev_err(xpc_part, "the reserved page's partid of %d is outside " 1588c2ecf20Sopenharmony_ci "supported range (< 0 || >= %d)\n", rp->SAL_partid, 1598c2ecf20Sopenharmony_ci xp_max_npartitions); 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci rp->version = XPC_RP_VERSION; 1648c2ecf20Sopenharmony_ci rp->max_npartitions = xp_max_npartitions; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* establish the actual sizes of the nasid masks */ 1678c2ecf20Sopenharmony_ci if (rp->SAL_version == 1) { 1688c2ecf20Sopenharmony_ci /* SAL_version 1 didn't set the nasids_size field */ 1698c2ecf20Sopenharmony_ci rp->SAL_nasids_size = 128; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci xpc_nasid_mask_nbytes = rp->SAL_nasids_size; 1728c2ecf20Sopenharmony_ci xpc_nasid_mask_nlongs = BITS_TO_LONGS(rp->SAL_nasids_size * 1738c2ecf20Sopenharmony_ci BITS_PER_BYTE); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* setup the pointers to the various items in the reserved page */ 1768c2ecf20Sopenharmony_ci xpc_part_nasids = XPC_RP_PART_NASIDS(rp); 1778c2ecf20Sopenharmony_ci xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci ret = xpc_arch_ops.setup_rsvd_page(rp); 1808c2ecf20Sopenharmony_ci if (ret != 0) 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * Set timestamp of when reserved page was setup by XPC. 1858c2ecf20Sopenharmony_ci * This signifies to the remote partition that our reserved 1868c2ecf20Sopenharmony_ci * page is initialized. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci new_ts_jiffies = jiffies; 1898c2ecf20Sopenharmony_ci if (new_ts_jiffies == 0 || new_ts_jiffies == rp->ts_jiffies) 1908c2ecf20Sopenharmony_ci new_ts_jiffies++; 1918c2ecf20Sopenharmony_ci rp->ts_jiffies = new_ts_jiffies; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci xpc_rsvd_page = rp; 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_civoid 1988c2ecf20Sopenharmony_cixpc_teardown_rsvd_page(void) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci /* a zero timestamp indicates our rsvd page is not initialized */ 2018c2ecf20Sopenharmony_ci xpc_rsvd_page->ts_jiffies = 0; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* 2058c2ecf20Sopenharmony_ci * Get a copy of a portion of the remote partition's rsvd page. 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * remote_rp points to a buffer that is cacheline aligned for BTE copies and 2088c2ecf20Sopenharmony_ci * is large enough to contain a copy of their reserved page header and 2098c2ecf20Sopenharmony_ci * part_nasids mask. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_cienum xp_retval 2128c2ecf20Sopenharmony_cixpc_get_remote_rp(int nasid, unsigned long *discovered_nasids, 2138c2ecf20Sopenharmony_ci struct xpc_rsvd_page *remote_rp, unsigned long *remote_rp_pa) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci int l; 2168c2ecf20Sopenharmony_ci enum xp_retval ret; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* get the reserved page's physical address */ 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci *remote_rp_pa = xpc_get_rsvd_page_pa(nasid); 2218c2ecf20Sopenharmony_ci if (*remote_rp_pa == 0) 2228c2ecf20Sopenharmony_ci return xpNoRsvdPageAddr; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* pull over the reserved page header and part_nasids mask */ 2258c2ecf20Sopenharmony_ci ret = xp_remote_memcpy(xp_pa(remote_rp), *remote_rp_pa, 2268c2ecf20Sopenharmony_ci XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes); 2278c2ecf20Sopenharmony_ci if (ret != xpSuccess) 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (discovered_nasids != NULL) { 2318c2ecf20Sopenharmony_ci unsigned long *remote_part_nasids = 2328c2ecf20Sopenharmony_ci XPC_RP_PART_NASIDS(remote_rp); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci for (l = 0; l < xpc_nasid_mask_nlongs; l++) 2358c2ecf20Sopenharmony_ci discovered_nasids[l] |= remote_part_nasids[l]; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* zero timestamp indicates the reserved page has not been setup */ 2398c2ecf20Sopenharmony_ci if (remote_rp->ts_jiffies == 0) 2408c2ecf20Sopenharmony_ci return xpRsvdPageNotSet; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (XPC_VERSION_MAJOR(remote_rp->version) != 2438c2ecf20Sopenharmony_ci XPC_VERSION_MAJOR(XPC_RP_VERSION)) { 2448c2ecf20Sopenharmony_ci return xpBadVersion; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* check that both remote and local partids are valid for each side */ 2488c2ecf20Sopenharmony_ci if (remote_rp->SAL_partid < 0 || 2498c2ecf20Sopenharmony_ci remote_rp->SAL_partid >= xp_max_npartitions || 2508c2ecf20Sopenharmony_ci remote_rp->max_npartitions <= xp_partition_id) { 2518c2ecf20Sopenharmony_ci return xpInvalidPartid; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (remote_rp->SAL_partid == xp_partition_id) 2558c2ecf20Sopenharmony_ci return xpLocalPartid; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return xpSuccess; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/* 2618c2ecf20Sopenharmony_ci * See if the other side has responded to a partition deactivate request 2628c2ecf20Sopenharmony_ci * from us. Though we requested the remote partition to deactivate with regard 2638c2ecf20Sopenharmony_ci * to us, we really only need to wait for the other side to disengage from us. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_ciint 2668c2ecf20Sopenharmony_cixpc_partition_disengaged(struct xpc_partition *part) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci short partid = XPC_PARTID(part); 2698c2ecf20Sopenharmony_ci int disengaged; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci disengaged = !xpc_arch_ops.partition_engaged(partid); 2728c2ecf20Sopenharmony_ci if (part->disengage_timeout) { 2738c2ecf20Sopenharmony_ci if (!disengaged) { 2748c2ecf20Sopenharmony_ci if (time_is_after_jiffies(part->disengage_timeout)) { 2758c2ecf20Sopenharmony_ci /* timelimit hasn't been reached yet */ 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* 2808c2ecf20Sopenharmony_ci * Other side hasn't responded to our deactivate 2818c2ecf20Sopenharmony_ci * request in a timely fashion, so assume it's dead. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci dev_info(xpc_part, "deactivate request to remote " 2858c2ecf20Sopenharmony_ci "partition %d timed out\n", partid); 2868c2ecf20Sopenharmony_ci xpc_disengage_timedout = 1; 2878c2ecf20Sopenharmony_ci xpc_arch_ops.assume_partition_disengaged(partid); 2888c2ecf20Sopenharmony_ci disengaged = 1; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci part->disengage_timeout = 0; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* cancel the timer function, provided it's not us */ 2938c2ecf20Sopenharmony_ci if (!in_interrupt()) 2948c2ecf20Sopenharmony_ci del_singleshot_timer_sync(&part->disengage_timer); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci DBUG_ON(part->act_state != XPC_P_AS_DEACTIVATING && 2978c2ecf20Sopenharmony_ci part->act_state != XPC_P_AS_INACTIVE); 2988c2ecf20Sopenharmony_ci if (part->act_state != XPC_P_AS_INACTIVE) 2998c2ecf20Sopenharmony_ci xpc_wakeup_channel_mgr(part); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci xpc_arch_ops.cancel_partition_deactivation_request(part); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci return disengaged; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* 3078c2ecf20Sopenharmony_ci * Mark specified partition as active. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_cienum xp_retval 3108c2ecf20Sopenharmony_cixpc_mark_partition_active(struct xpc_partition *part) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci unsigned long irq_flags; 3138c2ecf20Sopenharmony_ci enum xp_retval ret; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part)); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci spin_lock_irqsave(&part->act_lock, irq_flags); 3188c2ecf20Sopenharmony_ci if (part->act_state == XPC_P_AS_ACTIVATING) { 3198c2ecf20Sopenharmony_ci part->act_state = XPC_P_AS_ACTIVE; 3208c2ecf20Sopenharmony_ci ret = xpSuccess; 3218c2ecf20Sopenharmony_ci } else { 3228c2ecf20Sopenharmony_ci DBUG_ON(part->reason == xpSuccess); 3238c2ecf20Sopenharmony_ci ret = part->reason; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&part->act_lock, irq_flags); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return ret; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/* 3318c2ecf20Sopenharmony_ci * Start the process of deactivating the specified partition. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_civoid 3348c2ecf20Sopenharmony_cixpc_deactivate_partition(const int line, struct xpc_partition *part, 3358c2ecf20Sopenharmony_ci enum xp_retval reason) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci unsigned long irq_flags; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci spin_lock_irqsave(&part->act_lock, irq_flags); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (part->act_state == XPC_P_AS_INACTIVE) { 3428c2ecf20Sopenharmony_ci XPC_SET_REASON(part, reason, line); 3438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&part->act_lock, irq_flags); 3448c2ecf20Sopenharmony_ci if (reason == xpReactivating) { 3458c2ecf20Sopenharmony_ci /* we interrupt ourselves to reactivate partition */ 3468c2ecf20Sopenharmony_ci xpc_arch_ops.request_partition_reactivation(part); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci return; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci if (part->act_state == XPC_P_AS_DEACTIVATING) { 3518c2ecf20Sopenharmony_ci if ((part->reason == xpUnloading && reason != xpUnloading) || 3528c2ecf20Sopenharmony_ci reason == xpReactivating) { 3538c2ecf20Sopenharmony_ci XPC_SET_REASON(part, reason, line); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&part->act_lock, irq_flags); 3568c2ecf20Sopenharmony_ci return; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci part->act_state = XPC_P_AS_DEACTIVATING; 3608c2ecf20Sopenharmony_ci XPC_SET_REASON(part, reason, line); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&part->act_lock, irq_flags); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* ask remote partition to deactivate with regard to us */ 3658c2ecf20Sopenharmony_ci xpc_arch_ops.request_partition_deactivation(part); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* set a timelimit on the disengage phase of the deactivation request */ 3688c2ecf20Sopenharmony_ci part->disengage_timeout = jiffies + (xpc_disengage_timelimit * HZ); 3698c2ecf20Sopenharmony_ci part->disengage_timer.expires = part->disengage_timeout; 3708c2ecf20Sopenharmony_ci add_timer(&part->disengage_timer); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", 3738c2ecf20Sopenharmony_ci XPC_PARTID(part), reason); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci xpc_partition_going_down(part, reason); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci/* 3798c2ecf20Sopenharmony_ci * Mark specified partition as inactive. 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_civoid 3828c2ecf20Sopenharmony_cixpc_mark_partition_inactive(struct xpc_partition *part) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci unsigned long irq_flags; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "setting partition %d to INACTIVE\n", 3878c2ecf20Sopenharmony_ci XPC_PARTID(part)); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci spin_lock_irqsave(&part->act_lock, irq_flags); 3908c2ecf20Sopenharmony_ci part->act_state = XPC_P_AS_INACTIVE; 3918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&part->act_lock, irq_flags); 3928c2ecf20Sopenharmony_ci part->remote_rp_pa = 0; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci/* 3968c2ecf20Sopenharmony_ci * SAL has provided a partition and machine mask. The partition mask 3978c2ecf20Sopenharmony_ci * contains a bit for each even nasid in our partition. The machine 3988c2ecf20Sopenharmony_ci * mask contains a bit for each even nasid in the entire machine. 3998c2ecf20Sopenharmony_ci * 4008c2ecf20Sopenharmony_ci * Using those two bit arrays, we can determine which nasids are 4018c2ecf20Sopenharmony_ci * known in the machine. Each should also have a reserved page 4028c2ecf20Sopenharmony_ci * initialized if they are available for partitioning. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_civoid 4058c2ecf20Sopenharmony_cixpc_discovery(void) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci void *remote_rp_base; 4088c2ecf20Sopenharmony_ci struct xpc_rsvd_page *remote_rp; 4098c2ecf20Sopenharmony_ci unsigned long remote_rp_pa; 4108c2ecf20Sopenharmony_ci int region; 4118c2ecf20Sopenharmony_ci int region_size; 4128c2ecf20Sopenharmony_ci int max_regions; 4138c2ecf20Sopenharmony_ci int nasid; 4148c2ecf20Sopenharmony_ci unsigned long *discovered_nasids; 4158c2ecf20Sopenharmony_ci enum xp_retval ret; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + 4188c2ecf20Sopenharmony_ci xpc_nasid_mask_nbytes, 4198c2ecf20Sopenharmony_ci GFP_KERNEL, &remote_rp_base); 4208c2ecf20Sopenharmony_ci if (remote_rp == NULL) 4218c2ecf20Sopenharmony_ci return; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci discovered_nasids = kcalloc(xpc_nasid_mask_nlongs, sizeof(long), 4248c2ecf20Sopenharmony_ci GFP_KERNEL); 4258c2ecf20Sopenharmony_ci if (discovered_nasids == NULL) { 4268c2ecf20Sopenharmony_ci kfree(remote_rp_base); 4278c2ecf20Sopenharmony_ci return; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* 4318c2ecf20Sopenharmony_ci * The term 'region' in this context refers to the minimum number of 4328c2ecf20Sopenharmony_ci * nodes that can comprise an access protection grouping. The access 4338c2ecf20Sopenharmony_ci * protection is in regards to memory, IOI and IPI. 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_ci region_size = xp_region_size; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (is_uv_system()) 4388c2ecf20Sopenharmony_ci max_regions = 256; 4398c2ecf20Sopenharmony_ci else { 4408c2ecf20Sopenharmony_ci max_regions = 64; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci switch (region_size) { 4438c2ecf20Sopenharmony_ci case 128: 4448c2ecf20Sopenharmony_ci max_regions *= 2; 4458c2ecf20Sopenharmony_ci fallthrough; 4468c2ecf20Sopenharmony_ci case 64: 4478c2ecf20Sopenharmony_ci max_regions *= 2; 4488c2ecf20Sopenharmony_ci fallthrough; 4498c2ecf20Sopenharmony_ci case 32: 4508c2ecf20Sopenharmony_ci max_regions *= 2; 4518c2ecf20Sopenharmony_ci region_size = 16; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci for (region = 0; region < max_regions; region++) { 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (xpc_exiting) 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "searching region %d\n", region); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci for (nasid = (region * region_size * 2); 4638c2ecf20Sopenharmony_ci nasid < ((region + 1) * region_size * 2); nasid += 2) { 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (xpc_exiting) 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "checking nasid %d\n", nasid); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (test_bit(nasid / 2, xpc_part_nasids)) { 4718c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "PROM indicates Nasid %d is " 4728c2ecf20Sopenharmony_ci "part of the local partition; skipping " 4738c2ecf20Sopenharmony_ci "region\n", nasid); 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!(test_bit(nasid / 2, xpc_mach_nasids))) { 4788c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "PROM indicates Nasid %d was " 4798c2ecf20Sopenharmony_ci "not on Numa-Link network at reset\n", 4808c2ecf20Sopenharmony_ci nasid); 4818c2ecf20Sopenharmony_ci continue; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (test_bit(nasid / 2, discovered_nasids)) { 4858c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "Nasid %d is part of a " 4868c2ecf20Sopenharmony_ci "partition which was previously " 4878c2ecf20Sopenharmony_ci "discovered\n", nasid); 4888c2ecf20Sopenharmony_ci continue; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* pull over the rsvd page header & part_nasids mask */ 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci ret = xpc_get_remote_rp(nasid, discovered_nasids, 4948c2ecf20Sopenharmony_ci remote_rp, &remote_rp_pa); 4958c2ecf20Sopenharmony_ci if (ret != xpSuccess) { 4968c2ecf20Sopenharmony_ci dev_dbg(xpc_part, "unable to get reserved page " 4978c2ecf20Sopenharmony_ci "from nasid %d, reason=%d\n", nasid, 4988c2ecf20Sopenharmony_ci ret); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (ret == xpLocalPartid) 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci continue; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci xpc_arch_ops.request_partition_activation(remote_rp, 5078c2ecf20Sopenharmony_ci remote_rp_pa, nasid); 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci kfree(discovered_nasids); 5128c2ecf20Sopenharmony_ci kfree(remote_rp_base); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/* 5168c2ecf20Sopenharmony_ci * Given a partid, get the nasids owned by that partition from the 5178c2ecf20Sopenharmony_ci * remote partition's reserved page. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_cienum xp_retval 5208c2ecf20Sopenharmony_cixpc_initiate_partid_to_nasids(short partid, void *nasid_mask) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct xpc_partition *part; 5238c2ecf20Sopenharmony_ci unsigned long part_nasid_pa; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci part = &xpc_partitions[partid]; 5268c2ecf20Sopenharmony_ci if (part->remote_rp_pa == 0) 5278c2ecf20Sopenharmony_ci return xpPartitionDown; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci memset(nasid_mask, 0, xpc_nasid_mask_nbytes); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci part_nasid_pa = (unsigned long)XPC_RP_PART_NASIDS(part->remote_rp_pa); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return xp_remote_memcpy(xp_pa(nasid_mask), part_nasid_pa, 5348c2ecf20Sopenharmony_ci xpc_nasid_mask_nbytes); 5358c2ecf20Sopenharmony_ci} 536