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.
-- 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
- 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?
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;
{
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;
}
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;
}
/* 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) |
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),
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),
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);
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);
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);
}
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);
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);
{
unsigned int i, cnt;
- cnt = d->config_cnt;
+ cnt = d->config_cached;
if (show_hex >= 3 && config_fetch(d, cnt, 256-cnt))
{
cnt = 256;
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;
}
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
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)
.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
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
.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
.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
.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