nvdimm: enumerate NVDIMM SPA ranges from the root device

Move the enumeration of NVDIMM SPA ranges from the spa GEOM class
initializer into the NVDIMM root device. This will be necessary for a
later change where NVDIMM namespaces require NVDIMM device enumeration
to be reliably ordered before SPA enumeration.

Submitted by:	D Scott Phillips <d.scott.phillips@intel.com>
Sponsored by:	Intel Corporation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D18734
This commit is contained in:
Konstantin Belousov 2019-01-31 22:43:20 +00:00
parent eec189c70b
commit 7dcbca8d67
3 changed files with 60 additions and 111 deletions

View file

@ -227,6 +227,31 @@ nvdimm_resume(device_t dev)
return (0);
}
static int
nvdimm_root_create_spa(void *nfitsubtbl, void *arg)
{
enum SPA_mapping_type spa_type;
ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr;
struct SPA_mapping *spa;
struct nvdimm_root_dev *dev;
int error;
nfitaddr = nfitsubtbl;
dev = arg;
spa_type = nvdimm_spa_type_from_uuid(
(struct uuid *)nfitaddr->RangeGuid);
if (spa_type == SPA_TYPE_UNKNOWN)
return (0);
spa = malloc(sizeof(struct SPA_mapping), M_NVDIMM, M_WAITOK | M_ZERO);
error = nvdimm_spa_init(spa, nfitaddr, spa_type);
if (error != 0) {
nvdimm_spa_fini(spa);
free(spa, M_NVDIMM);
}
SLIST_INSERT_HEAD(&dev->spas, spa, link);
return (0);
}
static ACPI_STATUS
nvdimm_root_create_dev(ACPI_HANDLE handle, UINT32 nesting_level, void *context,
void **return_value)
@ -276,6 +301,7 @@ nvdimm_root_attach(device_t dev)
{
ACPI_HANDLE handle;
ACPI_STATUS status;
ACPI_TABLE_NFIT *nfitbl;
int error;
handle = acpi_get_handle(dev);
@ -284,15 +310,33 @@ nvdimm_root_attach(device_t dev)
if (ACPI_FAILURE(status))
device_printf(dev, "failed adding children\n");
error = bus_generic_attach(dev);
if (error != 0)
return (error);
status = AcpiGetTable(ACPI_SIG_NFIT, 1, (ACPI_TABLE_HEADER **)&nfitbl);
if (ACPI_FAILURE(status)) {
device_printf(dev, "cannot get NFIT\n");
return (ENXIO);
}
error = nvdimm_iterate_nfit(nfitbl, ACPI_NFIT_TYPE_SYSTEM_ADDRESS,
nvdimm_root_create_spa, device_get_softc(dev));
AcpiPutTable(&nfitbl->Header);
return (error);
}
static int
nvdimm_root_detach(device_t dev)
{
struct nvdimm_root_dev *root;
struct SPA_mapping *spa, *next;
device_t *children;
int i, error, num_children;
root = device_get_softc(dev);
SLIST_FOREACH_SAFE(spa, &root->spas, link, next) {
nvdimm_spa_fini(spa);
SLIST_REMOVE_HEAD(&root->spas, link);
free(spa, M_NVDIMM);
}
error = bus_generic_detach(dev);
if (error != 0)
return (error);
@ -356,6 +400,7 @@ static device_method_t nvdimm_root_methods[] = {
static driver_t nvdimm_root_driver = {
"nvdimm_root",
nvdimm_root_methods,
sizeof(struct nvdimm_root_dev),
};
DRIVER_MODULE(nvdimm_root, acpi, nvdimm_root_driver, nvdimm_root_devclass, NULL,

View file

@ -82,19 +82,6 @@ __FBSDID("$FreeBSD$");
#define UUID_INITIALIZER_PERSISTENT_VIRTUAL_CD \
{0x08018188,0x42cd,0xbb48,0x10,0x0f,{0x53,0x87,0xd5,0x3d,0xed,0x3d}}
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;
struct uuid u_id;
@ -419,22 +406,17 @@ nvdimm_spa_g_access(struct g_provider *pp, int r, int w, int e)
return (0);
}
static g_init_t nvdimm_spa_g_init;
static g_fini_t nvdimm_spa_g_fini;
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,
};
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)
int
nvdimm_spa_init(struct SPA_mapping *spa, ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr,
enum SPA_mapping_type spa_type)
{
struct make_dev_args mda;
struct sglist *spa_sg;
@ -512,7 +494,7 @@ nvdimm_spa_init_one(struct SPA_mapping *spa, ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr,
if (error1 == 0)
error1 = error;
} else {
g_topology_assert();
g_topology_lock();
spa->spa_g = g_new_geomf(&nvdimm_spa_g_class, "spa%d",
spa->spa_nfit_idx);
spa->spa_g->softc = spa;
@ -526,12 +508,13 @@ nvdimm_spa_init_one(struct SPA_mapping *spa, ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr,
spa->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 (error1);
}
static void
nvdimm_spa_fini_one(struct SPA_mapping *spa)
void
nvdimm_spa_fini(struct SPA_mapping *spa)
{
mtx_lock(&spa->spa_g_mtx);
@ -563,87 +546,3 @@ nvdimm_spa_fini_one(struct SPA_mapping *spa)
mtx_destroy(&spa->spa_g_mtx);
mtx_destroy(&spa->spa_g_stat_mtx);
}
static int
nvdimm_spa_parse(void *nfitsubtbl, void *arg)
{
ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr;
struct SPA_mapping *spa;
enum SPA_mapping_type spa_type;
int error, *i;
i = arg;
spa = &spa_mappings[(*i)++];
nfitaddr = nfitsubtbl;
spa_type = nvdimm_spa_type_from_uuid(
(struct uuid *)&nfitaddr->RangeGuid);
if (spa_type == SPA_TYPE_UNKNOWN) {
printf("Unknown SPA UUID %d ", nfitaddr->RangeIndex);
printf_uuid((struct uuid *)&nfitaddr->RangeGuid);
printf("\n");
return (0);
}
error = nvdimm_spa_init_one(spa, nfitaddr, spa_type);
if (error != 0)
nvdimm_spa_fini_one(spa);
return (0);
}
static int
nvdimm_spa_init1(ACPI_TABLE_NFIT *nfitbl)
{
int error, i;
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)
{
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;
}
error = nvdimm_spa_init1(nfitbl);
if (error != 0)
printf("nvdimm_spa_g_init: error %d\n", error);
AcpiPutTable(&nfitbl->Header);
}
static void
nvdimm_spa_g_fini(struct g_class *mp __unused)
{
int i;
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;
}

View file

@ -44,6 +44,10 @@ __BUS_ACCESSOR(nvdimm_root, acpi_handle, NVDIMM_ROOT, ACPI_HANDLE, ACPI_HANDLE)
__BUS_ACCESSOR(nvdimm_root, device_handle, NVDIMM_ROOT, DEVICE_HANDLE,
nfit_handle_t)
struct nvdimm_root_dev {
SLIST_HEAD(, SPA_mapping) spas;
};
struct nvdimm_dev {
device_t nv_dev;
nfit_handle_t nv_handle;
@ -64,6 +68,7 @@ enum SPA_mapping_type {
};
struct SPA_mapping {
SLIST_ENTRY(SPA_mapping) link;
enum SPA_mapping_type spa_type;
int spa_domain;
int spa_nfit_idx;
@ -84,14 +89,14 @@ struct SPA_mapping {
bool spa_g_proc_exiting;
};
extern struct SPA_mapping *spa_mappings;
extern int spa_mappings_cnt;
MALLOC_DECLARE(M_NVDIMM);
enum SPA_mapping_type nvdimm_spa_type_from_uuid(struct uuid *);
struct nvdimm_dev *nvdimm_find_by_handle(nfit_handle_t nv_handle);
int nvdimm_iterate_nfit(ACPI_TABLE_NFIT *nfitbl, enum AcpiNfitType type,
int (*cb)(void *, void *), void *arg);
int nvdimm_spa_init(struct SPA_mapping *spa, ACPI_NFIT_SYSTEM_ADDRESS *nfitaddr,
enum SPA_mapping_type spa_type);
void nvdimm_spa_fini(struct SPA_mapping *spa);
#endif /* __DEV_NVDIMM_VAR_H__ */