]> mj.ucw.cz Git - pciutils.git/commitdiff
Register caching rewrite
authorMartin Mares <mj@ucw.cz>
Tue, 23 Aug 2005 21:12:22 +0000 (21:12 +0000)
committerMartin Mares <mj@ucw.cz>
Fri, 5 May 2006 12:18:29 +0000 (14:18 +0200)
git-archimport-id: mj@ucw.cz--public/pciutils--main--2.2--patch-76

ChangeLog
TODO
lspci.c
lspci.man
setpci.man

index e43ed8dd55999bbe0db2c7d633ccae217e0e3bf9..526da1e52d548ae6397b31350261e40f0286007a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,21 @@
 2005-08-23  Martin Mares  <mj@ucw.cz>
 
+       * lspci.man, setpci.man: Improved the man pages. Documented all access
+       methods and which operations are privileged.
+
+       * lspci.c: Another rewrite of config register caching, now also including
+       lots of internal checks. It should be now perfectly able to cope with
+       portions of the configuration space being inaccessible, for example
+       due to insufficient access rights.
+
        * lspci.c (show_pcix_nobridge, show_pcix_bridge): Cleaned up dumping of PCI-X
        capabilities. Includes partial support for PCI-X 2.0 (probably incomplete
        as I haven't seen the spec).
 
        * lspci.c: Quell warnings about unused parameters.
 
+       * lspci.c: Removed C++ comments.
+
        * lib/header.h: Merged definitions of extended capabilities and some new
        PCI-X capability bits from linux-2.6.11/include/pci.h.
 
diff --git a/TODO b/TODO
index bf48ef48062b6b356209ab46d73f428cb250cc11..cfd09e7a782fb536a49ccb3c70ed878acba5cda8 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,7 +1,3 @@
-- lspci: don't die when non-root tries to dump cardbus data; mention the
-  "available only to root" things in the man page. And possibly adjust exit code.
-- reading of VPD
-
 - names.c: rewrite
 
 - update the web page
@@ -11,6 +7,7 @@
 - some extended capabilities are currently only partially decoded
 - finish PCI-X 2.0 capabilities
 - finish PCI Express support
+- reading of VPD
 
 PCIIDS:
 - another mirror at Atrey?
diff --git a/lspci.c b/lspci.c
index bbe1a22b3b086a43635f73ba1ac7e38ca717936f..b00ea48ad745259cdc55ac79894737df7e624ecc 100644 (file)
--- a/lspci.c
+++ b/lspci.c
@@ -64,8 +64,9 @@ static struct pci_access *pacc;
 struct device {
   struct device *next;
   struct pci_dev *dev;
-  unsigned int config_cnt, config_bufsize;
-  byte *config;
+  unsigned int config_cached, config_bufsize;
+  byte *config;                                /* Cached configuration space data */
+  byte *present;                       /* Maps which configuration bytes are present */
 };
 
 static struct device *first_dev;
@@ -75,17 +76,26 @@ config_fetch(struct device *d, unsigned int pos, unsigned int len)
 {
   unsigned int end = pos+len;
   int result;
-  if (end <= d->config_cnt)
+
+  while (pos < d->config_bufsize && len && d->present[pos])
+    pos++, len--;
+  while (pos+len <= d->config_bufsize && len && d->present[pos+len-1])
+    len--;
+  if (!len)
     return 1;
+
   if (end > d->config_bufsize)
     {
+      int orig_size = d->config_bufsize;
       while (end > d->config_bufsize)
        d->config_bufsize *= 2;
       d->config = xrealloc(d->config, d->config_bufsize);
+      d->present = xrealloc(d->present, d->config_bufsize);
+      bzero(d->present + orig_size, d->config_bufsize - orig_size);
     }
   result = pci_read_block(d->dev, pos, d->config + pos, len);
-  if (result && pos == d->config_cnt)
-    d->config_cnt = end;
+  if (result)
+    memset(d->present + pos, 1, len);
   return result;
 }
 
@@ -99,18 +109,20 @@ scan_device(struct pci_dev *p)
   d = xmalloc(sizeof(struct device));
   bzero(d, sizeof(*d));
   d->dev = p;
-  d->config_cnt = d->config_bufsize = 64;
+  d->config_cached = d->config_bufsize = 64;
   d->config = xmalloc(64);
+  d->present = xmalloc(64);
+  memset(d->present, 1, 64);
   if (!pci_read_block(p, 0, d->config, 64))
-    die("Unable to read the configuration space header.");
+    die("Unable to read the standard configuration space header");
   if ((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 (!config_fetch(d, 64, 64))
-       die("Unable to read cardbus bridge extension data.");
+      if (config_fetch(d, 64, 64))
+       d->config_cached += 64;
     }
-  pci_setup_cache(p, d->config, d->config_cnt);
+  pci_setup_cache(p, d->config, d->config_cached);
   pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES);
   return d;
 }
