[U-Boot] [RFC, 1/2] NVMe: add NVMe driver support

Jon Nettleton jon at solid-run.com
Fri Jul 28 13:44:34 UTC 2017


Well it is a series.  Some can probably be squashed.  I can post it to
a branch in github if it is easier.  Otherwise here is the rest.

>From f1ab1f30fe52bea7dc5c647b0570d73d907b8d90 Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon at solid-run.com>
Date: Fri, 28 Jul 2017 08:54:09 +0200
Subject: [PATCH 1/6] nvme: Only support CONFIG_BLK

There is no reason to support devices that don't work with
CONFIG_BLK.  If needed the other drivers should be fixed.

Signed-off-by: Jon Nettleton <jon at solid-run.com>
---
 common/nvme.c         | 33 ---------------------------
 drivers/block/Kconfig |  1 +
 drivers/block/nvme.c  | 63 ---------------------------------------------------
 drivers/block/nvme.h  |  2 --
 include/nvme.h        | 10 +-------
 5 files changed, 2 insertions(+), 107 deletions(-)

diff --git a/common/nvme.c b/common/nvme.c
index ed3250f43f..cdbfa665a0 100644
--- a/common/nvme.c
+++ b/common/nvme.c
@@ -21,7 +21,6 @@ struct blk_desc *nvme_get_dev(int dev)
 }
 #endif

-#ifdef CONFIG_BLK
 struct udevice *udev;
 static unsigned long nvme_bread(struct udevice *dev, lbaint_t start,
  lbaint_t blkcnt, void *dst)
