*
* 用于映射 resource 资源,并获取 PCI BAR
* @param dev:DPDK 中关于某一个 PCI 设备的抽象实例
* @param res_id:说明要获取第几个 BAR
* @param uio_res:用来存放 PCI BAR 资源的结构
* @param map_idx、uio_res:数组的计数器
*/
int
pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
struct mapped_pci_resource *uio_res, int map_idx)
{
..... // 省略
// 打开 /dev/bus/pci/devices/{pci_addr}/resource0..N 文件
if (!wc_activate || fd < 0) {
snprintf(devname, sizeof(devname),
"%s/" PCI_PRI_FMT "/resource%d",
rte_pci_get_sysfs_path(),
loc->domain, loc->bus, loc->devid,
loc->function, res_idx);
/* then try to map resource file */
fd = open(devname, O_RDWR);
if (fd < 0) {
RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
devname, strerror(errno));
goto error;
}
}
/* try mapping somewhere close to the end of hugepages */
if (pci_map_addr == NULL)
pci_map_addr = pci_find_max_end_va();
// 进行 mmap() 映射,拿到 PCI BAR 在进程虚拟空间下的地址
mapaddr = pci_map_resource(pci_map_addr, fd, 0,
(size_t)dev->mem_resource[res_idx].len, 0);
close(fd);
if (mapaddr == MAP_FAILED)
goto error;
pci_map_addr = RTE_PTR_ADD(mapaddr,
(size_t)dev->mem_resource[res_idx].len);
// 将拿到的 PCI BAR 映射至进程虚拟空间内的地址存起来
maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr;
maps[map_idx].size = dev->mem_resource[res_idx].len;
maps[map_idx].addr = mapaddr;
maps[map_idx].offset = 0;
strcpy(maps[map_idx].path, devname);
dev->mem_resource[res_idx].addr = mapaddr;
return 0;
error:
rte_free(maps[map_idx].path);
return -1;
}
/*
* 对 pci/resource0..N 进行 mmap(),将 PCI BAR 空间通过 mmap 的方式映射到进程内部的虚拟空间,供用户态应用来操作设备
*/
void *
pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
int additional_flags)
{
void *mapaddr;
// 核心便是这句 mmap,其中要注意的是 offset 必须为 0
mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE,
MAP_SHARED | additional_flags, fd, offset);
if (mapaddr == MAP_FAILED) {
RTE_LOG(ERR, EAL,
"%s(): cannot mmap(%d, %p, 0x%zx, 0x%llx): %s (%p)\n",
__func__, fd, requested_addr, size,
(unsigned long long)offset,
strerror(errno), mapaddr);
} else
RTE_LOG(DEBUG, EAL, " PCI memory mapped at %p\n", mapaddr);
return mapaddr;
}