diff --git a/MAINTAINERS b/MAINTAINERS index 5ec1e366a1..11e11d51a7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -914,6 +914,14 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-nios.git F: arch/nios2/ +NVMe +M: Bin Meng +S: Maintained +F: drivers/nvme/ +F: cmd/nvme.c +F: include/nvme.h +F: doc/develop/driver-model/nvme.rst + ONENAND #M: Lukasz Majewski S: Orphaned (Since 2017-01) diff --git a/arch/x86/cpu/u-boot-64.lds b/arch/x86/cpu/u-boot-64.lds index 98c7f8e9c5..ee0812aefb 100644 --- a/arch/x86/cpu/u-boot-64.lds +++ b/arch/x86/cpu/u-boot-64.lds @@ -107,4 +107,5 @@ SECTIONS /DISCARD/ : { *(.plt*) } /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) } + /DISCARD/ : { *(.note.gnu.property) } } diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds index 4a655bf9b5..346f60bdac 100644 --- a/arch/x86/cpu/u-boot-spl.lds +++ b/arch/x86/cpu/u-boot-spl.lds @@ -82,6 +82,7 @@ SECTIONS /DISCARD/ : { *(.plt*) } /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) } + /DISCARD/ : { *(.note.gnu.property) } #if defined(CONFIG_SPL_X86_16BIT_INIT) || defined(CONFIG_TPL_X86_16BIT_INIT) /* diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds index a283c290ee..22fde01e74 100644 --- a/arch/x86/cpu/u-boot.lds +++ b/arch/x86/cpu/u-boot.lds @@ -105,6 +105,7 @@ SECTIONS /DISCARD/ : { *(.plt*) } /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) } + /DISCARD/ : { *(.note.gnu.property) } #ifdef CONFIG_X86_16BIT_INIT /* diff --git a/doc/develop/driver-model/index.rst b/doc/develop/driver-model/index.rst index 10a76256b0..7366ef818c 100644 --- a/doc/develop/driver-model/index.rst +++ b/doc/develop/driver-model/index.rst @@ -19,6 +19,7 @@ subsystems i2c-howto livetree migration + nvme of-plat pci-info pmic-framework diff --git a/doc/README.nvme b/doc/develop/driver-model/nvme.rst similarity index 88% rename from doc/README.nvme rename to doc/develop/driver-model/nvme.rst index e8f9be149e..736c0a063d 100644 --- a/doc/README.nvme +++ b/doc/develop/driver-model/nvme.rst @@ -1,10 +1,12 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# Copyright (C) 2017 NXP Semiconductors -# Copyright (C) 2017 Bin Meng +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (C) 2017 NXP Semiconductors +.. Copyright (C) 2017 Bin Meng + +NVMe Support +============ What is NVMe -============ +------------ NVM Express (NVMe) is a register level interface that allows host software to communicate with a non-volatile memory subsystem. This interface is optimized @@ -48,6 +50,8 @@ identified. To list all of the NVMe hard disks, try: +.. code-block:: none + => nvme info Device 0: Vendor: 0x8086 Rev: 8DV10131 Prod: CVFT535600LS400BGN Type: Hard Disk @@ -55,10 +59,14 @@ To list all of the NVMe hard disks, try: and print out detailed information for controller and namespaces via: +.. code-block:: none + => nvme detail Raw block read/write to can be done via the 'nvme read/write' commands: +.. code-block:: none + => nvme read a0000000 0 11000 => tftp 80000000 /tftpboot/kernel.itb @@ -66,6 +74,8 @@ Raw block read/write to can be done via the 'nvme read/write' commands: Of course, file system command can be used on the NVMe hard disk as well: +.. code-block:: none + => fatls nvme 0:1 32376967 kernel.itb 22929408 100m @@ -81,4 +91,7 @@ QEMU supports NVMe emulation and we can test NVMe driver with QEMU x86 running U-Boot. Please see README.x86 for how to build u-boot.rom image for QEMU x86. Example command line to call QEMU x86 below with emulated NVMe device: -$ ./qemu-system-i386 -drive file=nvme.img,if=none,id=drv0 -device nvme,drive=drv0,serial=QEMUNVME0001 -bios u-boot.rom + +.. code-block:: bash + + $ ./qemu-system-i386 -drive file=nvme.img,if=none,id=drv0 -device nvme,drive=drv0,serial=QEMUNVME0001 -bios u-boot.rom 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 -#include -#include #include -#include -#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..f6465ea7f4 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -81,7 +81,7 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2, u64 *prp_pool; int length = total_len; int i, nprps; - u32 prps_per_page = (page_size >> 3) - 1; + u32 prps_per_page = page_size >> 3; u32 num_pages; length -= (page_size - offset); @@ -157,7 +157,7 @@ static u16 nvme_read_completion_status(struct nvme_queue *nvmeq, u16 index) invalidate_dcache_range(start, stop); - return le16_to_cpu(readw(&(nvmeq->cqes[index].status))); + return readw(&(nvmeq->cqes[index].status)); } /** @@ -221,7 +221,7 @@ static int nvme_submit_sync_cmd(struct nvme_queue *nvmeq, } if (result) - *result = le32_to_cpu(readl(&(nvmeq->cqes[head].result))); + *result = readl(&(nvmeq->cqes[head].result)); if (++head == nvmeq->q_depth) { head = 0; @@ -304,7 +304,7 @@ static int nvme_enable_ctrl(struct nvme_dev *dev) { dev->ctrl_config &= ~NVME_CC_SHN_MASK; dev->ctrl_config |= NVME_CC_ENABLE; - writel(cpu_to_le32(dev->ctrl_config), &dev->bar->cc); + writel(dev->ctrl_config, &dev->bar->cc); return nvme_wait_ready(dev, true); } @@ -313,7 +313,7 @@ static int nvme_disable_ctrl(struct nvme_dev *dev) { dev->ctrl_config &= ~NVME_CC_SHN_MASK; dev->ctrl_config &= ~NVME_CC_ENABLE; - writel(cpu_to_le32(dev->ctrl_config), &dev->bar->cc); + writel(dev->ctrl_config, &dev->bar->cc); return nvme_wait_ready(dev, false); } @@ -387,7 +387,6 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) aqa = nvmeq->q_depth - 1; aqa |= aqa << 16; - aqa |= aqa << 16; dev->page_size = 1 << page_shift; @@ -706,10 +705,9 @@ static int nvme_blk_probe(struct udevice *udev) if (!id) return -ENOMEM; - 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 = trailing_strtol(udev->name); if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)(long)id)) { free(id); return -EIO; @@ -719,11 +717,9 @@ static int nvme_blk_probe(struct udevice *udev) flbas = id->flbas & NVME_NS_FLBAS_LBA_MASK; ns->flbas = flbas; ns->lba_shift = id->lbaf[flbas].ds; - ns->mode_select_num_blocks = le64_to_cpu(id->nsze); - ns->mode_select_block_len = 1 << ns->lba_shift; list_add(&ns->list, &ndev->namespaces); - desc->lba = ns->mode_select_num_blocks; + desc->lba = le64_to_cpu(id->nsze); desc->log2blksz = ns->lba_shift; desc->blksz = 1 << ns->lba_shift; desc->bdev = udev; @@ -835,6 +831,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); @@ -879,8 +876,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; + 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; + + /* + * 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) + goto free_id; + } + + free(id); return 0; +free_id: + free(id); free_queue: free((void *)ndev->queues); free_nvme: diff --git a/drivers/nvme/nvme.h b/drivers/nvme/nvme.h index aa4b3bac67..c6aae4da5d 100644 --- a/drivers/nvme/nvme.h +++ b/drivers/nvme/nvme.h @@ -633,8 +633,6 @@ struct nvme_ns { int devnum; int lba_shift; u8 flbas; - u64 mode_select_num_blocks; - u32 mode_select_block_len; }; #endif /* __DRIVER_NVME_H__ */