summaryrefslogtreecommitdiffstats
path: root/ls-map.c
diff options
context:
space:
mode:
Diffstat (limited to 'ls-map.c')
-rw-r--r--ls-map.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/ls-map.c b/ls-map.c
new file mode 100644
index 0000000..a77eb0c
--- /dev/null
+++ b/ls-map.c
@@ -0,0 +1,184 @@
+/*
+ * The PCI Utilities -- Bus Mapping Mode
+ *
+ * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL v2+.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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(" <overlap bug>");
+ break;
+ case 2:
+ printf(" <crossing bug>");
+ 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();
+}