初始化分析
一个设备驱动要实现的功能根据实际需要可能千差万别,但是究其本质来说无非两件事情:一个是内存的操作,另外一个就是中断的处理。Igb_uio驱动和igb驱动都是网卡这个PCI设备的驱动,相同点就是要使能PCI设备,分配内存等,不同的就在于对内存和中断的处理方式的差异。
下面看下igb_uio驱动与igb驱动相比的probe函数的不同之处:
◆记录设备的资源
igb_uio模块遍历此PCI设备BAR空间,对应于类型为存储器空间IORESOURCE_MEM的BAR,将其物理地址、大小等信息保存到uio_info结构的mem数组中之中;类型为寄存器空间IORESOURCE_IO的BAR,将其物理地址、大小等信息保存到uio_info结构的port数组中。
从上图可知,此网卡PCI设备有三个BAR空间,BAR0类型为存储器空间,物理地址为0xfbd00000,大小为128K;BAR2类型为寄存器空间,物理地址为0xb000,大小为32字节;BAR3类型为存储器空间,物理地址为0xfbd40000,大小为16K。
Igb驱动也会遍历BAR空间,但是它不会记录空间的物理地址,而是调用ioremap函数将物理地址映射为虚拟地址,驱动在内核态读写操作映射出来的虚拟地址。
/** IO resource type: */
#define IORESOURCE_IO 0x00000100
#define IORESOURCE_MEM 0x00000200
424 pci_uio_ioport_map(struct rte_pci_device *dev, int bar, 425 struct rte_pci_ioport *p) 426 { 427 FILE *f; 428 char buf[BUFSIZ]; 429 char filename[PATH_MAX]; 430 uint64_t phys_addr, end_addr, flags; 431 int fd, i; 432 void *addr; 433 434 /* open and read addresses of the corresponding resource in sysfs */ 435 snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource", 436 rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus, 437 dev->addr.devid, dev->addr.function); 438 f = fopen(filename, "r"); 439 if (f == NULL) { 440 RTE_LOG(ERR, EAL, "Cannot open sysfs resource: %s ", 441 strerror(errno)); 442 return -1; 443 } 444 for (i = 0; i < bar + 1; i++) { 445 if (fgets(buf, sizeof(buf), f) == NULL) { 446 RTE_LOG(ERR, EAL, "Cannot read sysfs resource "); 447 goto error; 448 } 449 } 450 if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr, 451 &end_addr, &flags) < 0) 452 goto error; 453 if ((flags & IORESOURCE_IO) == 0) { 454 RTE_LOG(ERR, EAL, "BAR %d is not an IO resource ", bar); 455 goto error; 456 } 457 snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource%d", 458 rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus, 459 dev->addr.devid, dev->addr.function, bar); 460 461 /* mmap the pci resource */ 462 fd = open(filename, O_RDWR); 463 if (fd < 0) { 464 RTE_LOG(ERR, EAL, "Cannot open %s: %s ", filename, 465 strerror(errno)); 466 goto error; 467 } 468 addr = mmap(NULL, end_addr + 1, PROT_READ | PROT_WRITE, 469 MAP_SHARED, fd, 0); 470 close(fd); 471 if (addr == MAP_FAILED) { 472 RTE_LOG(ERR, EAL, "Cannot mmap IO port resource: %s ", 473 strerror(errno)); 474 goto error; 475 } 476 477 /* strangely, the base address is mmap addr + phys_addr */ 478 p->base = (uintptr_t)addr + phys_addr; 479 p->len = end_addr + 1; 480 RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%"PRIx64" ", p->base); 481 fclose(f); 482 483 return 0; 484 485 error: 486 fclose(f); 487 return -1; 488 }
rte_pci_ioport_map
read & write