⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xpc_partition.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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-2006 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 <linux/kernel.h>#include <linux/sysctl.h>#include <linux/cache.h>#include <linux/mmzone.h>#include <linux/nodemask.h>#include <asm/uncached.h>#include <asm/sn/bte.h>#include <asm/sn/intr.h>#include <asm/sn/sn_sal.h>#include <asm/sn/nodepda.h>#include <asm/sn/addrs.h>#include <asm/sn/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 u64xpc_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). */voidxpc_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). */voidxpc_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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -