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> 38c79cee71SKyle Evans #include <sys/systm.h> 396db7f8e5SKonstantin Belousov #include <sys/bio.h> 40ad30b2f2SBen Widawsky #include <sys/bitstring.h> 416db7f8e5SKonstantin Belousov #include <sys/bus.h> 426db7f8e5SKonstantin Belousov #include <sys/kernel.h> 436db7f8e5SKonstantin Belousov #include <sys/lock.h> 446db7f8e5SKonstantin Belousov #include <sys/malloc.h> 456db7f8e5SKonstantin Belousov #include <sys/module.h> 466db7f8e5SKonstantin Belousov #include <sys/uuid.h> 47963c89ffSConrad Meyer 486db7f8e5SKonstantin Belousov #include <contrib/dev/acpica/include/acpi.h> 496db7f8e5SKonstantin Belousov #include <contrib/dev/acpica/include/accommon.h> 506db7f8e5SKonstantin Belousov #include <contrib/dev/acpica/include/acuuid.h> 516db7f8e5SKonstantin Belousov #include <dev/acpica/acpivar.h> 52963c89ffSConrad Meyer 536db7f8e5SKonstantin Belousov #include <dev/nvdimm/nvdimm_var.h> 546db7f8e5SKonstantin Belousov 556db7f8e5SKonstantin Belousov #define _COMPONENT ACPI_OEM 566db7f8e5SKonstantin Belousov ACPI_MODULE_NAME("NVDIMM") 576db7f8e5SKonstantin Belousov 58ad30b2f2SBen Widawsky static struct uuid intel_nvdimm_dsm_uuid = 59ad30b2f2SBen Widawsky {0x4309AC30,0x0D11,0x11E4,0x91,0x91,{0x08,0x00,0x20,0x0C,0x9A,0x66}}; 60ad30b2f2SBen Widawsky #define INTEL_NVDIMM_DSM_REV 1 61ad30b2f2SBen Widawsky #define INTEL_NVDIMM_DSM_GET_LABEL_SIZE 4 62ad30b2f2SBen Widawsky #define INTEL_NVDIMM_DSM_GET_LABEL_DATA 5 63ad30b2f2SBen Widawsky 646db7f8e5SKonstantin Belousov static devclass_t nvdimm_devclass; 656db7f8e5SKonstantin Belousov MALLOC_DEFINE(M_NVDIMM, "nvdimm", "NVDIMM driver memory"); 666db7f8e5SKonstantin Belousov 67ad30b2f2SBen Widawsky static int 68ad30b2f2SBen Widawsky read_label_area_size(struct nvdimm_dev *nv) 69ad30b2f2SBen Widawsky { 70ad30b2f2SBen Widawsky ACPI_OBJECT *result_buffer; 71ad30b2f2SBen Widawsky ACPI_HANDLE handle; 72ad30b2f2SBen Widawsky ACPI_STATUS status; 73ad30b2f2SBen Widawsky ACPI_BUFFER result; 74ad30b2f2SBen Widawsky uint32_t *out; 75ad30b2f2SBen Widawsky int error; 76ad30b2f2SBen Widawsky 77ad30b2f2SBen Widawsky handle = nvdimm_root_get_acpi_handle(nv->nv_dev); 78ad30b2f2SBen Widawsky if (handle == NULL) 79ad30b2f2SBen Widawsky return (ENODEV); 80ad30b2f2SBen Widawsky result.Length = ACPI_ALLOCATE_BUFFER; 81ad30b2f2SBen Widawsky result.Pointer = NULL; 82ad30b2f2SBen Widawsky status = acpi_EvaluateDSM(handle, (uint8_t *)&intel_nvdimm_dsm_uuid, 83ad30b2f2SBen Widawsky INTEL_NVDIMM_DSM_REV, INTEL_NVDIMM_DSM_GET_LABEL_SIZE, NULL, 84ad30b2f2SBen Widawsky &result); 85ad30b2f2SBen Widawsky error = ENXIO; 86ad30b2f2SBen Widawsky if (ACPI_SUCCESS(status) && result.Pointer != NULL && 87ad30b2f2SBen Widawsky result.Length >= sizeof(ACPI_OBJECT)) { 88ad30b2f2SBen Widawsky result_buffer = result.Pointer; 89ad30b2f2SBen Widawsky if (result_buffer->Type == ACPI_TYPE_BUFFER && 90ad30b2f2SBen Widawsky result_buffer->Buffer.Length >= 12) { 91ad30b2f2SBen Widawsky out = (uint32_t *)result_buffer->Buffer.Pointer; 92ad30b2f2SBen Widawsky nv->label_area_size = out[1]; 93ad30b2f2SBen Widawsky nv->max_label_xfer = out[2]; 94ad30b2f2SBen Widawsky error = 0; 95ad30b2f2SBen Widawsky } 96ad30b2f2SBen Widawsky } 97ad30b2f2SBen Widawsky if (result.Pointer != NULL) 98ad30b2f2SBen Widawsky AcpiOsFree(result.Pointer); 99ad30b2f2SBen Widawsky return (error); 100ad30b2f2SBen Widawsky } 101ad30b2f2SBen Widawsky 102ad30b2f2SBen Widawsky static int 103ad30b2f2SBen Widawsky read_label_area(struct nvdimm_dev *nv, uint8_t *dest, off_t offset, 104ad30b2f2SBen Widawsky off_t length) 105ad30b2f2SBen Widawsky { 106ad30b2f2SBen Widawsky ACPI_BUFFER result; 107ad30b2f2SBen Widawsky ACPI_HANDLE handle; 108ad30b2f2SBen Widawsky ACPI_OBJECT params_pkg, params_buf, *result_buf; 109ad30b2f2SBen Widawsky ACPI_STATUS status; 110ad30b2f2SBen Widawsky uint32_t params[2]; 111ad30b2f2SBen Widawsky off_t to_read; 112ad30b2f2SBen Widawsky int error; 113ad30b2f2SBen Widawsky 114ad30b2f2SBen Widawsky error = 0; 115ad30b2f2SBen Widawsky handle = nvdimm_root_get_acpi_handle(nv->nv_dev); 116ad30b2f2SBen Widawsky if (offset < 0 || length <= 0 || 117ad30b2f2SBen Widawsky offset + length > nv->label_area_size || 118ad30b2f2SBen Widawsky handle == NULL) 119ad30b2f2SBen Widawsky return (ENODEV); 120ad30b2f2SBen Widawsky params_pkg.Type = ACPI_TYPE_PACKAGE; 121ad30b2f2SBen Widawsky params_pkg.Package.Count = 1; 122ad30b2f2SBen Widawsky params_pkg.Package.Elements = ¶ms_buf; 123ad30b2f2SBen Widawsky params_buf.Type = ACPI_TYPE_BUFFER; 124ad30b2f2SBen Widawsky params_buf.Buffer.Length = sizeof(params); 125ad30b2f2SBen Widawsky params_buf.Buffer.Pointer = (UINT8 *)params; 126ad30b2f2SBen Widawsky while (length > 0) { 127ad30b2f2SBen Widawsky to_read = MIN(length, nv->max_label_xfer); 128ad30b2f2SBen Widawsky params[0] = offset; 129ad30b2f2SBen Widawsky params[1] = to_read; 130ad30b2f2SBen Widawsky result.Length = ACPI_ALLOCATE_BUFFER; 131ad30b2f2SBen Widawsky result.Pointer = NULL; 132ad30b2f2SBen Widawsky status = acpi_EvaluateDSM(handle, 133ad30b2f2SBen Widawsky (uint8_t *)&intel_nvdimm_dsm_uuid, INTEL_NVDIMM_DSM_REV, 134ad30b2f2SBen Widawsky INTEL_NVDIMM_DSM_GET_LABEL_DATA, ¶ms_pkg, &result); 135ad30b2f2SBen Widawsky if (ACPI_FAILURE(status) || 136ad30b2f2SBen Widawsky result.Length < sizeof(ACPI_OBJECT) || 137ad30b2f2SBen Widawsky result.Pointer == NULL) { 138ad30b2f2SBen Widawsky error = ENXIO; 139ad30b2f2SBen Widawsky break; 140ad30b2f2SBen Widawsky } 141ad30b2f2SBen Widawsky result_buf = (ACPI_OBJECT *)result.Pointer; 142ad30b2f2SBen Widawsky if (result_buf->Type != ACPI_TYPE_BUFFER || 143ad30b2f2SBen Widawsky result_buf->Buffer.Pointer == NULL || 144ad30b2f2SBen Widawsky result_buf->Buffer.Length != 4 + to_read || 145ad30b2f2SBen Widawsky ((uint16_t *)result_buf->Buffer.Pointer)[0] != 0) { 146ad30b2f2SBen Widawsky error = ENXIO; 147ad30b2f2SBen Widawsky break; 148ad30b2f2SBen Widawsky } 149ad30b2f2SBen Widawsky bcopy(result_buf->Buffer.Pointer + 4, dest, to_read); 150ad30b2f2SBen Widawsky dest += to_read; 151ad30b2f2SBen Widawsky offset += to_read; 152ad30b2f2SBen Widawsky length -= to_read; 153ad30b2f2SBen Widawsky if (result.Pointer != NULL) { 154ad30b2f2SBen Widawsky AcpiOsFree(result.Pointer); 155ad30b2f2SBen Widawsky result.Pointer = NULL; 156ad30b2f2SBen Widawsky } 157ad30b2f2SBen Widawsky } 158ad30b2f2SBen Widawsky if (result.Pointer != NULL) 159ad30b2f2SBen Widawsky AcpiOsFree(result.Pointer); 160ad30b2f2SBen Widawsky return (error); 161ad30b2f2SBen Widawsky } 162ad30b2f2SBen Widawsky 163ad30b2f2SBen Widawsky static uint64_t 164ad30b2f2SBen Widawsky fletcher64(const void *data, size_t length) 165ad30b2f2SBen Widawsky { 166ad30b2f2SBen Widawsky size_t i; 167ad30b2f2SBen Widawsky uint32_t a, b; 168ad30b2f2SBen Widawsky const uint32_t *d; 169ad30b2f2SBen Widawsky 170ad30b2f2SBen Widawsky a = 0; 171ad30b2f2SBen Widawsky b = 0; 172ad30b2f2SBen Widawsky d = (const uint32_t *)data; 173ad30b2f2SBen Widawsky length = length / sizeof(uint32_t); 174ad30b2f2SBen Widawsky for (i = 0; i < length; i++) { 175ad30b2f2SBen Widawsky a += d[i]; 176ad30b2f2SBen Widawsky b += a; 177ad30b2f2SBen Widawsky } 178ad30b2f2SBen Widawsky return ((uint64_t)b << 32 | a); 179ad30b2f2SBen Widawsky } 180ad30b2f2SBen Widawsky 181ad30b2f2SBen Widawsky static bool 182ad30b2f2SBen Widawsky label_index_is_valid(struct nvdimm_label_index *index, uint32_t max_labels, 183ad30b2f2SBen Widawsky size_t size, size_t offset) 184ad30b2f2SBen Widawsky { 185ad30b2f2SBen Widawsky uint64_t checksum; 186ad30b2f2SBen Widawsky 187178d6bc8SD Scott Phillips index = (struct nvdimm_label_index *)((uint8_t *)index + size * offset); 188ad30b2f2SBen Widawsky if (strcmp(index->signature, NVDIMM_INDEX_BLOCK_SIGNATURE) != 0) 189ad30b2f2SBen Widawsky return false; 190ad30b2f2SBen Widawsky checksum = index->checksum; 191ad30b2f2SBen Widawsky index->checksum = 0; 192ad30b2f2SBen Widawsky if (checksum != fletcher64(index, size) || 193ad30b2f2SBen Widawsky index->this_offset != size * offset || index->this_size != size || 194ad30b2f2SBen Widawsky index->other_offset != size * (offset == 0 ? 1 : 0) || 195ad30b2f2SBen Widawsky index->seq == 0 || index->seq > 3 || index->slot_cnt > max_labels || 196ad30b2f2SBen Widawsky index->label_size != 1) 197ad30b2f2SBen Widawsky return false; 198ad30b2f2SBen Widawsky return true; 199ad30b2f2SBen Widawsky } 200ad30b2f2SBen Widawsky 201ad30b2f2SBen Widawsky static int 202ad30b2f2SBen Widawsky read_label(struct nvdimm_dev *nv, int num) 203ad30b2f2SBen Widawsky { 204ad30b2f2SBen Widawsky struct nvdimm_label_entry *entry, *i, *next; 205ad30b2f2SBen Widawsky uint64_t checksum; 206ad30b2f2SBen Widawsky off_t offset; 207ad30b2f2SBen Widawsky int error; 208ad30b2f2SBen Widawsky 209ad30b2f2SBen Widawsky offset = nv->label_index->label_offset + 210ad30b2f2SBen Widawsky num * (128 << nv->label_index->label_size); 211ad30b2f2SBen Widawsky entry = malloc(sizeof(*entry), M_NVDIMM, M_WAITOK); 212ad30b2f2SBen Widawsky error = read_label_area(nv, (uint8_t *)&entry->label, offset, 213ad30b2f2SBen Widawsky sizeof(struct nvdimm_label)); 214ad30b2f2SBen Widawsky if (error != 0) { 215ad30b2f2SBen Widawsky free(entry, M_NVDIMM); 216ad30b2f2SBen Widawsky return (error); 217ad30b2f2SBen Widawsky } 218ad30b2f2SBen Widawsky checksum = entry->label.checksum; 219ad30b2f2SBen Widawsky entry->label.checksum = 0; 220ad30b2f2SBen Widawsky if (checksum != fletcher64(&entry->label, sizeof(entry->label)) || 221ad30b2f2SBen Widawsky entry->label.slot != num) { 222ad30b2f2SBen Widawsky free(entry, M_NVDIMM); 223ad30b2f2SBen Widawsky return (ENXIO); 224ad30b2f2SBen Widawsky } 225ad30b2f2SBen Widawsky 226ad30b2f2SBen Widawsky /* Insertion ordered by dimm_phys_addr */ 227ad30b2f2SBen Widawsky if (SLIST_EMPTY(&nv->labels) || 228ad30b2f2SBen Widawsky entry->label.dimm_phys_addr <= 229ad30b2f2SBen Widawsky SLIST_FIRST(&nv->labels)->label.dimm_phys_addr) { 230ad30b2f2SBen Widawsky SLIST_INSERT_HEAD(&nv->labels, entry, link); 231ad30b2f2SBen Widawsky return (0); 232ad30b2f2SBen Widawsky } 233ad30b2f2SBen Widawsky SLIST_FOREACH_SAFE(i, &nv->labels, link, next) { 234ad30b2f2SBen Widawsky if (next == NULL || 235ad30b2f2SBen Widawsky entry->label.dimm_phys_addr <= next->label.dimm_phys_addr) { 236ad30b2f2SBen Widawsky SLIST_INSERT_AFTER(i, entry, link); 237ad30b2f2SBen Widawsky return (0); 238ad30b2f2SBen Widawsky } 239ad30b2f2SBen Widawsky } 240c79cee71SKyle Evans __assert_unreachable(); 241ad30b2f2SBen Widawsky } 242ad30b2f2SBen Widawsky 243ad30b2f2SBen Widawsky static int 244ad30b2f2SBen Widawsky read_labels(struct nvdimm_dev *nv) 245ad30b2f2SBen Widawsky { 246178d6bc8SD Scott Phillips struct nvdimm_label_index *indices, *index1; 247ad30b2f2SBen Widawsky size_t bitfield_size, index_size, num_labels; 248ad30b2f2SBen Widawsky int error, n; 249ad30b2f2SBen Widawsky bool index_0_valid, index_1_valid; 250ad30b2f2SBen Widawsky 251ad30b2f2SBen Widawsky for (index_size = 256; ; index_size += 256) { 252ad30b2f2SBen Widawsky num_labels = 8 * (index_size - 253ad30b2f2SBen Widawsky sizeof(struct nvdimm_label_index)); 254ad30b2f2SBen Widawsky if (index_size + num_labels * sizeof(struct nvdimm_label) >= 255ad30b2f2SBen Widawsky nv->label_area_size) 256ad30b2f2SBen Widawsky break; 257ad30b2f2SBen Widawsky } 258ad30b2f2SBen Widawsky num_labels = (nv->label_area_size - index_size) / 259ad30b2f2SBen Widawsky sizeof(struct nvdimm_label); 260ad30b2f2SBen Widawsky bitfield_size = roundup2(num_labels, 8) / 8; 261ad30b2f2SBen Widawsky indices = malloc(2 * index_size, M_NVDIMM, M_WAITOK); 262178d6bc8SD Scott Phillips index1 = (void *)((uint8_t *)indices + index_size); 263ad30b2f2SBen Widawsky error = read_label_area(nv, (void *)indices, 0, 2 * index_size); 264ad30b2f2SBen Widawsky if (error != 0) { 265ad30b2f2SBen Widawsky free(indices, M_NVDIMM); 266ad30b2f2SBen Widawsky return (error); 267ad30b2f2SBen Widawsky } 268ad30b2f2SBen Widawsky index_0_valid = label_index_is_valid(indices, num_labels, index_size, 269ad30b2f2SBen Widawsky 0); 270ad30b2f2SBen Widawsky index_1_valid = label_index_is_valid(indices, num_labels, index_size, 271ad30b2f2SBen Widawsky 1); 272ad30b2f2SBen Widawsky if (!index_0_valid && !index_1_valid) { 273ad30b2f2SBen Widawsky free(indices, M_NVDIMM); 274ad30b2f2SBen Widawsky return (ENXIO); 275ad30b2f2SBen Widawsky } 276178d6bc8SD Scott Phillips if (index_0_valid && index_1_valid) { 277178d6bc8SD Scott Phillips if (((int)indices->seq - (int)index1->seq + 3) % 3 == 1) { 278178d6bc8SD Scott Phillips /* index 0 was more recently updated */ 279178d6bc8SD Scott Phillips index_1_valid = false; 280178d6bc8SD Scott Phillips } else { 281178d6bc8SD Scott Phillips /* 282178d6bc8SD Scott Phillips * either index 1 was more recently updated, 283178d6bc8SD Scott Phillips * or the sequence numbers are equal, in which 284178d6bc8SD Scott Phillips * case the specification says the block with 285178d6bc8SD Scott Phillips * the higher offset is to be treated as valid 286178d6bc8SD Scott Phillips */ 287ad30b2f2SBen Widawsky index_0_valid = false; 288178d6bc8SD Scott Phillips } 289178d6bc8SD Scott Phillips } 290ad30b2f2SBen Widawsky nv->label_index = malloc(index_size, M_NVDIMM, M_WAITOK); 291178d6bc8SD Scott Phillips bcopy(index_0_valid ? indices : index1, nv->label_index, index_size); 292ad30b2f2SBen Widawsky free(indices, M_NVDIMM); 293178d6bc8SD Scott Phillips bit_ffc_at((bitstr_t *)nv->label_index->free, 0, 294178d6bc8SD Scott Phillips nv->label_index->slot_cnt, &n); 295178d6bc8SD Scott Phillips while (n >= 0) { 296ad30b2f2SBen Widawsky read_label(nv, n); 297178d6bc8SD Scott Phillips bit_ffc_at((bitstr_t *)nv->label_index->free, n + 1, 298178d6bc8SD Scott Phillips nv->label_index->slot_cnt, &n); 299ad30b2f2SBen Widawsky } 300ad30b2f2SBen Widawsky return (0); 301ad30b2f2SBen Widawsky } 302ad30b2f2SBen Widawsky 3036db7f8e5SKonstantin Belousov struct nvdimm_dev * 3046db7f8e5SKonstantin Belousov nvdimm_find_by_handle(nfit_handle_t nv_handle) 3056db7f8e5SKonstantin Belousov { 306fc4a961aSKonstantin Belousov struct nvdimm_dev *res; 307fc4a961aSKonstantin Belousov device_t *dimms; 308fc4a961aSKonstantin Belousov int i, error, num_dimms; 3096db7f8e5SKonstantin Belousov 3106db7f8e5SKonstantin Belousov res = NULL; 311fc4a961aSKonstantin Belousov error = devclass_get_devices(nvdimm_devclass, &dimms, &num_dimms); 312fc4a961aSKonstantin Belousov if (error != 0) 313fc4a961aSKonstantin Belousov return (NULL); 314fc4a961aSKonstantin Belousov for (i = 0; i < num_dimms; i++) { 315fc4a961aSKonstantin Belousov if (nvdimm_root_get_device_handle(dimms[i]) == nv_handle) { 316fc4a961aSKonstantin Belousov res = device_get_softc(dimms[i]); 3176db7f8e5SKonstantin Belousov break; 3186db7f8e5SKonstantin Belousov } 3196db7f8e5SKonstantin Belousov } 320fc4a961aSKonstantin Belousov free(dimms, M_TEMP); 3216db7f8e5SKonstantin Belousov return (res); 3226db7f8e5SKonstantin Belousov } 3236db7f8e5SKonstantin Belousov 3246db7f8e5SKonstantin Belousov static int 3256db7f8e5SKonstantin Belousov nvdimm_probe(device_t dev) 3266db7f8e5SKonstantin Belousov { 3276db7f8e5SKonstantin Belousov 3286db7f8e5SKonstantin Belousov return (BUS_PROBE_NOWILDCARD); 3296db7f8e5SKonstantin Belousov } 3306db7f8e5SKonstantin Belousov 3316db7f8e5SKonstantin Belousov static int 3326db7f8e5SKonstantin Belousov nvdimm_attach(device_t dev) 3336db7f8e5SKonstantin Belousov { 3346db7f8e5SKonstantin Belousov struct nvdimm_dev *nv; 3356db7f8e5SKonstantin Belousov ACPI_TABLE_NFIT *nfitbl; 3366db7f8e5SKonstantin Belousov ACPI_HANDLE handle; 3376db7f8e5SKonstantin Belousov ACPI_STATUS status; 338ad30b2f2SBen Widawsky int error; 3396db7f8e5SKonstantin Belousov 3406db7f8e5SKonstantin Belousov nv = device_get_softc(dev); 341fc4a961aSKonstantin Belousov handle = nvdimm_root_get_acpi_handle(dev); 342963c89ffSConrad Meyer MPASS(handle != NULL); 3436db7f8e5SKonstantin Belousov nv->nv_dev = dev; 344fc4a961aSKonstantin Belousov nv->nv_handle = nvdimm_root_get_device_handle(dev); 3456db7f8e5SKonstantin Belousov 3466db7f8e5SKonstantin Belousov status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl); 3476db7f8e5SKonstantin Belousov if (ACPI_FAILURE(status)) { 3486db7f8e5SKonstantin Belousov if (bootverbose) 3496db7f8e5SKonstantin Belousov device_printf(dev, "cannot get NFIT\n"); 3506db7f8e5SKonstantin Belousov return (ENXIO); 3516db7f8e5SKonstantin Belousov } 3527674dce0SKonstantin Belousov acpi_nfit_get_flush_addrs(nfitbl, nv->nv_handle, &nv->nv_flush_addr, 3537674dce0SKonstantin Belousov &nv->nv_flush_addr_cnt); 3546db7f8e5SKonstantin Belousov AcpiPutTable(&nfitbl->Header); 355ad30b2f2SBen Widawsky error = read_label_area_size(nv); 356ad30b2f2SBen Widawsky if (error == 0) { 357ad30b2f2SBen Widawsky /* 358ad30b2f2SBen Widawsky * Ignoring errors reading labels. Not all NVDIMMs 359ad30b2f2SBen Widawsky * support labels and namespaces. 360ad30b2f2SBen Widawsky */ 361ad30b2f2SBen Widawsky read_labels(nv); 362ad30b2f2SBen Widawsky } 3636db7f8e5SKonstantin Belousov return (0); 3646db7f8e5SKonstantin Belousov } 3656db7f8e5SKonstantin Belousov 3666db7f8e5SKonstantin Belousov static int 3676db7f8e5SKonstantin Belousov nvdimm_detach(device_t dev) 3686db7f8e5SKonstantin Belousov { 3696db7f8e5SKonstantin Belousov struct nvdimm_dev *nv; 370ad30b2f2SBen Widawsky struct nvdimm_label_entry *label, *next; 3716db7f8e5SKonstantin Belousov 3726db7f8e5SKonstantin Belousov nv = device_get_softc(dev); 3736db7f8e5SKonstantin Belousov free(nv->nv_flush_addr, M_NVDIMM); 374ad30b2f2SBen Widawsky free(nv->label_index, M_NVDIMM); 375ad30b2f2SBen Widawsky SLIST_FOREACH_SAFE(label, &nv->labels, link, next) { 376ad30b2f2SBen Widawsky SLIST_REMOVE_HEAD(&nv->labels, link); 377ad30b2f2SBen Widawsky free(label, M_NVDIMM); 378ad30b2f2SBen Widawsky } 3796db7f8e5SKonstantin Belousov return (0); 3806db7f8e5SKonstantin Belousov } 3816db7f8e5SKonstantin Belousov 3826db7f8e5SKonstantin Belousov static int 3836db7f8e5SKonstantin Belousov nvdimm_suspend(device_t dev) 3846db7f8e5SKonstantin Belousov { 3856db7f8e5SKonstantin Belousov 3866db7f8e5SKonstantin Belousov return (0); 3876db7f8e5SKonstantin Belousov } 3886db7f8e5SKonstantin Belousov 3896db7f8e5SKonstantin Belousov static int 3906db7f8e5SKonstantin Belousov nvdimm_resume(device_t dev) 3916db7f8e5SKonstantin Belousov { 3926db7f8e5SKonstantin Belousov 3936db7f8e5SKonstantin Belousov return (0); 3946db7f8e5SKonstantin Belousov } 3956db7f8e5SKonstantin Belousov 3966db7f8e5SKonstantin Belousov static device_method_t nvdimm_methods[] = { 3976db7f8e5SKonstantin Belousov DEVMETHOD(device_probe, nvdimm_probe), 3986db7f8e5SKonstantin Belousov DEVMETHOD(device_attach, nvdimm_attach), 3996db7f8e5SKonstantin Belousov DEVMETHOD(device_detach, nvdimm_detach), 4006db7f8e5SKonstantin Belousov DEVMETHOD(device_suspend, nvdimm_suspend), 4016db7f8e5SKonstantin Belousov DEVMETHOD(device_resume, nvdimm_resume), 4026db7f8e5SKonstantin Belousov DEVMETHOD_END 4036db7f8e5SKonstantin Belousov }; 4046db7f8e5SKonstantin Belousov 4056db7f8e5SKonstantin Belousov static driver_t nvdimm_driver = { 4066db7f8e5SKonstantin Belousov "nvdimm", 4076db7f8e5SKonstantin Belousov nvdimm_methods, 4086db7f8e5SKonstantin Belousov sizeof(struct nvdimm_dev), 4096db7f8e5SKonstantin Belousov }; 4106db7f8e5SKonstantin Belousov 411963c89ffSConrad Meyer DRIVER_MODULE(nvdimm, nvdimm_acpi_root, nvdimm_driver, nvdimm_devclass, NULL, 412fc4a961aSKonstantin Belousov NULL); 4136db7f8e5SKonstantin Belousov MODULE_DEPEND(nvdimm, acpi, 1, 1, 1); 414