From 84d437d6877b64a10d7371fcc4cc47194c845273 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Tue, 23 Aug 2005 21:12:22 +0000 Subject: [PATCH] Register caching rewrite git-archimport-id: mj@ucw.cz--public/pciutils--main--2.2--patch-76 --- ChangeLog | 10 ++++ TODO | 5 +- lspci.c | 88 +++++++++++++++++++++++++---------- lspci.man | 133 +++++++++++++++++++++++++++++++++++++---------------- setpci.man | 45 ++++++------------ 5 files changed, 181 insertions(+), 100 deletions(-) diff --git a/ChangeLog b/ChangeLog index e43ed8d..526da1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,21 @@ 2005-08-23 Martin Mares + * 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 bf48ef4..cfd09e7 100644 --- 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 bbe1a22..b00ea48 100644 --- 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(""); + puts(""); 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\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; } diff --git a/lspci.man b/lspci.man index a5112d2..25da19b 100644 --- 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 +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 -as PCI ID database instead of @SHAREDIR@/pci.ids. -.TP -.B -p -Use -.B -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 -Force use of Linux /proc/bus/pci style configuration access, using +Force use of the linux_proc access method, using .B -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 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 diff --git a/setpci.man b/setpci.man index 6eb2bde..80f1a68 100644 --- a/setpci.man +++ b/setpci.man @@ -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 -Force use of Linux /proc/bus/pci style configuration access, using -.B -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 -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 -- 2.39.2