Register valid PMEM regions probed via NFIT to Xen hypervisor. No frametable and M2P table are created for those PMEM regions at this stage.
Signed-off-by: Haozhong Zhang <haozhong.zh...@intel.com> --- Cc: Andrew Cooper <andrew.coop...@citrix.com> Cc: Jan Beulich <jbeul...@suse.com> --- xen/common/Makefile | 1 + xen/common/pmem.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ xen/drivers/acpi/nfit.c | 12 ++++- xen/include/xen/pmem.h | 28 +++++++++++ 4 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 xen/common/pmem.c create mode 100644 xen/include/xen/pmem.h diff --git a/xen/common/Makefile b/xen/common/Makefile index 39e2614546..46f9d1f57f 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -29,6 +29,7 @@ obj-y += notifier.o obj-y += page_alloc.o obj-$(CONFIG_HAS_PDX) += pdx.o obj-$(CONFIG_PERF_COUNTERS) += perfc.o +obj-${CONFIG_NVDIMM_PMEM} += pmem.o obj-y += preempt.o obj-y += random.o obj-y += rangeset.o diff --git a/xen/common/pmem.c b/xen/common/pmem.c new file mode 100644 index 0000000000..49648222a6 --- /dev/null +++ b/xen/common/pmem.c @@ -0,0 +1,130 @@ +/* + * xen/common/pmem.c + * + * Copyright (C) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms and conditions of the GNU General Public + * License, version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; If not, see <http://www.gnu.org/licenses/>. + */ + +#include <xen/errno.h> +#include <xen/list.h> +#include <xen/pmem.h> + +/* + * All PMEM regions presenting in NFIT SPA range structures are linked + * in this list. + */ +static LIST_HEAD(pmem_raw_regions); +static unsigned int nr_raw_regions; + +struct pmem { + struct list_head link; /* link to one of PMEM region list */ + unsigned long smfn; /* start MFN of the PMEM region */ + unsigned long emfn; /* end MFN of the PMEM region */ + + union { + struct { + unsigned int pxm; /* proximity domain of the PMEM region */ + } raw; + } u; +}; + +static bool check_overlap(unsigned long smfn1, unsigned long emfn1, + unsigned long smfn2, unsigned long emfn2) +{ + return (smfn1 >= smfn2 && smfn1 < emfn2) || + (emfn1 > smfn2 && emfn1 <= emfn2); +} + +/** + * Add a PMEM region to a list. All PMEM regions in the list are + * sorted in the ascending order of the start address. A PMEM region, + * whose range is overlapped with anyone in the list, cannot be added + * to the list. + * + * Parameters: + * list: the list to which a new PMEM region will be added + * smfn, emfn: the range of the new PMEM region + * entry: return the new entry added to the list + * + * Return: + * On success, return 0 and the new entry added to the list is + * returned via @entry. Otherwise, return an error number and the + * value of @entry is undefined. + */ +static int pmem_list_add(struct list_head *list, + unsigned long smfn, unsigned long emfn, + struct pmem **entry) +{ + struct list_head *cur; + struct pmem *new_pmem; + int rc = 0; + + list_for_each_prev(cur, list) + { + struct pmem *cur_pmem = list_entry(cur, struct pmem, link); + unsigned long cur_smfn = cur_pmem->smfn; + unsigned long cur_emfn = cur_pmem->emfn; + + if ( check_overlap(smfn, emfn, cur_smfn, cur_emfn) ) + { + rc = -EEXIST; + goto out; + } + + if ( cur_smfn < smfn ) + break; + } + + new_pmem = xzalloc(struct pmem); + if ( !new_pmem ) + { + rc = -ENOMEM; + goto out; + } + new_pmem->smfn = smfn; + new_pmem->emfn = emfn; + list_add(&new_pmem->link, cur); + + out: + if ( !rc && entry ) + *entry = new_pmem; + + return rc; +} + +/** + * Register a pmem region to Xen. + * + * Parameters: + * smfn, emfn: start and end MFNs of the pmem region + * pxm: the proximity domain of the pmem region + * + * Return: + * On success, return 0. Otherwise, an error number is returned. + */ +int pmem_register(unsigned long smfn, unsigned long emfn, unsigned int pxm) +{ + int rc; + struct pmem *pmem; + + if ( smfn >= emfn ) + return -EINVAL; + + rc = pmem_list_add(&pmem_raw_regions, smfn, emfn, &pmem); + if ( !rc ) + pmem->u.raw.pxm = pxm; + nr_raw_regions++; + + return rc; +} diff --git a/xen/drivers/acpi/nfit.c b/xen/drivers/acpi/nfit.c index b88a587b8d..68750c2edc 100644 --- a/xen/drivers/acpi/nfit.c +++ b/xen/drivers/acpi/nfit.c @@ -20,6 +20,7 @@ #include <xen/init.h> #include <xen/mm.h> #include <xen/pfn.h> +#include <xen/pmem.h> /* * GUID of a byte addressable persistent memory region @@ -148,6 +149,7 @@ static void __init acpi_nfit_register_pmem(struct acpi_nfit_desc *desc) struct nfit_memdev_desc *memdev_desc; struct acpi_nfit_system_address *spa; unsigned long smfn, emfn; + int rc; list_for_each_entry(memdev_desc, &desc->memdev_list, link) { @@ -165,7 +167,15 @@ static void __init acpi_nfit_register_pmem(struct acpi_nfit_desc *desc) continue; smfn = paddr_to_pfn(spa->address); emfn = paddr_to_pfn(spa->address + spa->length); - printk(XENLOG_INFO "NFIT: PMEM MFNs 0x%lx - 0x%lx\n", smfn, emfn); + rc = pmem_register(smfn, emfn, spa->proximity_domain); + if ( !rc ) + printk(XENLOG_INFO + "NFIT: PMEM MFNs 0x%lx - 0x%lx on PXM %u registered\n", + smfn, emfn, spa->proximity_domain); + else + printk(XENLOG_ERR + "NFIT: failed to register PMEM MFNs 0x%lx - 0x%lx on PXM %u, err %d\n", + smfn, emfn, spa->proximity_domain, rc); } } diff --git a/xen/include/xen/pmem.h b/xen/include/xen/pmem.h new file mode 100644 index 0000000000..41cb9bb04f --- /dev/null +++ b/xen/include/xen/pmem.h @@ -0,0 +1,28 @@ +/* + * xen/include/xen/pmem.h + * + * Copyright (C) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms and conditions of the GNU General Public + * License, version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __XEN_PMEM_H__ +#define __XEN_PMEM_H__ +#ifdef CONFIG_NVDIMM_PMEM + +#include <xen/types.h> + +int pmem_register(unsigned long smfn, unsigned long emfn, unsigned int pxm); + +#endif /* CONFIG_NVDIMM_PMEM */ +#endif /* __XEN_PMEM_H__ */ -- 2.14.1 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel