/* * The PCI Utilities -- Bus Mapping Mode * * Copyright (c) 1997--2008 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ #include #include #include #include "lspci.h" 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 domain = (filter.domain >= 0 ? filter.domain : 0); int dev, func; int verbose = pacc->debugging; struct bus_info *bi = bus_info + bus; struct device *d; if (verbose) printf("Mapping bus %04x:%02x\n", domain, 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, domain, 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 %04x:%02x:%02x.%d\n", domain, 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(" "); break; case 2: printf(" "); break; } putchar('\n'); } } } void map_the_bus(void) { if (pacc->method == PCI_ACCESS_PROC_BUS_PCI || pacc->method == PCI_ACCESS_SYS_BUS_PCI || pacc->method == PCI_ACCESS_WIN32_CFGMGR32 || pacc->method == PCI_ACCESS_DUMP) printf("WARNING: Bus mapping can be reliable only with direct hardware access enabled.\n\n"); bus_info = xmalloc(sizeof(struct bus_info) * 256); memset(bus_info, 0, 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(); }