#include #include #include #include #include LIST_HEAD(pci_root_buses); #define IO_SPACE_LIMIT 0xffff struct resource ioport_resource = { .name = "PCI IO", .start = 0, .end = IO_SPACE_LIMIT, .flags = IORESOURCE_IO, }; struct resource iomem_resource = { .name = "PCI mem", .start = 0, .end = -1, .flags = IORESOURCE_MEM, }; static inline int pci_domain_nr(struct pci_bus *bus) { struct pci_sysdata *sd = bus->sysdata; return sd->domain; } static struct pci_bus * pci_alloc_bus(void) { struct pci_bus *b; b = kzalloc(sizeof(*b), GFP_KERNEL); if (b) { INIT_LIST_HEAD(&b->node); INIT_LIST_HEAD(&b->children); INIT_LIST_HEAD(&b->devices); INIT_LIST_HEAD(&b->slots); INIT_LIST_HEAD(&b->resources); } return b; } struct pci_bus * pci_create_bus(int bus, struct pci_ops *ops, void *sysdata) { int error; struct pci_bus *b, *b2; b = pci_alloc_bus(); if (!b) return NULL; b->sysdata = sysdata; b->ops = ops; b2 = pci_find_bus(pci_domain_nr(b), bus); if (b2) { /* If we already got to this bus through a different bridge, ignore it */ dbgprintf("bus already known\n"); goto err_out; } // down_write(&pci_bus_sem); list_add_tail(&b->node, &pci_root_buses); // up_write(&pci_bus_sem); b->number = b->secondary = bus; b->resource[0] = &ioport_resource; b->resource[1] = &iomem_resource; return b; err_out: kfree(b); return NULL; } static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) { struct pci_bus* child; struct list_head *tmp; if(bus->number == busnr) return bus; list_for_each(tmp, &bus->children) { child = pci_do_find_bus(pci_bus_b(tmp), busnr); if(child) return child; } return NULL; } /** * pci_find_bus - locate PCI bus from a given domain and bus number * @domain: number of PCI domain to search * @busnr: number of desired PCI bus * * Given a PCI bus number and domain number, the desired PCI bus is located * in the global list of PCI buses. If the bus is found, a pointer to its * data structure is returned. If no bus is found, %NULL is returned. */ struct pci_bus * pci_find_bus(int domain, int busnr) { struct pci_bus *bus = NULL; struct pci_bus *tmp_bus; while ((bus = pci_find_next_bus(bus)) != NULL) { if (pci_domain_nr(bus) != domain) continue; tmp_bus = pci_do_find_bus(bus, busnr); if (tmp_bus) return tmp_bus; } return NULL; } /** * pci_find_next_bus - begin or continue searching for a PCI bus * @from: Previous PCI bus found, or %NULL for new search. * * Iterates through the list of known PCI busses. A new search is * initiated by passing %NULL as the @from argument. Otherwise if * @from is not %NULL, searches continue from next device on the * global list. */ struct pci_bus * pci_find_next_bus(const struct pci_bus *from) { struct list_head *n; struct pci_bus *b = NULL; // WARN_ON(in_interrupt()); // down_read(&pci_bus_sem); n = from ? from->node.next : pci_root_buses.next; if (n != &pci_root_buses) b = pci_bus_b(n); // up_read(&pci_bus_sem); return b; }