@@ -132,21 +144,34 @@ scan_devices(void)
 
 /* Config space accesses */
 
+static void
+check_conf_range(struct device *d, unsigned int pos, unsigned int len)
+{
+  while (len)
+    if (!d->present[pos])
+      die("Internal bug: Accessing non-read configuration byte at position %x", pos);
+    else
+      pos++, len--;
+}
+
 static inline byte
 get_conf_byte(struct device *d, unsigned int pos)
 {
+  check_conf_range(d, pos, 1);
   return d->config[pos];
 }
 
 static word
 get_conf_word(struct device *d, unsigned int pos)
 {
+  check_conf_range(d, pos, 2);
   return d->config[pos] | (d->config[pos+1] << 8);
 }
 
 static u32
 get_conf_long(struct device *d, unsigned int pos)
 {
+  check_conf_range(d, pos, 4);
   return d->config[pos] |
     (d->config[pos+1] << 8) |
     (d->config[pos+2] << 16) |
@@ -482,9 +507,9 @@ show_pcix_nobridge(struct device *d, int where)
         1 << (9 + ((command & PCI_PCIX_COMMAND_MAX_MEM_READ_BYTE_COUNT) >> 2U)),
         max_outstanding[(command & PCI_PCIX_COMMAND_MAX_OUTSTANDING_SPLIT_TRANS) >> 4U]);
   printf("\t\tStatus: Dev=%02x:%02x.%d 64bit%c 133MHz%c SCD%c USC%c DC=%s DMMRBC=%u DMOST=%u DMCRS=%u RSCEM%c 266MHz%c 533MHz%c\n",
-        ((status >> 8) & 0xff),                        // bus
-        ((status >> 3) & 0x1f),                        // device
-        (status & PCI_PCIX_STATUS_FUNCTION),           // function
+        ((status >> 8) & 0xff),
+        ((status >> 3) & 0x1f),
+        (status & PCI_PCIX_STATUS_FUNCTION),
         FLAG(status, PCI_PCIX_STATUS_64BIT),
         FLAG(status, PCI_PCIX_STATUS_133MHZ),
         FLAG(status, PCI_PCIX_STATUS_SC_DISCARDED),
@@ -524,9 +549,9 @@ show_pcix_bridge(struct device *d, int where)
         sec_clock_freq[(secstatus >> 6) & 7]);
   status = get_conf_long(d, where + PCI_PCIX_BRIDGE_STATUS);
   printf("\t\tStatus: Dev=%02x:%02x.%d 64bit%c 133MHz%c SCD%c USC%c SCO%c SRD%c\n", 
-        ((status >> 8) & 0xff),                        // bus
-        ((status >> 3) & 0x1f),                        // device
-        (status & PCI_PCIX_BRIDGE_STATUS_FUNCTION),    // function
+        ((status >> 8) & 0xff),
+        ((status >> 3) & 0x1f),
+        (status & PCI_PCIX_BRIDGE_STATUS_FUNCTION),
         FLAG(status, PCI_PCIX_BRIDGE_STATUS_64BIT),
         FLAG(status, PCI_PCIX_BRIDGE_STATUS_133MHZ),
         FLAG(status, PCI_PCIX_BRIDGE_STATUS_SC_DISCARDED),
@@ -1321,7 +1346,7 @@ show_caps(struct device *d)
          printf("\tCapabilities: ");
          if (!config_fetch(d, where, 4))
            {
-             puts("<available only to root>");
+             puts("<access denied>");
              break;
            }
          id = get_conf_byte(d, where + PCI_CAP_LIST_ID);
@@ -1493,7 +1518,7 @@ show_htype2(struct device *d)
   int i;
   word cmd = get_conf_word(d, PCI_COMMAND);
   word brc = get_conf_word(d, PCI_CB_BRIDGE_CONTROL);
-  word exca = get_conf_word(d, PCI_CB_LEGACY_MODE_BASE);
+  word exca;
   int verb = verbose > 2;
 
   show_bases(d, 1);
@@ -1541,6 +1566,14 @@ show_htype2(struct device *d)
           FLAG(brc, PCI_CB_BRIDGE_CTL_CB_RESET),
           FLAG(brc, PCI_CB_BRIDGE_CTL_16BIT_INT),
           FLAG(brc, PCI_CB_BRIDGE_CTL_POST_WRITES));
