nvme: Fix multipage prp-list

The nvme driver falsely assumed that the last entry on a page
of the prp-list always points to the next page of the prp-list.
This potentially can lead to the illegal creation of pages on
the prp-list with only a single entry. This change now ensures
that splitting the prp-list into multiple pages, behaves now as
required by the NVME-Spec.

Related to this, also the size of the memory allocation is adjusted
accordingly.

Signed-off-by: Alexander Sowarka <alexander.sowarka@aerq.com>
This commit is contained in:
Alexander Sowarka 2022-08-28 21:30:20 +02:00 committed by Tom Rini
parent 9895bda2ed
commit 4ca8d95ce1

View File

@ -72,7 +72,7 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
} }
nprps = DIV_ROUND_UP(length, page_size); nprps = DIV_ROUND_UP(length, page_size);
num_pages = DIV_ROUND_UP(nprps, prps_per_page); num_pages = DIV_ROUND_UP(nprps - 1, prps_per_page - 1);
if (nprps > dev->prp_entry_num) { if (nprps > dev->prp_entry_num) {
free(dev->prp_pool); free(dev->prp_pool);
@ -85,13 +85,13 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
printf("Error: malloc prp_pool fail\n"); printf("Error: malloc prp_pool fail\n");
return -ENOMEM; return -ENOMEM;
} }
dev->prp_entry_num = prps_per_page * num_pages; dev->prp_entry_num = num_pages * (prps_per_page - 1) + 1;
} }
prp_pool = dev->prp_pool; prp_pool = dev->prp_pool;
i = 0; i = 0;
while (nprps) { while (nprps) {
if (i == ((page_size >> 3) - 1)) { if ((i == (prps_per_page - 1)) && nprps > 1) {
*(prp_pool + i) = cpu_to_le64((ulong)prp_pool + *(prp_pool + i) = cpu_to_le64((ulong)prp_pool +
page_size); page_size);
i = 0; i = 0;
@ -104,7 +104,7 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
*prp2 = (ulong)dev->prp_pool; *prp2 = (ulong)dev->prp_pool;
flush_dcache_range((ulong)dev->prp_pool, (ulong)dev->prp_pool + flush_dcache_range((ulong)dev->prp_pool, (ulong)dev->prp_pool +
dev->prp_entry_num * sizeof(u64)); num_pages * page_size);
return 0; return 0;
} }