vtophys: Add vtophys_get_paddr_pci()
Add a new virtual to physical (vtophys) method for spdk_vtophys_notify() that works for PCI memory (namely NVMe CMBs and PMRs). This new method searches all the BARs on all the detected PCI devices to see if the vaddr resides inside any of them. Change-Id: I68afbeffd958cf40c1e8652e13da5531811b522b Signed-off-by: Stephen Bates <sbates@raithlin.com> Reviewed-on: https://review.gerrithub.io/398872 Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com> Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
parent
720c627a93
commit
35a331a949
@ -240,12 +240,40 @@ vtophys_get_paddr_pagemap(uint64_t vaddr)
|
||||
return paddr;
|
||||
}
|
||||
|
||||
/* Try to get the paddr from pci devices */
|
||||
static uint64_t
|
||||
vtophys_get_paddr_pci(uint64_t vaddr)
|
||||
{
|
||||
uintptr_t paddr;
|
||||
struct rte_pci_device *dev;
|
||||
struct rte_mem_resource *res;
|
||||
unsigned r;
|
||||
|
||||
#if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 2)
|
||||
FOREACH_DEVICE_ON_PCIBUS(dev) {
|
||||
#else
|
||||
TAILQ_FOREACH(dev, &pci_device_list, next) {
|
||||
#endif
|
||||
for (r = 0; r < PCI_MAX_RESOURCE; r++) {
|
||||
res = &dev->mem_resource[r];
|
||||
if (res->phys_addr && vaddr >= (uint64_t)res->addr &&
|
||||
vaddr < (uint64_t)res->addr + res->len) {
|
||||
paddr = res->phys_addr + (vaddr - (uint64_t)res->addr);
|
||||
DEBUG_PRINT("%s: %p -> %p\n", __func__, (void *)vaddr,
|
||||
(void *)paddr);
|
||||
return paddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SPDK_VTOPHYS_ERROR;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_vtophys_notify(void *cb_ctx, struct spdk_mem_map *map,
|
||||
enum spdk_mem_map_notify_action action,
|
||||
void *vaddr, size_t len)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc = 0, pci_phys = 0;
|
||||
uint64_t paddr;
|
||||
|
||||
if ((uintptr_t)vaddr & ~MASK_256TB) {
|
||||
@ -286,13 +314,18 @@ spdk_vtophys_notify(void *cb_ctx, struct spdk_mem_map *map,
|
||||
/* Get the physical address from /proc/self/pagemap. */
|
||||
paddr = vtophys_get_paddr_pagemap((uint64_t)vaddr);
|
||||
if (paddr == SPDK_VTOPHYS_ERROR) {
|
||||
DEBUG_PRINT("could not get phys addr for %p\n", vaddr);
|
||||
return -EFAULT;
|
||||
/* Get the physical address from PCI devices */
|
||||
paddr = vtophys_get_paddr_pci((uint64_t)vaddr);
|
||||
if (paddr == SPDK_VTOPHYS_ERROR) {
|
||||
DEBUG_PRINT("could not get phys addr for %p\n", vaddr);
|
||||
return -EFAULT;
|
||||
}
|
||||
pci_phys = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (paddr & MASK_2MB) {
|
||||
/* Since PCI paddr can break the 2MiB physical alginment skip this check for that. */
|
||||
if (!pci_phys && (paddr & MASK_2MB)) {
|
||||
DEBUG_PRINT("invalid paddr 0x%" PRIx64 " - must be 2MB aligned\n", paddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -476,8 +509,13 @@ spdk_vtophys(void *buf)
|
||||
/*
|
||||
* SPDK_VTOPHYS_ERROR has all bits set, so if the lookup returned SPDK_VTOPHYS_ERROR,
|
||||
* we will still bitwise-or it with the buf offset below, but the result will still be
|
||||
* SPDK_VTOPHYS_ERROR.
|
||||
* SPDK_VTOPHYS_ERROR. However now that we do + rather than | (due to PCI vtophys being
|
||||
* unaligned) we must now check the return value before addition.
|
||||
*/
|
||||
SPDK_STATIC_ASSERT(SPDK_VTOPHYS_ERROR == UINT64_C(-1), "SPDK_VTOPHYS_ERROR should be all 1s");
|
||||
return paddr_2mb | ((uint64_t)buf & MASK_2MB);
|
||||
if (paddr_2mb == SPDK_VTOPHYS_ERROR) {
|
||||
return SPDK_VTOPHYS_ERROR;
|
||||
} else {
|
||||
return paddr_2mb + ((uint64_t)buf & MASK_2MB);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user