+
+  if (d->config_cached < 128)
+    {
+      printf("\t<access denied to the rest>\n");
+      return;
+    }
+
+  exca = get_conf_word(d, PCI_CB_LEGACY_MODE_BASE);
   if (exca)
     printf("\t16-bit legacy interface ports at %04x\n", exca);
 }
@@ -1559,7 +1592,7 @@ show_verbose(struct device *d)
   byte max_lat, min_gnt;
   byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN);
   unsigned int irq = p->irq;
-  word subsys_v, subsys_d;
+  word subsys_v = 0, subsys_d = 0;
   char ssnamebuf[256];
 
   show_terse(d);
@@ -1578,14 +1611,16 @@ show_verbose(struct device *d)
       if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
        printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
       irq = int_pin = min_gnt = max_lat = 0;
-      subsys_v = subsys_d = 0;
       break;
     case PCI_HEADER_TYPE_CARDBUS:
       if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
        printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
       min_gnt = max_lat = 0;
-      subsys_v = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
-      subsys_d = get_conf_word(d, PCI_CB_SUBSYSTEM_ID);
+      if (d->config_cached >= 128)
+       {
+         subsys_v = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
+         subsys_d = get_conf_word(d, PCI_CB_SUBSYSTEM_ID);
+       }
       break;
     default:
       printf("\t!!! Unknown header type %02x\n", htype);
