aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hw/nvme-int.h6
-rw-r--r--src/hw/nvme.c61
2 files changed, 24 insertions, 43 deletions
diff --git a/src/hw/nvme-int.h b/src/hw/nvme-int.h
index 9564c17..f0d717d 100644
--- a/src/hw/nvme-int.h
+++ b/src/hw/nvme-int.h
@@ -10,8 +10,6 @@
#include "types.h" // u32
#include "pcidevice.h" // struct pci_device
-#define NVME_MAX_PRPL_ENTRIES 15 /* Allows requests up to 64kb */
-
/* Data structures */
/* The register file of a NVMe host controller. This struct follows the naming
@@ -122,10 +120,6 @@ struct nvme_namespace {
/* Page aligned buffer of size NVME_PAGE_SIZE. */
char *dma_buffer;
-
- /* Page List */
- u32 prpl_len;
- u64 prpl[NVME_MAX_PRPL_ENTRIES];
};
/* Data structures for NVMe admin identify commands */
diff --git a/src/hw/nvme.c b/src/hw/nvme.c
index 20976fc..e9c449d 100644
--- a/src/hw/nvme.c
+++ b/src/hw/nvme.c
@@ -469,39 +469,23 @@ nvme_bounce_xfer(struct nvme_namespace *ns, u64 lba, void *buf, u16 count,
return res;
}
-static void nvme_reset_prpl(struct nvme_namespace *ns)
-{
- ns->prpl_len = 0;
-}
-
-static int nvme_add_prpl(struct nvme_namespace *ns, u64 base)
-{
- if (ns->prpl_len >= NVME_MAX_PRPL_ENTRIES)
- return -1;
-
- ns->prpl[ns->prpl_len++] = base;
-
- return 0;
-}
+#define NVME_MAX_PRPL_ENTRIES 15 /* Allows requests up to 64kb */
// Transfer data using page list (if applicable)
static int
nvme_prpl_xfer(struct nvme_namespace *ns, u64 lba, void *buf, u16 count,
int write)
{
- int first_page = 1;
u32 base = (long)buf;
s32 size;
if (count > ns->max_req_size)
count = ns->max_req_size;
- nvme_reset_prpl(ns);
-
size = count * ns->block_size;
/* Special case for transfers that fit into PRP1, but are unaligned */
if (((size + (base & ~NVME_PAGE_MASK)) <= NVME_PAGE_SIZE))
- return nvme_io_xfer(ns, lba, buf, NULL, count, write);
+ goto single;
/* Every request has to be page aligned */
if (base & ~NVME_PAGE_MASK)
@@ -511,28 +495,31 @@ nvme_prpl_xfer(struct nvme_namespace *ns, u64 lba, void *buf, u16 count,
if (size & (ns->block_size - 1ULL))
goto bounce;
- for (; size > 0; base += NVME_PAGE_SIZE, size -= NVME_PAGE_SIZE) {
- if (first_page) {
- /* First page is special */
- first_page = 0;
- continue;
+ /* Build PRP list if we need to describe more than 2 pages */
+ if ((ns->block_size * count) > (NVME_PAGE_SIZE * 2)) {
+ u32 prpl_len = 0;
+ u64 *prpl = (void*)ns->dma_buffer;
+ int first_page = 1;
+ for (; size > 0; base += NVME_PAGE_SIZE, size -= NVME_PAGE_SIZE) {
+ if (first_page) {
+ /* First page is special */
+ first_page = 0;
+ continue;
+ }
+ if (prpl_len >= NVME_MAX_PRPL_ENTRIES)
+ goto bounce;
+ prpl[prpl_len++] = base;
}
- if (nvme_add_prpl(ns, base))
- goto bounce;
+ return nvme_io_xfer(ns, lba, buf, prpl, count, write);
}
- void *prp2;
- if ((ns->block_size * count) > (NVME_PAGE_SIZE * 2)) {
- /* We need to describe more than 2 pages, rely on PRP List */
- prp2 = ns->prpl;
- } else if ((ns->block_size * count) > NVME_PAGE_SIZE) {
- /* Directly embed the 2nd page if we only need 2 pages */
- prp2 = (void *)(long)ns->prpl[0];
- } else {
- /* One page is enough, don't expose anything else */
- prp2 = NULL;
- }
- return nvme_io_xfer(ns, lba, buf, prp2, count, write);
+ /* Directly embed the 2nd page if we only need 2 pages */
+ if ((ns->block_size * count) > NVME_PAGE_SIZE)
+ return nvme_io_xfer(ns, lba, buf, buf + NVME_PAGE_SIZE, count, write);
+
+single:
+ /* One page is enough, don't expose anything else */
+ return nvme_io_xfer(ns, lba, buf, NULL, count, write);
bounce:
/* Use bounce buffer to make transfer */