X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fnvme%2Fnvme.c;h=f915817aaa431cfbc4f0fad5457ef8674f20d546;hb=bb1bb4bb5df9df4d3f07e39a632daaff79e4b77e;hp=ec32d0de27a1f1b7e4dcee80bfce5b1fb1889f47;hpb=95431aa54cfe87f7451f588663256b3aec09a79a;p=oweals%2Fu-boot.git diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index ec32d0de27..f915817aaa 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2017 NXP Semiconductors * Copyright (C) 2017 Bin Meng - * - * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -74,6 +73,9 @@ 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 num_pages; + length -= (page_size - offset); if (length <= 0) { @@ -90,15 +92,20 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2, } nprps = DIV_ROUND_UP(length, page_size); + num_pages = DIV_ROUND_UP(nprps, prps_per_page); if (nprps > dev->prp_entry_num) { free(dev->prp_pool); - dev->prp_pool = malloc(nprps << 3); + /* + * Always increase in increments of pages. It doesn't waste + * much memory and reduces the number of allocations. + */ + dev->prp_pool = memalign(page_size, num_pages * page_size); if (!dev->prp_pool) { printf("Error: malloc prp_pool fail\n"); return -ENOMEM; } - dev->prp_entry_num = nprps; + dev->prp_entry_num = prps_per_page * num_pages; } prp_pool = dev->prp_pool; @@ -116,6 +123,9 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2, } *prp2 = (ulong)dev->prp_pool; + flush_dcache_range((ulong)dev->prp_pool, (ulong)dev->prp_pool + + dev->prp_entry_num * sizeof(u64)); + return 0; } @@ -562,9 +572,6 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (result <= 0) return result; - if (result < nr_io_queues) - nr_io_queues = result; - dev->max_qid = nr_io_queues; /* Free previously allocated queues */ @@ -576,14 +583,19 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) static int nvme_get_info_from_identify(struct nvme_dev *dev) { - ALLOC_CACHE_ALIGN_BUFFER(char, buf, sizeof(struct nvme_id_ctrl)); - struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf; + struct nvme_id_ctrl *ctrl; int ret; int shift = NVME_CAP_MPSMIN(dev->cap) + 12; - ret = nvme_identify(dev, 0, 1, (dma_addr_t)ctrl); - if (ret) + ctrl = memalign(dev->page_size, sizeof(struct nvme_id_ctrl)); + if (!ctrl) + return -ENOMEM; + + ret = nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl); + if (ret) { + free(ctrl); return -EIO; + } dev->nn = le32_to_cpu(ctrl->nn); dev->vwc = ctrl->vwc; @@ -614,6 +626,19 @@ static int nvme_get_info_from_identify(struct nvme_dev *dev) dev->max_transfer_shift = 20; } + free(ctrl); + return 0; +} + +int nvme_get_namespace_id(struct udevice *udev, u32 *ns_id, u8 *eui64) +{ + struct nvme_ns *ns = dev_get_priv(udev); + + if (ns_id) + *ns_id = ns->ns_id; + if (eui64) + memcpy(eui64, ns->eui64, sizeof(ns->eui64)); + return 0; } @@ -642,17 +667,23 @@ static int nvme_blk_probe(struct udevice *udev) struct blk_desc *desc = dev_get_uclass_platdata(udev); struct nvme_ns *ns = dev_get_priv(udev); u8 flbas; - ALLOC_CACHE_ALIGN_BUFFER(char, buf, sizeof(struct nvme_id_ns)); - struct nvme_id_ns *id = (struct nvme_id_ns *)buf; struct pci_child_platdata *pplat; + struct nvme_id_ns *id; + + id = memalign(ndev->page_size, sizeof(struct nvme_id_ns)); + 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; - if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)id)) + if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)(long)id)) { + free(id); return -EIO; + } + memcpy(&ns->eui64, &id->eui64, sizeof(id->eui64)); flbas = id->flbas & NVME_NS_FLBAS_LBA_MASK; ns->flbas = flbas; ns->lba_shift = id->lbaf[flbas].ds; @@ -668,8 +699,8 @@ static int nvme_blk_probe(struct udevice *udev) sprintf(desc->vendor, "0x%.4x", pplat->vendor); memcpy(desc->product, ndev->serial, sizeof(ndev->serial)); memcpy(desc->revision, ndev->firmware_rev, sizeof(ndev->firmware_rev)); - part_init(desc); + free(id); return 0; } @@ -689,9 +720,8 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr, u16 lbas = 1 << (dev->max_transfer_shift - ns->lba_shift); u64 total_lbas = blkcnt; - if (!read) - flush_dcache_range((unsigned long)buffer, - (unsigned long)buffer + total_len); + flush_dcache_range((unsigned long)buffer, + (unsigned long)buffer + total_len); c.rw.opcode = read ? nvme_cmd_read : nvme_cmd_write; c.rw.flags = 0; @@ -723,7 +753,7 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr, &c, NULL, IO_TIMEOUT); if (status) break; - temp_len -= lbas << ns->lba_shift; + temp_len -= (u32)lbas << ns->lba_shift; buffer += lbas << ns->lba_shift; } @@ -791,16 +821,7 @@ static int nvme_probe(struct udevice *udev) printf("Error: %s: Out of memory!\n", udev->name); goto free_nvme; } - memset(ndev->queues, 0, - sizeof(NVME_Q_NUM * sizeof(struct nvme_queue *))); - - ndev->prp_pool = malloc(MAX_PRP_POOL); - if (!ndev->prp_pool) { - ret = -ENOMEM; - printf("Error: %s: Out of memory!\n", udev->name); - goto free_nvme; - } - ndev->prp_entry_num = MAX_PRP_POOL >> 3; + memset(ndev->queues, 0, NVME_Q_NUM * sizeof(struct nvme_queue *)); ndev->cap = nvme_readq(&ndev->bar->cap); ndev->q_depth = min_t(int, NVME_CAP_MQES(ndev->cap) + 1, NVME_Q_DEPTH); @@ -811,6 +832,15 @@ static int nvme_probe(struct udevice *udev) if (ret) goto free_queue; + /* Allocate after the page size is known */ + ndev->prp_pool = memalign(ndev->page_size, MAX_PRP_POOL); + if (!ndev->prp_pool) { + ret = -ENOMEM; + printf("Error: %s: Out of memory!\n", udev->name); + goto free_nvme; + } + ndev->prp_entry_num = MAX_PRP_POOL >> 3; + ret = nvme_setup_io_queues(ndev); if (ret) goto free_queue;