@@ -1700,7 +1735,7 @@ show_hex_dump(struct device *d)
 {
   unsigned int i, cnt;
 
-  cnt = d->config_cnt;
+  cnt = d->config_cached;
   if (show_hex >= 3 && config_fetch(d, cnt, 256-cnt))
     {
       cnt = 256;
@@ -1733,8 +1768,11 @@ show_machine(struct device *d)
       sd_id = get_conf_word(d, PCI_SUBSYSTEM_ID);
       break;
     case PCI_HEADER_TYPE_CARDBUS:
-      sv_id = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
-      sd_id = get_conf_word(d, PCI_CB_SUBSYSTEM_ID);
+      if (d->config_cached >= 128)
+       {
+         sv_id = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
+         sd_id = get_conf_word(d, PCI_CB_SUBSYSTEM_ID);
+       }
       break;
     }
 
index a5112d2ff701c52ad0d34a99ae6e1d906a02cc22..25da19bfd9b9544936589bd89c26711c5ea3d448 100644 (file)
--- a/lspci.man
+++ b/lspci.man
@@ -10,45 +10,65 @@ lspci \- list all PCI devices
 is a utility for displaying information about all PCI buses in the system and
 all devices connected to them.
 
+By default, it shows a brief list of devices. Use the options described
+below to request either a more verbose output or output intended for
+parsing by other programs.
+
 If you are going to report bugs in PCI device drivers or in
 .I lspci
-itself, please include output of "lspci -vvx".
+itself, please include output of "lspci -vvx" or even better "lspci -vvxxx"
+(however, see below for possible caveats).
+
+Some parts of the output, especially in the highly verbose modes, is probably
+intelligible only to experienced PCI hackers. For the exact definitions of
+the fields, please consult either the PCI specifications or the
+.B header.h
+and
+.B /usr/include/linux/pci.h
+include files.
+
+Access to some parts of the PCI configuration space is restricted to root
+on many operating systems, so the features of
+.I lspci
+available to normal users are limited. However,
+.I lspci
+tries its best to display as much as available and mark all other
+information with
+.I <access denied>
+text.
 
 .SH OPTIONS
 .TP
 .B -v
-Tells
-.I lspci
-to be verbose and display detailed information about all devices.
+Be verbose and display detailed information about all devices.
 .TP
 .B -vv
-Tells
-.I lspci
-to be very verbose and display even more information (actually everything the
-PCI device is able to tell). The exact meaning of these data is not explained
-in this manual page, if you want to know more, consult
-.B /usr/include/linux/pci.h
-or the PCI specs.
+Be very verbose and display more details. This level includes everything deemed
+useful.
+.TP
+.B -vvv
+Be even more verbose and display everything we are able to parse,
+even if it doesn't look interesting at all (e.g., undefined memory regions).
 .TP
 .B -n
 Show PCI vendor and device codes as numbers instead of looking them up in the
-PCI ID database.
+PCI ID list.
 .TP
 .B -x
-Show hexadecimal dump of first 64 bytes of the PCI configuration space (the standard
-header). Useful for debugging of drivers and
-.I lspci
-itself.
+Show hexadecimal dump of the standard part of the configuration space (the first
+64 bytes or 128 bytes for CardBus bridges).
 .TP
 .B -xxx
-Show hexadecimal dump of whole PCI configuration space. Available only for root
+Show hexadecimal dump of the whole PCI configuration space. It is available only to root
 as several PCI devices
 .B crash
-when you try to read undefined portions of the config space (this behavior probably
-doesn't violate the PCI standard, but it's at least very stupid).
+when you try to read some parts of the config space (this behavior probably
+doesn't violate the PCI standard, but it's at least very stupid). However, such
+devices are rare, so you needn't worry much.
 .TP
 .B -xxxx
-Show hexadecimal dump of the extended PCI configuration space.
+Show hexadecimal dump of the extended (4096-byte) PCI configuration space available
+on PCI-X 2.0 and PCI Express buses.
 .TP
 .B -b
 Bus-centric view. Show all IRQ numbers and addresses as seen by the cards on the
@@ -75,12 +95,7 @@ hexadecimal and may be omitted or given as "*", both meaning "any value".
 Use
 .B
 <file>
-as PCI ID database instead of @SHAREDIR@/pci.ids.
-.TP
-.B -p <dir>
-Use
-.B <dir>
-as directory containing PCI bus information instead of /proc/bus/pci.
+as the PCI ID list instead of @SHAREDIR@/pci.ids.
 .TP
 .B -m
 Dump PCI device data in machine readable form (both normal and verbose format supported)
@@ -98,41 +113,79 @@ Shows
 .I lspci
 version. This option should be used stand-alone.
 
-.SH PCILIB OPTIONS
+.SH PCILIB AND ITS OPTIONS
 The PCI utilities use PCILIB (a portable library providing platform-independent
-functions for PCI configuration space access) to talk to the PCI cards. The following
-options control parameters of the library, especially what access method it uses.
+functions for PCI configuration space access) to talk to the PCI cards. It supports
+the following access methods:
+
+.TP
+.B linux_sysfs
+The
+.B /sys
+filesystem on Linux 2.6 and newer. The standard header of the config space is available
+to all users, the rest only to root. Supports extended configuration space and PCI domains.
+.TP
+.B linux_proc
+The
+.B /proc/bus/pci
+interface supported by Linux 2.1 and newer. The standard header of the config space is available
+to all users, the rest only to root.
+.TP
+.B intel_conf1
+Direct hardware access via Intel configuration mechanism 1. Available on i386 and compatibles
+on Linux, Solaris/x86, GNU Hurd and Windows. Requires root privileges.
+.TP
+.B intel_conf2
+Direct hardware access via Intel configuration mechanism 2. Available on i386 and compatibles
+on Linux, Solaris/x86 and GNU Hurd. Requires root privileges. Warning: This method
+is able to address only first 16 devices on any bus and it seems to be very
+unreliable in many cases.
+.TP
+.B fbsd_device
+The
+.B /dev/pci
+device on FreeBSD. Requires root privileges.
+.TP
+.B aix_device
+Access method used on AIX. Requires root privileges.
+.TP
+.B nbsd_libpci
+The
+.B /dev/pci0
+device on NetBSD accessed using the local libpci library.
+
+.P
 By default, PCILIB uses the first available access method and displays no debugging
-messages. Each switch is accompanied by a list of hardware/software configurations
-it's supported in.
+messages, but you can use the following switches to control its behavior:
 
 .TP
 .B -P <dir>
