1 /* 2 * The PCI Utilities -- Bus Mapping Mode 3 * 4 * Copyright (c) 1997--2008 Martin Mares <[email protected]> 5 * 6 * Can be freely distributed and used under the terms of the GNU GPL v2+. 7 * 8 * SPDX-License-Identifier: GPL-2.0-or-later 9 */ 10 11 #include <stdio.h> 12 #include <string.h> 13 #include <stdlib.h> 14 15 #include "lspci.h" 16 17 struct bus_bridge { 18 struct bus_bridge *next; 19 byte this, dev, func, first, last, bug; 20 }; 21 22 struct bus_info { 23 byte exists; 24 byte guestbook; 25 struct bus_bridge *bridges, *via; 26 }; 27 28 static struct bus_info *bus_info; 29 30 static void 31 map_bridge(struct bus_info *bi, struct device *d, int np, int ns, int nl) 32 { 33 struct bus_bridge *b = xmalloc(sizeof(struct bus_bridge)); 34 struct pci_dev *p = d->dev; 35 36 b->next = bi->bridges; 37 bi->bridges = b; 38 b->this = get_conf_byte(d, np); 39 b->dev = p->dev; 40 b->func = p->func; 41 b->first = get_conf_byte(d, ns); 42 b->last = get_conf_byte(d, nl); 43 printf("## %02x:%02x.%d is a bridge from %02x to %02x-%02x\n", 44 p->bus, p->dev, p->func, b->this, b->first, b->last); 45 if (b->this != p->bus) 46 printf("!!! Bridge points to invalid primary bus.\n"); 47 if (b->first > b->last) 48 { 49 printf("!!! Bridge points to invalid bus range.\n"); 50 b->last = b->first; 51 } 52 } 53 54 static void 55 do_map_bus(int bus) 56 { 57 int domain = (filter.domain >= 0 ? filter.domain : 0); 58 int dev, func; 59 int verbose = pacc->debugging; 60 struct bus_info *bi = bus_info + bus; 61 struct device *d; 62 63 if (verbose) 64 printf("Mapping bus %04x:%02x\n", domain, bus); 65 for (dev = 0; dev < 32; dev++) 66 if (filter.slot < 0 || filter.slot == dev) 67 { 68 int func_limit = 1; 69 for (func = 0; func < func_limit; func++) 70 if (filter.func < 0 || filter.func == func) 71 { 72 struct pci_dev *p = pci_get_dev(pacc, domain, bus, dev, func); 73 u16 vendor = pci_read_word(p, PCI_VENDOR_ID); 74 if (vendor && vendor != 0xffff) 75 { 76 if (!func && (pci_read_byte(p, PCI_HEADER_TYPE) & 0x80)) 77 func_limit = 8; 78 if (verbose) 79 printf("Discovered device %04x:%02x:%02x.%d\n", domain, bus, dev, func); 80 bi->exists = 1; 81 if (d = scan_device(p)) 82 { 83 show_device(d); 84 switch (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f) 85 { 86 case PCI_HEADER_TYPE_BRIDGE: 87 map_bridge(bi, d, PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS); 88 break; 89 case PCI_HEADER_TYPE_CARDBUS: 90 map_bridge(bi, d, PCI_CB_PRIMARY_BUS, PCI_CB_CARD_BUS, PCI_CB_SUBORDINATE_BUS); 91 break; 92 } 93 free(d); 94 } 95 else if (verbose) 96 printf("But it was filtered out.\n"); 97 } 98 pci_free_dev(p); 99 } 100 } 101 } 102 103 static void 104 do_map_bridges(int bus, int min, int max) 105 { 106 struct bus_info *bi = bus_info + bus; 107 struct bus_bridge *b; 108 109 bi->guestbook = 1; 110 for (b=bi->bridges; b; b=b->next) 111 { 112 if (bus_info[b->first].guestbook) 113 b->bug = 1; 114 else if (b->first < min || b->last > max) 115 b->bug = 2; 116 else 117 { 118 bus_info[b->first].via = b; 119 do_map_bridges(b->first, b->first, b->last); 120 } 121 } 122 } 123 124 static void 125 map_bridges(void) 126 { 127 int i; 128 129 printf("\nSummary of buses:\n\n"); 130 for (i=0; i<256; i++) 131 if (bus_info[i].exists && !bus_info[i].guestbook) 132 do_map_bridges(i, 0, 255); 133 for (i=0; i<256; i++) 134 { 135 struct bus_info *bi = bus_info + i; 136 struct bus_bridge *b = bi->via; 137 138 if (bi->exists) 139 { 140 printf("%02x: ", i); 141 if (b) 142 printf("Entered via %02x:%02x.%d\n", b->this, b->dev, b->func); 143 else if (!i) 144 printf("Primary host bus\n"); 145 else 146 printf("Secondary host bus (?)\n"); 147 } 148 for (b=bi->bridges; b; b=b->next) 149 { 150 printf("\t%02x.%d Bridge to %02x-%02x", b->dev, b->func, b->first, b->last); 151 switch (b->bug) 152 { 153 case 1: 154 printf(" <overlap bug>"); 155 break; 156 case 2: 157 printf(" <crossing bug>"); 158 break; 159 } 160 putchar('\n'); 161 } 162 } 163 } 164 165 void 166 map_the_bus(void) 167 { 168 if (pacc->method == PCI_ACCESS_PROC_BUS_PCI || 169 pacc->method == PCI_ACCESS_SYS_BUS_PCI || 170 pacc->method == PCI_ACCESS_WIN32_CFGMGR32 || 171 pacc->method == PCI_ACCESS_DUMP) 172 printf("WARNING: Bus mapping can be reliable only with direct hardware access enabled.\n\n"); 173 bus_info = xmalloc(sizeof(struct bus_info) * 256); 174 memset(bus_info, 0, sizeof(struct bus_info) * 256); 175 if (filter.bus >= 0) 176 do_map_bus(filter.bus); 177 else 178 { 179 int bus; 180 for (bus=0; bus<256; bus++) 181 do_map_bus(bus); 182 } 183 map_bridges(); 184 } 185