Index: sys/dev/nvdimm/nvdimm_spa.c =================================================================== --- sys/dev/nvdimm/nvdimm_spa.c +++ sys/dev/nvdimm/nvdimm_spa.c @@ -64,19 +64,6 @@ #include #include -struct SPA_mapping *spa_mappings; -int spa_mappings_cnt; - -static int -nvdimm_spa_count(void *nfitsubtbl __unused, void *arg) -{ - int *cnt; - - cnt = arg; - (*cnt)++; - return (0); -} - static struct nvdimm_SPA_uuid_list_elm { const char *u_name; const char *u_id_str; @@ -125,6 +112,19 @@ }, }; +static int +spa_type_from_uuid(const struct uuid *u) +{ + int i; + + for (i = 0; i < nitems(nvdimm_SPA_uuid_list); i++) { + if (uuidcmp(u, &nvdimm_SPA_uuid_list[i].u_id) != 0) + continue; + return (i); + } + return (SPA_TYPE_UNKNOWN); +} + static vm_memattr_t nvdimm_spa_memattr(struct SPA_mapping *spa) { @@ -276,30 +276,30 @@ static void nvdimm_spa_g_thread(void *arg) { - struct SPA_mapping *spa; + struct g_spa_softc *sc; struct bio *bp; struct uio auio; struct iovec aiovec; int error; - spa = arg; + sc = arg; for (;;) { - mtx_lock(&spa->spa_g_mtx); + mtx_lock(&sc->spa_g_mtx); for (;;) { - bp = bioq_takefirst(&spa->spa_g_queue); + bp = bioq_takefirst(&sc->spa_g_queue); if (bp != NULL) break; - msleep(&spa->spa_g_queue, &spa->spa_g_mtx, PRIBIO, + msleep(&sc->spa_g_queue, &sc->spa_g_mtx, PRIBIO, "spa_g", 0); - if (!spa->spa_g_proc_run) { - spa->spa_g_proc_exiting = true; - wakeup(&spa->spa_g_queue); - mtx_unlock(&spa->spa_g_mtx); + if (!sc->spa_g_proc_run) { + sc->spa_g_proc_exiting = true; + wakeup(&sc->spa_g_queue); + mtx_unlock(&sc->spa_g_mtx); kproc_exit(0); } continue; } - mtx_unlock(&spa->spa_g_mtx); + mtx_unlock(&sc->spa_g_mtx); if (bp->bio_cmd != BIO_READ && bp->bio_cmd != BIO_WRITE && bp->bio_cmd != BIO_FLUSH) { error = EOPNOTSUPP; @@ -308,13 +308,15 @@ error = 0; if (bp->bio_cmd == BIO_FLUSH) { - if (spa->spa_kva != NULL) { - pmap_large_map_wb(spa->spa_kva, spa->spa_len); + if (sc->spa->spa_kva != NULL) { + pmap_large_map_wb(sc->spa->spa_kva, + sc->spa->spa_len); } else { pmap_flush_cache_phys_range( - (vm_paddr_t)spa->spa_phys_base, - (vm_paddr_t)spa->spa_phys_base + - spa->spa_len, nvdimm_spa_memattr(spa)); + (vm_paddr_t)sc->spa->spa_phys_base, + (vm_paddr_t)sc->spa->spa_phys_base + + sc->spa->spa_len, + nvdimm_spa_memattr(sc->spa)); } /* * XXX flush IMC @@ -323,8 +325,8 @@ } if ((bp->bio_flags & BIO_UNMAPPED) != 0) { - if (spa->spa_kva != NULL) { - aiovec.iov_base = (char *)spa->spa_kva + + if (sc->spa->spa_kva != NULL) { + aiovec.iov_base = (char *)sc->spa->spa_kva + bp->bio_offset; aiovec.iov_len = bp->bio_length; auio.uio_iov = &aiovec; @@ -338,7 +340,8 @@ error = uiomove_fromphys(bp->bio_ma, bp->bio_ma_offset, bp->bio_length, &auio); } else { - nvdimm_spa_g_all_unmapped(spa, bp, bp->bio_cmd); + nvdimm_spa_g_all_unmapped(sc->spa, bp, + bp->bio_cmd); error = 0; } } else { @@ -352,9 +355,9 @@ auio.uio_rw = bp->bio_cmd == BIO_READ ? UIO_READ : UIO_WRITE; auio.uio_td = curthread; - error = nvdimm_spa_uio(spa, &auio); + error = nvdimm_spa_uio(sc->spa, &auio); } - devstat_end_transaction_bio(spa->spa_g_devstat, bp); + devstat_end_transaction_bio(sc->spa_g_devstat, bp); completed: bp->bio_completed = bp->bio_length; g_io_deliver(bp, error); @@ -364,18 +367,18 @@ static void nvdimm_spa_g_start(struct bio *bp) { - struct SPA_mapping *spa; + struct g_spa_softc *sc; - spa = bp->bio_to->geom->softc; + sc = bp->bio_to->geom->softc; if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { - mtx_lock(&spa->spa_g_stat_mtx); - devstat_start_transaction_bio(spa->spa_g_devstat, bp); - mtx_unlock(&spa->spa_g_stat_mtx); + mtx_lock(&sc->spa_g_stat_mtx); + devstat_start_transaction_bio(sc->spa_g_devstat, bp); + mtx_unlock(&sc->spa_g_stat_mtx); } - mtx_lock(&spa->spa_g_mtx); - bioq_disksort(&spa->spa_g_queue, bp); - wakeup(&spa->spa_g_queue); - mtx_unlock(&spa->spa_g_mtx); + mtx_lock(&sc->spa_g_mtx); + bioq_disksort(&sc->spa_g_queue, bp); + wakeup(&sc->spa_g_queue); + mtx_unlock(&sc->spa_g_mtx); } static int @@ -385,31 +388,98 @@ return (0); } -static g_init_t nvdimm_spa_g_init; -static g_fini_t nvdimm_spa_g_fini; +static g_ctl_destroy_geom_t nvdimm_spa_g_destroy_geom; struct g_class nvdimm_spa_g_class = { .name = "SPA", .version = G_VERSION, .start = nvdimm_spa_g_start, .access = nvdimm_spa_g_access, - .init = nvdimm_spa_g_init, - .fini = nvdimm_spa_g_fini, + .destroy_geom = nvdimm_spa_g_destroy_geom, }; DECLARE_GEOM_CLASS(nvdimm_spa_g_class, g_spa); static int -nvdimm_spa_init_one(struct SPA_mapping *spa, ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr, - int spa_type) +nvdimm_spa_g_create(struct SPA_mapping *spa) { + struct g_spa_softc *sc; + int error; + + sc = malloc(sizeof(*sc), M_NVDIMM, M_WAITOK | M_ZERO); + sc->spa = spa; + bioq_init(&sc->spa_g_queue); + mtx_init(&sc->spa_g_mtx, "spag", NULL, MTX_DEF); + mtx_init(&sc->spa_g_stat_mtx, "spagst", NULL, MTX_DEF); + sc->spa_g_proc_run = true; + sc->spa_g_proc_exiting = false; + error = kproc_create(nvdimm_spa_g_thread, sc, &sc->spa_g_proc, 0, 0, + "g_spa%d", spa->spa_nfit_idx); + if (error != 0) { + printf("NVDIMM SPA%d cannot create geom worker, error %d\n", + spa->spa_nfit_idx, error); + return (error); + } + g_topology_lock(); + spa->spa_g = g_new_geomf(&nvdimm_spa_g_class, "spa%d", + spa->spa_nfit_idx); + spa->spa_g->softc = sc; + sc->spa_p = g_new_providerf(spa->spa_g, "spa%d", spa->spa_nfit_idx); + sc->spa_p->mediasize = spa->spa_len; + sc->spa_p->sectorsize = DEV_BSIZE; + sc->spa_p->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE | + G_PF_ACCEPT_UNMAPPED; + g_error_provider(sc->spa_p, 0); + sc->spa_g_devstat = devstat_new_entry("spa", spa->spa_nfit_idx, + DEV_BSIZE, DEVSTAT_ALL_SUPPORTED, DEVSTAT_TYPE_DIRECT, + DEVSTAT_PRIORITY_MAX); + g_topology_unlock(); + return (0); +} + +static int nvdimm_spa_g_destroy_geom(struct gctl_req *req, struct g_class *cp, + struct g_geom *gp) +{ + struct g_spa_softc *sc; + + sc = gp->softc; + mtx_lock(&sc->spa_g_mtx); + sc->spa_g_proc_run = false; + wakeup(&sc->spa_g_queue); + while (!sc->spa_g_proc_exiting) + msleep(&sc->spa_g_queue, &sc->spa_g_mtx, PRIBIO, "spa_e", 0); + mtx_unlock(&sc->spa_g_mtx); + g_topology_lock(); + g_wither_geom(gp, ENXIO); + g_topology_unlock(); + sc->spa_p = NULL; + if (sc->spa_g_devstat != NULL) { + devstat_remove_entry(sc->spa_g_devstat); + sc->spa_g_devstat = NULL; + } + sc->spa->spa_g = NULL; + free(sc, M_NVDIMM); + gp->softc = NULL; + + return (0); +} + +static int +nvdimm_spa_init_one(void *nfitsubtbl, void *arg) +{ + struct SPA_mapping *spa; + ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr; struct make_dev_args mda; struct sglist *spa_sg; int error, error1; - spa->spa_type = spa_type; + spa = arg; + nfitaddr = nfitsubtbl; + if (spa->spa_nfit_idx != nfitaddr->RangeIndex) + return (0); + + spa->spa_type = spa_type_from_uuid((struct uuid *)&nfitaddr->RangeGuid); spa->spa_domain = ((nfitaddr->Flags & ACPI_NFIT_PROXIMITY_VALID) != 0) ? nfitaddr->ProximityDomain : -1; - spa->spa_nfit_idx = nfitaddr->RangeIndex; spa->spa_phys_base = nfitaddr->Address; spa->spa_len = nfitaddr->Length; spa->spa_efi_mem_flags = nfitaddr->MemoryMapping; @@ -417,11 +487,9 @@ printf("NVDIMM SPA%d base %#016jx len %#016jx %s fl %#jx\n", spa->spa_nfit_idx, (uintmax_t)spa->spa_phys_base, (uintmax_t)spa->spa_len, - nvdimm_SPA_uuid_list[spa_type].u_name, + nvdimm_SPA_uuid_list[spa->spa_type].u_name, spa->spa_efi_mem_flags); } - if (!nvdimm_SPA_uuid_list[spa_type].u_usr_acc) - return (0); error1 = pmap_large_map(spa->spa_phys_base, spa->spa_len, &spa->spa_kva, nvdimm_spa_memattr(spa)); @@ -465,34 +533,10 @@ error1 = error; } - bioq_init(&spa->spa_g_queue); - mtx_init(&spa->spa_g_mtx, "spag", NULL, MTX_DEF); - mtx_init(&spa->spa_g_stat_mtx, "spagst", NULL, MTX_DEF); - spa->spa_g_proc_run = true; - spa->spa_g_proc_exiting = false; - error = kproc_create(nvdimm_spa_g_thread, spa, &spa->spa_g_proc, 0, 0, - "g_spa%d", spa->spa_nfit_idx); - if (error != 0) { - printf("NVDIMM SPA%d cannot create geom worker, error %d\n", - spa->spa_nfit_idx, error); - if (error1 == 0) - error1 = error; - } else { - g_topology_assert(); - spa->spa_g = g_new_geomf(&nvdimm_spa_g_class, "spa%d", - spa->spa_nfit_idx); - spa->spa_g->softc = spa; - spa->spa_p = g_new_providerf(spa->spa_g, "spa%d", - spa->spa_nfit_idx); - spa->spa_p->mediasize = spa->spa_len; - spa->spa_p->sectorsize = DEV_BSIZE; - spa->spa_p->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE | - G_PF_ACCEPT_UNMAPPED; - g_error_provider(spa->spa_p, 0); - spa->spa_g_devstat = devstat_new_entry("spa", spa->spa_nfit_idx, - DEV_BSIZE, DEVSTAT_ALL_SUPPORTED, DEVSTAT_TYPE_DIRECT, - DEVSTAT_PRIORITY_MAX); - } + error = nvdimm_spa_g_create(spa); + if (error1 != 0) + error1 = error; + return (error1); } @@ -500,23 +544,8 @@ nvdimm_spa_fini_one(struct SPA_mapping *spa) { - mtx_lock(&spa->spa_g_mtx); - spa->spa_g_proc_run = false; - wakeup(&spa->spa_g_queue); - while (!spa->spa_g_proc_exiting) - msleep(&spa->spa_g_queue, &spa->spa_g_mtx, PRIBIO, "spa_e", 0); - mtx_unlock(&spa->spa_g_mtx); - if (spa->spa_g != NULL) { - g_topology_lock(); - g_wither_geom(spa->spa_g, ENXIO); - g_topology_unlock(); - spa->spa_g = NULL; - spa->spa_p = NULL; - } - if (spa->spa_g_devstat != NULL) { - devstat_remove_entry(spa->spa_g_devstat); - spa->spa_g_devstat = NULL; - } + if (spa->spa_g != NULL) + nvdimm_spa_g_destroy_geom(NULL, spa->spa_g->class, spa->spa_g); if (spa->spa_dev != NULL) { destroy_dev(spa->spa_dev); spa->spa_dev = NULL; @@ -526,42 +555,78 @@ pmap_large_unmap(spa->spa_kva, spa->spa_len); spa->spa_kva = NULL; } - mtx_destroy(&spa->spa_g_mtx); - mtx_destroy(&spa->spa_g_stat_mtx); } static int -nvdimm_spa_parse(void *nfitsubtbl, void *arg) +nvdimm_spa_create_dev(void *nfitsubtbl, void *arg) { ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr; - struct SPA_mapping *spa; - int error, *i, j; + int i; - i = arg; - spa = &spa_mappings[*i]; nfitaddr = nfitsubtbl; + i = spa_type_from_uuid((struct uuid *)&nfitaddr->RangeGuid); + if (i == SPA_TYPE_UNKNOWN || !nvdimm_SPA_uuid_list[i].u_usr_acc) + return (0); + BUS_ADD_CHILD(arg, 1, "nvdimm_spa", nfitaddr->RangeIndex); + return (0); +} - for (j = 0; j < nitems(nvdimm_SPA_uuid_list); j++) { - /* XXXKIB: is ACPI UUID representation compatible ? */ - if (uuidcmp((struct uuid *)&nfitaddr->RangeGuid, - &nvdimm_SPA_uuid_list[j].u_id) != 0) - continue; - error = nvdimm_spa_init_one(spa, nfitaddr, j); - if (error != 0) - nvdimm_spa_fini_one(spa); - break; - } - if (j == nitems(nvdimm_SPA_uuid_list) && bootverbose) { - printf("Unknown SPA UUID %d ", nfitaddr->RangeIndex); - printf_uuid((struct uuid *)&nfitaddr->RangeGuid); - printf("\n"); - } - (*i)++; +static void +nvdimm_spa_identify(driver_t *driver, device_t parent) +{ + ACPI_TABLE_NFIT *nfitbl; + ACPI_STATUS status; + + if (acpi_disabled("nvdimm")) + return; + status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl); + if (ACPI_FAILURE(status)) + return; + nvdimm_iterate_nfit(nfitbl, ACPI_NFIT_TYPE_SYSTEM_ADDRESS, + nvdimm_spa_create_dev, parent); + AcpiPutTable(&nfitbl->Header); +} + +static int +nvdimm_spa_probe(device_t dev) +{ + + return (BUS_PROBE_NOWILDCARD); +} + +static int +nvdimm_spa_attach(device_t dev) +{ + struct SPA_mapping *spa; + ACPI_TABLE_NFIT *nfitbl; + ACPI_STATUS status; + int error; + + spa = device_get_softc(dev); + status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl); + if (ACPI_FAILURE(status)) + return (ENXIO); + spa->spa_nfit_idx = device_get_unit(dev); + error = nvdimm_iterate_nfit(nfitbl, ACPI_NFIT_TYPE_SYSTEM_ADDRESS, + nvdimm_spa_init_one, spa); + AcpiPutTable(&nfitbl->Header); + if (error != 0) + nvdimm_spa_fini_one(spa); + return (error); +} + +static int +nvdimm_spa_detach(device_t dev) +{ + struct SPA_mapping *spa; + + spa = device_get_softc(dev); + nvdimm_spa_fini_one(spa); return (0); } static int -nvdimm_spa_init1(ACPI_TABLE_NFIT *nfitbl) +nvdimm_spa_init(void) { struct nvdimm_SPA_uuid_list_elm *sle; int error, i; @@ -571,63 +636,54 @@ error = parse_uuid(sle->u_id_str, &sle->u_id); if (error != 0) { if (bootverbose) - printf("nvdimm_identify: error %d parsing " + printf("nvdimm_spa_init: error %d parsing " "known SPA UUID %d %s\n", error, i, sle->u_id_str); return (error); } } - error = nvdimm_iterate_nfit(nfitbl, ACPI_NFIT_TYPE_SYSTEM_ADDRESS, - nvdimm_spa_count, &spa_mappings_cnt); - if (error != 0) - return (error); - spa_mappings = malloc(sizeof(struct SPA_mapping) * spa_mappings_cnt, - M_NVDIMM, M_WAITOK | M_ZERO); - i = 0; - error = nvdimm_iterate_nfit(nfitbl, ACPI_NFIT_TYPE_SYSTEM_ADDRESS, - nvdimm_spa_parse, &i); - if (error != 0) { - free(spa_mappings, M_NVDIMM); - spa_mappings = NULL; - return (error); - } return (0); } -static void -nvdimm_spa_g_init(struct g_class *mp __unused) +static int +nvdimm_spa_modev(struct module *mod, int what, void *arg) { - ACPI_TABLE_NFIT *nfitbl; - ACPI_STATUS status; int error; - spa_mappings_cnt = 0; - spa_mappings = NULL; - if (acpi_disabled("nvdimm")) - return; - status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl); - if (ACPI_FAILURE(status)) { - if (bootverbose) - printf("nvdimm_spa_g_init: cannot find NFIT\n"); - return; + switch (what) { + case MOD_LOAD: + error = nvdimm_spa_init(); + break; + + case MOD_UNLOAD: + case MOD_QUIESCE: + error = 0; + break; + + default: + error = EOPNOTSUPP; + break; } - error = nvdimm_spa_init1(nfitbl); - if (error != 0) - printf("nvdimm_spa_g_init: error %d\n", error); - AcpiPutTable(&nfitbl->Header); + + return (error); } -static void -nvdimm_spa_g_fini(struct g_class *mp __unused) -{ - int i; +static device_method_t nvdimm_spa_methods[] = { + DEVMETHOD(device_identify, nvdimm_spa_identify), + DEVMETHOD(device_probe, nvdimm_spa_probe), + DEVMETHOD(device_attach, nvdimm_spa_attach), + DEVMETHOD(device_detach, nvdimm_spa_detach), + DEVMETHOD_END +}; - if (spa_mappings == NULL) - return; - for (i = 0; i < spa_mappings_cnt; i++) - nvdimm_spa_fini_one(&spa_mappings[i]); - free(spa_mappings, M_NVDIMM); - spa_mappings = NULL; - spa_mappings_cnt = 0; -} +static driver_t nvdimm_spa_driver = { + "nvdimm_spa", + nvdimm_spa_methods, + sizeof(struct SPA_mapping), +}; + +static devclass_t nvdimm_spa_devclass; +DRIVER_MODULE(nvdimm_spa, acpi, nvdimm_spa_driver, nvdimm_spa_devclass, + nvdimm_spa_modev, 0); +MODULE_DEPEND(nvdimm_spa, acpi, 1, 1, 1); Index: sys/dev/nvdimm/nvdimm_var.h =================================================================== --- sys/dev/nvdimm/nvdimm_var.h +++ sys/dev/nvdimm/nvdimm_var.h @@ -51,6 +51,7 @@ 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 { @@ -61,15 +62,19 @@ uint64_t spa_len; uint64_t spa_efi_mem_flags; void *spa_kva; + struct vm_object *spa_obj; struct cdev *spa_dev; struct g_geom *spa_g; +}; + +struct g_spa_softc { + struct SPA_mapping *spa; 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; }; @@ -79,9 +84,6 @@ void *arg; }; -extern struct SPA_mapping *spa_mappings; -extern int spa_mappings_cnt; - MALLOC_DECLARE(M_NVDIMM); struct nvdimm_dev *nvdimm_find_by_handle(nfit_handle_t nv_handle);