-Force use of Linux /proc/bus/pci style configuration access, using
+Force use of the linux_proc access method, using
 .B <dir>
-instead of /proc/bus/pci. (Linux 2.1 or newer only)
+instead of /proc/bus/pci.
 .TP
 .B -H1
-Use direct hardware access via Intel configuration mechanism 1. (i386 and compatible only)
+Use direct hardware access via Intel configuration mechanism 1.
 .TP
 .B -H2
-Use direct hardware access via Intel configuration mechanism 2. Warning: This method
-is able to address only first 16 devices on any bus and it seems to be very
-unreliable in many cases. (i386 and compatible only)
+Use direct hardware access via Intel configuration mechanism 2.
 .TP
 .B -F <file>
 Extract all information from given file containing output of lspci -x. This is very
 useful for analysis of user-supplied bug reports, because you can display the
 hardware configuration in any way you want without disturbing the user with
-requests for more dumps. (All systems)
+requests for more dumps.
 .TP
 .B -G
-Increase debug level of the library. (All systems)
+Increase debug level of the library.
 
 .SH FILES
 .TP
 .B @SHAREDIR@/pci.ids
-A list of all known PCI ID's (vendors, devices, classes and subclasses).
+A list of all known PCI ID's (vendors, devices, classes and subclasses). Maintained
+at http://pciids.sourceforge.net/, use the
+.B update-pciids
+utility to download the most recent version.
 .TP
 .B /proc/bus/pci
 An interface to PCI bus configuration space provided by the post-2.1.82 Linux
index 6eb2bde8bf03429e595738f8863619182d3fcad8..80f1a68c8f4fd7b1f0db0bb7374cd359093ce244 100644 (file)
@@ -15,6 +15,12 @@ is a utility for querying and configuring PCI devices.
 
 All numbers are entered in hexadecimal notation.
 
+Root privileges are necessary for almost all operations, excluding reads
+of the standard header of the configuration space on some operating systems.
+Please see
+.BR lspci(8)
+for details on access rights.
+
 .SH OPTIONS
 .TP
 .B -v
@@ -43,7 +49,6 @@ Shows
 .I setpci
 version. This option should be used stand-alone.
 
-
 .SH DEVICE SELECTION
 .PP
 Before each sequence of operations you need to select which devices you wish that
@@ -91,10 +96,12 @@ to be changed to values of the corresponding bits in the
 .SH REGISTER NAMES
 .PP
 .B setpci
-knows the following configuration register names. See PCI bus specs for their precise
+knows the following configuration register names. See PCI bus specifications for their precise
 meaning or consult
+.B header.h
+or
 .B /usr/include/linux/pci.h
-for few comments.
+for a couple of comments.
 .PP
 .nf
 VENDOR_ID
@@ -164,34 +171,10 @@ CB_LEGACY_MODE_BASE
 
 .SH PCILIB OPTIONS
 The PCI utilities use PCILIB (a portable library providing platform-independent
-functions for PCI configuration space access) to talk to the PCI cards. The following
-options control parameters of the library, especially what access method it uses.
-By default, PCILIB uses the first available access method and displays no debugging
-messages. Each switch is accompanied by a list of hardware/software configurations
-it's supported in.
-
-.TP
-.B -P <dir>
-Force use of Linux /proc/bus/pci style configuration access, using
-.B <dir>
-instead of /proc/bus/pci. (Linux 2.1 or newer only)
-.TP
-.B -H1
-Use direct hardware access via Intel configuration mechanism 1. (i386 and compatible only)
-.TP
-.B -H2
-Use direct hardware access via Intel configuration mechanism 2. Warning: This method
-is able to address only first 16 devices on any bus and it seems to be very
-unreliable in many cases. (i386 and compatible only)
-.TP
-.B -F <file>
-Extract all information from given file containing output of lspci -x. This is very
-useful for analysis of user-supplied bug reports, because you can display the
-hardware configuration in any way you want without disturbing the user with
-requests for more dumps. (All systems)
-.TP
-.B -G
-Increase debug level of the library. (All systems)
+functions for PCI configuration space access) to talk to the PCI cards. Please
+see
+.BR lspci(8)
+for a list of switches controlling behavior of the library.
 
 .SH EXAMPLES
 .PP