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: George Dunlap <george.dun...@eu.citrix.com> Cc: Ian Jackson <ian.jack...@eu.citrix.com> Cc: Jan Beulich <jbeul...@suse.com> Cc: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> Cc: Stefano Stabellini <sstabell...@kernel.org> Cc: Tim Deegan <t...@xen.org> Cc: Wei Liu <wei.l...@citrix.com> Changes in v4: * Simplify return paths of pmem_list_add(). --- xen/common/Makefile | 1 + xen/common/pmem.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ xen/drivers/acpi/nfit.c | 12 ++++- xen/include/xen/pmem.h | 28 +++++++++++ 4 files changed, 162 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 66cc2c8995..57fa4601b8 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..aa0a1d166d --- /dev/null +++ b/xen/common/pmem.c @@ -0,0 +1,122 @@ +/* + * 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; + + 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) ) + return -EEXIST; + + if ( cur_smfn < smfn ) + break; + } + + new_pmem = xzalloc(struct pmem); + if ( !new_pmem ) + return -ENOMEM; + + new_pmem->smfn = smfn; + new_pmem->emfn = emfn; + list_add(&new_pmem->link, cur); + if ( entry ) + *entry = new_pmem; + + return 0; +} + +/** + * 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 0a44983aad..6f85d4d911 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 @@ -153,6 +154,7 @@ static void __init acpi_nfit_register_pmem(struct acpi_nfit_desc *desc) struct acpi_nfit_system_address *spa; unsigned long smfn, emfn; bool failed; + int rc; list_for_each_entry(spa_desc, &desc->spa_list, link) { @@ -188,7 +190,15 @@ static void __init acpi_nfit_register_pmem(struct acpi_nfit_desc *desc) continue; } - 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.15.1 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xenproject.org https://lists.xenproject.org/mailman/listinfo/xen-devel