- for(d=first_dev; d; d=d->next)
- show_device(d);
-}
-
-/* Tree output */
-
-struct bridge {
- struct bridge *chain; /* Single-linked list of bridges */
- struct bridge *next, *child; /* Tree of bridges */
- struct bus *first_bus; /* List of busses connected to this bridge */
- unsigned int primary, secondary, subordinate; /* Bus numbers */
- struct device *br_dev;
-};
-
-struct bus {
- unsigned int number;
- struct bus *sibling;
- struct device *first_dev, **last_dev;
-};
-
-static struct bridge host_bridge = { NULL, NULL, NULL, NULL, ~0, 0, ~0, NULL };
-
-static struct bus *
-find_bus(struct bridge *b, unsigned int n)
-{
- struct bus *bus;
-
- for(bus=b->first_bus; bus; bus=bus->sibling)
- if (bus->number == n)
- break;
- return bus;
-}
-
-static struct bus *
-new_bus(struct bridge *b, unsigned int n)
-{
- struct bus *bus = xmalloc(sizeof(struct bus));
-
- bus = xmalloc(sizeof(struct bus));
- bus->number = n;
- bus->sibling = b->first_bus;
- bus->first_dev = NULL;
- bus->last_dev = &bus->first_dev;
- b->first_bus = bus;
- return bus;
-}
-
-static void
-insert_dev(struct device *d, struct bridge *b)
-{
- struct pci_dev *p = d->dev;
- struct bus *bus;
-
- if (! (bus = find_bus(b, p->bus)))
- {
- struct bridge *c;
- for(c=b->child; c; c=c->next)
- if (c->secondary <= p->bus && p->bus <= c->subordinate)
- return insert_dev(d, c);
- bus = new_bus(b, p->bus);
- }
- /* Simple insertion at the end _does_ guarantee the correct order as the
- * original device list was sorted by (bus, devfn) lexicographically
- * and all devices on the new list have the same bus number.
- */
- *bus->last_dev = d;
- bus->last_dev = &d->next;
- d->next = NULL;
-}
-
-static void
-grow_tree(void)
-{
- struct device *d, *d2;
- struct bridge **last_br, *b;
-
- /* Build list of bridges */
-
- last_br = &host_bridge.chain;
- for(d=first_dev; d; d=d->next)
- {
- word class = get_conf_word(d, PCI_CLASS_DEVICE);
- byte ht = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
- if (class == PCI_CLASS_BRIDGE_PCI &&
- (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS))
- {
- b = xmalloc(sizeof(struct bridge));
- if (ht == PCI_HEADER_TYPE_BRIDGE)
- {
- b->primary = get_conf_byte(d, PCI_CB_PRIMARY_BUS);
- b->secondary = get_conf_byte(d, PCI_CB_CARD_BUS);
- b->subordinate = get_conf_byte(d, PCI_CB_SUBORDINATE_BUS);
- }
- else
- {
- b->primary = get_conf_byte(d, PCI_PRIMARY_BUS);
- b->secondary = get_conf_byte(d, PCI_SECONDARY_BUS);
- b->subordinate = get_conf_byte(d, PCI_SUBORDINATE_BUS);
- }
- *last_br = b;
- last_br = &b->chain;
- b->next = b->child = NULL;
- b->first_bus = NULL;
- b->br_dev = d;
- }
- }
- *last_br = NULL;
-
- /* Create a bridge tree */
-
- for(b=&host_bridge; b; b=b->chain)
- {
- struct bridge *c, *best;
- best = NULL;
- for(c=&host_bridge; c; c=c->chain)
- if (c != b && b->primary >= c->secondary && b->primary <= c->subordinate &&
- (!best || best->subordinate - best->primary > c->subordinate - c->primary))
- best = c;
- if (best)
- {
- b->next = best->child;
- best->child = b;
- }
- }
-
- /* Insert secondary bus for each bridge */
-
- for(b=&host_bridge; b; b=b->chain)
- if (!find_bus(b, b->secondary))
- new_bus(b, b->secondary);
-
- /* Create bus structs and link devices */
-
- for(d=first_dev; d;)
- {
- d2 = d->next;
- insert_dev(d, &host_bridge);
- d = d2;
- }
-}
-
-static void
-print_it(byte *line, byte *p)
-{
- *p++ = '\n';
- *p = 0;
- fputs(line, stdout);
- for(p=line; *p; p++)
- if (*p == '+' || *p == '|')
- *p = '|';
- else
- *p = ' ';
-}
-
-static void show_tree_bridge(struct bridge *, byte *, byte *);
-
-static void
-show_tree_dev(struct device *d, byte *line, byte *p)
-{
- struct pci_dev *q = d->dev;
- struct bridge *b;
- char namebuf[256];
-
- p += sprintf(p, "%02x.%x", q->dev, q->func);
- for(b=&host_bridge; b; b=b->chain)
- if (b->br_dev == d)
- {
- if (b->secondary == b->subordinate)
- p += sprintf(p, "-[%02x]-", b->secondary);
- else
- p += sprintf(p, "-[%02x-%02x]-", b->secondary, b->subordinate);
- show_tree_bridge(b, line, p);
- return;
- }
- if (verbose)
- p += sprintf(p, " %s",
- pci_lookup_name(pacc, namebuf, sizeof(namebuf),
- PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
- q->vendor_id, q->device_id));
- print_it(line, p);
-}
-
-static void
-show_tree_bus(struct bus *b, byte *line, byte *p)
-{
- if (!b->first_dev)
- print_it(line, p);
- else if (!b->first_dev->next)
- {
- *p++ = '-';
- *p++ = '-';
- show_tree_dev(b->first_dev, line, p);
- }
- else
- {
- struct device *d = b->first_dev;
- while (d->next)
- {
- p[0] = '+';
- p[1] = '-';
- show_tree_dev(d, line, p+2);
- d = d->next;
- }
- p[0] = '\\';
- p[1] = '-';
- show_tree_dev(d, line, p+2);
- }
-}
-
-static void
-show_tree_bridge(struct bridge *b, byte *line, byte *p)
-{
- *p++ = '-';
- if (!b->first_bus->sibling)
- {
- if (b == &host_bridge)
- p += sprintf(p, "[%02x]-", b->first_bus->number);
- show_tree_bus(b->first_bus, line, p);
- }
- else
- {
- struct bus *u = b->first_bus;
- byte *k;
-
- while (u->sibling)
- {
- k = p + sprintf(p, "+-[%02x]-", u->number);
- show_tree_bus(u, line, k);
- u = u->sibling;
- }
- k = p + sprintf(p, "\\-[%02x]-", u->number);
- show_tree_bus(u, line, k);
- }
-}
-
-static void
-show_forest(void)
-{
- char line[256];
-
- grow_tree();
- show_tree_bridge(&host_bridge, line, line);
-}
-
-/* Bus mapping mode */
-
-struct bus_bridge {
- struct bus_bridge *next;
- byte this, dev, func, first, last, bug;
-};
-
-struct bus_info {
- byte exists;
- byte guestbook;
- struct bus_bridge *bridges, *via;
-};
-
-static struct bus_info *bus_info;
-
-static void
-map_bridge(struct bus_info *bi, struct device *d, int np, int ns, int nl)
-{
- struct bus_bridge *b = xmalloc(sizeof(struct bus_bridge));
- struct pci_dev *p = d->dev;
-
- b->next = bi->bridges;
- bi->bridges = b;
- b->this = get_conf_byte(d, np);
- b->dev = p->dev;
- b->func = p->func;
- b->first = get_conf_byte(d, ns);
- b->last = get_conf_byte(d, nl);
- printf("## %02x.%02x:%d is a bridge from %02x to %02x-%02x\n",
- p->bus, p->dev, p->func, b->this, b->first, b->last);
- if (b->this != p->bus)
- printf("!!! Bridge points to invalid primary bus.\n");
- if (b->first > b->last)
- {
- printf("!!! Bridge points to invalid bus range.\n");
- b->last = b->first;
- }
-}
-
-static void
-do_map_bus(int bus)
-{
- int dev, func;
- int verbose = pacc->debugging;
- struct bus_info *bi = bus_info + bus;
- struct device *d;
-
- if (verbose)
- printf("Mapping bus %02x\n", bus);
- for(dev = 0; dev < 32; dev++)
- if (filter.slot < 0 || filter.slot == dev)
- {
- int func_limit = 1;
- for(func = 0; func < func_limit; func++)
- if (filter.func < 0 || filter.func == func)
- {
- struct pci_dev *p = pci_get_dev(pacc, bus, dev, func);
- u16 vendor = pci_read_word(p, PCI_VENDOR_ID);
- if (vendor && vendor != 0xffff)
- {
- if (!func && (pci_read_byte(p, PCI_HEADER_TYPE) & 0x80))
- func_limit = 8;
- if (verbose)
- printf("Discovered device %02x:%02x.%d\n", bus, dev, func);
- bi->exists = 1;
- if (d = scan_device(p))
- {
- show_device(d);
- switch (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f)
- {
- case PCI_HEADER_TYPE_BRIDGE:
- map_bridge(bi, d, PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS);
- break;
- case PCI_HEADER_TYPE_CARDBUS:
- map_bridge(bi, d, PCI_CB_PRIMARY_BUS, PCI_CB_CARD_BUS, PCI_CB_SUBORDINATE_BUS);
- break;
- }
- free(d);
- }
- else if (verbose)
- printf("But it was filtered out.\n");
- }
- pci_free_dev(p);
- }
- }
-}
-
-static void
-do_map_bridges(int bus, int min, int max)
-{
- struct bus_info *bi = bus_info + bus;
- struct bus_bridge *b;
-
- bi->guestbook = 1;
- for(b=bi->bridges; b; b=b->next)
- {
- if (bus_info[b->first].guestbook)
- b->bug = 1;
- else if (b->first < min || b->last > max)
- b->bug = 2;
- else
- {
- bus_info[b->first].via = b;
- do_map_bridges(b->first, b->first, b->last);
- }
- }
-}
-
-static void
-map_bridges(void)
-{
- int i;
-
- printf("\nSummary of buses:\n\n");
- for(i=0; i<256; i++)
- if (bus_info[i].exists && !bus_info[i].guestbook)
- do_map_bridges(i, 0, 255);
- for(i=0; i<256; i++)
- {
- struct bus_info *bi = bus_info + i;
- struct bus_bridge *b = bi->via;
-
- if (bi->exists)
- {
- printf("%02x: ", i);
- if (b)
- printf("Entered via %02x:%02x.%d\n", b->this, b->dev, b->func);
- else if (!i)
- printf("Primary host bus\n");
- else
- printf("Secondary host bus (?)\n");
- }
- for(b=bi->bridges; b; b=b->next)
- {
- printf("\t%02x.%d Bridge to %02x-%02x", b->dev, b->func, b->first, b->last);
- switch (b->bug)
- {
- case 1:
- printf(" <overlap bug>");
- break;
- case 2:
- printf(" <crossing bug>");
- break;
- }
- putchar('\n');
- }
- }
-}
-
-static void
-map_the_bus(void)
-{
- if (pacc->method == PCI_ACCESS_PROC_BUS_PCI ||
- pacc->method == PCI_ACCESS_DUMP)
- printf("WARNING: Bus mapping can be reliable only with direct hardware access enabled.\n\n");
- else if (!check_root())
- die("Only root can map the bus.");
- bus_info = xmalloc(sizeof(struct bus_info) * 256);
- bzero(bus_info, sizeof(struct bus_info) * 256);
- if (filter.bus >= 0)
- do_map_bus(filter.bus);
- else
- {
- int bus;
- for(bus=0; bus<256; bus++)
- do_map_bus(bus);
- }
- map_bridges();