]> mj.ucw.cz Git - pciutils.git/commitdiff
Added `bus mapping mode' (-M) which scans the whole configuration space
authorMartin Mares <mj@ucw.cz>
Wed, 27 Jan 1999 14:52:53 +0000 (14:52 +0000)
committerMartin Mares <mj@ucw.cz>
Fri, 5 May 2006 12:10:04 +0000 (14:10 +0200)
to find devices hiding behind misconfigured or misdesigned bus bridges.
This is intended only for debugging purposes and it's available only to root
as it can crash several well-known buggy chips.

ChangeLog
lib/access.c
lib/generic.c
lspci.c
lspci.man

index 03a77e20358b81eb1e4207d55f74f71a09b8f458..19c3edd5b1fab7738aa11e470483529e9212e0a8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
+Wed Jan 27 14:59:16 1999  Martin Mares  <mj@albireo.ucw.cz>
+
+       * lspci.c: Implemented bus mapping mode (-M).
+
+       * lspci.c (scan_devices): Split to scan_devices() and scan_device().
+       (show): Split to show() and show_device().
+
+       * lib/access.c (pci_init): When a->method == PCI_ACCESS_AUTO,
+       set it to the real access method afterwards.
+
+Mon Jan 25 23:46:13 1999  Martin Mares  <mj@albireo.ucw.cz>
+
+       * lib/generic.c (pci_generic_fill_info): If in buscentric mode,
+       don't check PCI_COMMAND for I/O and memory enables.
+
 Mon Jan 25 21:28:49 1999  Martin Mares  <mj@albireo.ucw.cz>
 
+
        * Makefile: Added target `release' which substitutes new version
        number to .spec, .lsm and README. Also rewrote target `dist'.
 
index 343abd8446855282cca1264bb679d1704970e36e..986b54a22be3cf9a89dbe558214c712b04ecf790 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     $Id: access.c,v 1.2 1999/01/24 21:35:35 mj Exp $
+ *     $Id: access.c,v 1.3 1999/01/27 14:53:02 mj Exp $
  *
  *     The PCI Library -- User Access
  *
@@ -139,6 +139,7 @@ pci_init(struct pci_access *a)
              {
                a->debug("...OK\n");
                a->methods = pci_methods[i];
+               a->method = i;
                break;
              }
            a->debug("...No.\n");
index 11dc121c919868442c4ea2c247367353148961d2..b586c95131e7a4e44fc568ea836836651bb91d0a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     $Id: generic.c,v 1.2 1999/01/25 22:10:45 geert Exp $
+ *     $Id: generic.c,v 1.3 1999/01/27 14:53:03 mj Exp $
  *
  *     The PCI Library -- Generic Direct Access Functions
  *
@@ -115,10 +115,10 @@ pci_generic_fill_info(struct pci_dev *d, int flags)
              d->base_addr[i] = x;
              if (x & PCI_BASE_ADDRESS_SPACE_IO)
                {
-                 if (!(cmd & PCI_COMMAND_IO))
+                 if (!a->buscentric && !(cmd & PCI_COMMAND_IO))
                    d->base_addr[i] = 0;
                }
-             else if (cmd & PCI_COMMAND_MEMORY)
+             else if (a->buscentric || (cmd & PCI_COMMAND_MEMORY))
                {
                  if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
                    {
diff --git a/lspci.c b/lspci.c
index 45390d919d27f8e113afdd5dc9a6c39e3fe1a64d..e5ff280d0df4b614a7d74b4e2566e9ce7801cdcf 100644 (file)
--- a/lspci.c
+++ b/lspci.c
@@ -1,5 +1,5 @@
 /*
- *     $Id: lspci.c,v 1.20 1999/01/24 21:38:47 mj Exp $
+ *     $Id: lspci.c,v 1.21 1999/01/27 14:52:55 mj Exp $
  *
  *     Linux PCI Utilities -- List All PCI Devices
  *
@@ -24,8 +24,9 @@ static int show_hex;                  /* Show contents of config space as hexadecimal numbers *
 static struct pci_filter filter;       /* Device filter */
 static int show_tree;                  /* Show bus tree */
 static int machine_readable;           /* Generate machine-readable output */
+static int map_mode;                   /* Bus mapping mode enabled */
 
-static char options[] = "nvbxs:d:ti:mg" GENERIC_OPTIONS ;
+static char options[] = "nvbxs:d:ti:mgM" GENERIC_OPTIONS ;
 
 static char help_msg[] = "\
 Usage: lspci [<switches>]\n\
@@ -38,7 +39,8 @@ Usage: lspci [<switches>]\n\
 -d [<vendor>]:[<device>]\tShow only selected devices\n\
 -t\t\tShow bus tree\n\
 -m\t\tProduce machine-readable output\n\
--i <file>\tUse specified ID database instead of %s\n"
+-i <file>\tUse specified ID database instead of %s\n\
+-M\t\tEnable `bus mapping' mode (dangerous; root only)\n"
 GENERIC_HELP
 ;
 
