创建PCIE根总线
pci_scan_root_bus_msi:创建根总线,ops是root bus 的函数操作集合,sysdata是pcie控制器的管理的数据结构指针,resource指针是拥有的资源的列表,msi是 msi控制的指针
struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resources, struct msi_controller *msi)
{
struct pci_bus *b;
//创建根总线
b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
//关联msi指针
b->msi = msi;
//扫描根总线
pci_scan_child_bus(b);
return b;
}
root总线下面连接一个EP端点,驱动模型如下所示:
pci_create_root_bus
struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata, struct list_head *resources)
{
struct pci_bus *b;
struct pci_host_bridge *bridge;
struct resource_entry *window, *n;
//创建根总线数据结构体
b = pci_alloc_bus(NULL); //b = kzalloc(sizeof(*b), GFP_KERNEL);
b->sysdata = sysdata;
b->ops = ops;
b->number = b->busn_res.start = bus;
b->domain_nr = 0;
//创建一个虚拟的sysfs系统的device节点
bridge = pci_alloc_host_bridge(b);
bridge->dev.parent = parent;
bridge->dev.release = pci_release_host_bridge_dev;
dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
device_register(&bridge->dev);
b->bridge = get_device(&bridge->dev);
b->dev.of_node = NULL;
b->dev.msi_domain = NULL;
b->dev.class = &pcibus_class;
b->dev.parent = b->bridge; //上面创建的虚拟的device指针
dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
device_register(&b->dev);
resource_list_for_each_entry_safe(window, n, resources) {
list_move_tail(&window->node, &bridge->windows); //将资源移到bridge资源列表中
res = window->res;
if (res->flags & IORESOURCE_BUS)
pci_bus_insert_busn_res(b, bus, res->end);
else
pci_bus_add_resource(b, res, 0);
}
//将总线添加到系统的root总线列表中
list_add_tail(&b->node, &pci_root_buses);
}
pci_alloc_host_bridge
struct pci_host_bridge {
struct device dev;
struct pci_bus *bus; /* root bus */
};
struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
{
struct pci_host_bridge *bridge;
bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
INIT_LIST_HEAD(&bridge->windows);
bridge->bus = b;
return bridge;
}
扫描PCIE总线
pci_scan_child_bus
unsigned int pci_scan_child_bus(struct pci_bus *bus)
{
unsigned int devfn, pass, max = bus->busn_res.start;
struct pci_dev *dev;
//一条总线有32个设备,每个设备有8种功能
for (devfn = 0; devfn < 0x100; devfn += 8)
pci_scan_slot(bus, devfn);
for (pass = 0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list) {
if (pci_is_bridge(dev))
max = pci_scan_bridge(bus, dev, max, pass);
}
}
pci_scan_slot
int pci_scan_slot(struct pci_bus *bus, int devfn)
{
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->is_added)
nr++;
for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
dev = pci_scan_single_device(bus, devfn + fn);
if (dev) {
if (!dev->is_added)
nr++;
dev->multifunction = 1;
}
}
}
pci_scan_single_device
struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
dev = pci_scan_device(bus, devfn);
pci_device_add(dev, bus);
return dev;
}
pci_scan_device
struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
//读 vendor id
pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000);
dev = pci_alloc_dev(bus);
dev->devfn = devfn;
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
pci_setup_device(dev);//读出bar空间大小,设置相关配置空间的属性
}
pci_setup_device
int pci_setup_device(struct pci_dev *dev)
{
pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);
dev->sysdata = dev->bus->sysdata;
dev->dev.parent = dev->bus->bridge;
dev->dev.bus = &pci_bus_type;
dev->hdr_type = hdr_type & 0x7f;
dev->multifunction = !!(hdr_type & 0x80);
dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn));
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
dev->class = class >> 8;
dev->cfg_size = pci_cfg_space_size(dev); //获取配置空间的大小,PCIE默认是4K
switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
pci_read_irq(dev); //读取中断线,中断引脚等,PCIE默认使用msi中断方式
pci_read_bases(dev, 6, PCI_ROM_ADDRESS); //获取pci设备的bar映射空间大小
break;
case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
pci_read_irq(dev);
pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
break;
}
return 0;
}
pci_read_bases
//howmany参数是6,rom这里不再描述
void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
for (pos = 0; pos < howmany; pos++) {
struct resource *res = &dev->resource[pos];
reg = PCI_BASE_ADDRESS_0 + (pos << 2);
pos += __pci_read_base(dev, pci_bar_unknown, res, reg);
}
}
__pci_read_base
int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct resource *res, unsigned int pos)
{
pci_read_config_dword(dev, pos, &l);
pci_write_config_dword(dev, pos, l | mask); //往bar寄存器的基地址写全1
pci_read_config_dword(dev, pos, &sz); //得到需要映射的bar空间大小
pci_write_config_dword(dev, pos, l); //恢复原值
}
pci_device_add
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
{
device_initialize(&dev->dev);
pci_init_capabilities(dev);
list_add_tail(&dev->bus_list, &bus->devices);
device_add(&dev->dev);
}