[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC XEN PATCH v2 02/15] xen: probe pmem regions via ACPI NFIT
Probe the address ranges of pmem regions via ACPI NFIT and report them to Xen hypervisor. Signed-off-by: Haozhong Zhang <haozhong.zhang@xxxxxxxxx> --- Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- xen/arch/x86/acpi/boot.c | 4 ++ xen/common/Makefile | 1 + xen/common/pmem.c | 106 ++++++++++++++++++++++++++++++++++++++++++ xen/drivers/acpi/Makefile | 2 + xen/drivers/acpi/nfit.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ xen/include/acpi/actbl.h | 1 + xen/include/acpi/actbl1.h | 42 +++++++++++++++++ xen/include/xen/acpi.h | 4 ++ xen/include/xen/pmem.h | 28 +++++++++++ 9 files changed, 304 insertions(+) create mode 100644 xen/common/pmem.c create mode 100644 xen/drivers/acpi/nfit.c create mode 100644 xen/include/xen/pmem.h diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c index 33c9133812..83d73868d6 100644 --- a/xen/arch/x86/acpi/boot.c +++ b/xen/arch/x86/acpi/boot.c @@ -754,5 +754,9 @@ int __init acpi_boot_init(void) acpi_table_parse(ACPI_SIG_BGRT, acpi_invalidate_bgrt); +#ifdef CONFIG_PMEM + acpi_nfit_init(); +#endif + return 0; } diff --git a/xen/common/Makefile b/xen/common/Makefile index 0fed30bcc6..16c273b6d4 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_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..3c150cf1dd --- /dev/null +++ b/xen/common/pmem.c @@ -0,0 +1,106 @@ +/* + * 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> +#include <xen/spinlock.h> + +/* + * All pmem regions probed via SPA range structures of ACPI NFIT are + * linked in pmem_regions. + */ +static DEFINE_SPINLOCK(pmem_regions_lock); +static LIST_HEAD(pmem_regions); + +struct pmem { + struct list_head link; /* link to pmem_list */ + unsigned long smfn; /* start MFN of the whole pmem region */ + unsigned long emfn; /* end MFN of the whole pmem region */ +}; + +static bool check_overlap(unsigned long smfn1, unsigned long emfn1, + unsigned long smfn2, unsigned long emfn2) +{ + return smfn1 < emfn2 && smfn2 < emfn1; +} + +static struct pmem *alloc_pmem_struct(unsigned long smfn, unsigned long emfn) +{ + struct pmem *pmem = xzalloc(struct pmem); + + if ( !pmem ) + return NULL; + + pmem->smfn = smfn; + pmem->emfn = emfn; + + return pmem; +} + +static int pmem_list_add(struct list_head *list, struct pmem *entry) +{ + struct list_head *cur; + unsigned long smfn = entry->smfn, emfn = entry->emfn; + + 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 -EINVAL; + + if ( cur_smfn < smfn ) + break; + } + + list_add(&entry->link, cur); + + return 0; +} + +/** + * Register a pmem region to Xen. It's used by Xen hypervisor to collect + * all pmem regions can be used later. + * + * Parameters: + * smfn, emfn: start and end MFNs of the pmem region + * + * Return: + * On success, return 0. Otherwise, an error number is returned. + */ +int pmem_register(unsigned long smfn, unsigned long emfn) +{ + int rc; + struct pmem *pmem; + + if ( smfn >= emfn ) + return -EINVAL; + + pmem = alloc_pmem_struct(smfn, emfn); + if ( !pmem ) + return -ENOMEM; + + spin_lock(&pmem_regions_lock); + rc = pmem_list_add(&pmem_regions, pmem); + spin_unlock(&pmem_regions_lock); + + return rc; +} diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile index 444b11d583..cef9d90222 100644 --- a/xen/drivers/acpi/Makefile +++ b/xen/drivers/acpi/Makefile @@ -9,3 +9,5 @@ obj-$(CONFIG_HAS_CPUFREQ) += pmstat.o obj-$(CONFIG_X86) += hwregs.o obj-$(CONFIG_X86) += reboot.o + +obj-$(CONFIG_PMEM) += nfit.o diff --git a/xen/drivers/acpi/nfit.c b/xen/drivers/acpi/nfit.c new file mode 100644 index 0000000000..ceac121dd2 --- /dev/null +++ b/xen/drivers/acpi/nfit.c @@ -0,0 +1,116 @@ +/* + * xen/drivers/acpi/nfit.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/acpi.h> +#include <xen/errno.h> +#include <xen/init.h> +#include <xen/mm.h> +#include <xen/pfn.h> +#include <xen/pmem.h> + +static struct acpi_table_nfit *nfit __read_mostly = NULL; + +/* ACPI 6.1: GUID of a byte addressable persistent memory region */ +static const uint8_t nfit_spa_pmem_uuid[] = +{ + 0x79, 0xd3, 0xf0, 0x66, 0xf3, 0xb4, 0x74, 0x40, + 0xac, 0x43, 0x0d, 0x33, 0x18, 0xb7, 0x8c, 0xdb, +}; + +/** + * Enumerate each sub-table of NFIT. + * + * For a sub-table of type @type, @parse_cb() (if not NULL) is called + * to parse the sub-table. @parse_cb() returns 0 on success, and + * returns non-zero error code on errors. + * + * Parameters: + * nfit: NFIT + * type: the type of sub-table that will be parsed + * parse_cb: the function used to parse each sub-table + * arg: the argument passed to @parse_cb() + * + * Return: + * 0 on success, non-zero on failure + */ +static int acpi_nfit_foreach_subtable( + struct acpi_table_nfit *nfit, enum acpi_nfit_type type, + int (*parse_cb)(const struct acpi_nfit_header *, void *arg), void *arg) +{ + struct acpi_table_header *table = (struct acpi_table_header *)nfit; + struct acpi_nfit_header *hdr; + uint32_t hdr_offset = sizeof(*nfit); + int ret = 0; + + while ( hdr_offset < table->length ) + { + hdr = (void *)nfit + hdr_offset; + hdr_offset += hdr->length; + if ( hdr->type == type && parse_cb ) + { + ret = parse_cb(hdr, arg); + if ( ret ) + break; + } + } + + return ret; +} + +static int __init acpi_nfit_spa_probe_pmem(const struct acpi_nfit_header *hdr, + void *opaque) +{ + struct acpi_nfit_system_address *spa = + (struct acpi_nfit_system_address *)hdr; + unsigned long smfn = paddr_to_pfn(spa->address); + unsigned long emfn = paddr_to_pfn(spa->address + spa->length); + int rc; + + if ( memcmp(spa->range_guid, nfit_spa_pmem_uuid, 16) ) + return 0; + + rc = pmem_register(smfn, emfn); + if ( rc ) + printk(XENLOG_ERR + "NFIT: failed to add pmem mfns: 0x%lx - 0x%lx, err %d\n", + smfn, emfn, rc); + else + printk(XENLOG_INFO "NFIT: pmem mfn 0x%lx - 0x%lx\n", smfn, emfn); + + /* ignore the error and continue to add the next pmem range */ + return 0; +} + +void __init acpi_nfit_init(void) +{ + acpi_status status; + acpi_physical_address nfit_addr; + acpi_native_uint nfit_len; + + status = acpi_get_table_phys(ACPI_SIG_NFIT, 0, &nfit_addr, &nfit_len); + if ( ACPI_FAILURE(status) ) + return; + + map_pages_to_xen((unsigned long)__va(nfit_addr), PFN_DOWN(nfit_addr), + PFN_UP(nfit_addr + nfit_len) - PFN_DOWN(nfit_addr), + PAGE_HYPERVISOR); + nfit = (struct acpi_table_nfit *)__va(nfit_addr); + + acpi_nfit_foreach_subtable(nfit, ACPI_NFIT_TYPE_SYSTEM_ADDRESS, + acpi_nfit_spa_probe_pmem, NULL); +} diff --git a/xen/include/acpi/actbl.h b/xen/include/acpi/actbl.h index 3079176992..6e113b0873 100644 --- a/xen/include/acpi/actbl.h +++ b/xen/include/acpi/actbl.h @@ -71,6 +71,7 @@ #define ACPI_SIG_XSDT "XSDT" /* Extended System Description Table */ #define ACPI_SIG_SSDT "SSDT" /* Secondary System Description Table */ #define ACPI_RSDP_NAME "RSDP" /* Short name for RSDP, not signature */ +#define ACPI_SIG_NFIT "NFIT" /* NVDIMM Firmware Interface Table */ /* * All tables and structures must be byte-packed to match the ACPI diff --git a/xen/include/acpi/actbl1.h b/xen/include/acpi/actbl1.h index e1991362dc..a59ac11325 100644 --- a/xen/include/acpi/actbl1.h +++ b/xen/include/acpi/actbl1.h @@ -905,6 +905,48 @@ struct acpi_msct_proximity { /******************************************************************************* * + * NFIT - NVDIMM Interface Table (ACPI 6.0+) + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_nfit { + struct acpi_table_header header; /* Common ACPI table header */ + u32 reserved; /* Reserved, must be zero */ +}; + +/* Subtable header for NFIT */ + +struct acpi_nfit_header { + u16 type; + u16 length; +}; + +/* Values for subtable type in struct acpi_nfit_header */ + +enum acpi_nfit_type { + ACPI_NFIT_TYPE_SYSTEM_ADDRESS = 0, +}; + +/* + * NFIT Subtables + */ + +/* type 0: System Physical Address Range Structure */ +struct acpi_nfit_system_address { + struct acpi_nfit_header header; + u16 range_index; + u16 flags; + u32 reserved; /* Reseved, must be zero */ + u32 proximity_domain; + u8 range_guid[16]; + u64 address; + u64 length; + u64 memory_mapping; +}; + +/******************************************************************************* + * * SBST - Smart Battery Specification Table * Version 1 * diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h index 30ec0eec5f..8edb9a275e 100644 --- a/xen/include/xen/acpi.h +++ b/xen/include/xen/acpi.h @@ -180,4 +180,8 @@ void acpi_reboot(void); void acpi_dmar_zap(void); void acpi_dmar_reinstate(void); +#ifdef CONFIG_PMEM +void acpi_nfit_init(void); +#endif /* CONFIG_PMEM */ + #endif /*_LINUX_ACPI_H*/ diff --git a/xen/include/xen/pmem.h b/xen/include/xen/pmem.h new file mode 100644 index 0000000000..1144e86f98 --- /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_PMEM + +#include <xen/types.h> + +int pmem_register(unsigned long smfn, unsigned long emfn); + +#endif /* CONFIG_PMEM */ +#endif /* __XEN_PMEM_H__ */ -- 2.12.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |