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);  
		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);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值