Index: stable/12/sys/dev/nvdimm/nvdimm.c =================================================================== --- stable/12/sys/dev/nvdimm/nvdimm.c (revision 343846) +++ stable/12/sys/dev/nvdimm/nvdimm.c (revision 343847) @@ -1,409 +1,349 @@ /*- * Copyright (c) 2017 The FreeBSD Foundation * All rights reserved. * Copyright (c) 2018, 2019 Intel Corporation * * This software was developed by Konstantin Belousov * under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_acpi.h" #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define _COMPONENT ACPI_OEM ACPI_MODULE_NAME("NVDIMM") static devclass_t nvdimm_devclass; static devclass_t nvdimm_root_devclass; MALLOC_DEFINE(M_NVDIMM, "nvdimm", "NVDIMM driver memory"); struct nvdimm_dev * nvdimm_find_by_handle(nfit_handle_t nv_handle) { struct nvdimm_dev *res; device_t *dimms; int i, error, num_dimms; res = NULL; error = devclass_get_devices(nvdimm_devclass, &dimms, &num_dimms); if (error != 0) return (NULL); for (i = 0; i < num_dimms; i++) { if (nvdimm_root_get_device_handle(dimms[i]) == nv_handle) { res = device_get_softc(dimms[i]); break; } } free(dimms, M_TEMP); return (res); } static int -nvdimm_parse_flush_addr(void *nfitsubtbl, void *arg) -{ - ACPI_NFIT_FLUSH_ADDRESS *nfitflshaddr; - struct nvdimm_dev *nv; - int i; - - nfitflshaddr = nfitsubtbl; - nv = arg; - if (nfitflshaddr->DeviceHandle != nv->nv_handle) - return (0); - - MPASS(nv->nv_flush_addr == NULL && nv->nv_flush_addr_cnt == 0); - nv->nv_flush_addr = mallocarray(nfitflshaddr->HintCount, - sizeof(uint64_t *), M_NVDIMM, M_WAITOK); - for (i = 0; i < nfitflshaddr->HintCount; i++) - nv->nv_flush_addr[i] = (uint64_t *)nfitflshaddr->HintAddress[i]; - nv->nv_flush_addr_cnt = nfitflshaddr->HintCount; - return (0); -} - -int -nvdimm_iterate_nfit(ACPI_TABLE_NFIT *nfitbl, enum AcpiNfitType type, - int (*cb)(void *, void *), void *arg) -{ - ACPI_NFIT_HEADER *nfithdr; - ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr; - ACPI_NFIT_MEMORY_MAP *nfitmap; - ACPI_NFIT_INTERLEAVE *nfitintrl; - ACPI_NFIT_SMBIOS *nfitsmbios; - ACPI_NFIT_CONTROL_REGION *nfitctlreg; - ACPI_NFIT_DATA_REGION *nfitdtreg; - ACPI_NFIT_FLUSH_ADDRESS *nfitflshaddr; - char *ptr; - int error; - - error = 0; - for (ptr = (char *)(nfitbl + 1); - ptr < (char *)nfitbl + nfitbl->Header.Length; - ptr += nfithdr->Length) { - nfithdr = (ACPI_NFIT_HEADER *)ptr; - if (nfithdr->Type != type) - continue; - switch (nfithdr->Type) { - case ACPI_NFIT_TYPE_SYSTEM_ADDRESS: - nfitaddr = __containerof(nfithdr, - ACPI_NFIT_SYSTEM_ADDRESS, Header); - error = cb(nfitaddr, arg); - break; - case ACPI_NFIT_TYPE_MEMORY_MAP: - nfitmap = __containerof(nfithdr, - ACPI_NFIT_MEMORY_MAP, Header); - error = cb(nfitmap, arg); - break; - case ACPI_NFIT_TYPE_INTERLEAVE: - nfitintrl = __containerof(nfithdr, - ACPI_NFIT_INTERLEAVE, Header); - error = cb(nfitintrl, arg); - break; - case ACPI_NFIT_TYPE_SMBIOS: - nfitsmbios = __containerof(nfithdr, - ACPI_NFIT_SMBIOS, Header); - error = cb(nfitsmbios, arg); - break; - case ACPI_NFIT_TYPE_CONTROL_REGION: - nfitctlreg = __containerof(nfithdr, - ACPI_NFIT_CONTROL_REGION, Header); - error = cb(nfitctlreg, arg); - break; - case ACPI_NFIT_TYPE_DATA_REGION: - nfitdtreg = __containerof(nfithdr, - ACPI_NFIT_DATA_REGION, Header); - error = cb(nfitdtreg, arg); - break; - case ACPI_NFIT_TYPE_FLUSH_ADDRESS: - nfitflshaddr = __containerof(nfithdr, - ACPI_NFIT_FLUSH_ADDRESS, Header); - error = cb(nfitflshaddr, arg); - break; - case ACPI_NFIT_TYPE_RESERVED: - default: - if (bootverbose) - printf("NFIT subtype %d unknown\n", - nfithdr->Type); - error = 0; - break; - } - if (error != 0) - break; - } - return (error); -} - -static int nvdimm_probe(device_t dev) { return (BUS_PROBE_NOWILDCARD); } static int nvdimm_attach(device_t dev) { struct nvdimm_dev *nv; ACPI_TABLE_NFIT *nfitbl; ACPI_HANDLE handle; ACPI_STATUS status; nv = device_get_softc(dev); handle = nvdimm_root_get_acpi_handle(dev); if (handle == NULL) return (EINVAL); nv->nv_dev = dev; nv->nv_handle = nvdimm_root_get_device_handle(dev); status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl); if (ACPI_FAILURE(status)) { if (bootverbose) device_printf(dev, "cannot get NFIT\n"); return (ENXIO); } - nvdimm_iterate_nfit(nfitbl, ACPI_NFIT_TYPE_FLUSH_ADDRESS, - nvdimm_parse_flush_addr, nv); + acpi_nfit_get_flush_addrs(nfitbl, nv->nv_handle, &nv->nv_flush_addr, + &nv->nv_flush_addr_cnt); AcpiPutTable(&nfitbl->Header); return (0); } static int nvdimm_detach(device_t dev) { struct nvdimm_dev *nv; nv = device_get_softc(dev); free(nv->nv_flush_addr, M_NVDIMM); return (0); } static int nvdimm_suspend(device_t dev) { return (0); } static int nvdimm_resume(device_t dev) { return (0); } -static int -nvdimm_root_create_spa(void *nfitsubtbl, void *arg) +static ACPI_STATUS +find_dimm(ACPI_HANDLE handle, UINT32 nesting_level, void *context, + void **return_value) { - enum SPA_mapping_type spa_type; - ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr; - struct SPA_mapping *spa; - struct nvdimm_root_dev *dev; - int error; + ACPI_DEVICE_INFO *device_info; + ACPI_STATUS status; - nfitaddr = nfitsubtbl; - dev = arg; - spa_type = nvdimm_spa_type_from_uuid( - (struct uuid *)nfitaddr->RangeGuid); - if (spa_type == SPA_TYPE_UNKNOWN) - return (0); - spa = malloc(sizeof(struct SPA_mapping), M_NVDIMM, M_WAITOK | M_ZERO); - error = nvdimm_spa_init(spa, nfitaddr, spa_type); - if (error != 0) { - nvdimm_spa_fini(spa); - free(spa, M_NVDIMM); + status = AcpiGetObjectInfo(handle, &device_info); + if (ACPI_FAILURE(status)) + return_ACPI_STATUS(AE_ERROR); + if (device_info->Address == (uintptr_t)context) { + *(ACPI_HANDLE *)return_value = handle; + return_ACPI_STATUS(AE_CTRL_TERMINATE); } - SLIST_INSERT_HEAD(&dev->spas, spa, link); - return (0); + return_ACPI_STATUS(AE_OK); } -static ACPI_STATUS -nvdimm_root_create_dev(ACPI_HANDLE handle, UINT32 nesting_level, void *context, - void **return_value) +static ACPI_HANDLE +get_dimm_acpi_handle(ACPI_HANDLE root_handle, nfit_handle_t adr) { + ACPI_HANDLE res; ACPI_STATUS status; - ACPI_DEVICE_INFO *device_info; - device_t parent, child; + + res = NULL; + status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, root_handle, 1, find_dimm, + NULL, (void *)(uintptr_t)adr, &res); + if (ACPI_FAILURE(status)) + res = NULL; + return (res); +} + +static int +nvdimm_root_create_devs(device_t dev, ACPI_TABLE_NFIT *nfitbl) +{ + ACPI_HANDLE root_handle, dimm_handle; + device_t child; + nfit_handle_t *dimm_ids, *dimm; uintptr_t *ivars; + int num_dimm_ids; - parent = context; - child = BUS_ADD_CHILD(parent, 100, "nvdimm", -1); - if (child == NULL) { - device_printf(parent, "failed to create nvdimm\n"); - return_ACPI_STATUS(AE_ERROR); + root_handle = acpi_get_handle(dev); + acpi_nfit_get_dimm_ids(nfitbl, &dimm_ids, &num_dimm_ids); + for (dimm = dimm_ids; dimm < dimm_ids + num_dimm_ids; dimm++) { + dimm_handle = get_dimm_acpi_handle(root_handle, *dimm); + child = BUS_ADD_CHILD(dev, 100, "nvdimm", -1); + if (child == NULL) { + device_printf(dev, "failed to create nvdimm\n"); + return (ENXIO); + } + ivars = mallocarray(NVDIMM_ROOT_IVAR_MAX, sizeof(uintptr_t), + M_NVDIMM, M_ZERO | M_WAITOK); + device_set_ivars(child, ivars); + nvdimm_root_set_acpi_handle(child, dimm_handle); + nvdimm_root_set_device_handle(child, *dimm); } - status = AcpiGetObjectInfo(handle, &device_info); - if (ACPI_FAILURE(status)) { - device_printf(parent, "failed to get nvdimm device info\n"); - return_ACPI_STATUS(AE_ERROR); + free(dimm_ids, M_NVDIMM); + return (0); +} + +static int +nvdimm_root_create_spas(struct nvdimm_root_dev *dev, ACPI_TABLE_NFIT *nfitbl) +{ + ACPI_NFIT_SYSTEM_ADDRESS **spas, **spa; + struct SPA_mapping *spa_mapping; + enum SPA_mapping_type spa_type; + int error, num_spas; + + error = 0; + acpi_nfit_get_spa_ranges(nfitbl, &spas, &num_spas); + for (spa = spas; spa < spas + num_spas; spa++) { + spa_type = nvdimm_spa_type_from_uuid( + (struct uuid *)(*spa)->RangeGuid); + if (spa_type == SPA_TYPE_UNKNOWN) + continue; + spa_mapping = malloc(sizeof(struct SPA_mapping), M_NVDIMM, + M_WAITOK | M_ZERO); + error = nvdimm_spa_init(spa_mapping, *spa, spa_type); + if (error != 0) { + nvdimm_spa_fini(spa_mapping); + free(spa, M_NVDIMM); + break; + } + SLIST_INSERT_HEAD(&dev->spas, spa_mapping, link); } - ivars = mallocarray(NVDIMM_ROOT_IVAR_MAX - 1, sizeof(uintptr_t), - M_NVDIMM, M_ZERO | M_WAITOK); - device_set_ivars(child, ivars); - nvdimm_root_set_acpi_handle(child, handle); - nvdimm_root_set_device_handle(child, device_info->Address); - return_ACPI_STATUS(AE_OK); + free(spas, M_NVDIMM); + return (error); } static char *nvdimm_root_id[] = {"ACPI0012", NULL}; static int nvdimm_root_probe(device_t dev) { if (acpi_disabled("nvdimm")) return (ENXIO); if (ACPI_ID_PROBE(device_get_parent(dev), dev, nvdimm_root_id) != NULL) { device_set_desc(dev, "ACPI NVDIMM root device"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int nvdimm_root_attach(device_t dev) { - ACPI_HANDLE handle; - ACPI_STATUS status; + struct nvdimm_root_dev *root; ACPI_TABLE_NFIT *nfitbl; + ACPI_STATUS status; int error; - handle = acpi_get_handle(dev); - status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, handle, 1, - nvdimm_root_create_dev, NULL, dev, NULL); - if (ACPI_FAILURE(status)) - device_printf(dev, "failed adding children\n"); - error = bus_generic_attach(dev); - if (error != 0) - return (error); status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl); if (ACPI_FAILURE(status)) { device_printf(dev, "cannot get NFIT\n"); return (ENXIO); } - error = nvdimm_iterate_nfit(nfitbl, ACPI_NFIT_TYPE_SYSTEM_ADDRESS, - nvdimm_root_create_spa, device_get_softc(dev)); + error = nvdimm_root_create_devs(dev, nfitbl); + if (error != 0) + return (error); + error = bus_generic_attach(dev); + if (error != 0) + return (error); + root = device_get_softc(dev); + error = nvdimm_root_create_spas(root, nfitbl); AcpiPutTable(&nfitbl->Header); return (error); } static int nvdimm_root_detach(device_t dev) { struct nvdimm_root_dev *root; struct SPA_mapping *spa, *next; device_t *children; int i, error, num_children; root = device_get_softc(dev); SLIST_FOREACH_SAFE(spa, &root->spas, link, next) { nvdimm_spa_fini(spa); SLIST_REMOVE_HEAD(&root->spas, link); free(spa, M_NVDIMM); } error = bus_generic_detach(dev); if (error != 0) return (error); error = device_get_children(dev, &children, &num_children); if (error != 0) return (error); for (i = 0; i < num_children; i++) free(device_get_ivars(children[i]), M_NVDIMM); free(children, M_TEMP); error = device_delete_children(dev); return (error); } static int nvdimm_root_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) { if (index < 0 || index >= NVDIMM_ROOT_IVAR_MAX) return (ENOENT); *result = ((uintptr_t *)device_get_ivars(child))[index]; return (0); } static int nvdimm_root_write_ivar(device_t dev, device_t child, int index, uintptr_t value) { if (index < 0 || index >= NVDIMM_ROOT_IVAR_MAX) return (ENOENT); ((uintptr_t *)device_get_ivars(child))[index] = value; return (0); } static device_method_t nvdimm_methods[] = { DEVMETHOD(device_probe, nvdimm_probe), DEVMETHOD(device_attach, nvdimm_attach), DEVMETHOD(device_detach, nvdimm_detach), DEVMETHOD(device_suspend, nvdimm_suspend), DEVMETHOD(device_resume, nvdimm_resume), DEVMETHOD_END }; static driver_t nvdimm_driver = { "nvdimm", nvdimm_methods, sizeof(struct nvdimm_dev), }; static device_method_t nvdimm_root_methods[] = { DEVMETHOD(device_probe, nvdimm_root_probe), DEVMETHOD(device_attach, nvdimm_root_attach), DEVMETHOD(device_detach, nvdimm_root_detach), DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_read_ivar, nvdimm_root_read_ivar), DEVMETHOD(bus_write_ivar, nvdimm_root_write_ivar), DEVMETHOD_END }; static driver_t nvdimm_root_driver = { "nvdimm_root", nvdimm_root_methods, sizeof(struct nvdimm_root_dev), }; DRIVER_MODULE(nvdimm_root, acpi, nvdimm_root_driver, nvdimm_root_devclass, NULL, NULL); DRIVER_MODULE(nvdimm, nvdimm_root, nvdimm_driver, nvdimm_devclass, NULL, NULL); MODULE_DEPEND(nvdimm, acpi, 1, 1, 1); Index: stable/12/sys/dev/nvdimm/nvdimm_nfit.c =================================================================== --- stable/12/sys/dev/nvdimm/nvdimm_nfit.c (nonexistent) +++ stable/12/sys/dev/nvdimm/nvdimm_nfit.c (revision 343847) @@ -0,0 +1,203 @@ +/*- + * Copyright (c) 2018 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include + +static int +uint32_t_compare(const void *a, const void *b) +{ + + return (*(const uint32_t *)a - *(const uint32_t *)b); +} + +static int +find_matches(ACPI_TABLE_NFIT *nfitbl, uint16_t type, uint16_t offset, + uint64_t mask, uint64_t value, void **ptrs, int ptrs_len) +{ + ACPI_NFIT_HEADER *h, *end; + uint64_t val; + size_t load_size; + int count; + + h = (ACPI_NFIT_HEADER *)(nfitbl + 1); + end = (ACPI_NFIT_HEADER *)((char *)nfitbl + + nfitbl->Header.Length); + load_size = roundup2(flsl(mask), 8) / 8; + count = 0; + + while (h < end) { + if (h->Type == type) { + bcopy((char *)h + offset, &val, load_size); + val &= mask; + if (val == value) { + if (ptrs_len > 0) { + ptrs[count] = h; + ptrs_len--; + } + count++; + } + } + if (h->Length == 0) + break; + h = (ACPI_NFIT_HEADER *)((char *)h + h->Length); + } + return (count); +} + +static void +malloc_find_matches(ACPI_TABLE_NFIT *nfitbl, uint16_t type, uint16_t offset, + uint64_t mask, uint64_t value, void ***ptrs, int *ptrs_len) +{ + int count; + + count = find_matches(nfitbl, type, offset, mask, value, NULL, 0); + *ptrs_len = count; + if (count == 0) { + *ptrs = NULL; + return; + } + *ptrs = mallocarray(count, sizeof(void *), M_NVDIMM, M_WAITOK); + find_matches(nfitbl, type, offset, mask, value, *ptrs, *ptrs_len); +} + +void +acpi_nfit_get_dimm_ids(ACPI_TABLE_NFIT *nfitbl, nfit_handle_t **listp, + int *countp) +{ + ACPI_NFIT_SYSTEM_ADDRESS **spas; + ACPI_NFIT_MEMORY_MAP ***regions; + int i, j, k, maxids, num_spas, *region_counts; + + acpi_nfit_get_spa_ranges(nfitbl, &spas, &num_spas); + if (num_spas == 0) { + *listp = NULL; + *countp = 0; + return; + } + regions = mallocarray(num_spas, sizeof(uint16_t *), M_NVDIMM, + M_WAITOK); + region_counts = mallocarray(num_spas, sizeof(int), M_NVDIMM, M_WAITOK); + for (i = 0; i < num_spas; i++) { + acpi_nfit_get_region_mappings_by_spa_range(nfitbl, + spas[i]->RangeIndex, ®ions[i], ®ion_counts[i]); + } + maxids = 0; + for (i = 0; i < num_spas; i++) { + maxids += region_counts[i]; + } + *listp = mallocarray(maxids, sizeof(nfit_handle_t), M_NVDIMM, M_WAITOK); + k = 0; + for (i = 0; i < num_spas; i++) { + for (j = 0; j < region_counts[i]; j++) + (*listp)[k++] = regions[i][j]->DeviceHandle; + } + qsort((*listp), maxids, sizeof(uint32_t), uint32_t_compare); + i = 0; + for (j = 1; j < maxids; j++) { + if ((*listp)[i] != (*listp)[j]) + (*listp)[++i] = (*listp)[j]; + } + *countp = i + 1; + free(region_counts, M_NVDIMM); + for (i = 0; i < num_spas; i++) + free(regions[i], M_NVDIMM); + free(regions, M_NVDIMM); + free(spas, M_NVDIMM); +} + +void +acpi_nfit_get_spa_range(ACPI_TABLE_NFIT *nfitbl, uint16_t range_index, + ACPI_NFIT_SYSTEM_ADDRESS **spa) +{ + + *spa = NULL; + find_matches(nfitbl, ACPI_NFIT_TYPE_SYSTEM_ADDRESS, + offsetof(ACPI_NFIT_SYSTEM_ADDRESS, RangeIndex), UINT16_MAX, + range_index, (void **)spa, 1); +} + +void +acpi_nfit_get_spa_ranges(ACPI_TABLE_NFIT *nfitbl, + ACPI_NFIT_SYSTEM_ADDRESS ***listp, int *countp) +{ + + malloc_find_matches(nfitbl, ACPI_NFIT_TYPE_SYSTEM_ADDRESS, 0, 0, 0, + (void ***)listp, countp); +} + +void +acpi_nfit_get_region_mappings_by_spa_range(ACPI_TABLE_NFIT *nfitbl, + uint16_t spa_range_index, ACPI_NFIT_MEMORY_MAP ***listp, int *countp) +{ + + malloc_find_matches(nfitbl, ACPI_NFIT_TYPE_MEMORY_MAP, + offsetof(ACPI_NFIT_MEMORY_MAP, RangeIndex), UINT16_MAX, + spa_range_index, (void ***)listp, countp); +} + +void acpi_nfit_get_control_region(ACPI_TABLE_NFIT *nfitbl, + uint16_t control_region_index, ACPI_NFIT_CONTROL_REGION **out) +{ + + *out = NULL; + find_matches(nfitbl, ACPI_NFIT_TYPE_CONTROL_REGION, + offsetof(ACPI_NFIT_CONTROL_REGION, RegionIndex), UINT16_MAX, + control_region_index, (void **)out, 1); +} + +void +acpi_nfit_get_flush_addrs(ACPI_TABLE_NFIT *nfitbl, nfit_handle_t dimm, + uint64_t ***listp, int *countp) +{ + ACPI_NFIT_FLUSH_ADDRESS *subtable; + int i; + + subtable = NULL; + find_matches(nfitbl, ACPI_NFIT_TYPE_FLUSH_ADDRESS, + offsetof(ACPI_NFIT_FLUSH_ADDRESS, DeviceHandle), UINT32_MAX, + dimm, (void **)&subtable, 1); + if (subtable == NULL || subtable->HintCount == 0) { + *listp = NULL; + *countp = 0; + return; + } + *countp = subtable->HintCount; + *listp = mallocarray(subtable->HintCount, sizeof(uint64_t *), M_NVDIMM, + M_WAITOK); + for (i = 0; i < subtable->HintCount; i++) + (*listp)[i] = (uint64_t *)(intptr_t)subtable->HintAddress[i]; +} Property changes on: stable/12/sys/dev/nvdimm/nvdimm_nfit.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/sys/dev/nvdimm/nvdimm_var.h =================================================================== --- stable/12/sys/dev/nvdimm/nvdimm_var.h (revision 343846) +++ stable/12/sys/dev/nvdimm/nvdimm_var.h (revision 343847) @@ -1,102 +1,112 @@ /*- * Copyright (c) 2017 The FreeBSD Foundation * All rights reserved. * Copyright (c) 2018, 2019 Intel Corporation * * This software was developed by Konstantin Belousov * under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __DEV_NVDIMM_VAR_H__ #define __DEV_NVDIMM_VAR_H__ typedef uint32_t nfit_handle_t; enum nvdimm_root_ivar { NVDIMM_ROOT_IVAR_ACPI_HANDLE, NVDIMM_ROOT_IVAR_DEVICE_HANDLE, NVDIMM_ROOT_IVAR_MAX, }; __BUS_ACCESSOR(nvdimm_root, acpi_handle, NVDIMM_ROOT, ACPI_HANDLE, ACPI_HANDLE) __BUS_ACCESSOR(nvdimm_root, device_handle, NVDIMM_ROOT, DEVICE_HANDLE, nfit_handle_t) struct nvdimm_root_dev { SLIST_HEAD(, SPA_mapping) spas; }; struct nvdimm_dev { device_t nv_dev; nfit_handle_t nv_handle; uint64_t **nv_flush_addr; int nv_flush_addr_cnt; }; enum SPA_mapping_type { SPA_TYPE_VOLATILE_MEMORY = 0, SPA_TYPE_PERSISTENT_MEMORY = 1, SPA_TYPE_CONTROL_REGION = 2, SPA_TYPE_DATA_REGION = 3, SPA_TYPE_VOLATILE_VIRTUAL_DISK = 4, SPA_TYPE_VOLATILE_VIRTUAL_CD = 5, SPA_TYPE_PERSISTENT_VIRTUAL_DISK= 6, SPA_TYPE_PERSISTENT_VIRTUAL_CD = 7, SPA_TYPE_UNKNOWN = 127, }; struct SPA_mapping { SLIST_ENTRY(SPA_mapping) link; enum SPA_mapping_type spa_type; int spa_domain; int spa_nfit_idx; uint64_t spa_phys_base; uint64_t spa_len; uint64_t spa_efi_mem_flags; void *spa_kva; struct cdev *spa_dev; struct g_geom *spa_g; struct g_provider *spa_p; struct bio_queue_head spa_g_queue; struct mtx spa_g_mtx; struct mtx spa_g_stat_mtx; struct devstat *spa_g_devstat; struct proc *spa_g_proc; struct vm_object *spa_obj; bool spa_g_proc_run; bool spa_g_proc_exiting; }; MALLOC_DECLARE(M_NVDIMM); +void acpi_nfit_get_dimm_ids(ACPI_TABLE_NFIT *nfitbl, nfit_handle_t **listp, + int *countp); +void acpi_nfit_get_spa_range(ACPI_TABLE_NFIT *nfitbl, uint16_t range_index, + ACPI_NFIT_SYSTEM_ADDRESS **spa); +void acpi_nfit_get_spa_ranges(ACPI_TABLE_NFIT *nfitbl, + ACPI_NFIT_SYSTEM_ADDRESS ***listp, int *countp); +void acpi_nfit_get_region_mappings_by_spa_range(ACPI_TABLE_NFIT *nfitbl, + uint16_t spa_range_index, ACPI_NFIT_MEMORY_MAP ***listp, int *countp); +void acpi_nfit_get_control_region(ACPI_TABLE_NFIT *nfitbl, + uint16_t control_region_index, ACPI_NFIT_CONTROL_REGION **out); +void acpi_nfit_get_flush_addrs(ACPI_TABLE_NFIT *nfitbl, nfit_handle_t dimm, + uint64_t ***listp, int *countp); enum SPA_mapping_type nvdimm_spa_type_from_uuid(struct uuid *); struct nvdimm_dev *nvdimm_find_by_handle(nfit_handle_t nv_handle); -int nvdimm_iterate_nfit(ACPI_TABLE_NFIT *nfitbl, enum AcpiNfitType type, - int (*cb)(void *, void *), void *arg); int nvdimm_spa_init(struct SPA_mapping *spa, ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr, enum SPA_mapping_type spa_type); void nvdimm_spa_fini(struct SPA_mapping *spa); #endif /* __DEV_NVDIMM_VAR_H__ */ Index: stable/12/sys/modules/nvdimm/Makefile =================================================================== --- stable/12/sys/modules/nvdimm/Makefile (revision 343846) +++ stable/12/sys/modules/nvdimm/Makefile (revision 343847) @@ -1,11 +1,12 @@ # $FreeBSD$ .PATH: ${SRCTOP}/sys/dev/nvdimm KMOD= nvdimm SRCS= nvdimm.c \ + nvdimm_nfit.c \ nvdimm_spa.c SRCS+= acpi_if.h bus_if.h device_if.h .include Index: stable/12 =================================================================== --- stable/12 (revision 343846) +++ stable/12 (revision 343847) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r343629