16db7f8e5SKonstantin Belousov /*- 26db7f8e5SKonstantin Belousov * Copyright (c) 2017 The FreeBSD Foundation 36db7f8e5SKonstantin Belousov * All rights reserved. 4fc4a961aSKonstantin Belousov * Copyright (c) 2018, 2019 Intel Corporation 56db7f8e5SKonstantin Belousov * 66db7f8e5SKonstantin Belousov * This software was developed by Konstantin Belousov <kib@FreeBSD.org> 76db7f8e5SKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 86db7f8e5SKonstantin Belousov * 96db7f8e5SKonstantin Belousov * Redistribution and use in source and binary forms, with or without 106db7f8e5SKonstantin Belousov * modification, are permitted provided that the following conditions 116db7f8e5SKonstantin Belousov * are met: 126db7f8e5SKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 136db7f8e5SKonstantin Belousov * notice, this list of conditions and the following disclaimer. 146db7f8e5SKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 156db7f8e5SKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 166db7f8e5SKonstantin Belousov * documentation and/or other materials provided with the distribution. 176db7f8e5SKonstantin Belousov * 186db7f8e5SKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 196db7f8e5SKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 206db7f8e5SKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 216db7f8e5SKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 226db7f8e5SKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 236db7f8e5SKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 246db7f8e5SKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 256db7f8e5SKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 266db7f8e5SKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 276db7f8e5SKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 286db7f8e5SKonstantin Belousov * SUCH DAMAGE. 296db7f8e5SKonstantin Belousov */ 306db7f8e5SKonstantin Belousov 316db7f8e5SKonstantin Belousov #include <sys/cdefs.h> 326db7f8e5SKonstantin Belousov __FBSDID("$FreeBSD$"); 336db7f8e5SKonstantin Belousov 346db7f8e5SKonstantin Belousov #include "opt_acpi.h" 356db7f8e5SKonstantin Belousov #include "opt_ddb.h" 366db7f8e5SKonstantin Belousov 376db7f8e5SKonstantin Belousov #include <sys/param.h> 386db7f8e5SKonstantin Belousov #include <sys/bio.h> 396db7f8e5SKonstantin Belousov #include <sys/bus.h> 406db7f8e5SKonstantin Belousov #include <sys/kernel.h> 416db7f8e5SKonstantin Belousov #include <sys/lock.h> 426db7f8e5SKonstantin Belousov #include <sys/malloc.h> 436db7f8e5SKonstantin Belousov #include <sys/module.h> 446db7f8e5SKonstantin Belousov #include <sys/uuid.h> 456db7f8e5SKonstantin Belousov #include <contrib/dev/acpica/include/acpi.h> 466db7f8e5SKonstantin Belousov #include <contrib/dev/acpica/include/accommon.h> 476db7f8e5SKonstantin Belousov #include <contrib/dev/acpica/include/acuuid.h> 486db7f8e5SKonstantin Belousov #include <dev/acpica/acpivar.h> 496db7f8e5SKonstantin Belousov #include <dev/nvdimm/nvdimm_var.h> 506db7f8e5SKonstantin Belousov 516db7f8e5SKonstantin Belousov #define _COMPONENT ACPI_OEM 526db7f8e5SKonstantin Belousov ACPI_MODULE_NAME("NVDIMM") 536db7f8e5SKonstantin Belousov 546db7f8e5SKonstantin Belousov static devclass_t nvdimm_devclass; 55fc4a961aSKonstantin Belousov static devclass_t nvdimm_root_devclass; 566db7f8e5SKonstantin Belousov MALLOC_DEFINE(M_NVDIMM, "nvdimm", "NVDIMM driver memory"); 576db7f8e5SKonstantin Belousov 586db7f8e5SKonstantin Belousov struct nvdimm_dev * 596db7f8e5SKonstantin Belousov nvdimm_find_by_handle(nfit_handle_t nv_handle) 606db7f8e5SKonstantin Belousov { 61fc4a961aSKonstantin Belousov struct nvdimm_dev *res; 62fc4a961aSKonstantin Belousov device_t *dimms; 63fc4a961aSKonstantin Belousov int i, error, num_dimms; 646db7f8e5SKonstantin Belousov 656db7f8e5SKonstantin Belousov res = NULL; 66fc4a961aSKonstantin Belousov error = devclass_get_devices(nvdimm_devclass, &dimms, &num_dimms); 67fc4a961aSKonstantin Belousov if (error != 0) 68fc4a961aSKonstantin Belousov return (NULL); 69fc4a961aSKonstantin Belousov for (i = 0; i < num_dimms; i++) { 70fc4a961aSKonstantin Belousov if (nvdimm_root_get_device_handle(dimms[i]) == nv_handle) { 71fc4a961aSKonstantin Belousov res = device_get_softc(dimms[i]); 726db7f8e5SKonstantin Belousov break; 736db7f8e5SKonstantin Belousov } 746db7f8e5SKonstantin Belousov } 75fc4a961aSKonstantin Belousov free(dimms, M_TEMP); 766db7f8e5SKonstantin Belousov return (res); 776db7f8e5SKonstantin Belousov } 786db7f8e5SKonstantin Belousov 796db7f8e5SKonstantin Belousov static int 806db7f8e5SKonstantin Belousov nvdimm_parse_flush_addr(void *nfitsubtbl, void *arg) 816db7f8e5SKonstantin Belousov { 826db7f8e5SKonstantin Belousov ACPI_NFIT_FLUSH_ADDRESS *nfitflshaddr; 836db7f8e5SKonstantin Belousov struct nvdimm_dev *nv; 846db7f8e5SKonstantin Belousov int i; 856db7f8e5SKonstantin Belousov 866db7f8e5SKonstantin Belousov nfitflshaddr = nfitsubtbl; 876db7f8e5SKonstantin Belousov nv = arg; 886db7f8e5SKonstantin Belousov if (nfitflshaddr->DeviceHandle != nv->nv_handle) 896db7f8e5SKonstantin Belousov return (0); 906db7f8e5SKonstantin Belousov 916db7f8e5SKonstantin Belousov MPASS(nv->nv_flush_addr == NULL && nv->nv_flush_addr_cnt == 0); 92fc4a961aSKonstantin Belousov nv->nv_flush_addr = mallocarray(nfitflshaddr->HintCount, 93fc4a961aSKonstantin Belousov sizeof(uint64_t *), M_NVDIMM, M_WAITOK); 946db7f8e5SKonstantin Belousov for (i = 0; i < nfitflshaddr->HintCount; i++) 956db7f8e5SKonstantin Belousov nv->nv_flush_addr[i] = (uint64_t *)nfitflshaddr->HintAddress[i]; 966db7f8e5SKonstantin Belousov nv->nv_flush_addr_cnt = nfitflshaddr->HintCount; 976db7f8e5SKonstantin Belousov return (0); 986db7f8e5SKonstantin Belousov } 996db7f8e5SKonstantin Belousov 1006db7f8e5SKonstantin Belousov int 1016db7f8e5SKonstantin Belousov nvdimm_iterate_nfit(ACPI_TABLE_NFIT *nfitbl, enum AcpiNfitType type, 1026db7f8e5SKonstantin Belousov int (*cb)(void *, void *), void *arg) 1036db7f8e5SKonstantin Belousov { 1046db7f8e5SKonstantin Belousov ACPI_NFIT_HEADER *nfithdr; 1056db7f8e5SKonstantin Belousov ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr; 1066db7f8e5SKonstantin Belousov ACPI_NFIT_MEMORY_MAP *nfitmap; 1076db7f8e5SKonstantin Belousov ACPI_NFIT_INTERLEAVE *nfitintrl; 1086db7f8e5SKonstantin Belousov ACPI_NFIT_SMBIOS *nfitsmbios; 1096db7f8e5SKonstantin Belousov ACPI_NFIT_CONTROL_REGION *nfitctlreg; 1106db7f8e5SKonstantin Belousov ACPI_NFIT_DATA_REGION *nfitdtreg; 1116db7f8e5SKonstantin Belousov ACPI_NFIT_FLUSH_ADDRESS *nfitflshaddr; 1126db7f8e5SKonstantin Belousov char *ptr; 1136db7f8e5SKonstantin Belousov int error; 1146db7f8e5SKonstantin Belousov 1156db7f8e5SKonstantin Belousov error = 0; 1166db7f8e5SKonstantin Belousov for (ptr = (char *)(nfitbl + 1); 1176db7f8e5SKonstantin Belousov ptr < (char *)nfitbl + nfitbl->Header.Length; 1186db7f8e5SKonstantin Belousov ptr += nfithdr->Length) { 1196db7f8e5SKonstantin Belousov nfithdr = (ACPI_NFIT_HEADER *)ptr; 1206db7f8e5SKonstantin Belousov if (nfithdr->Type != type) 1216db7f8e5SKonstantin Belousov continue; 1226db7f8e5SKonstantin Belousov switch (nfithdr->Type) { 1236db7f8e5SKonstantin Belousov case ACPI_NFIT_TYPE_SYSTEM_ADDRESS: 1246db7f8e5SKonstantin Belousov nfitaddr = __containerof(nfithdr, 1256db7f8e5SKonstantin Belousov ACPI_NFIT_SYSTEM_ADDRESS, Header); 1266db7f8e5SKonstantin Belousov error = cb(nfitaddr, arg); 1276db7f8e5SKonstantin Belousov break; 1286db7f8e5SKonstantin Belousov case ACPI_NFIT_TYPE_MEMORY_MAP: 1296db7f8e5SKonstantin Belousov nfitmap = __containerof(nfithdr, 1306db7f8e5SKonstantin Belousov ACPI_NFIT_MEMORY_MAP, Header); 1316db7f8e5SKonstantin Belousov error = cb(nfitmap, arg); 1326db7f8e5SKonstantin Belousov break; 1336db7f8e5SKonstantin Belousov case ACPI_NFIT_TYPE_INTERLEAVE: 1346db7f8e5SKonstantin Belousov nfitintrl = __containerof(nfithdr, 1356db7f8e5SKonstantin Belousov ACPI_NFIT_INTERLEAVE, Header); 1366db7f8e5SKonstantin Belousov error = cb(nfitintrl, arg); 1376db7f8e5SKonstantin Belousov break; 1386db7f8e5SKonstantin Belousov case ACPI_NFIT_TYPE_SMBIOS: 1396db7f8e5SKonstantin Belousov nfitsmbios = __containerof(nfithdr, 1406db7f8e5SKonstantin Belousov ACPI_NFIT_SMBIOS, Header); 1416db7f8e5SKonstantin Belousov error = cb(nfitsmbios, arg); 1426db7f8e5SKonstantin Belousov break; 1436db7f8e5SKonstantin Belousov case ACPI_NFIT_TYPE_CONTROL_REGION: 1446db7f8e5SKonstantin Belousov nfitctlreg = __containerof(nfithdr, 1456db7f8e5SKonstantin Belousov ACPI_NFIT_CONTROL_REGION, Header); 1466db7f8e5SKonstantin Belousov error = cb(nfitctlreg, arg); 1476db7f8e5SKonstantin Belousov break; 1486db7f8e5SKonstantin Belousov case ACPI_NFIT_TYPE_DATA_REGION: 1496db7f8e5SKonstantin Belousov nfitdtreg = __containerof(nfithdr, 1506db7f8e5SKonstantin Belousov ACPI_NFIT_DATA_REGION, Header); 1516db7f8e5SKonstantin Belousov error = cb(nfitdtreg, arg); 1526db7f8e5SKonstantin Belousov break; 1536db7f8e5SKonstantin Belousov case ACPI_NFIT_TYPE_FLUSH_ADDRESS: 1546db7f8e5SKonstantin Belousov nfitflshaddr = __containerof(nfithdr, 1556db7f8e5SKonstantin Belousov ACPI_NFIT_FLUSH_ADDRESS, Header); 1566db7f8e5SKonstantin Belousov error = cb(nfitflshaddr, arg); 1576db7f8e5SKonstantin Belousov break; 1586db7f8e5SKonstantin Belousov case ACPI_NFIT_TYPE_RESERVED: 1596db7f8e5SKonstantin Belousov default: 1606db7f8e5SKonstantin Belousov if (bootverbose) 1616db7f8e5SKonstantin Belousov printf("NFIT subtype %d unknown\n", 1626db7f8e5SKonstantin Belousov nfithdr->Type); 1636db7f8e5SKonstantin Belousov error = 0; 1646db7f8e5SKonstantin Belousov break; 1656db7f8e5SKonstantin Belousov } 1666db7f8e5SKonstantin Belousov if (error != 0) 1676db7f8e5SKonstantin Belousov break; 1686db7f8e5SKonstantin Belousov } 1696db7f8e5SKonstantin Belousov return (error); 1706db7f8e5SKonstantin Belousov } 1716db7f8e5SKonstantin Belousov 1726db7f8e5SKonstantin Belousov static int 1736db7f8e5SKonstantin Belousov nvdimm_probe(device_t dev) 1746db7f8e5SKonstantin Belousov { 1756db7f8e5SKonstantin Belousov 1766db7f8e5SKonstantin Belousov return (BUS_PROBE_NOWILDCARD); 1776db7f8e5SKonstantin Belousov } 1786db7f8e5SKonstantin Belousov 1796db7f8e5SKonstantin Belousov static int 1806db7f8e5SKonstantin Belousov nvdimm_attach(device_t dev) 1816db7f8e5SKonstantin Belousov { 1826db7f8e5SKonstantin Belousov struct nvdimm_dev *nv; 1836db7f8e5SKonstantin Belousov ACPI_TABLE_NFIT *nfitbl; 1846db7f8e5SKonstantin Belousov ACPI_HANDLE handle; 1856db7f8e5SKonstantin Belousov ACPI_STATUS status; 1866db7f8e5SKonstantin Belousov 1876db7f8e5SKonstantin Belousov nv = device_get_softc(dev); 188fc4a961aSKonstantin Belousov handle = nvdimm_root_get_acpi_handle(dev); 1896db7f8e5SKonstantin Belousov if (handle == NULL) 1906db7f8e5SKonstantin Belousov return (EINVAL); 1916db7f8e5SKonstantin Belousov nv->nv_dev = dev; 192fc4a961aSKonstantin Belousov nv->nv_handle = nvdimm_root_get_device_handle(dev); 1936db7f8e5SKonstantin Belousov 1946db7f8e5SKonstantin Belousov status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl); 1956db7f8e5SKonstantin Belousov if (ACPI_FAILURE(status)) { 1966db7f8e5SKonstantin Belousov if (bootverbose) 1976db7f8e5SKonstantin Belousov device_printf(dev, "cannot get NFIT\n"); 1986db7f8e5SKonstantin Belousov return (ENXIO); 1996db7f8e5SKonstantin Belousov } 2006db7f8e5SKonstantin Belousov nvdimm_iterate_nfit(nfitbl, ACPI_NFIT_TYPE_FLUSH_ADDRESS, 2016db7f8e5SKonstantin Belousov nvdimm_parse_flush_addr, nv); 2026db7f8e5SKonstantin Belousov AcpiPutTable(&nfitbl->Header); 2036db7f8e5SKonstantin Belousov return (0); 2046db7f8e5SKonstantin Belousov } 2056db7f8e5SKonstantin Belousov 2066db7f8e5SKonstantin Belousov static int 2076db7f8e5SKonstantin Belousov nvdimm_detach(device_t dev) 2086db7f8e5SKonstantin Belousov { 2096db7f8e5SKonstantin Belousov struct nvdimm_dev *nv; 2106db7f8e5SKonstantin Belousov 2116db7f8e5SKonstantin Belousov nv = device_get_softc(dev); 2126db7f8e5SKonstantin Belousov free(nv->nv_flush_addr, M_NVDIMM); 2136db7f8e5SKonstantin Belousov return (0); 2146db7f8e5SKonstantin Belousov } 2156db7f8e5SKonstantin Belousov 2166db7f8e5SKonstantin Belousov static int 2176db7f8e5SKonstantin Belousov nvdimm_suspend(device_t dev) 2186db7f8e5SKonstantin Belousov { 2196db7f8e5SKonstantin Belousov 2206db7f8e5SKonstantin Belousov return (0); 2216db7f8e5SKonstantin Belousov } 2226db7f8e5SKonstantin Belousov 2236db7f8e5SKonstantin Belousov static int 2246db7f8e5SKonstantin Belousov nvdimm_resume(device_t dev) 2256db7f8e5SKonstantin Belousov { 2266db7f8e5SKonstantin Belousov 2276db7f8e5SKonstantin Belousov return (0); 2286db7f8e5SKonstantin Belousov } 2296db7f8e5SKonstantin Belousov 230fc4a961aSKonstantin Belousov static ACPI_STATUS 231fc4a961aSKonstantin Belousov nvdimm_root_create_dev(ACPI_HANDLE handle, UINT32 nesting_level, void *context, 232fc4a961aSKonstantin Belousov void **return_value) 233fc4a961aSKonstantin Belousov { 234fc4a961aSKonstantin Belousov ACPI_STATUS status; 235fc4a961aSKonstantin Belousov ACPI_DEVICE_INFO *device_info; 236fc4a961aSKonstantin Belousov device_t parent, child; 237fc4a961aSKonstantin Belousov uintptr_t *ivars; 238fc4a961aSKonstantin Belousov 239fc4a961aSKonstantin Belousov parent = context; 240fc4a961aSKonstantin Belousov child = BUS_ADD_CHILD(parent, 100, "nvdimm", -1); 241fc4a961aSKonstantin Belousov if (child == NULL) { 242fc4a961aSKonstantin Belousov device_printf(parent, "failed to create nvdimm\n"); 243fc4a961aSKonstantin Belousov return_ACPI_STATUS(AE_ERROR); 244fc4a961aSKonstantin Belousov } 245fc4a961aSKonstantin Belousov status = AcpiGetObjectInfo(handle, &device_info); 246fc4a961aSKonstantin Belousov if (ACPI_FAILURE(status)) { 247fc4a961aSKonstantin Belousov device_printf(parent, "failed to get nvdimm device info\n"); 248fc4a961aSKonstantin Belousov return_ACPI_STATUS(AE_ERROR); 249fc4a961aSKonstantin Belousov } 250fc4a961aSKonstantin Belousov ivars = mallocarray(NVDIMM_ROOT_IVAR_MAX - 1, sizeof(uintptr_t), 251fc4a961aSKonstantin Belousov M_NVDIMM, M_ZERO | M_WAITOK); 252fc4a961aSKonstantin Belousov device_set_ivars(child, ivars); 253fc4a961aSKonstantin Belousov nvdimm_root_set_acpi_handle(child, handle); 254fc4a961aSKonstantin Belousov nvdimm_root_set_device_handle(child, device_info->Address); 255fc4a961aSKonstantin Belousov return_ACPI_STATUS(AE_OK); 256fc4a961aSKonstantin Belousov } 257fc4a961aSKonstantin Belousov 258fc4a961aSKonstantin Belousov static char *nvdimm_root_id[] = {"ACPI0012", NULL}; 259fc4a961aSKonstantin Belousov 260fc4a961aSKonstantin Belousov static int 261fc4a961aSKonstantin Belousov nvdimm_root_probe(device_t dev) 262fc4a961aSKonstantin Belousov { 263fc4a961aSKonstantin Belousov int rv; 264fc4a961aSKonstantin Belousov 265fc4a961aSKonstantin Belousov if (acpi_disabled("nvdimm")) 266fc4a961aSKonstantin Belousov return (ENXIO); 267fc4a961aSKonstantin Belousov rv = ACPI_ID_PROBE(device_get_parent(dev), dev, nvdimm_root_id, NULL); 268fc4a961aSKonstantin Belousov if (rv <= 0) 269fc4a961aSKonstantin Belousov device_set_desc(dev, "ACPI NVDIMM root device"); 270fc4a961aSKonstantin Belousov 271fc4a961aSKonstantin Belousov return (rv); 272fc4a961aSKonstantin Belousov } 273fc4a961aSKonstantin Belousov 274fc4a961aSKonstantin Belousov static int 275fc4a961aSKonstantin Belousov nvdimm_root_attach(device_t dev) 276fc4a961aSKonstantin Belousov { 277fc4a961aSKonstantin Belousov ACPI_HANDLE handle; 278fc4a961aSKonstantin Belousov ACPI_STATUS status; 279fc4a961aSKonstantin Belousov int error; 280fc4a961aSKonstantin Belousov 281fc4a961aSKonstantin Belousov handle = acpi_get_handle(dev); 282fc4a961aSKonstantin Belousov status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, handle, 1, 283fc4a961aSKonstantin Belousov nvdimm_root_create_dev, NULL, dev, NULL); 284fc4a961aSKonstantin Belousov if (ACPI_FAILURE(status)) 285fc4a961aSKonstantin Belousov device_printf(dev, "failed adding children\n"); 286fc4a961aSKonstantin Belousov error = bus_generic_attach(dev); 287fc4a961aSKonstantin Belousov return (error); 288fc4a961aSKonstantin Belousov } 289fc4a961aSKonstantin Belousov 290fc4a961aSKonstantin Belousov static int 291fc4a961aSKonstantin Belousov nvdimm_root_detach(device_t dev) 292fc4a961aSKonstantin Belousov { 293fc4a961aSKonstantin Belousov device_t *children; 294fc4a961aSKonstantin Belousov int i, error, num_children; 295fc4a961aSKonstantin Belousov 296fc4a961aSKonstantin Belousov error = bus_generic_detach(dev); 297fc4a961aSKonstantin Belousov if (error != 0) 298fc4a961aSKonstantin Belousov return (error); 299fc4a961aSKonstantin Belousov error = device_get_children(dev, &children, &num_children); 300fc4a961aSKonstantin Belousov if (error != 0) 301fc4a961aSKonstantin Belousov return (error); 302fc4a961aSKonstantin Belousov for (i = 0; i < num_children; i++) 303fc4a961aSKonstantin Belousov free(device_get_ivars(children[i]), M_NVDIMM); 304fc4a961aSKonstantin Belousov free(children, M_TEMP); 305fc4a961aSKonstantin Belousov error = device_delete_children(dev); 306fc4a961aSKonstantin Belousov return (error); 307fc4a961aSKonstantin Belousov } 308fc4a961aSKonstantin Belousov 309fc4a961aSKonstantin Belousov static int 310fc4a961aSKonstantin Belousov nvdimm_root_read_ivar(device_t dev, device_t child, int index, 311fc4a961aSKonstantin Belousov uintptr_t *result) 312fc4a961aSKonstantin Belousov { 313fc4a961aSKonstantin Belousov 314fc4a961aSKonstantin Belousov if (index < 0 || index >= NVDIMM_ROOT_IVAR_MAX) 315fc4a961aSKonstantin Belousov return (ENOENT); 316fc4a961aSKonstantin Belousov *result = ((uintptr_t *)device_get_ivars(child))[index]; 317fc4a961aSKonstantin Belousov return (0); 318fc4a961aSKonstantin Belousov } 319fc4a961aSKonstantin Belousov 320fc4a961aSKonstantin Belousov static int 321fc4a961aSKonstantin Belousov nvdimm_root_write_ivar(device_t dev, device_t child, int index, 322fc4a961aSKonstantin Belousov uintptr_t value) 323fc4a961aSKonstantin Belousov { 324fc4a961aSKonstantin Belousov 325fc4a961aSKonstantin Belousov if (index < 0 || index >= NVDIMM_ROOT_IVAR_MAX) 326fc4a961aSKonstantin Belousov return (ENOENT); 327fc4a961aSKonstantin Belousov ((uintptr_t *)device_get_ivars(child))[index] = value; 328fc4a961aSKonstantin Belousov return (0); 329fc4a961aSKonstantin Belousov } 330fc4a961aSKonstantin Belousov 3316db7f8e5SKonstantin Belousov static device_method_t nvdimm_methods[] = { 3326db7f8e5SKonstantin Belousov DEVMETHOD(device_probe, nvdimm_probe), 3336db7f8e5SKonstantin Belousov DEVMETHOD(device_attach, nvdimm_attach), 3346db7f8e5SKonstantin Belousov DEVMETHOD(device_detach, nvdimm_detach), 3356db7f8e5SKonstantin Belousov DEVMETHOD(device_suspend, nvdimm_suspend), 3366db7f8e5SKonstantin Belousov DEVMETHOD(device_resume, nvdimm_resume), 3376db7f8e5SKonstantin Belousov DEVMETHOD_END 3386db7f8e5SKonstantin Belousov }; 3396db7f8e5SKonstantin Belousov 3406db7f8e5SKonstantin Belousov static driver_t nvdimm_driver = { 3416db7f8e5SKonstantin Belousov "nvdimm", 3426db7f8e5SKonstantin Belousov nvdimm_methods, 3436db7f8e5SKonstantin Belousov sizeof(struct nvdimm_dev), 3446db7f8e5SKonstantin Belousov }; 3456db7f8e5SKonstantin Belousov 346fc4a961aSKonstantin Belousov static device_method_t nvdimm_root_methods[] = { 347fc4a961aSKonstantin Belousov DEVMETHOD(device_probe, nvdimm_root_probe), 348fc4a961aSKonstantin Belousov DEVMETHOD(device_attach, nvdimm_root_attach), 349fc4a961aSKonstantin Belousov DEVMETHOD(device_detach, nvdimm_root_detach), 350fc4a961aSKonstantin Belousov DEVMETHOD(bus_add_child, bus_generic_add_child), 351fc4a961aSKonstantin Belousov DEVMETHOD(bus_read_ivar, nvdimm_root_read_ivar), 352fc4a961aSKonstantin Belousov DEVMETHOD(bus_write_ivar, nvdimm_root_write_ivar), 353fc4a961aSKonstantin Belousov DEVMETHOD_END 354fc4a961aSKonstantin Belousov }; 3556db7f8e5SKonstantin Belousov 356fc4a961aSKonstantin Belousov static driver_t nvdimm_root_driver = { 357fc4a961aSKonstantin Belousov "nvdimm_root", 358fc4a961aSKonstantin Belousov nvdimm_root_methods, 359fc4a961aSKonstantin Belousov }; 3606db7f8e5SKonstantin Belousov 361fc4a961aSKonstantin Belousov DRIVER_MODULE(nvdimm_root, acpi, nvdimm_root_driver, nvdimm_root_devclass, NULL, 362fc4a961aSKonstantin Belousov NULL); 363fc4a961aSKonstantin Belousov DRIVER_MODULE(nvdimm, nvdimm_root, nvdimm_driver, nvdimm_devclass, NULL, NULL); 3646db7f8e5SKonstantin Belousov MODULE_DEPEND(nvdimm, acpi, 1, 1, 1); 365