@@ -71,35 +73,45 @@ struct device {
 
 static struct device *first_dev;
 
+static struct device *
+scan_device(struct pci_dev *p)
+{
+  int how_much = (show_hex > 2) ? 256 : 64;
+  struct device *d;
+
+  if (!pci_filter_match(&filter, p))
+    return NULL;
+  d = xmalloc(sizeof(struct device));
+  bzero(d, sizeof(*d));
+  d->dev = p;
+  if (!pci_read_block(p, 0, d->config, how_much))
+    die("Unable to read %d bytes of configuration space.", how_much);
+  if (how_much < 128 && (d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
+    {
+      /* For cardbus bridges, we need to fetch 64 bytes more to get the full standard header... */
+      if (!pci_read_block(p, 0, d->config+64, 64))
+       die("Unable to read cardbus bridge extension data.");
+      how_much = 128;
+    }
+  d->config_cnt = how_much;
+  pci_setup_cache(p, d->config, d->config_cnt);
+  pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE);
+  return d;
+}
+
 static void
 scan_devices(void)
 {
   struct device *d;
-  int how_much = (show_hex > 2) ? 256 : 64;
   struct pci_dev *p;
 
   pci_scan_bus(pacc);
   for(p=pacc->devices; p; p=p->next)
-    {
-      if (!pci_filter_match(&filter, p))
-       continue;
-      d = xmalloc(sizeof(struct device));
-      d->next = first_dev;
-      first_dev = d;
-      d->dev = p;
-      if (!pci_read_block(p, 0, d->config, how_much))
-       die("Unable to read %d bytes of configuration space.", how_much);
-      if (how_much < 128 && (d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
-       {
-         /* For cardbus bridges, we need to fetch 64 bytes more to get the full standard header... */
-         if (!pci_read_block(p, 0, d->config+64, 64))
-           die("Unable to read cardbus bridge extension data.");
-         how_much = 128;
-       }
-      d->config_cnt = how_much;
-      pci_setup_cache(p, d->config, d->config_cnt);
-      pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE);
-    }
+    if (d = scan_device(p))
+      {
+       d->next = first_dev;
+       first_dev = d;
+      }
 }
 
 static int
@@ -718,24 +730,28 @@ show_machine(struct device *d)
     }
 }
 
+static void
+show_device(struct device *d)
+{
+  if (machine_readable)
+    show_machine(d);
+  else if (verbose)
+    show_verbose(d);
+  else
+    show_terse(d);
+  if (show_hex)
+    show_hex_dump(d);
+  if (verbose || show_hex)
+    putchar('\n');
+}
+
 static void
 show(void)
 {
   struct device *d;
 
   for(d=first_dev; d; d=d->next)
-    {
-      if (machine_readable)
-       show_machine(d);
-      else if (verbose)
-       show_verbose(d);
-      else
-       show_terse(d);
-      if (show_hex)
-       show_hex_dump(d);
-      if (verbose || show_hex)
-       putchar('\n');
-    }
+    show_device(d);
 }
 
 /* Tree output */
@@ -978,6 +994,108 @@ show_forest(void)
   show_tree_bridge(&host_bridge, line, line);
 }
 
+/* Bus mapping mode */
+
+struct bus_bridge {
+  struct bus_bridge *next;
+  byte first, last;
+};
+
+struct bus_info {
+  byte exists;
+  byte covered;
+  struct bus_bridge *bridges;
+};
+
+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;
+  int prim = get_conf_byte(d, np);
+
+  b->next = bi->bridges;
+  bi->bridges = b;
+  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, prim, b->first, b->last);
+  if (prim != 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)
+      {
+       for(func = 0; func < 8; 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 (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
+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);
+    }
+}
+
 /* Main */
 
 int
@@ -1029,6 +1147,9 @@ main(int argc, char **argv)
       case 'm':
        machine_readable++;
        break;
+      case 'M':
+       map_mode++;
+       break;
       default:
        if (parse_generic_option(i, pacc, optarg))
          break;
@@ -1040,12 +1161,17 @@ main(int argc, char **argv)
     goto bad;
 
   pci_init(pacc);
-  scan_devices();
-  sort_them();
-  if (show_tree)
-    show_forest();
+  if (map_mode)
+    map_the_bus();
   else
-    show();
+    {
+      scan_devices();
+      sort_them();
+      if (show_tree)
+       show_forest();
+      else
+       show();
+    }
   pci_cleanup(pacc);
 
   return 0;
index 6021d9278f1b17dd5cbd45fe044268dddf021d38..dd91ce65a15ca2dd66bb17a3f6f67246fc72ef26 100644 (file)
--- a/lspci.man
+++ b/lspci.man
@@ -85,6 +85,15 @@ as directory containing PCI bus information instead of /proc/bus/pci.
 .B -m
 Dump PCI device data in machine readable form (both normal and verbose format supported)
 for easy parsing by scripts.
+.TP
+.B -M
+Invoke bus mapping mode which scans the bus extensively to find all devices including
+those behind misconfigured bridges etc. Please note that this is intended only for
+debugging and as it can crash the machine (only in case of buggy devices, but
+unfortunately these happen to exist), it's available only to root. Also using
+-M on PCI access methods which don't directly touch the hardware has no
+sense since the results are (modulo bugs in lspci) identical to normal listing
+modes.
 
 .SH PCILIB OPTIONS
 The PCI utilities use PCILIB (a portable library providing platform-independent