PCIE的mmio内存映射访问机制+ 配置空间 +mmap + resource + /dev/mem
https://blog.csdn.net/Jmilk/article/details/106007926
打开 dpdk-18.08/drivers/bus/pci/linux/pci.c 可以看到以下内容:
#define PCI_MAX_RESOURCE 6
/*
* PCI 扫描文件系统下的 resource 文件
* @param filename: 通常为 /sys/bus/pci/devices/{pci_addr}/resource 文件
* @param dev[out]: dpdk 中对一个 PCI 设备的抽象
*/
static int
pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
{
FILE *f;
char buf[BUFSIZ];
int i;
uint64_t phys_addr, end_addr, flags;
f = fopen(filename, "r"); // 先打开 resource 文件,只读
if (f == NULL) {
RTE_LOG(ERR, EAL, "Cannot open sysfs resource\n");
return -1;
}
// 扫描 6 次,因为 PCI 最多有 6 个 BAR
for (i = 0; i<PCI_MAX_RESOURCE; i++) {
if (fgets(buf, sizeof(buf), f) == NULL) {
RTE_LOG(ERR, EAL,
"%s(): cannot read resource\n", __func__);
goto error;
}
// 扫描 resource 文件拿到 BAR
if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
&end_addr, &flags) < 0)
goto error;
// 如果是 Memory BAR,则进行记录
if (flags & IORESOURCE_MEM) {
dev->mem_resource[i].phys_addr = phys_addr;
dev->mem_resource[i].len = end_addr - phys_addr + 1;
/* not mapped for now */
dev->mem_resource[i].addr = NULL;
}
}
fclose(f);
return 0;
error:
fclose(f);
return -1;
}
/*
* 扫描 PCI resource 文件中的某一行
* @param line: 某一行
* @param len: 长度,为第一个参数字符串的长度
* @param phys_addr[out]: PCI BAR 的起始地址,这个地址要 mmap() 才能用
* @param end_addr[out]: PCI BAR 的结束地址
* @param flags[out]: PCI BAR 的标志
*/
int
pci_parse_one_sysfs_resource(char *line, size_t len, uint64_t *phys_addr,
uint64_t *end_addr, uint64_t *flags)
{
union pci_resource_info {
struct {
char *phys_addr;
char *end_addr;
char *flags;
};
char *ptrs[PCI_RESOURCE_FMT_NVAL];
} res_info;
// 字符串处理
if (rte_strsplit(line, len, res_info.ptrs, 3, ' ') != 3) {
RTE_LOG(ERR, EAL,
"%s(): bad resource format\n", __func__);
return -1;
}
errno = 0;
// 字符串处理,拿到 PCI BAR 起始地址、PCI BAR 结束地址、PCI BAR 标志
*phys_addr = strtoull(res_info.phys_addr, NULL, 16);
*end_addr = strtoull(res_info.end_addr, NULL