[PATCH 1/2] nvme: Move block dev creation from uclass post probe to driver probe

At present the block device creation happens in the NVMe uclass driver post probe phase. Move it to driver probe phase instead. A per-child platdata is added to store the namespace id, so that we can obtain it in the block driver probe phase, without the assumption that the ns id is encoded in the block device name.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
drivers/nvme/nvme-uclass.c | 30 ------------------------------ drivers/nvme/nvme.c | 30 +++++++++++++++++++++++++----- drivers/nvme/nvme.h | 14 ++++++++++++++ 3 files changed, 39 insertions(+), 35 deletions(-)
diff --git a/drivers/nvme/nvme-uclass.c b/drivers/nvme/nvme-uclass.c index 277e31e1f3..610166d76e 100644 --- a/drivers/nvme/nvme-uclass.c +++ b/drivers/nvme/nvme-uclass.c @@ -5,39 +5,9 @@ */
#include <common.h> -#include <blk.h> -#include <errno.h> #include <dm.h> -#include <dm/device.h> -#include "nvme.h" - -static int nvme_uclass_post_probe(struct udevice *udev) -{ - char name[20]; - struct udevice *ns_udev; - int i, ret; - struct nvme_dev *ndev = dev_get_priv(udev); - - /* Create a blk device for each namespace */ - for (i = 0; i < ndev->nn; i++) { - /* - * Encode the namespace id to the device name so that - * we can extract it when doing the probe. - */ - sprintf(name, "blk#%d", i); - - /* The real blksz and size will be set by nvme_blk_probe() */ - ret = blk_create_devicef(udev, "nvme-blk", name, IF_TYPE_NVME, - -1, 512, 0, &ns_udev); - if (ret) - return ret; - } - - return 0; -}
UCLASS_DRIVER(nvme) = { .name = "nvme", .id = UCLASS_NVME, - .post_probe = nvme_uclass_post_probe, }; diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index c61dab20c5..0b4a73d170 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -696,10 +696,11 @@ int nvme_scan_namespace(void) static int nvme_blk_probe(struct udevice *udev) { struct nvme_dev *ndev = dev_get_priv(udev->parent); + struct nvme_child_plat *nvme_pplat = dev_get_parent_plat(udev); struct blk_desc *desc = dev_get_uclass_plat(udev); struct nvme_ns *ns = dev_get_priv(udev); u8 flbas; - struct pci_child_plat *pplat; + struct pci_child_plat *pci_pplat; struct nvme_id_ns *id;
id = memalign(ndev->page_size, sizeof(struct nvme_id_ns)); @@ -708,8 +709,7 @@ static int nvme_blk_probe(struct udevice *udev)
memset(ns, 0, sizeof(*ns)); ns->dev = ndev; - /* extract the namespace id from the block device name */ - ns->ns_id = trailing_strtol(udev->name) + 1; + ns->ns_id = nvme_pplat->ns_id; if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)(long)id)) { free(id); return -EIO; @@ -727,8 +727,8 @@ static int nvme_blk_probe(struct udevice *udev) desc->log2blksz = ns->lba_shift; desc->blksz = 1 << ns->lba_shift; desc->bdev = udev; - pplat = dev_get_parent_plat(udev->parent); - sprintf(desc->vendor, "0x%.4x", pplat->vendor); + pci_pplat = dev_get_parent_plat(udev->parent); + sprintf(desc->vendor, "0x%.4x", pci_pplat->vendor); memcpy(desc->product, ndev->serial, sizeof(ndev->serial)); memcpy(desc->revision, ndev->firmware_rev, sizeof(ndev->firmware_rev));
@@ -879,6 +879,25 @@ static int nvme_probe(struct udevice *udev)
nvme_get_info_from_identify(ndev);
+ /* Create a blk device for each namespace */ + for (int i = 1; i <= ndev->nn; i++) { + struct udevice *ns_udev; + struct nvme_child_plat *pplat; + char name[20]; + + sprintf(name, "blk#%d", i); + + /* The real blksz and size will be set by nvme_blk_probe() */ + ret = blk_create_devicef(udev, "nvme-blk", name, IF_TYPE_NVME, + -1, 512, 0, &ns_udev); + if (ret) + goto free_queue; + + /* Update the platform data */ + pplat = dev_get_parent_plat(ns_udev); + pplat->ns_id = i; + } + return 0;
free_queue: @@ -893,6 +912,7 @@ U_BOOT_DRIVER(nvme) = { .bind = nvme_bind, .probe = nvme_probe, .priv_auto = sizeof(struct nvme_dev), + .per_child_plat_auto = sizeof(struct nvme_child_plat), };
struct pci_device_id nvme_supported[] = { diff --git a/drivers/nvme/nvme.h b/drivers/nvme/nvme.h index aa4b3bac67..11b3ab6872 100644 --- a/drivers/nvme/nvme.h +++ b/drivers/nvme/nvme.h @@ -637,4 +637,18 @@ struct nvme_ns { u32 mode_select_block_len; };
+/** + * An NVM Express child (namespace) platdata + * + * Every blk device on a NVMe bus has this per-child data. + * + * It can be accessed using dev_get_parent_plat(dev) if dev->parent is a + * NVMe device (i.e. UCLASS_NVME) + * + * @ns_id: namespace id + */ +struct nvme_child_plat { + unsigned ns_id; +}; + #endif /* __DRIVER_NVME_H__ */

At present for each namespace there is a block device created for it. There won't be any issue if the number of supported namespaces reported from the NVMe device is only 1.
Since QEMU commit 7f0f1acedf15 ("hw/block/nvme: support multiple namespaces"), the number of supported namespaces reported has been changed from 1 to 256, but the active namespace depends on the command line parameters passed to QEMU, with the most common case that namespace 1 being active and all other 255 inactive.
If a namespace is not active, the namespace identify command returns a zero filled data structure. We can use field NSZE (namespace size) to decide if a block device should be created.
Reported-by: Heinrich Schuchardt xypron.glpk@gmx.de Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
drivers/nvme/nvme.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index 0b4a73d170..5ec5eaca16 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -835,6 +835,7 @@ static int nvme_probe(struct udevice *udev) { int ret; struct nvme_dev *ndev = dev_get_priv(udev); + struct nvme_id_ns *id;
ndev->instance = trailing_strtol(udev->name);
@@ -880,26 +881,46 @@ static int nvme_probe(struct udevice *udev) nvme_get_info_from_identify(ndev);
/* Create a blk device for each namespace */ + + id = memalign(ndev->page_size, sizeof(struct nvme_id_ns)); + if (!id) { + ret = -ENOMEM; + goto free_queue; + } + for (int i = 1; i <= ndev->nn; i++) { struct udevice *ns_udev; struct nvme_child_plat *pplat; char name[20];
+ memset(id, 0, sizeof(*id)); + if (nvme_identify(ndev, i, 0, (dma_addr_t)(long)id)) { + ret = -EIO; + goto free_id; + } + + /* skip inactive namespace */ + if (!id->nsze) + continue; + sprintf(name, "blk#%d", i);
/* The real blksz and size will be set by nvme_blk_probe() */ ret = blk_create_devicef(udev, "nvme-blk", name, IF_TYPE_NVME, -1, 512, 0, &ns_udev); if (ret) - goto free_queue; + goto free_id;
/* Update the platform data */ pplat = dev_get_parent_plat(ns_udev); pplat->ns_id = i; }
+ free(id); return 0;
+free_id: + free(id); free_queue: free((void *)ndev->queues); free_nvme:
participants (1)
-
Bin Meng