@@ -34,19 +33,6 @@ static unsigned long nvme_bwrite(struct udevice
*dev, lbaint_t start,
 {
  return nvme_write(dev, start, blkcnt, buffer);
 }
-#else
-static unsigned long nvme_bread(struct blk_desc *block_dev, lbaint_t start,
- lbaint_t blkcnt, void *dst)
-{
- return nvme_read(block_dev->devnum, start, blkcnt, dst);
-}
-
-static unsigned long nvme_bwrite(struct blk_desc *block_dev, lbaint_t start,
- lbaint_t blkcnt, const void *buffer)
-{
- return nvme_write(block_dev->devnum, start, blkcnt, buffer);
-}
-#endif

 int __nvme_initialize(void)
 {
@@ -54,25 +40,15 @@ int __nvme_initialize(void)
  int i;

  for (i = 0; i < CONFIG_SYS_NVME_MAX_DEVICE; i++) {
-#ifdef CONFIG_BLK
  rc = init_nvme(udev);
  if (!rc)
  rc = scan_nvme(udev);
-#else
- rc = init_nvme(i);
- if (!rc)
- rc = scan_nvme(i);
-#endif

  if (!rc && nvme_dev_desc[i].lba > 0) {
  nvme_dev_desc[i].if_type = IF_TYPE_NVME;
  nvme_dev_desc[i].devnum = i;
  nvme_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
  nvme_dev_desc[i].type = DEV_TYPE_HARDDISK;
-#ifndef CONFIG_BLK
- nvme_dev_desc[i].block_read = nvme_bread;
- nvme_dev_desc[i].block_write = nvme_bwrite;
-#endif

  part_init(&nvme_dev_desc[i]);
  ret = i;
@@ -88,7 +64,6 @@ int __nvme_initialize(void)
 }
 int nvme_initialize(void) __attribute__((weak, alias("__nvme_initialize")));

-#ifdef CONFIG_BLK
 static void nvme_name(char *str, int cardnum)
 {
  sprintf(str, "nvme#%u", cardnum);
@@ -117,11 +92,3 @@ U_BOOT_DRIVER(nvme) = {
  .priv_auto_alloc_size = sizeof(struct nvme_ns),
 };
 U_BOOT_PCI_DEVICE(nvme, nvme_supported);
-#else
-U_BOOT_LEGACY_BLK(nvme) = {
- .if_typename = "nvme",
- .if_type = IF_TYPE_NVME,
- .max_devs = CONFIG_SYS_NVME_MAX_DEVICE,
- .desc = nvme_dev_desc,
-};
-#endif
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 129208f980..de1a3a50c1 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -63,6 +63,7 @@ endmenu
 config NVME
  bool "Support NVMe devices"
  depends on PCI
+ depends on BLK
  help
   This option enables supporting for all NVMe devices.
   It supports the basic functions before using NVMe devices
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 2e06477206..80fbd27d95 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -549,13 +549,8 @@ static int nvme_get_info_from_identify(struct
nvme_dev *dev)
  if (ctrl->mdts)
  dev->max_transfer_shift = (ctrl->mdts + shift);

-#ifdef CONFIG_BLK
  dm_pci_read_config16(dev->pdev, PCI_VENDOR_ID, &vendor);
  dm_pci_read_config16(dev->pdev, PCI_DEVICE_ID, &device);
-#else
- pci_read_config_word(dev->pci_dev, PCI_VENDOR_ID, &vendor);
- pci_read_config_word(dev->pci_dev, PCI_DEVICE_ID, &device);
-#endif
  if ((vendor == PCI_VENDOR_ID_INTEL) &&
     (device == 0x0953) && ctrl->vs[3]) {
  unsigned int max_transfer_shift;
@@ -571,22 +566,14 @@ static int nvme_get_info_from_identify(struct
nvme_dev *dev)
  return 0;
 }

-#ifdef CONFIG_BLK
 int init_nvme(struct udevice *udev)
-#else
-int init_nvme(int devnum)
-#endif
 {
  static int init_done;
  pci_dev_t pci_dev;
  int ret;
-#ifdef CONFIG_BLK
  struct nvme_ns *ns = dev_get_priv(udev);
  struct nvme_dev *dev = ns->dev;
  int devnum = trailing_strtol(udev->name);
-#else
- struct nvme_dev *dev;
-#endif
  u32 val;
  u64 cap;

@@ -611,15 +598,9 @@ int init_nvme(int devnum)

  dev->instance = nvme_info.idx - 1;
  INIT_LIST_HEAD(&dev->namespaces);
-#ifdef CONFIG_BLK
  dev->pdev = udev;
  dev->bar = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0,
  PCI_REGION_MEM);
-#else
- dev->pci_dev = pci_dev;
- dev->bar = pci_map_bar(dev->pci_dev, PCI_BASE_ADDRESS_0,
- PCI_REGION_MEM);
-#endif
  if (readl(&dev->bar->csts) == -1) {
  ret = -ENODEV;
  printf("Error: nvme%d: Out of Memory!\n", nvme_info.idx - 1);
@@ -644,25 +625,13 @@ int init_nvme(int devnum)

  /* Try to enable I/O accesses and bus-mastering */
  val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-#ifdef CONFIG_BLK
  dm_pci_write_config32(udev, PCI_COMMAND, val);
-#else
- pci_write_config_dword(dev->pci_dev, PCI_COMMAND, val);
-#endif

  /* Print a debug message with the IO base address */
-#ifdef CONFIG_BLK
  dm_pci_read_config32(udev, PCI_BASE_ADDRESS_0, &val);
-#else
- pci_read_config_dword(dev->pci_dev, PCI_BASE_ADDRESS_0, &val);
-#endif

  /* Make sure it worked */
-#ifdef CONFIG_BLK
  dm_pci_read_config32(udev, PCI_COMMAND, &val);
-#else
- pci_read_config_dword(dev->pci_dev, PCI_COMMAND, &val);
-#endif
  if (!(val & PCI_COMMAND_MEMORY)) {
  printf("Can't enable I/O memory\n");
  ret = -ENOSPC;
@@ -732,18 +701,11 @@ static struct nvme_ns *find_ns_by_devnum(int devnum)
  return NULL;
 }

-#ifdef CONFIG_BLK
 int scan_nvme(struct udevice *udev)
 {
  struct nvme_ns *ns = dev_get_priv(udev);
  struct nvme_dev *dev = ns->dev;
  int devnum = trailing_strtol(udev->name);
-#else
-int scan_nvme(int devnum)
-{
- struct nvme_ns *ns;
- struct nvme_dev *dev;
-#endif
  int ret;
  u8 flbas;
  u16 vendor;
@@ -783,15 +745,10 @@ int scan_nvme(int devnum)
  nvme_dev_desc[devnum].lba = ns->mode_select_num_blocks;
  nvme_dev_desc[devnum].log2blksz = ns->lba_shift;
  nvme_dev_desc[devnum].blksz = 1 << ns->lba_shift;
-#ifdef CONFIG_BLK
  nvme_dev_desc[devnum].bdev = dev->pdev;
  dm_pci_read_config16(dev->pdev, PCI_VENDOR_ID, &vendor);
  udev->priv = ns;
  udev->uclass_platdata = (void *)&nvme_dev_desc[devnum];
-#else
- nvme_dev_desc[devnum].priv = (void *)ns;
- pci_read_config_word(dev->pci_dev, PCI_VENDOR_ID, &vendor);
-#endif
  sprintf(vendor_c, "0x%.4x", vendor);
  memcpy(nvme_dev_desc[devnum].product,
        dev->serial, sizeof(dev->serial));
@@ -895,13 +852,9 @@ static void print_metadata_cap(u8 mc, int devnum)

 int nvme_print_info(int devnum)
 {
-#ifdef CONFIG_BLK
  struct udevice *udev;
  blk_get_device(IF_TYPE_NVME, devnum, &udev);
  struct nvme_ns *ns = dev_get_priv(udev);
-#else
- struct nvme_ns *ns = nvme_dev_desc[devnum].priv;
-#endif
  if (!ns) {
  printf("Can not find device %d\n", devnum);
  return -EINVAL;
@@ -927,20 +880,12 @@ int nvme_print_info(int devnum)
  return 0;
 }

-#ifdef CONFIG_BLK
 ulong nvme_write(struct udevice *udev, ulong blknr, lbaint_t blkcnt,
  const void *buffer)
 {
  struct nvme_ns *ns = dev_get_priv(udev);
  struct nvme_dev *dev = ns->dev;
  int devnum = ns->devnum;
-#else
-ulong nvme_write(int devnum, ulong blknr, lbaint_t blkcnt,
- const void *buffer)
-{
- struct nvme_ns *ns = nvme_dev_desc[devnum].priv;
- struct nvme_dev *dev = ns->dev;
-#endif
  struct nvme_command c;
  int status;
  u64 prp2;
@@ -987,20 +932,12 @@ ulong nvme_write(int devnum, ulong blknr, lbaint_t blkcnt,
  return (total_len - temp_len) >> nvme_dev_desc[devnum].log2blksz;
 }

-#ifdef CONFIG_BLK
 ulong nvme_read(struct udevice *udev, ulong blknr, lbaint_t blkcnt,
  void *buffer)
 {
  struct nvme_ns *ns = dev_get_priv(udev);
  struct nvme_dev *dev = ns->dev;
  int devnum = ns->devnum;
-#else
-ulong nvme_read(int devnum, ulong blknr, lbaint_t blkcnt,
- void *buffer)
-{
- struct nvme_ns *ns = nvme_dev_desc[devnum].priv;
- struct nvme_dev *dev = ns->dev;
-#endif
  struct nvme_command c;
  int status;
  u64 prp2;
diff --git a/drivers/block/nvme.h b/drivers/block/nvme.h
index 9345f90a1c..f0fad95b7b 100644
--- a/drivers/block/nvme.h
+++ b/drivers/block/nvme.h
@@ -61,9 +61,7 @@ struct nvme_dev {
  struct nvme_queue **queues;
  u32 __iomem *dbs;
  unsigned int cardnum;
-#ifdef CONFIG_BLK
  struct udevice *pdev;
-#endif
  pci_dev_t pci_dev;
  int instance;
  uint8_t *hw_addr;
diff --git a/include/nvme.h b/include/nvme.h
index 3f8f94f462..e13de19163 100644
--- a/include/nvme.h
+++ b/include/nvme.h
@@ -7,22 +7,14 @@
 #ifndef __NVME_H__
 #define __NVME_H__
 #include <part.h>
+#include <pci.h>

-#ifdef CONFIG_BLK
 int init_nvme(struct udevice *udev);
 int scan_nvme(struct udevice *udev);
 ulong nvme_read(struct udevice *udev, ulong blknr, lbaint_t blkcnt,
  void *buffer);
 ulong nvme_write(struct udevice *udev, ulong blknr, lbaint_t blkcnt,
  const void *buffer);
-#else
-int init_nvme(int devnum);
-int scan_nvme(int devnum);
-ulong nvme_read(int devnum, ulong blknr, lbaint_t blkcnt,
- void *buffer);
-ulong nvme_write(int devnum, ulong blknr, lbaint_t blkcnt,
- const void *buffer);
-#endif
 int nvme_print_info(int devnum);
 int nvme_initialize(void);
 int __nvme_initialize(void);
-- 
2.11.1


>From 5de8da9db30a54db6239f0947d61ef92043aac30 Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon at solid-run.com>
Date: Fri, 28 Jul 2017 09:00:48 +0200
Subject: [PATCH 2/6] NVMe: correctly identify NVMe Device.

IF_TYPE_NVME is not an unknown device any longer.

Signed-off-by: Jon Nettleton <jon at solid-run.com>
---
 disk/part.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/disk/part.c b/disk/part.c
index 983104e349..8a5d29923c 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -271,6 +271,9 @@ static void print_part_header(const char *type,
struct blk_desc *dev_desc)
  case IF_TYPE_HOST:
  puts("HOST");
  break;
+ case IF_TYPE_NVME:
+ puts("NVME");
+ break;
  default:
  puts ("UNKNOWN");
  break;
-- 
2.11.1


>From 81c8d7935b345bd9fb659e2a368bf1dab6325212 Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon at solid-run.com>
Date: Fri, 28 Jul 2017 09:04:08 +0200
Subject: [PATCH 3/6] NVMe: Only increment device if probing is successful

Any time along the init process we should make sure and decrement
the nvme id if we fail.  Otherwise constant probing will keep
incrementing the device counter.

Signed-off-by: Jon Nettleton <jon at solid-run.com>
---
 drivers/block/nvme.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 80fbd27d95..39eb066b6d 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -585,13 +585,13 @@ int init_nvme(struct udevice *udev)
  pci_dev  = pci_find_devices(nvme_supported, nvme_info.idx++);
  if (pci_dev == -1) {
  printf("Error: can't find pci device \"nvme%d\"\n",
-       nvme_info.idx - 1);
+       --nvme_info.idx);
  return -ENODEV;
  }

  dev = malloc(sizeof(*dev));
  if (dev == NULL) {
- printf("Error: nvme%d: Out of Memory!\n", nvme_info.idx - 1);
+ printf("Error: nvme%d: Out of Memory!\n", --nvme_info.idx);
  return -ENOMEM;
  }
  memset(dev, 0, sizeof(*dev));
@@ -603,7 +603,7 @@ int init_nvme(struct udevice *udev)
  PCI_REGION_MEM);
  if (readl(&dev->bar->csts) == -1) {
  ret = -ENODEV;
- printf("Error: nvme%d: Out of Memory!\n", nvme_info.idx - 1);
+ printf("Error: nvme%d: Out of Memory!\n", --nvme_info.idx);
  goto free_nvme;
  }

-- 
2.11.1


>From eca9727cc11832e9e1e8ecab174189242424bb5d Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon at solid-run.com>
Date: Fri, 28 Jul 2017 09:06:11 +0200
Subject: [PATCH 4/6] NVMe: fix number of blocks detection.

NVMe should use the nsze value from the queried device.  This will
reflect the total number of blocks of the device and fixes detecting
my Samsung 960 EVO 256GB.

Original:
Capacity: 40386.6 MB = 39.4 GB (82711872 x 512)

Fixed:
Capacity: 238475.1 MB = 232.8 GB (488397168 x 512)
Signed-off-by: Jon Nettleton <jon at solid-run.com>
---
 drivers/block/nvme.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 39eb066b6d..6d2437503b 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -739,7 +739,7 @@ int scan_nvme(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->nuse);
+ ns->mode_select_num_blocks = le64_to_cpu(id->nsze);
  ns->mode_select_block_len = 1 << ns->lba_shift;
  list_add(&ns->list, &dev->namespaces);
  nvme_dev_desc[devnum].lba = ns->mode_select_num_blocks;
-- 
2.11.1


>From 92637e5499af333913284a9d8324b7ad861b7c54 Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon at solid-run.com>
Date: Fri, 28 Jul 2017 09:10:22 +0200
Subject: [PATCH 5/6] NVMe: Detect devices that are class Storage Express

This adds support to detect the catchall PCI class for NVMe devices.
It allows the drivers to work with most NVMe devices that don't need
specific detection due to quirks etc.  Tested against a Samsung
960 EVO drive.

Signed-off-by: Jon Nettleton <jon at solid-run.com>
---
 common/nvme.c        | 2 ++
 drivers/block/nvme.c | 6 +++++-
 include/pci_ids.h    | 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/common/nvme.c b/common/nvme.c
index cdbfa665a0..253e5bb7c2 100644
--- a/common/nvme.c
+++ b/common/nvme.c
@@ -12,8 +12,10 @@ struct blk_desc nvme_dev_desc[CONFIG_SYS_NVME_MAX_DEVICE];

 struct pci_device_id nvme_supported[] = {
  { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0953) },
+ { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) },
  {}
 };
+
 #ifdef CONFIG_PARTITIONS
 struct blk_desc *nvme_get_dev(int dev)
 {
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 6d2437503b..26d6400a22 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -582,7 +582,11 @@ int init_nvme(struct udevice *udev)
  return 0;
  }

- pci_dev  = pci_find_devices(nvme_supported, nvme_info.idx++);
+ pci_dev = pci_find_class(PCI_CLASS_STORAGE_EXPRESS, nvme_info.idx++);
+ if (pci_dev == -1) {
+ pci_dev = pci_find_devices(nvme_supported, nvme_info.idx);
+ }
+
  if (pci_dev == -1) {
  printf("Error: can't find pci device \"nvme%d\"\n",
        --nvme_info.idx);
diff --git a/include/pci_ids.h b/include/pci_ids.h
index ab6aa58adb..fdda679cc0 100644
--- a/include/pci_ids.h
+++ b/include/pci_ids.h
@@ -21,6 +21,7 @@
 #define PCI_CLASS_STORAGE_SATA 0x0106
 #define PCI_CLASS_STORAGE_SATA_AHCI 0x010601
 #define PCI_CLASS_STORAGE_SAS 0x0107
+#define PCI_CLASS_STORAGE_EXPRESS 0x010802
 #define PCI_CLASS_STORAGE_OTHER 0x0180

 #define PCI_BASE_CLASS_NETWORK 0x02
-- 
2.11.1


>From 98bcf3c2dbc0b611e4895b391bce7903597ecf3a Mon Sep 17 00:00:00 2001
From: Jon Nettleton <jon at solid-run.com>
Date: Fri, 28 Jul 2017 09:13:56 +0200
Subject: [PATCH 6/6] NVMe: match printf types to make GCC 6 happy.

This mistyping was making gcc 6 unhappy, so fix it up.

Signed-off-by: Jon Nettleton <jon at solid-run.com>
---
 cmd/nvme.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cmd/nvme.c b/cmd/nvme.c
index 5c8bf42bc9..49864baf4e 100644
--- a/cmd/nvme.c
+++ b/cmd/nvme.c
@@ -77,7 +77,7 @@ static int do_nvme_read(cmd_tbl_t *cmdtp, int flag, int argc,
  ulong n;
  lbaint_t blk = simple_strtoul(argv[2], NULL, 16);

- printf("\nNVME read: device %d block # %ld, count %ld ... ",
+ printf("\nNVME read: device %d block # %llu, count %lu ... ",
        nvme_curr_device, blk, cnt);

  time = get_timer(0);
@@ -108,7 +108,7 @@ static int do_nvme_write(cmd_tbl_t *cmdtp, int
flag, int argc,
  ulong n;
  lbaint_t blk = simple_strtoul(argv[2], NULL, 16);

- printf("\nNVME write: device %d block # %ld, count %ld ... ",
+ printf("\nNVME write: device %d block # %llu, count %lu ... ",
        nvme_curr_device, blk, cnt);

  time = get_timer(0);
-- 
2.11.1

On Fri, Jul 28, 2017 at 1:11 PM, Bin Meng <bmeng.cn at gmail.com> wrote:
> Hi Jon,
>
> On Fri, Jul 28, 2017 at 3:51 PM, Jon Nettleton <jon at solid-run.com> wrote:
>> Zhikang and Tom,
>>
>> Sorry for entering the list like this, however I wanted to reply to
>> this topic from my work account.  I attempted to email Zhikang
>> separately however the email was bounced back.
>>
>> I needed to make some changes in order to get Zhikang's work running
>> on our Macchiattobin board with a Samsung 960 EVO NVMe drive.  I
>> wanted to make this patchset accessible so it could be included in the
>> next submission to mainline it.  No reason to duplicate work.
>>
>> Since this is just a patchset for the RFC I will only leave it here
>> for whomever integrates the NVMe support, or if additional users want
>> to test against it.
>>
>
> Can you send the patch out instead of attachment? I may have some time
> to try the NVMe driver next week.
>
> Regards,
> Bin


More information about the U-Boot mailing list