Linux 下PCI驱动架构是Linux BUS,DEVICE,DRIVER架构。下面所有代码来自linux3.13.
struct pci_dev 是描述device的数据结构。
struct pci_driver是描述driver的数据结构。
struct pci_bus是描述bus的数据结构。
device和driver都是挂 bus上的。
PCI 的 driver和device要做匹配验证的时候,验证的是vendor,id,class信息。
static inline const struct pci_device_id * pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
{
if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
(id->device == PCI_ANY_ID || id->device == dev->device) &&
(id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&
(id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&
!((id->class ^ dev->class) & id->class_mask))
return id;
return NULL;
}
这个函数就是pci device和driver匹配的最底层函数。可以看到比较的是vendor,id,class信息。它的调用路径是:
pci_bus_match()->pci_match_device()->pci_match_one_device()
很多人介绍了pci driver该怎么写。但忽略了pci device何时被创建。
当一个pci driver注册到系统时,系统会去匹配pci driver和pci device。但这时其实pci device 已经被创建了,所以才能match。那pci device是在什么时候创建的呢?
答案是系统初始化时。
系统初始化时,会扫描pci总线,发现所有已经连在上面的设备,并为每个社保创建一个struct pci_dev对象。
struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata, struct list_head *resources)
{
struct pci_host_bridge_window *window;
bool found = false;
struct pci_bus *b;
int max;
list_for_each_entry(window, resources, list)
if (window->res->flags & IORESOURCE_BUS) {
found = true;
break;
}
b = pci_create_root_bus(parent, bus, ops, sysdata, resources); // 创建pci bus
if (!b)
return NULL;
if (!found) {
dev_info(&b->dev,
"No busn resource found for root bus, will use [bus %02x-ff]\n",
bus);
pci_bus_insert_busn_res(b, bus, 255);
}
max = pci_scan_child_bus(b); //扫描pci bus,找到pci设备
if (!found)
pci_bus_update_busn_res_end(b, max);
pci_bus_add_devices(b);
return b;
}
从pci bus的根开始扫描。
unsigned int pci_scan_child_bus(struct pci_bus *bus)
{
unsigned int devfn, pass, max = bus->busn_res.start;
struct pci_dev *dev;
dev_dbg(&bus->dev, "scanning bus\n");
/* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8)
pci_scan_slot(bus, devfn); //扫描slot
.
.
.
return max;
}
接着看pci_scan_slot()
int pci_scan_slot(struct pci_bus *bus, int devfn)
{
unsigned fn, nr = 0;
struct pci_dev *dev;
if (only_one_child(bus) && (devfn > 0))
return 0; /* Already scanned the entire slot */
dev = pci_scan_single_device(bus, devfn);//扫描设备,根据功能号
if (!dev)
return 0;
if (!dev->is_added)
nr++;
.
.
.
return nr;
}
继续,
struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
dev = pci_get_slot(bus, devfn);//看看slot上是不是已经有devfn对应的设备了
if (dev) {
pci_dev_put(dev);
return dev;
}
dev = pci_scan_device(bus, devfn); //slot上还没有,那就扫描一下
if (!dev)
return NULL;
pci_device_add(dev, bus);
return dev;
}
继续看pci_scan_device()
static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
u32 l;
if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000)) //读一读硬件,看看有没有devfn的设备存在
return NULL;
dev = pci_alloc_dev(bus); //有硬件设备存在,那就创建一个struct pci_dev的对象来代表它吧
if (!dev)
return NULL;
dev->devfn = devfn;
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
pci_set_of_node(dev); //看看device tree dts里有信息没
if (pci_setup_device(dev)) { //初始化pci_dev对象,包括vendor,id,class信息。
pci_bus_put(dev->bus);
kfree(dev);
return NULL;
}
return dev;
}
好了,基本的步骤就是如此。当然扫描还会一层一层的走下去,因为如果有pci桥,就会多一层。
还有热插拔的设备,插上后会被创建device。
看完struct pci_dev的创建,就能更完整地理解pci驱动的架构了。
On kernel 4.3, the following list shows the sequence of the PCI bus create and scan.
Dec 9 17:43:25 ubuntu kernel: [ 0.538740] alexTrace: acpi_init() acpi_disabled=0
Dec 9 17:43:25 ubuntu kernel: [ 0.613669] alexTrace: acpi_pci_root_init register pci_root_handler
Dec 9 17:43:25 ubuntu kernel: [ 0.775337] alexTrace: acpi_pci_root_add
Dec 9 17:43:25 ubuntu kernel: [ 0.781491] alexTrace,pci_acpi_scan_root
Dec 9 17:43:25 ubuntu kernel: [ 0.784897] alexTrace: pci_create_root_bus
Dec 9 17:43:25 ubuntu kernel: [ 0.789678] alexdebug: pci_scan_child_bus
Dec 9 17:43:25 ubuntu kernel: [ 0.789730] alexdebug: pci_scan_slot devfn 0
Dec 9 17:43:25 ubuntu kernel: [ 0.789776] alexdebug: pci_scan_single_device devfn=0
Dec 9 17:43:25 ubuntu kernel: [ 0.789883] alexdebug: pci_scan_device devfn=0,debugcount=0
Dec 9 17:43:25 ubuntu kernel: [ 0.914795] alexdebug: pci_scan_bridge
Dec 9 17:43:25 ubuntu kernel: [ 0.914812] alexdebug: pci_scan_child_bus
The first PCI scan starts from ACPI.
If ACPI is disabled, then it starts from pci_legacy_init().