1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
   | /*  * device说明见下文,bus是根总线号,ops是配置空间读写函数的接口,需要驱动作者  * 传入回调函数, 会在pci_scan_child_bus->pci_scan_slot->pci_scan_single_device->  * pci_scan_device->pci_bus_read_dev_vendor_id调用到该ops中的read函数。sysdata  * 传入私有数据。resources链表的元素是struct pci_host_bridge_window, 是dts上  * 读上来的总线号,mem空间,I/O空间的信息, 一般一个pci_host_bridge_window对应  * 一个信息  */ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, 		struct pci_ops *ops, void *sysdata, struct list_head *resources) { 	... 	/* 	 * 分配 struct pci_host_bridge, 初始化其中的windows链表 	 * windows链表上的存的结构是:struct pci_host_bridge_window 	 * struct pci_host_bridge_window { 	 * 	struct list_head list; 	 * 	struct resource *res;	/* host bridge aperture (CPU address) */ 	 * 	resource_size_t offset;	/* bus address + offset = CPU address */ 	 * }; 	 */ 	bridge = pci_alloc_host_bridge();
  	/* 	 * 输入参数parent来自pci host驱动中pci host核心结构的struct device *dev, 	 * dev来自 platform_device 中的dev。可以以drivers/pci/host下的pci-mvebu.c 	 * 作为例子, 其中所谓的pci host核心结构是:struct mvebu_pcie 	 */ 	bridge->dev.parent = parent;
  	/* 分配 struct pci_bus */ 	b = pci_alloc_bus(NULL);
  	b->sysdata = sysdata; 	b->ops = ops; 	b->number = b->busn_res.start = bus; 	/* 在pcie dts节点中找见domain字段, 加入pci_bus的domain_nr */ 	pci_bus_assign_domain_nr(b, parent); 	/* 	 * 在pci_root_buses全局链表中找相应domain下的bus, 首次调用的时候返回NULL 	 * 上面分配的pci_root_buses是在当前函数的最后才加入pci_root_buses中的,现在该 	 * 全局链表为空 	 */ 	b2 = pci_find_bus(pci_domain_nr(b), bus); 	/* 	 * 上面两行处理有关pci domain的信息,kernel pci子系统怎么处理pci domain 	 * 的呢? 首先数据结构是全局的链表:pci_root_buses, 局部链表:pci_domain_busn_res_list 	 * pci_root_buses中存放每个pci domain的根总线,根总线在pci_create_root_bus 	 * 函数的结尾被添加到pci_root_buses链表中。pci_domain_busn_res_list存放 	 * 各个domain的信息, 包括domain号、domain包含的bus号范围, 该链表上存放 	 * 存放的结构是:struct pci_domain_busn_res, 在函数get_pci_domain_busn_res 	 * 中查找相应domain号的pci_domain_busn_res, 如果没有就分配一个新的 	 * pci_domain_busn_res, 然后加到pci_domain_busn_res_list上 	 */
  	bridge->bus = b; 	dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); 	error = pcibios_root_bridge_prepare(bridge);
  	error = device_register(&bridge->dev);
  	b->bridge = get_device(&bridge->dev); 	device_enable_async_suspend(b->bridge); 	pci_set_bus_of_node(b);
  	if (!parent) 		set_dev_node(b->bridge, pcibus_to_node(b));
  	b->dev.class = &pcibus_class; 	/* b->bridge 为对应pci_host_bridge中struct device dev的指针 */ 	b->dev.parent = b->bridge; 	dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus); 	error = device_register(&b->dev);
  	pcibios_add_bus(b);
  	/* Create legacy_io and legacy_mem files for this bus */ 	pci_create_legacy_files(b);
  	... 	/* 	 * 取出pci_create_root_bus函数传入的链表resources中的pci_host_bridge_window, 	 * 把每个pci_host_bridge_window加入pci_host_bridge中的window链表中 	 */ 	list_for_each_entry_safe(window, n, resources, list) { 		list_move_tail(&window->list, &bridge->windows); 		res = window->res; 		offset = window->offset; 		if (res->flags & IORESOURCE_BUS) 		    	/* 			 * 一般的,resources链表上有bus number, MEM space, I/O 			 * space的节点,如果是bus number节点则调用以下函数。该 			 * 函数会找到当前pci_bus的父结构,生成pci_bus中的busn_res 			 * 并和父结构中的struct resource busn_res建立联系。 			 * 如果父子在bus号上存在冲突,则返回冲突的bus号[1] 			 */ 			pci_bus_insert_busn_res(b, bus, res->end); 		else 			/* 			 * 向pci_bus中的链表resources中加入struct pci_bus_resource 			 * 记录mem, io的资源 			 */ 			pci_bus_add_resource(b, res, 0); 		if (offset) { 			if (resource_type(res) == IORESOURCE_IO) 				fmt = " (bus address [%#06llx-%#06llx])"; 			else 				fmt = " (bus address [%#010llx-%#010llx])"; 			snprintf(bus_addr, sizeof(bus_addr), fmt, 				 (unsigned long long) (res->start - offset), 				 (unsigned long long) (res->end - offset)); 		} else 			bus_addr[0] = '\0'; 		dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr); 	}
  	down_write(&pci_bus_sem); 	/* 把创建的pci_bus加入全局链表pci_root_buses中 */ 	list_add_tail(&b->node, &pci_root_buses); 	up_write(&pci_bus_sem);
  	return b; 	... }
   |