PCIE总线驱动学习笔记1
创建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); elsepci_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 idpci_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默认是4Kswitch (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寄存器的基地址写全1pci_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);
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
