In Linux, each PCI device has a corresponding structure called pci_dev, which is used to record some bus and configuration information of the PCI device. Therefore, traversing all PCI devices is equivalent to traversing the pci_dev struct. The program is only a means to traverse PCI devices. How is PCI structured in the computer and what is the relationship between PCI and PCI, it is the essence of traversing all PCI devices.
Many PCI devices are attached to the PCI bus, which are classified into level-1 bus and level-2 bus. The secondary bus belongs to the primary bus. That is to say, there are several PCI devices and several PCI buses under the bus, and there are PCI devices under the bus, the structure of PCI bus in Linux is pci_bus. The relationship is roughly as follows:
In this way, if you traverse all pci_dev, you only need to find the root bus and then use the search algorithm to traverse all PCI devices.
In # include <Linux/PCI. h> there is a global variable pci_root_buses in the file, which is the global variable we are looking for. With this variable, there is basically no problem, the following shows a typical PCI diagram in Baidu Library:
This figure contains all the instructions. pci_root_buses is a list structure (related list structure, which can be found in some Linux books). All pci_bus is mounted on pci_root_buses, in this way, all the level-1 buses can be traversed, while the children field in the pci_bus structure can access the lower-level bus, and the dev field can access all the pci_dev structures. This completely solves the problem of traversing all PCI devices. (PS. some PCI bridge things are also involved here. Because I have no in-depth understanding, I may not traverse all of them, but I can solve this problem by using some other fields of these two structs ). The following code is tested by me:
static void searchPciBus(struct list_head *tobus){ struct pci_dev *pci; struct list_head *list,*list_pci_dev; struct pci_bus *subbus,*bus; if(tobus==NULL) { return ; } if(tobus->next==&tobus) { return ; } list_for_each(list,tobus) { bus=list_entry(list,struct pci_bus,node); if(bus->devices.next==&bus->devices) { return ; } list_for_each(list_pci_dev,&bus->devices) { pci=list_entry(list_pci_dev,struct pci_dev,bus_list); count++; } if(bus->children.next!=&bus->children) { list_for_each(list_pci_dev,&bus->children) { subbus=list_entry(list_pci_dev,struct pci_bus,node); searchPciBus(list_pci_dev); } } }}
In the program, only searchpcibus (& pci_root_buses. In the program, I use recursion to implement search. The idea is the figure above, which is easy to understand.
PS. I don't know much about Linux and hardware. If there is anything wrong with it, don't be surprised. I want to learn more from you.