PCIE的mmio記憶體對映訪問機制+ 配置空間
阿新 • • 發佈:2020-09-13
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