]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/nvdimm/nvdimm.c
Merge lldb trunk r366426, resolve conflicts, and update FREEBSD-Xlist.
[FreeBSD/FreeBSD.git] / sys / dev / nvdimm / nvdimm.c
1 /*-
2  * Copyright (c) 2017 The FreeBSD Foundation
3  * All rights reserved.
4  * Copyright (c) 2018, 2019 Intel Corporation
5  *
6  * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
7  * under sponsorship from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "opt_acpi.h"
35 #include "opt_ddb.h"
36
37 #include <sys/param.h>
38 #include <sys/bio.h>
39 #include <sys/bitstring.h>
40 #include <sys/bus.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/module.h>
45 #include <sys/uuid.h>
46 #include <contrib/dev/acpica/include/acpi.h>
47 #include <contrib/dev/acpica/include/accommon.h>
48 #include <contrib/dev/acpica/include/acuuid.h>
49 #include <dev/acpica/acpivar.h>
50 #include <dev/nvdimm/nvdimm_var.h>
51
52 #define _COMPONENT      ACPI_OEM
53 ACPI_MODULE_NAME("NVDIMM")
54
55 static struct uuid intel_nvdimm_dsm_uuid =
56     {0x4309AC30,0x0D11,0x11E4,0x91,0x91,{0x08,0x00,0x20,0x0C,0x9A,0x66}};
57 #define INTEL_NVDIMM_DSM_REV 1
58 #define INTEL_NVDIMM_DSM_GET_LABEL_SIZE 4
59 #define INTEL_NVDIMM_DSM_GET_LABEL_DATA 5
60
61 static devclass_t nvdimm_devclass;
62 static devclass_t nvdimm_root_devclass;
63 MALLOC_DEFINE(M_NVDIMM, "nvdimm", "NVDIMM driver memory");
64
65 static int
66 read_label_area_size(struct nvdimm_dev *nv)
67 {
68         ACPI_OBJECT *result_buffer;
69         ACPI_HANDLE handle;
70         ACPI_STATUS status;
71         ACPI_BUFFER result;
72         uint32_t *out;
73         int error;
74
75         handle = nvdimm_root_get_acpi_handle(nv->nv_dev);
76         if (handle == NULL)
77                 return (ENODEV);
78         result.Length = ACPI_ALLOCATE_BUFFER;
79         result.Pointer = NULL;
80         status = acpi_EvaluateDSM(handle, (uint8_t *)&intel_nvdimm_dsm_uuid,
81             INTEL_NVDIMM_DSM_REV, INTEL_NVDIMM_DSM_GET_LABEL_SIZE, NULL,
82             &result);
83         error = ENXIO;
84         if (ACPI_SUCCESS(status) && result.Pointer != NULL &&
85             result.Length >= sizeof(ACPI_OBJECT)) {
86                 result_buffer = result.Pointer;
87                 if (result_buffer->Type == ACPI_TYPE_BUFFER &&
88                     result_buffer->Buffer.Length >= 12) {
89                         out = (uint32_t *)result_buffer->Buffer.Pointer;
90                         nv->label_area_size = out[1];
91                         nv->max_label_xfer = out[2];
92                         error = 0;
93                 }
94         }
95         if (result.Pointer != NULL)
96                 AcpiOsFree(result.Pointer);
97         return (error);
98 }
99
100 static int
101 read_label_area(struct nvdimm_dev *nv, uint8_t *dest, off_t offset,
102     off_t length)
103 {
104         ACPI_BUFFER result;
105         ACPI_HANDLE handle;
106         ACPI_OBJECT params_pkg, params_buf, *result_buf;
107         ACPI_STATUS status;
108         uint32_t params[2];
109         off_t to_read;
110         int error;
111
112         error = 0;
113         handle = nvdimm_root_get_acpi_handle(nv->nv_dev);
114         if (offset < 0 || length <= 0 ||
115             offset + length > nv->label_area_size ||
116             handle == NULL)
117                 return (ENODEV);
118         params_pkg.Type = ACPI_TYPE_PACKAGE;
119         params_pkg.Package.Count = 1;
120         params_pkg.Package.Elements = &params_buf;
121         params_buf.Type = ACPI_TYPE_BUFFER;
122         params_buf.Buffer.Length = sizeof(params);
123         params_buf.Buffer.Pointer = (UINT8 *)params;
124         while (length > 0) {
125                 to_read = MIN(length, nv->max_label_xfer);
126                 params[0] = offset;
127                 params[1] = to_read;
128                 result.Length = ACPI_ALLOCATE_BUFFER;
129                 result.Pointer = NULL;
130                 status = acpi_EvaluateDSM(handle,
131                     (uint8_t *)&intel_nvdimm_dsm_uuid, INTEL_NVDIMM_DSM_REV,
132                     INTEL_NVDIMM_DSM_GET_LABEL_DATA, &params_pkg, &result);
133                 if (ACPI_FAILURE(status) ||
134                     result.Length < sizeof(ACPI_OBJECT) ||
135                     result.Pointer == NULL) {
136                         error = ENXIO;
137                         break;
138                 }
139                 result_buf = (ACPI_OBJECT *)result.Pointer;
140                 if (result_buf->Type != ACPI_TYPE_BUFFER ||
141                     result_buf->Buffer.Pointer == NULL ||
142                     result_buf->Buffer.Length != 4 + to_read ||
143                     ((uint16_t *)result_buf->Buffer.Pointer)[0] != 0) {
144                         error = ENXIO;
145                         break;
146                 }
147                 bcopy(result_buf->Buffer.Pointer + 4, dest, to_read);
148                 dest += to_read;
149                 offset += to_read;
150                 length -= to_read;
151                 if (result.Pointer != NULL) {
152                         AcpiOsFree(result.Pointer);
153                         result.Pointer = NULL;
154                 }
155         }
156         if (result.Pointer != NULL)
157                 AcpiOsFree(result.Pointer);
158         return (error);
159 }
160
161 static uint64_t
162 fletcher64(const void *data, size_t length)
163 {
164         size_t i;
165         uint32_t a, b;
166         const uint32_t *d;
167
168         a = 0;
169         b = 0;
170         d = (const uint32_t *)data;
171         length = length / sizeof(uint32_t);
172         for (i = 0; i < length; i++) {
173                 a += d[i];
174                 b += a;
175         }
176         return ((uint64_t)b << 32 | a);
177 }
178
179 static bool
180 label_index_is_valid(struct nvdimm_label_index *index, uint32_t max_labels,
181     size_t size, size_t offset)
182 {
183         uint64_t checksum;
184
185         index = (struct nvdimm_label_index *)((uint8_t *)index + offset);
186         if (strcmp(index->signature, NVDIMM_INDEX_BLOCK_SIGNATURE) != 0)
187                 return false;
188         checksum = index->checksum;
189         index->checksum = 0;
190         if (checksum != fletcher64(index, size) ||
191             index->this_offset != size * offset || index->this_size != size ||
192             index->other_offset != size * (offset == 0 ? 1 : 0) ||
193             index->seq == 0 || index->seq > 3 || index->slot_cnt > max_labels ||
194             index->label_size != 1)
195                 return false;
196         return true;
197 }
198
199 static int
200 read_label(struct nvdimm_dev *nv, int num)
201 {
202         struct nvdimm_label_entry *entry, *i, *next;
203         uint64_t checksum;
204         off_t offset;
205         int error;
206
207         offset = nv->label_index->label_offset +
208             num * (128 << nv->label_index->label_size);
209         entry = malloc(sizeof(*entry), M_NVDIMM, M_WAITOK);
210         error = read_label_area(nv, (uint8_t *)&entry->label, offset,
211             sizeof(struct nvdimm_label));
212         if (error != 0) {
213                 free(entry, M_NVDIMM);
214                 return (error);
215         }
216         checksum = entry->label.checksum;
217         entry->label.checksum = 0;
218         if (checksum != fletcher64(&entry->label, sizeof(entry->label)) ||
219             entry->label.slot != num) {
220                 free(entry, M_NVDIMM);
221                 return (ENXIO);
222         }
223
224         /* Insertion ordered by dimm_phys_addr */
225         if (SLIST_EMPTY(&nv->labels) ||
226             entry->label.dimm_phys_addr <=
227             SLIST_FIRST(&nv->labels)->label.dimm_phys_addr) {
228                 SLIST_INSERT_HEAD(&nv->labels, entry, link);
229                 return (0);
230         }
231         SLIST_FOREACH_SAFE(i, &nv->labels, link, next) {
232                 if (next == NULL ||
233                     entry->label.dimm_phys_addr <= next->label.dimm_phys_addr) {
234                         SLIST_INSERT_AFTER(i, entry, link);
235                         return (0);
236                 }
237         }
238         __unreachable();
239 }
240
241 static int
242 read_labels(struct nvdimm_dev *nv)
243 {
244         struct nvdimm_label_index *indices;
245         size_t bitfield_size, index_size, num_labels;
246         int error, n;
247         bool index_0_valid, index_1_valid;
248
249         for (index_size = 256; ; index_size += 256) {
250                 num_labels = 8 * (index_size -
251                     sizeof(struct nvdimm_label_index));
252                 if (index_size + num_labels * sizeof(struct nvdimm_label) >=
253                     nv->label_area_size)
254                         break;
255         }
256         num_labels = (nv->label_area_size - index_size) /
257             sizeof(struct nvdimm_label);
258         bitfield_size = roundup2(num_labels, 8) / 8;
259         indices = malloc(2 * index_size, M_NVDIMM, M_WAITOK);
260         error = read_label_area(nv, (void *)indices, 0, 2 * index_size);
261         if (error != 0) {
262                 free(indices, M_NVDIMM);
263                 return (error);
264         }
265         index_0_valid = label_index_is_valid(indices, num_labels, index_size,
266             0);
267         index_1_valid = label_index_is_valid(indices, num_labels, index_size,
268             1);
269         if (!index_0_valid && !index_1_valid) {
270                 free(indices, M_NVDIMM);
271                 return (ENXIO);
272         }
273         if (index_0_valid && index_1_valid &&
274             (indices[1].seq > indices[0].seq ||
275             (indices[1].seq == 1 && indices[0].seq == 3)))
276                 index_0_valid = false;
277         nv->label_index = malloc(index_size, M_NVDIMM, M_WAITOK);
278         bcopy(indices + (index_0_valid ? 0 : 1), nv->label_index, index_size);
279         free(indices, M_NVDIMM);
280         for (bit_ffc_at((bitstr_t *)nv->label_index->free, 0, num_labels, &n);
281              n >= 0;
282              bit_ffc_at((bitstr_t *)nv->label_index->free, n + 1, num_labels,
283              &n)) {
284                 read_label(nv, n);
285         }
286         return (0);
287 }
288
289 struct nvdimm_dev *
290 nvdimm_find_by_handle(nfit_handle_t nv_handle)
291 {
292         struct nvdimm_dev *res;
293         device_t *dimms;
294         int i, error, num_dimms;
295
296         res = NULL;
297         error = devclass_get_devices(nvdimm_devclass, &dimms, &num_dimms);
298         if (error != 0)
299                 return (NULL);
300         for (i = 0; i < num_dimms; i++) {
301                 if (nvdimm_root_get_device_handle(dimms[i]) == nv_handle) {
302                         res = device_get_softc(dimms[i]);
303                         break;
304                 }
305         }
306         free(dimms, M_TEMP);
307         return (res);
308 }
309
310 static int
311 nvdimm_probe(device_t dev)
312 {
313
314         return (BUS_PROBE_NOWILDCARD);
315 }
316
317 static int
318 nvdimm_attach(device_t dev)
319 {
320         struct nvdimm_dev *nv;
321         ACPI_TABLE_NFIT *nfitbl;
322         ACPI_HANDLE handle;
323         ACPI_STATUS status;
324         int error;
325
326         nv = device_get_softc(dev);
327         handle = nvdimm_root_get_acpi_handle(dev);
328         if (handle == NULL)
329                 return (EINVAL);
330         nv->nv_dev = dev;
331         nv->nv_handle = nvdimm_root_get_device_handle(dev);
332
333         status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl);
334         if (ACPI_FAILURE(status)) {
335                 if (bootverbose)
336                         device_printf(dev, "cannot get NFIT\n");
337                 return (ENXIO);
338         }
339         acpi_nfit_get_flush_addrs(nfitbl, nv->nv_handle, &nv->nv_flush_addr,
340             &nv->nv_flush_addr_cnt);
341         AcpiPutTable(&nfitbl->Header);
342         error = read_label_area_size(nv);
343         if (error == 0) {
344                 /*
345                  * Ignoring errors reading labels. Not all NVDIMMs
346                  * support labels and namespaces.
347                  */
348                 read_labels(nv);
349         }
350         return (0);
351 }
352
353 static int
354 nvdimm_detach(device_t dev)
355 {
356         struct nvdimm_dev *nv;
357         struct nvdimm_label_entry *label, *next;
358
359         nv = device_get_softc(dev);
360         free(nv->nv_flush_addr, M_NVDIMM);
361         free(nv->label_index, M_NVDIMM);
362         SLIST_FOREACH_SAFE(label, &nv->labels, link, next) {
363                 SLIST_REMOVE_HEAD(&nv->labels, link);
364                 free(label, M_NVDIMM);
365         }
366         return (0);
367 }
368
369 static int
370 nvdimm_suspend(device_t dev)
371 {
372
373         return (0);
374 }
375
376 static int
377 nvdimm_resume(device_t dev)
378 {
379
380         return (0);
381 }
382
383 static ACPI_STATUS
384 find_dimm(ACPI_HANDLE handle, UINT32 nesting_level, void *context,
385     void **return_value)
386 {
387         ACPI_DEVICE_INFO *device_info;
388         ACPI_STATUS status;
389
390         status = AcpiGetObjectInfo(handle, &device_info);
391         if (ACPI_FAILURE(status))
392                 return_ACPI_STATUS(AE_ERROR);
393         if (device_info->Address == (uintptr_t)context) {
394                 *(ACPI_HANDLE *)return_value = handle;
395                 return_ACPI_STATUS(AE_CTRL_TERMINATE);
396         }
397         return_ACPI_STATUS(AE_OK);
398 }
399
400 static ACPI_HANDLE
401 get_dimm_acpi_handle(ACPI_HANDLE root_handle, nfit_handle_t adr)
402 {
403         ACPI_HANDLE res;
404         ACPI_STATUS status;
405
406         res = NULL;
407         status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, root_handle, 1, find_dimm,
408             NULL, (void *)(uintptr_t)adr, &res);
409         if (ACPI_FAILURE(status))
410                 res = NULL;
411         return (res);
412 }
413
414 static int
415 nvdimm_root_create_devs(device_t dev, ACPI_TABLE_NFIT *nfitbl)
416 {
417         ACPI_HANDLE root_handle, dimm_handle;
418         device_t child;
419         nfit_handle_t *dimm_ids, *dimm;
420         uintptr_t *ivars;
421         int num_dimm_ids;
422
423         root_handle = acpi_get_handle(dev);
424         acpi_nfit_get_dimm_ids(nfitbl, &dimm_ids, &num_dimm_ids);
425         for (dimm = dimm_ids; dimm < dimm_ids + num_dimm_ids; dimm++) {
426                 dimm_handle = get_dimm_acpi_handle(root_handle, *dimm);
427                 child = BUS_ADD_CHILD(dev, 100, "nvdimm", -1);
428                 if (child == NULL) {
429                         device_printf(dev, "failed to create nvdimm\n");
430                         return (ENXIO);
431                 }
432                 ivars = mallocarray(NVDIMM_ROOT_IVAR_MAX, sizeof(uintptr_t),
433                     M_NVDIMM, M_ZERO | M_WAITOK);
434                 device_set_ivars(child, ivars);
435                 nvdimm_root_set_acpi_handle(child, dimm_handle);
436                 nvdimm_root_set_device_handle(child, *dimm);
437         }
438         free(dimm_ids, M_NVDIMM);
439         return (0);
440 }
441
442 static int
443 nvdimm_root_create_spas(struct nvdimm_root_dev *dev, ACPI_TABLE_NFIT *nfitbl)
444 {
445         ACPI_NFIT_SYSTEM_ADDRESS **spas, **spa;
446         struct SPA_mapping *spa_mapping;
447         enum SPA_mapping_type spa_type;
448         int error, num_spas;
449
450         error = 0;
451         acpi_nfit_get_spa_ranges(nfitbl, &spas, &num_spas);
452         for (spa = spas; spa < spas + num_spas; spa++) {
453                 spa_type = nvdimm_spa_type_from_uuid(
454                         (struct uuid *)(*spa)->RangeGuid);
455                 if (spa_type == SPA_TYPE_UNKNOWN)
456                         continue;
457                 spa_mapping = malloc(sizeof(struct SPA_mapping), M_NVDIMM,
458                     M_WAITOK | M_ZERO);
459                 error = nvdimm_spa_init(spa_mapping, *spa, spa_type);
460                 if (error != 0) {
461                         nvdimm_spa_fini(spa_mapping);
462                         free(spa, M_NVDIMM);
463                         break;
464                 }
465                 nvdimm_create_namespaces(spa_mapping, nfitbl);
466                 SLIST_INSERT_HEAD(&dev->spas, spa_mapping, link);
467         }
468         free(spas, M_NVDIMM);
469         return (error);
470 }
471
472 static char *nvdimm_root_id[] = {"ACPI0012", NULL};
473
474 static int
475 nvdimm_root_probe(device_t dev)
476 {
477         int rv;
478
479         if (acpi_disabled("nvdimm"))
480                 return (ENXIO);
481         rv = ACPI_ID_PROBE(device_get_parent(dev), dev, nvdimm_root_id, NULL);
482         if (rv <= 0)
483                 device_set_desc(dev, "ACPI NVDIMM root device");
484
485         return (rv);
486 }
487
488 static int
489 nvdimm_root_attach(device_t dev)
490 {
491         struct nvdimm_root_dev *root;
492         ACPI_TABLE_NFIT *nfitbl;
493         ACPI_STATUS status;
494         int error;
495
496         status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl);
497         if (ACPI_FAILURE(status)) {
498                 device_printf(dev, "cannot get NFIT\n");
499                 return (ENXIO);
500         }
501         error = nvdimm_root_create_devs(dev, nfitbl);
502         if (error != 0)
503                 return (error);
504         error = bus_generic_attach(dev);
505         if (error != 0)
506                 return (error);
507         root = device_get_softc(dev);
508         error = nvdimm_root_create_spas(root, nfitbl);
509         AcpiPutTable(&nfitbl->Header);
510         return (error);
511 }
512
513 static int
514 nvdimm_root_detach(device_t dev)
515 {
516         struct nvdimm_root_dev *root;
517         struct SPA_mapping *spa, *next;
518         device_t *children;
519         int i, error, num_children;
520
521         root = device_get_softc(dev);
522         SLIST_FOREACH_SAFE(spa, &root->spas, link, next) {
523                 nvdimm_destroy_namespaces(spa);
524                 nvdimm_spa_fini(spa);
525                 SLIST_REMOVE_HEAD(&root->spas, link);
526                 free(spa, M_NVDIMM);
527         }
528         error = bus_generic_detach(dev);
529         if (error != 0)
530                 return (error);
531         error = device_get_children(dev, &children, &num_children);
532         if (error != 0)
533                 return (error);
534         for (i = 0; i < num_children; i++)
535                 free(device_get_ivars(children[i]), M_NVDIMM);
536         free(children, M_TEMP);
537         error = device_delete_children(dev);
538         return (error);
539 }
540
541 static int
542 nvdimm_root_read_ivar(device_t dev, device_t child, int index,
543     uintptr_t *result)
544 {
545
546         if (index < 0 || index >= NVDIMM_ROOT_IVAR_MAX)
547                 return (ENOENT);
548         *result = ((uintptr_t *)device_get_ivars(child))[index];
549         return (0);
550 }
551
552 static int
553 nvdimm_root_write_ivar(device_t dev, device_t child, int index,
554     uintptr_t value)
555 {
556
557         if (index < 0 || index >= NVDIMM_ROOT_IVAR_MAX)
558                 return (ENOENT);
559         ((uintptr_t *)device_get_ivars(child))[index] = value;
560         return (0);
561 }
562
563 static int
564 nvdimm_root_child_location_str(device_t dev, device_t child, char *buf,
565     size_t buflen)
566 {
567         ACPI_HANDLE handle;
568         int res;
569
570         handle = nvdimm_root_get_acpi_handle(child);
571         if (handle != NULL)
572                 res = snprintf(buf, buflen, "handle=%s", acpi_name(handle));
573         else
574                 res = snprintf(buf, buflen, "");
575
576         if (res >= buflen)
577                 return (EOVERFLOW);
578         return (0);
579 }
580
581 static device_method_t nvdimm_methods[] = {
582         DEVMETHOD(device_probe, nvdimm_probe),
583         DEVMETHOD(device_attach, nvdimm_attach),
584         DEVMETHOD(device_detach, nvdimm_detach),
585         DEVMETHOD(device_suspend, nvdimm_suspend),
586         DEVMETHOD(device_resume, nvdimm_resume),
587         DEVMETHOD_END
588 };
589
590 static driver_t nvdimm_driver = {
591         "nvdimm",
592         nvdimm_methods,
593         sizeof(struct nvdimm_dev),
594 };
595
596 static device_method_t nvdimm_root_methods[] = {
597         DEVMETHOD(device_probe, nvdimm_root_probe),
598         DEVMETHOD(device_attach, nvdimm_root_attach),
599         DEVMETHOD(device_detach, nvdimm_root_detach),
600         DEVMETHOD(bus_add_child, bus_generic_add_child),
601         DEVMETHOD(bus_read_ivar, nvdimm_root_read_ivar),
602         DEVMETHOD(bus_write_ivar, nvdimm_root_write_ivar),
603         DEVMETHOD(bus_child_location_str, nvdimm_root_child_location_str),
604         DEVMETHOD_END
605 };
606
607 static driver_t nvdimm_root_driver = {
608         "nvdimm_root",
609         nvdimm_root_methods,
610         sizeof(struct nvdimm_root_dev),
611 };
612
613 DRIVER_MODULE(nvdimm_root, acpi, nvdimm_root_driver, nvdimm_root_devclass, NULL,
614     NULL);
615 DRIVER_MODULE(nvdimm, nvdimm_root, nvdimm_driver, nvdimm_devclass, NULL, NULL);
616 MODULE_DEPEND(nvdimm, acpi, 1, 1, 1);