diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2021-02-11 21:25:33 +0100 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2021-02-13 15:37:34 +0100 |
| commit | 7dc06cf18b266aa30ab60ffd33ac7cfce46bf06d (patch) | |
| tree | 0a17a5d606e6b6fa6b1635cd6e1b561b8144c4e9 | |
| parent | 3bcd26dd8ca045781fc577724098f3fad2067c56 (diff) | |
| download | playground-7dc06cf18b266aa30ab60ffd33ac7cfce46bf06d.tar.gz | |
nvme: add platform driver registrationnvme-platform
After the common code is detached from the PCI specific
ones, add a parallel part for platform_driver registration.
Keep it in the same file for the moment to allow rebasing,
it can be split into multiple modules later on.
This is completely untested and probably does not work.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
| -rw-r--r-- | drivers/nvme/host/Kconfig | 24 | ||||
| -rw-r--r-- | drivers/nvme/host/Makefile | 2 | ||||
| -rw-r--r-- | drivers/nvme/host/nvme.h | 5 | ||||
| -rw-r--r-- | drivers/nvme/host/pci.c | 136 |
4 files changed, 162 insertions, 5 deletions
diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig index a44d49d63968a..c9d77ba1021e5 100644 --- a/drivers/nvme/host/Kconfig +++ b/drivers/nvme/host/Kconfig @@ -3,10 +3,17 @@ config NVME_CORE tristate select BLK_DEV_INTEGRITY_T10 if BLK_DEV_INTEGRITY +config NVME_MMIO + tristate + select NVME_CORE + help + This is the common code shared by the PCIe driver (BLK_DEV_NVME) + and the platform driver used for on-chip implementations. + config BLK_DEV_NVME - tristate "NVM Express block device" + tristate "NVM Express block device using PCIe" depends on PCI && BLOCK - select NVME_CORE + select NVME_MMIO help The NVM Express driver is for solid state drives directly connected to the PCI or PCI Express bus. If you know you @@ -15,6 +22,19 @@ config BLK_DEV_NVME To compile this driver as a module, choose M here: the module will be called nvme. +config BLK_DEV_NVME_PLATFORM + tristate "NVM Express block device integrated on SoC" + depends on OF && BLOCK + select NVME_MMIO + help + NVM Express devices can be integrated into a System-on-Chip + (SoC) platform without a discoverable PCIe bus. + The NVMe platform driver supports such devices using + a device tree description. + + To compile this driver as a module, choose M here: the + module will be called nvme. + config NVME_MULTIPATH bool "NVMe multipath support" depends on NVME_CORE diff --git a/drivers/nvme/host/Makefile b/drivers/nvme/host/Makefile index d7f6a87687b8d..bbc5f9f3a51cf 100644 --- a/drivers/nvme/host/Makefile +++ b/drivers/nvme/host/Makefile @@ -3,7 +3,7 @@ ccflags-y += -I$(src) obj-$(CONFIG_NVME_CORE) += nvme-core.o -obj-$(CONFIG_BLK_DEV_NVME) += nvme.o +obj-$(CONFIG_NVME_MMIO) += nvme.o obj-$(CONFIG_NVME_FABRICS) += nvme-fabrics.o obj-$(CONFIG_NVME_RDMA) += nvme-rdma.o obj-$(CONFIG_NVME_FC) += nvme-fc.o diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 88a6b97247f50..83adc39808567 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -144,6 +144,11 @@ enum nvme_quirks { * NVMe 1.3 compliance. */ NVME_QUIRK_NO_NS_DESC_LIST = (1 << 15), + + /* + * MMIO based hardware that is not on a PCI bus + */ + NVME_QUIRK_PLATFORM_DEVICE = (1 << 16), }; /* diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index e36710367662c..b5e1532aeb27d 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -19,6 +19,7 @@ #include <linux/mutex.h> #include <linux/once.h> #include <linux/pci.h> +#include <linux/platform_device.h> #include <linux/suspend.h> #include <linux/t10-pi.h> #include <linux/types.h> @@ -185,7 +186,11 @@ static inline struct nvme_dev *to_nvme_dev(struct nvme_ctrl *ctrl) static inline struct pci_dev *nvme_pci_dev(struct nvme_dev *dev) { - return to_pci_dev(dev->dev); + if (IS_ENABLED(CONFIG_BLK_DEV_NVME) && + !(dev->ctrl.quirks & NVME_QUIRK_PLATFORM_DEVICE)) + return to_pci_dev(dev->dev); + + return NULL; } /* @@ -2909,6 +2914,108 @@ static void nvme_remove(struct nvme_dev *dev) nvme_release_prp_pools(dev); } +#if IS_ENABLED(CONFIG_BLK_DEV_NVME_PLATFORM) +static const struct nvme_ctrl_ops nvme_platform_ctrl_ops = { + .name = "platform", + .module = THIS_MODULE, + .flags = NVME_F_METADATA_SUPPORTED, + .reg_read32 = nvme_reg_read32, + .reg_write32 = nvme_reg_write32, + .reg_read64 = nvme_reg_read64, + .free_ctrl = nvme_free_ctrl, + .submit_async_event = nvme_submit_async_event, + .get_address = nvme_get_address, +}; + +static void nvme_platform_async_probe(void *data, async_cookie_t cookie) +{ + struct nvme_dev *dev = data; + + flush_work(&dev->ctrl.reset_work); + flush_work(&dev->ctrl.scan_work); + nvme_put_ctrl(&dev->ctrl); +} + +static int nvme_platform_probe(struct platform_device *pdev) +{ + int result; + struct nvme_dev *dev; + struct resource *res; + + dev = nvme_dev_alloc(&pdev->dev); + if (!dev) + return -ENOMEM; + + platform_set_drvdata(pdev, dev); + dev->bar = devm_platform_ioremap_resource(pdev, 0); + result = PTR_ERR_OR_ZERO(dev->bar); + if (result) + goto out; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + result = ENXIO; + goto out_unmap; + } + + dev->bar_mapped_size = resource_size(res); + dev->dbs = dev->bar + NVME_REG_DBS; + + dev->platform_irq = platform_get_irq(pdev, 0); + if (dev->platform_irq < 0) { + result = dev->platform_irq; + goto out_unmap; + } + + result = nvme_init_ctrl(&dev->ctrl, &pdev->dev, &nvme_platform_ctrl_ops, + NVME_QUIRK_SINGLE_VECTOR | + NVME_QUIRK_PLATFORM_DEVICE); + if (result) + goto out_unmap; + + nvme_reset_ctrl(&dev->ctrl); + async_schedule(nvme_platform_async_probe, dev); + + return 0; + +out_unmap: + devm_iounmap(&pdev->dev, dev->bar); +out: + nvme_dev_free(dev); + return result; +} + +static int nvme_platform_remove(struct platform_device *pdev) +{ + struct nvme_dev *dev = platform_get_drvdata(pdev); + + nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING); + platform_set_drvdata(pdev, NULL); + + nvme_remove(dev); + + nvme_uninit_ctrl(&dev->ctrl); + + return 0; +} + +struct of_device_id nvme_of_device_ids[] = { + { .compatible = "generic-nvmexpress", }, + {}, +}; + +struct platform_driver nvme_platform_driver = { + .driver = { + .name = "nvme-platform", + .owner = THIS_MODULE, + .of_match_table = nvme_of_device_ids, + }, + .probe = nvme_platform_probe, + .remove = nvme_platform_remove, +}; +#endif + +#if IS_ENABLED(CONFIG_BLK_DEV_NVME) static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = { .name = "pcie", .module = THIS_MODULE, @@ -3380,20 +3487,45 @@ static struct pci_driver nvme_driver = { .sriov_configure = pci_sriov_configure_simple, .err_handler = &nvme_pci_err_handler, }; +#endif static int __init nvme_init(void) { + int ret; + BUILD_BUG_ON(sizeof(struct nvme_create_cq) != 64); BUILD_BUG_ON(sizeof(struct nvme_create_sq) != 64); BUILD_BUG_ON(sizeof(struct nvme_delete_queue) != 64); BUILD_BUG_ON(IRQ_AFFINITY_MAX_SETS < 2); - return pci_register_driver(&nvme_driver); +#if IS_ENABLED(CONFIG_BLK_DEV_NVME) + ret = pci_register_driver(&nvme_driver); + if (ret) + return ret; +#endif + +#if IS_ENABLED(CONFIG_BLK_DEV_NVME_PLATFORM) + ret = platform_driver_register(&nvme_platform_driver); +#endif + +#if IS_ENABLED(CONFIG_BLK_DEV_NVME) + if (ret) + pci_unregister_driver(&nvme_driver); +#endif + + return ret; } static void __exit nvme_exit(void) { +#if IS_ENABLED(CONFIG_BLK_DEV_NVME) pci_unregister_driver(&nvme_driver); +#endif + +#if IS_ENABLED(CONFIG_BLK_DEV_NVME_PLATFORM) + platform_driver_unregister(&nvme_platform_driver); +#endif + flush_workqueue(nvme_wq); } |
