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> 39ad30b2f2SBen Widawsky #include <sys/bitstring.h> 406db7f8e5SKonstantin Belousov #include <sys/bus.h> 416db7f8e5SKonstantin Belousov #include <sys/kernel.h> 426db7f8e5SKonstantin Belousov #include <sys/lock.h> 436db7f8e5SKonstantin Belousov #include <sys/malloc.h> 446db7f8e5SKonstantin Belousov #include <sys/module.h> 456db7f8e5SKonstantin Belousov #include <sys/uuid.h> 46963c89ffSConrad Meyer 476db7f8e5SKonstantin Belousov #include <contrib/dev/acpica/include/acpi.h> 486db7f8e5SKonstantin Belousov #include <contrib/dev/acpica/include/accommon.h> 496db7f8e5SKonstantin Belousov #include <contrib/dev/acpica/include/acuuid.h> 506db7f8e5SKonstantin Belousov #include <dev/acpica/acpivar.h> 51963c89ffSConrad Meyer 526db7f8e5SKonstantin Belousov #include <dev/nvdimm/nvdimm_var.h> 536db7f8e5SKonstantin Belousov 546db7f8e5SKonstantin Belousov #define _COMPONENT ACPI_OEM 556db7f8e5SKonstantin Belousov ACPI_MODULE_NAME("NVDIMM") 566db7f8e5SKonstantin Belousov 57ad30b2f2SBen Widawsky static struct uuid intel_nvdimm_dsm_uuid = 58ad30b2f2SBen Widawsky {0x4309AC30,0x0D11,0x11E4,0x91,0x91,{0x08,0x00,0x20,0x0C,0x9A,0x66}}; 59ad30b2f2SBen Widawsky #define INTEL_NVDIMM_DSM_REV 1 60ad30b2f2SBen Widawsky #define INTEL_NVDIMM_DSM_GET_LABEL_SIZE 4 61ad30b2f2SBen Widawsky #define INTEL_NVDIMM_DSM_GET_LABEL_DATA 5 62ad30b2f2SBen Widawsky 636db7f8e5SKonstantin Belousov static devclass_t nvdimm_devclass; 646db7f8e5SKonstantin Belousov MALLOC_DEFINE(M_NVDIMM, "nvdimm", "NVDIMM driver memory"); 656db7f8e5SKonstantin Belousov 66ad30b2f2SBen Widawsky static int 67ad30b2f2SBen Widawsky read_label_area_size(struct nvdimm_dev *nv) 68ad30b2f2SBen Widawsky { 69ad30b2f2SBen Widawsky ACPI_OBJECT *result_buffer; 70ad30b2f2SBen Widawsky ACPI_HANDLE handle; 71ad30b2f2SBen Widawsky ACPI_STATUS status; 72ad30b2f2SBen Widawsky ACPI_BUFFER result; 73ad30b2f2SBen Widawsky uint32_t *out; 74ad30b2f2SBen Widawsky int error; 75ad30b2f2SBen Widawsky 76ad30b2f2SBen Widawsky handle = nvdimm_root_get_acpi_handle(nv->nv_dev); 77ad30b2f2SBen Widawsky if (handle == NULL) 78ad30b2f2SBen Widawsky return (ENODEV); 79ad30b2f2SBen Widawsky result.Length = ACPI_ALLOCATE_BUFFER; 80ad30b2f2SBen Widawsky result.Pointer = NULL; 81ad30b2f2SBen Widawsky status = acpi_EvaluateDSM(handle, (uint8_t *)&intel_nvdimm_dsm_uuid, 82ad30b2f2SBen Widawsky INTEL_NVDIMM_DSM_REV, INTEL_NVDIMM_DSM_GET_LABEL_SIZE, NULL, 83ad30b2f2SBen Widawsky &result); 84ad30b2f2SBen Widawsky error = ENXIO; 85ad30b2f2SBen Widawsky if (ACPI_SUCCESS(status) && result.Pointer != NULL && 86ad30b2f2SBen Widawsky result.Length >= sizeof(ACPI_OBJECT)) { 87ad30b2f2SBen Widawsky result_buffer = result.Pointer; 88ad30b2f2SBen Widawsky if (result_buffer->Type == ACPI_TYPE_BUFFER && 89ad30b2f2SBen Widawsky result_buffer->Buffer.Length >= 12) { 90ad30b2f2SBen Widawsky out = (uint32_t *)result_buffer->Buffer.Pointer; 91ad30b2f2SBen Widawsky nv->label_area_size = out[1]; 92ad30b2f2SBen Widawsky nv->max_label_xfer = out[2]; 93ad30b2f2SBen Widawsky error = 0; 94ad30b2f2SBen Widawsky } 95ad30b2f2SBen Widawsky } 96ad30b2f2SBen Widawsky if (result.Pointer != NULL) 97ad30b2f2SBen Widawsky AcpiOsFree(result.Pointer); 98ad30b2f2SBen Widawsky return (error); 99ad30b2f2SBen Widawsky } 100ad30b2f2SBen Widawsky 101ad30b2f2SBen Widawsky static int 102ad30b2f2SBen Widawsky read_label_area(struct nvdimm_dev *nv, uint8_t *dest, off_t offset, 103ad30b2f2SBen Widawsky off_t length) 104ad30b2f2SBen Widawsky { 105ad30b2f2SBen Widawsky ACPI_BUFFER result; 106ad30b2f2SBen Widawsky ACPI_HANDLE handle; 107ad30b2f2SBen Widawsky ACPI_OBJECT params_pkg, params_buf, *result_buf; 108ad30b2f2SBen Widawsky ACPI_STATUS status; 109ad30b2f2SBen Widawsky uint32_t params[2]; 110ad30b2f2SBen Widawsky off_t to_read; 111ad30b2f2SBen Widawsky int error; 112ad30b2f2SBen Widawsky 113ad30b2f2SBen Widawsky error = 0; 114ad30b2f2SBen Widawsky handle = nvdimm_root_get_acpi_handle(nv->nv_dev); 115ad30b2f2SBen Widawsky if (offset < 0 || length <= 0 || 116ad30b2f2SBen Widawsky offset + length > nv->label_area_size || 117ad30b2f2SBen Widawsky handle == NULL) 118ad30b2f2SBen Widawsky return (ENODEV); 119ad30b2f2SBen Widawsky params_pkg.Type = ACPI_TYPE_PACKAGE; 120ad30b2f2SBen Widawsky params_pkg.Package.Count = 1; 121ad30b2f2SBen Widawsky params_pkg.Package.Elements = ¶ms_buf; 122ad30b2f2SBen Widawsky params_buf.Type = ACPI_TYPE_BUFFER; 123ad30b2f2SBen Widawsky params_buf.Buffer.Length = sizeof(params); 124ad30b2f2SBen Widawsky params_buf.Buffer.Pointer = (UINT8 *)params; 125ad30b2f2SBen Widawsky while (length > 0) { 126ad30b2f2SBen Widawsky to_read = MIN(length, nv->max_label_xfer); 127ad30b2f2SBen Widawsky params[0] = offset; 128ad30b2f2SBen Widawsky params[1] = to_read; 129ad30b2f2SBen Widawsky result.Length = ACPI_ALLOCATE_BUFFER; 130ad30b2f2SBen Widawsky result.Pointer = NULL; 131ad30b2f2SBen Widawsky status = acpi_EvaluateDSM(handle, 132ad30b2f2SBen Widawsky (uint8_t *)&intel_nvdimm_dsm_uuid, INTEL_NVDIMM_DSM_REV, 133ad30b2f2SBen Widawsky INTEL_NVDIMM_DSM_GET_LABEL_DATA, ¶ms_pkg, &result); 134ad30b2f2SBen Widawsky if (ACPI_FAILURE(status) || 135ad30b2f2SBen Widawsky result.Length < sizeof(ACPI_OBJECT) || 136ad30b2f2SBen Widawsky result.Pointer == NULL) { 137ad30b2f2SBen Widawsky error = ENXIO; 138ad30b2f2SBen Widawsky break; 139ad30b2f2SBen Widawsky } 140ad30b2f2SBen Widawsky result_buf = (ACPI_OBJECT *)result.Pointer; 141ad30b2f2SBen Widawsky if (result_buf->Type != ACPI_TYPE_BUFFER || 142ad30b2f2SBen Widawsky result_buf->Buffer.Pointer == NULL || 143ad30b2f2SBen Widawsky result_buf->Buffer.Length != 4 + to_read || 144ad30b2f2SBen Widawsky ((uint16_t *)result_buf->Buffer.Pointer)[0] != 0) { 145ad30b2f2SBen Widawsky error = ENXIO; 146ad30b2f2SBen Widawsky break; 147ad30b2f2SBen Widawsky } 148ad30b2f2SBen Widawsky bcopy(result_buf->Buffer.Pointer + 4, dest, to_read); 149ad30b2f2SBen Widawsky dest += to_read; 150ad30b2f2SBen Widawsky offset += to_read; 151ad30b2f2SBen Widawsky length -= to_read; 152ad30b2f2SBen Widawsky if (result.Pointer != NULL) { 153ad30b2f2SBen Widawsky AcpiOsFree(result.Pointer); 154ad30b2f2SBen Widawsky result.Pointer = NULL; 155ad30b2f2SBen Widawsky } 156ad30b2f2SBen Widawsky } 157ad30b2f2SBen Widawsky if (result.Pointer != NULL) 158ad30b2f2SBen Widawsky AcpiOsFree(result.Pointer); 159ad30b2f2SBen Widawsky return (error); 160ad30b2f2SBen Widawsky } 161ad30b2f2SBen Widawsky 162ad30b2f2SBen Widawsky static uint64_t 163ad30b2f2SBen Widawsky fletcher64(const void *data, size_t length) 164ad30b2f2SBen Widawsky { 165ad30b2f2SBen Widawsky size_t i; 166ad30b2f2SBen Widawsky uint32_t a, b; 167ad30b2f2SBen Widawsky const uint32_t *d; 168ad30b2f2SBen Widawsky 169ad30b2f2SBen Widawsky a = 0; 170ad30b2f2SBen Widawsky b = 0; 171ad30b2f2SBen Widawsky d = (const uint32_t *)data; 172ad30b2f2SBen Widawsky length = length / sizeof(uint32_t); 173ad30b2f2SBen Widawsky for (i = 0; i < length; i++) { 174ad30b2f2SBen Widawsky a += d[i]; 175ad30b2f2SBen Widawsky b += a; 176ad30b2f2SBen Widawsky } 177ad30b2f2SBen Widawsky return ((uint64_t)b << 32 | a); 178ad30b2f2SBen Widawsky } 179ad30b2f2SBen Widawsky 180ad30b2f2SBen Widawsky static bool 181ad30b2f2SBen Widawsky label_index_is_valid(struct nvdimm_label_index *index, uint32_t max_labels, 182ad30b2f2SBen Widawsky size_t size, size_t offset) 183ad30b2f2SBen Widawsky { 184ad30b2f2SBen Widawsky uint64_t checksum; 185ad30b2f2SBen Widawsky 186ad30b2f2SBen Widawsky index = (struct nvdimm_label_index *)((uint8_t *)index + offset); 187ad30b2f2SBen Widawsky if (strcmp(index->signature, NVDIMM_INDEX_BLOCK_SIGNATURE) != 0) 188ad30b2f2SBen Widawsky return false; 189ad30b2f2SBen Widawsky checksum = index->checksum; 190ad30b2f2SBen Widawsky index->checksum = 0; 191ad30b2f2SBen Widawsky if (checksum != fletcher64(index, size) || 192ad30b2f2SBen Widawsky index->this_offset != size * offset || index->this_size != size || 193ad30b2f2SBen Widawsky index->other_offset != size * (offset == 0 ? 1 : 0) || 194ad30b2f2SBen Widawsky index->seq == 0 || index->seq > 3 || index->slot_cnt > max_labels || 195ad30b2f2SBen Widawsky index->label_size != 1) 196ad30b2f2SBen Widawsky return false; 197ad30b2f2SBen Widawsky return true; 198ad30b2f2SBen Widawsky } 199ad30b2f2SBen Widawsky 200ad30b2f2SBen Widawsky static int 201ad30b2f2SBen Widawsky read_label(struct nvdimm_dev *nv, int num) 202ad30b2f2SBen Widawsky { 203ad30b2f2SBen Widawsky struct nvdimm_label_entry *entry, *i, *next; 204ad30b2f2SBen Widawsky uint64_t checksum; 205ad30b2f2SBen Widawsky off_t offset; 206ad30b2f2SBen Widawsky int error; 207ad30b2f2SBen Widawsky 208ad30b2f2SBen Widawsky offset = nv->label_index->label_offset + 209ad30b2f2SBen Widawsky num * (128 << nv->label_index->label_size); 210ad30b2f2SBen Widawsky entry = malloc(sizeof(*entry), M_NVDIMM, M_WAITOK); 211ad30b2f2SBen Widawsky error = read_label_area(nv, (uint8_t *)&entry->label, offset, 212ad30b2f2SBen Widawsky sizeof(struct nvdimm_label)); 213ad30b2f2SBen Widawsky if (error != 0) { 214ad30b2f2SBen Widawsky free(entry, M_NVDIMM); 215ad30b2f2SBen Widawsky return (error); 216ad30b2f2SBen Widawsky } 217ad30b2f2SBen Widawsky checksum = entry->label.checksum; 218ad30b2f2SBen Widawsky entry->label.checksum = 0; 219ad30b2f2SBen Widawsky if (checksum != fletcher64(&entry->label, sizeof(entry->label)) || 220ad30b2f2SBen Widawsky entry->label.slot != num) { 221ad30b2f2SBen Widawsky free(entry, M_NVDIMM); 222ad30b2f2SBen Widawsky return (ENXIO); 223ad30b2f2SBen Widawsky } 224ad30b2f2SBen Widawsky 225ad30b2f2SBen Widawsky /* Insertion ordered by dimm_phys_addr */ 226ad30b2f2SBen Widawsky if (SLIST_EMPTY(&nv->labels) || 227ad30b2f2SBen Widawsky entry->label.dimm_phys_addr <= 228ad30b2f2SBen Widawsky SLIST_FIRST(&nv->labels)->label.dimm_phys_addr) { 229ad30b2f2SBen Widawsky SLIST_INSERT_HEAD(&nv->labels, entry, link); 230ad30b2f2SBen Widawsky return (0); 231ad30b2f2SBen Widawsky } 232ad30b2f2SBen Widawsky SLIST_FOREACH_SAFE(i, &nv->labels, link, next) { 233ad30b2f2SBen Widawsky if (next == NULL || 234ad30b2f2SBen Widawsky entry->label.dimm_phys_addr <= next->label.dimm_phys_addr) { 235ad30b2f2SBen Widawsky SLIST_INSERT_AFTER(i, entry, link); 236ad30b2f2SBen Widawsky return (0); 237ad30b2f2SBen Widawsky } 238ad30b2f2SBen Widawsky } 239ad30b2f2SBen Widawsky __unreachable(); 240ad30b2f2SBen Widawsky } 241ad30b2f2SBen Widawsky 242ad30b2f2SBen Widawsky static int 243ad30b2f2SBen Widawsky read_labels(struct nvdimm_dev *nv) 244ad30b2f2SBen Widawsky { 245ad30b2f2SBen Widawsky struct nvdimm_label_index *indices; 246ad30b2f2SBen Widawsky size_t bitfield_size, index_size, num_labels; 247ad30b2f2SBen Widawsky int error, n; 248ad30b2f2SBen Widawsky bool index_0_valid, index_1_valid; 249ad30b2f2SBen Widawsky 250ad30b2f2SBen Widawsky for (index_size = 256; ; index_size += 256) { 251ad30b2f2SBen Widawsky num_labels = 8 * (index_size - 252ad30b2f2SBen Widawsky sizeof(struct nvdimm_label_index)); 253ad30b2f2SBen Widawsky if (index_size + num_labels * sizeof(struct nvdimm_label) >= 254ad30b2f2SBen Widawsky nv->label_area_size) 255ad30b2f2SBen Widawsky break; 256ad30b2f2SBen Widawsky } 257ad30b2f2SBen Widawsky num_labels = (nv->label_area_size - index_size) / 258ad30b2f2SBen Widawsky sizeof(struct nvdimm_label); 259ad30b2f2SBen Widawsky bitfield_size = roundup2(num_labels, 8) / 8; 260ad30b2f2SBen Widawsky indices = malloc(2 * index_size, M_NVDIMM, M_WAITOK); 261ad30b2f2SBen Widawsky error = read_label_area(nv, (void *)indices, 0, 2 * index_size); 262ad30b2f2SBen Widawsky if (error != 0) { 263ad30b2f2SBen Widawsky free(indices, M_NVDIMM); 264ad30b2f2SBen Widawsky return (error); 265ad30b2f2SBen Widawsky } 266ad30b2f2SBen Widawsky index_0_valid = label_index_is_valid(indices, num_labels, index_size, 267ad30b2f2SBen Widawsky 0); 268ad30b2f2SBen Widawsky index_1_valid = label_index_is_valid(indices, num_labels, index_size, 269ad30b2f2SBen Widawsky 1); 270ad30b2f2SBen Widawsky if (!index_0_valid && !index_1_valid) { 271ad30b2f2SBen Widawsky free(indices, M_NVDIMM); 272ad30b2f2SBen Widawsky return (ENXIO); 273ad30b2f2SBen Widawsky } 274ad30b2f2SBen Widawsky if (index_0_valid && index_1_valid && 275ad30b2f2SBen Widawsky (indices[1].seq > indices[0].seq || 276ad30b2f2SBen Widawsky (indices[1].seq == 1 && indices[0].seq == 3))) 277ad30b2f2SBen Widawsky index_0_valid = false; 278ad30b2f2SBen Widawsky nv->label_index = malloc(index_size, M_NVDIMM, M_WAITOK); 279ad30b2f2SBen Widawsky bcopy(indices + (index_0_valid ? 0 : 1), nv->label_index, index_size); 280ad30b2f2SBen Widawsky free(indices, M_NVDIMM); 281ad30b2f2SBen Widawsky for (bit_ffc_at((bitstr_t *)nv->label_index->free, 0, num_labels, &n); 282ad30b2f2SBen Widawsky n >= 0; 283ad30b2f2SBen Widawsky bit_ffc_at((bitstr_t *)nv->label_index->free, n + 1, num_labels, 284ad30b2f2SBen Widawsky &n)) { 285ad30b2f2SBen Widawsky read_label(nv, n); 286ad30b2f2SBen Widawsky } 287ad30b2f2SBen Widawsky return (0); 288ad30b2f2SBen Widawsky } 289ad30b2f2SBen Widawsky 2906db7f8e5SKonstantin Belousov struct nvdimm_dev * 2916db7f8e5SKonstantin Belousov nvdimm_find_by_handle(nfit_handle_t nv_handle) 2926db7f8e5SKonstantin Belousov { 293fc4a961aSKonstantin Belousov struct nvdimm_dev *res; 294fc4a961aSKonstantin Belousov device_t *dimms; 295fc4a961aSKonstantin Belousov int i, error, num_dimms; 2966db7f8e5SKonstantin Belousov 2976db7f8e5SKonstantin Belousov res = NULL; 298fc4a961aSKonstantin Belousov error = devclass_get_devices(nvdimm_devclass, &dimms, &num_dimms); 299fc4a961aSKonstantin Belousov if (error != 0) 300fc4a961aSKonstantin Belousov return (NULL); 301fc4a961aSKonstantin Belousov for (i = 0; i < num_dimms; i++) { 302fc4a961aSKonstantin Belousov if (nvdimm_root_get_device_handle(dimms[i]) == nv_handle) { 303fc4a961aSKonstantin Belousov res = device_get_softc(dimms[i]); 3046db7f8e5SKonstantin Belousov break; 3056db7f8e5SKonstantin Belousov } 3066db7f8e5SKonstantin Belousov } 307fc4a961aSKonstantin Belousov free(dimms, M_TEMP); 3086db7f8e5SKonstantin Belousov return (res); 3096db7f8e5SKonstantin Belousov } 3106db7f8e5SKonstantin Belousov 3116db7f8e5SKonstantin Belousov static int 3126db7f8e5SKonstantin Belousov nvdimm_probe(device_t dev) 3136db7f8e5SKonstantin Belousov { 3146db7f8e5SKonstantin Belousov 3156db7f8e5SKonstantin Belousov return (BUS_PROBE_NOWILDCARD); 3166db7f8e5SKonstantin Belousov } 3176db7f8e5SKonstantin Belousov 3186db7f8e5SKonstantin Belousov static int 3196db7f8e5SKonstantin Belousov nvdimm_attach(device_t dev) 3206db7f8e5SKonstantin Belousov { 3216db7f8e5SKonstantin Belousov struct nvdimm_dev *nv; 3226db7f8e5SKonstantin Belousov ACPI_TABLE_NFIT *nfitbl; 3236db7f8e5SKonstantin Belousov ACPI_HANDLE handle; 3246db7f8e5SKonstantin Belousov ACPI_STATUS status; 325ad30b2f2SBen Widawsky int error; 3266db7f8e5SKonstantin Belousov 3276db7f8e5SKonstantin Belousov nv = device_get_softc(dev); 328fc4a961aSKonstantin Belousov handle = nvdimm_root_get_acpi_handle(dev); 329963c89ffSConrad Meyer MPASS(handle != NULL); 3306db7f8e5SKonstantin Belousov nv->nv_dev = dev; 331fc4a961aSKonstantin Belousov nv->nv_handle = nvdimm_root_get_device_handle(dev); 3326db7f8e5SKonstantin Belousov 3336db7f8e5SKonstantin Belousov status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl); 3346db7f8e5SKonstantin Belousov if (ACPI_FAILURE(status)) { 3356db7f8e5SKonstantin Belousov if (bootverbose) 3366db7f8e5SKonstantin Belousov device_printf(dev, "cannot get NFIT\n"); 3376db7f8e5SKonstantin Belousov return (ENXIO); 3386db7f8e5SKonstantin Belousov } 3397674dce0SKonstantin Belousov acpi_nfit_get_flush_addrs(nfitbl, nv->nv_handle, &nv->nv_flush_addr, 3407674dce0SKonstantin Belousov &nv->nv_flush_addr_cnt); 3416db7f8e5SKonstantin Belousov AcpiPutTable(&nfitbl->Header); 342ad30b2f2SBen Widawsky error = read_label_area_size(nv); 343ad30b2f2SBen Widawsky if (error == 0) { 344ad30b2f2SBen Widawsky /* 345ad30b2f2SBen Widawsky * Ignoring errors reading labels. Not all NVDIMMs 346ad30b2f2SBen Widawsky * support labels and namespaces. 347ad30b2f2SBen Widawsky */ 348ad30b2f2SBen Widawsky read_labels(nv); 349ad30b2f2SBen Widawsky } 3506db7f8e5SKonstantin Belousov return (0); 3516db7f8e5SKonstantin Belousov } 3526db7f8e5SKonstantin Belousov 3536db7f8e5SKonstantin Belousov static int 3546db7f8e5SKonstantin Belousov nvdimm_detach(device_t dev) 3556db7f8e5SKonstantin Belousov { 3566db7f8e5SKonstantin Belousov struct nvdimm_dev *nv; 357ad30b2f2SBen Widawsky struct nvdimm_label_entry *label, *next; 3586db7f8e5SKonstantin Belousov 3596db7f8e5SKonstantin Belousov nv = device_get_softc(dev); 3606db7f8e5SKonstantin Belousov free(nv->nv_flush_addr, M_NVDIMM); 361ad30b2f2SBen Widawsky free(nv->label_index, M_NVDIMM); 362ad30b2f2SBen Widawsky SLIST_FOREACH_SAFE(label, &nv->labels, link, next) { 363ad30b2f2SBen Widawsky SLIST_REMOVE_HEAD(&nv->labels, link); 364ad30b2f2SBen Widawsky free(label, M_NVDIMM); 365ad30b2f2SBen Widawsky } 3666db7f8e5SKonstantin Belousov return (0); 3676db7f8e5SKonstantin Belousov } 3686db7f8e5SKonstantin Belousov 3696db7f8e5SKonstantin Belousov static int 3706db7f8e5SKonstantin Belousov nvdimm_suspend(device_t dev) 3716db7f8e5SKonstantin Belousov { 3726db7f8e5SKonstantin Belousov 3736db7f8e5SKonstantin Belousov return (0); 3746db7f8e5SKonstantin Belousov } 3756db7f8e5SKonstantin Belousov 3766db7f8e5SKonstantin Belousov static int 3776db7f8e5SKonstantin Belousov nvdimm_resume(device_t dev) 3786db7f8e5SKonstantin Belousov { 3796db7f8e5SKonstantin Belousov 3806db7f8e5SKonstantin Belousov return (0); 3816db7f8e5SKonstantin Belousov } 3826db7f8e5SKonstantin Belousov 3836db7f8e5SKonstantin Belousov static device_method_t nvdimm_methods[] = { 3846db7f8e5SKonstantin Belousov DEVMETHOD(device_probe, nvdimm_probe), 3856db7f8e5SKonstantin Belousov DEVMETHOD(device_attach, nvdimm_attach), 3866db7f8e5SKonstantin Belousov DEVMETHOD(device_detach, nvdimm_detach), 3876db7f8e5SKonstantin Belousov DEVMETHOD(device_suspend, nvdimm_suspend), 3886db7f8e5SKonstantin Belousov DEVMETHOD(device_resume, nvdimm_resume), 3896db7f8e5SKonstantin Belousov DEVMETHOD_END 3906db7f8e5SKonstantin Belousov }; 3916db7f8e5SKonstantin Belousov 3926db7f8e5SKonstantin Belousov static driver_t nvdimm_driver = { 3936db7f8e5SKonstantin Belousov "nvdimm", 3946db7f8e5SKonstantin Belousov nvdimm_methods, 3956db7f8e5SKonstantin Belousov sizeof(struct nvdimm_dev), 3966db7f8e5SKonstantin Belousov }; 3976db7f8e5SKonstantin Belousov 398963c89ffSConrad Meyer DRIVER_MODULE(nvdimm, nvdimm_acpi_root, nvdimm_driver, nvdimm_devclass, NULL, 399fc4a961aSKonstantin Belousov NULL); 4006db7f8e5SKonstantin Belousov MODULE_DEPEND(nvdimm, acpi, 1, 1, 1); 401