From: Martin Mares Date: Sun, 19 Apr 1998 11:02:25 +0000 (+0000) Subject: PCIutils 1.03. X-Git-Tag: v3.0.0~335 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=b2c9b37385b4f06bbdb0af0aca627dfc00df5afb;p=pciutils.git PCIutils 1.03. - setpci now works and has a (well, a bit confusing) man page. - lspci now understands the expansion ROM base addresses as reported by new kernels. --- diff --git a/ChangeLog b/ChangeLog index 5b34d8e..b8bb1ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Sun Apr 19 11:14:25 1998 Martin Mares + + * setpci.8: Written. + + * setpci.c: Finished. + + * lspci.c: Now able to fetch expansion ROM base from kernel device list + and print it if not in buscentric mode. + Tue Mar 31 23:11:57 1998 Martin Mares * setpci.c: Added. diff --git a/Makefile b/Makefile index bb58e36..e4ab630 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.7 1998/03/31 21:02:12 mj Exp $ +# $Id: Makefile,v 1.8 1998/04/19 11:02:25 mj Exp $ # Makefile for Linux PCI Utilities # (c) 1998 Martin Mares @@ -10,28 +10,24 @@ CFLAGS=$(OPT) -Wall -W -Wno-parentheses -Wstrict-prototypes -Wno-unused -Werror PREFIX=/ MANPREFIX=/usr -all: lspci - -#all: lspci setpci +all: lspci setpci lspci: lspci.o names.o filter.o +setpci: setpci.o filter.o lspci.o: lspci.c pciutils.h names.o: names.c pciutils.h filter.o: filter.c pciutils.h - -setpci: setpci.o filter.o - -setpci.o: setpci.c +setpci.o: setpci.c pciutils.h clean: rm -f `find . -name "*~" -or -name "*.[oa]" -or -name "\#*\#" -or -name TAGS -or -name core` rm -f lspci setpci pci.h install: all - install -o root -g root -m 755 -s lspci $(PREFIX)/sbin + install -o root -g root -m 755 -s lspci setpci $(PREFIX)/sbin install -o root -g root -m 644 pci.ids $(PREFIX)/etc - install -o root -g root -m 644 lspci.8 $(MANPREFIX)/man/man8 + install -o root -g root -m 644 lspci.8 setpci.8 $(MANPREFIX)/man/man8 dist: clean cp /usr/src/linux/include/linux/pci.h . diff --git a/README b/README index dfe0cbf..971b7cc 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This package contains the Linux PCI Utilities, version 1.02. +This package contains the Linux PCI Utilities, version 1.03. Copyright (c) 1998 Martin Mares @@ -10,10 +10,16 @@ for details. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - The Linux PCI Utilities currently contain only one utility -- lspci, -indented for displaying of detailed information about all PCI busses and -devices in the system, replacing the original /proc/pci interface. See -the manual page (lspci.8) for more details. + The Linux PCI Utilities contain various utilities for dealing with the PCI +bus in Linux: + + - lspci: displays detailed information about all PCI busses and devices + in the system, replacing the original /proc/pci interface. + + - setpci: allows to read from and write to PCI device configuration + registers. For example, you can adjust the latency timers with it. + + See manual pages for more details. If you have any bug reports or suggestions, send them to the author. diff --git a/lspci.8 b/lspci.8 index 3ccedb4..5601554 100644 --- a/lspci.8 +++ b/lspci.8 @@ -1,4 +1,4 @@ -.TH lspci 8 "15 February 98" "pciutils-1.02" "Linux PCI Utilities" +.TH lspci 8 "19 April 98" "pciutils-1.03" "Linux PCI Utilities" .IX lspci .SH NAME lspci \- list all PCI devices diff --git a/lspci.c b/lspci.c index f59ce91..90b2e58 100644 --- a/lspci.c +++ b/lspci.c @@ -1,5 +1,5 @@ /* - * $Id: lspci.c,v 1.10 1998/03/31 21:02:16 mj Exp $ + * $Id: lspci.c,v 1.11 1998/04/19 11:02:27 mj Exp $ * * Linux PCI Utilities -- List All PCI Devices * @@ -58,7 +58,7 @@ struct device { byte bus, devfn; word vendid, devid; unsigned int kernel_irq; - unsigned long kernel_base_addr[6]; + unsigned long kernel_base_addr[6], kernel_rom_base_addr; byte config[256]; }; @@ -98,7 +98,8 @@ scan_dev_list(void) struct device *d = xmalloc(sizeof(struct device)); unsigned int dfn, vend; - sscanf(line, "%x %x %x %lx %lx %lx %lx %lx %lx", + bzero(d, sizeof(*d)); + sscanf(line, "%x %x %x %lx %lx %lx %lx %lx %lx %lx", &dfn, &vend, &d->kernel_irq, @@ -107,7 +108,8 @@ scan_dev_list(void) &d->kernel_base_addr[2], &d->kernel_base_addr[3], &d->kernel_base_addr[4], - &d->kernel_base_addr[5]); + &d->kernel_base_addr[5], + &d->kernel_rom_base_addr); d->bus = dfn >> 8U; d->devfn = dfn & 0xff; d->vendid = vend >> 16U; @@ -313,16 +315,13 @@ show_bases(struct device *d, int cnt) static void show_htype0(struct device *d) { - u32 rom = get_conf_long(d, PCI_ROM_ADDRESS); + unsigned long rom = buscentric_view ? get_conf_long(d, PCI_ROM_ADDRESS) : d->kernel_rom_base_addr; show_bases(d, 6); if (rom & 1) - { - word cmd = get_conf_word(d, PCI_COMMAND); - printf("\tExpansion ROM at %08x%s\n", rom & ~0xfff, - (cmd & PCI_COMMAND_MEMORY) ? "" : " [disabled]"); - } + printf("\tExpansion ROM at %08lx%s\n", rom & PCI_ROM_ADDRESS_MASK, + (rom & PCI_ROM_ADDRESS_ENABLE) ? "" : " [disabled]"); } static void @@ -337,7 +336,7 @@ show_htype1(struct device *d) u32 pref_base = get_conf_word(d, PCI_PREF_MEMORY_BASE); u32 pref_limit = get_conf_word(d, PCI_PREF_MEMORY_LIMIT); u32 pref_type = pref_base & PCI_PREF_RANGE_TYPE_MASK; - u32 rom = get_conf_long(d, PCI_ROM_ADDRESS1); + unsigned long rom = buscentric_view ? get_conf_long(d, PCI_ROM_ADDRESS) : d->kernel_rom_base_addr; word brc = get_conf_word(d, PCI_BRIDGE_CONTROL); show_bases(d, 2); @@ -394,11 +393,8 @@ show_htype1(struct device *d) printf("\tSecondary status: SERR\n"); if (rom & 1) - { - word cmd = get_conf_word(d, PCI_COMMAND); - printf("\tExpansion ROM at %08x%s\n", rom & ~0xfff, - (cmd & PCI_COMMAND_MEMORY) ? "" : " [disabled]"); - } + printf("\tExpansion ROM at %08lx%s\n", rom & PCI_ROM_ADDRESS_MASK, + (rom & PCI_ROM_ADDRESS_ENABLE) ? "" : " [disabled]"); if (verbose > 1) printf("\tBridgeCtl: Parity%c SERR%c NoISA%c VGA%c MAbort%c >Reset%c FastB2B%c\n", diff --git a/pciutils.lsm b/pciutils.lsm index 63d6f3a..a6c7639 100644 --- a/pciutils.lsm +++ b/pciutils.lsm @@ -1,15 +1,15 @@ Begin3 Title: Linux PCI Utilities -Version: 1.02 -Entered-date: 980215 +Version: 1.03 +Entered-date: 980419 Description: This package contains various utilities for inspecting and setting of devices connected to the PCI bus. Requires kernel version 2.1.82 or newer (supporting the /proc/bus/pci interface). -Keywords: kernel, pci, proc, lspci +Keywords: kernel, pci, proc, lspci, setpci Author: mj@atrey.karlin.mff.cuni.cz (Martin Mares) Maintained-by: mj@atrey.karlin.mff.cuni.cz (Martin Mares) -Primary-site: atrey.karlin.mff.cuni.cz pub/local/mj/linux/pciutils-1.02.tar.gz -Alternate-site: sunsite.unc.edu pub/Linux/hardware/pciutils-1.02.tar.gz +Primary-site: atrey.karlin.mff.cuni.cz pub/linux/pci/pciutils-1.03.tar.gz +Alternate-site: sunsite.unc.edu pub/Linux/hardware/pciutils-1.03.tar.gz Copying-policy: GPL End diff --git a/setpci.8 b/setpci.8 new file mode 100644 index 0000000..836cfb2 --- /dev/null +++ b/setpci.8 @@ -0,0 +1,161 @@ +.TH setpci 8 "19 April 98" "pciutils-1.03" "Linux PCI Utilities" +.IX setpci +.SH NAME +lspci \- configure PCI devices +.SH SYNOPSIS +.B setpci +.RB [ options ] +.B devices +.BR operations ... + +.SH DESCRIPTION +.PP +.B setpci +is a utility for querying and configuring PCI devices. It requires Linux kernel 2.1.82 +or newer as it uses the /proc/bus/pci interface. +.PP +All numbers are entered in hexadecimal notation. + +.SH OPTIONS +.TP +.B -v +Tells +.I setpci +to be verbose and display detailed information about configuration space accesses. +.TP +.B -f +Tells +.I lspci +not to complain when there's nothing to do (when no devices are selected). +This option is intended for use in widely-distributed configuration scripts +where it's uncertain whether the device in question is present in the machine +or not. +.TP +.B -D +`Demo mode' -- simulate configuration space accesses instead of really doing them. +It's useful to try +.B setpci -vD +to see what your complex sequence of +.B setpci +operations does before you actually execute it. + +.SH DEVICE SELECTION +.PP +Before each sequence of operations you need to select which devices you wish that +operation to affect. +.TP +.B -s [[]:][][.[]] +Select devices in specified bus, slot and function. Each component of the device +address can be omitted or set as "*" meaning "any value". All numbers are +hexadecimal. E.g., "0:" means all devices on bus 0, "0" means all functions of device 0 +on any bus, "0.3" selects third function of device 0 on all busses and ".4" selects only +fourth function of each device. +.TP +.B -d []:[] +Select devices with specified vendor and device ID. Both ID's are given in +hexadecimal and may be omitted or given as "*" meaning "any value". + +.SH OPERATIONS +.PP +To query value of a configuration register, just name it (either by typing its name or +by typing register address with optional +.BR .B , +.B .W +or +.B .L +suffix specifying register width as byte, word or longword). +.PP +To set a register, write +.BR reg = values +where +.B reg +is the same you would use to query the register and +.B values +is a comma-separated list of values you want to write starting with the given +address. + +.SH REGISTER NAMES +.PP +.B setpci +knows the following configuration register names. See PCI bus specs for their precise +meaning or consult +.B /usr/include/linux/pci.h +for few comments. +.PP +.nf +VENDOR_ID +DEVICE_ID +COMMAND +STATUS +REVISION +CLASS_PROG +CLASS_DEVICE +CACHE_LINE_SIZE +LATENCY_TIMER +HEADER_TYPE +BIST +BASE_ADDRESS_0 +BASE_ADDRESS_1 +BASE_ADDRESS_2 +BASE_ADDRESS_3 +BASE_ADDRESS_4 +BASE_ADDRESS_5 +CARDBUS_CIS +SUBSYSTEM_VENDOR_ID +SUBSYSTEM_ID +ROM_ADDRESS +INTERRUPT_LINE +INTERRUPT_PIN +MIN_GNT +MAX_LAT +PRIMARY_BUS +SECONDARY_BUS +SUBORDINATE_BUS +SEC_LATENCY_TIMER +IO_BASE +IO_LIMIT +SEC_STATUS +MEMORY_BASE +MEMORY_LIMIT +PREF_MEMORY_BASE +PREF_MEMORY_LIMIT +PREF_BASE_UPPER32 +PREF_LIMIT_UPPER32 +IO_BASE_UPPER16 +IO_LIMIT_UPPER16 +BRIDGE_ROM_ADDRESS +BRIDGE_CONTROL +CB_CARDBUS_BASE +CB_CAPABILITIES +CB_SEC_STATUS +CB_BUS_NUMBER +CB_CARDBUS_NUMBER +CB_SUBORDINATE_BUS +CB_CARDBUS_LATENCY +CB_MEMORY_BASE_0 +CB_MEMORY_LIMIT_0 +CB_MEMORY_BASE_1 +CB_MEMORY_LIMIT_1 +CB_IO_BASE_0 +CB_IO_BASE_0_HI +CB_IO_LIMIT_0 +CB_IO_LIMIT_0_HI +CB_IO_BASE_1 +CB_IO_BASE_1_HI +CB_IO_LIMIT_1 +CB_IO_LIMIT_1_HI +CB_SUBSYSTEM_VENDOR_ID +CB_SUBSYSTEM_ID +CB_LEGACY_MODE_BASE + +.SH EXAMPLES +.PP +`setpci -d *:* latency_timer=40' sets the latency timer to 64 (40 hexadecimal). +.PP +`setpci -s 0 device_id vendor_id' lists ID's of devices in slot 0 in all busses. +.PP +`setpci -s 12:3.4 34.l=1,2,3' writes longword 1 to register 34, 2 to register 35 +and 3 to register 35 of device at bus 12, slot 3, function 4. + +.SH AUTHOR +The Linux PCI Utilities are maintained by Martin Mares . diff --git a/setpci.c b/setpci.c index 189b96a..b13ddb4 100644 --- a/setpci.c +++ b/setpci.c @@ -1,5 +1,5 @@ /* - * $Id: setpci.c,v 1.1 1998/03/31 21:02:20 mj Exp $ + * $Id: setpci.c,v 1.2 1998/04/19 11:02:29 mj Exp $ * * Linux PCI Utilities -- Manipulate PCI Configuration Registers * @@ -13,17 +13,21 @@ #include #include #include +#include +#include +#include #include "pciutils.h" static int force; /* Don't complain if no devices match */ static int verbose; /* Verbosity level */ +static int demo_mode; /* Only show */ struct device { struct device *next; byte bus, devfn, mark; word vendid, devid; - int fd; + int fd, need_write; }; static struct device *first_dev; @@ -51,6 +55,13 @@ xmalloc(unsigned int howmuch) return p; } +/* + * As libc doesn't support pread/pwrite yet, we have to call them directly + * or use lseek/read/write instead. + */ +static _syscall4(int, pread, unsigned int, fd, void *, buf, size_t, size, loff_t, where); +static _syscall4(int, pwrite, unsigned int, fd, void *, buf, size_t, size, loff_t, where); + static void scan_devices(void) { @@ -103,25 +114,88 @@ exec_op(struct op *op, struct device *dev) { char *mm[] = { NULL, "%02x", "%04x", NULL, "%08x" }; char *m = mm[op->width]; + unsigned int x; + int i; + __u32 x32; + __u16 x16; + __u8 x8; - if (dev->fd < 0) + if (!demo_mode && dev->fd < 0) { char name[64]; sprintf(name, PROC_BUS_PCI "/%02x/%02x.%x", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - dev->fd = open(name, O_RDWR ???? + if ((dev->fd = open(name, dev->need_write ? O_RDWR : O_RDONLY)) < 0) + { + perror(name); + exit(1); + } } if (verbose) - printf("%02x.%02x:%x.%c ", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), - "?BW?L"[op->width]); - if (op->num_values > 0) - { - } + printf("%02x:%02x.%x:%02x", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), op->addr); + if (op->num_values >= 0) + for(i=0; inum_values; i++) + { + if (verbose) + { + putchar(' '); + printf(m, op->values[i]); + } + if (demo_mode) + continue; + switch (op->width) + { + case 1: + x8 = op->values[i]; + i = pwrite(dev->fd, &x8, 1, op->addr); + break; + case 2: + x16 = __cpu_to_le16(op->values[i]); + i = pwrite(dev->fd, &x16, 2, op->addr); + break; + default: + x32 = __cpu_to_le32(op->values[i]); + i = pwrite(dev->fd, &x32, 4, op->addr); + break; + } + if (i != (int) op->width) + { + fprintf(stderr, "Error writing to %02x:%02x.%d: %m", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + exit(1); + } + } else { if (verbose) - printf("= "); + printf(" = "); + if (!demo_mode) + { + switch (op->width) + { + case 1: + i = pread(dev->fd, &x8, 1, op->addr); + x = x8; + break; + case 2: + i = pread(dev->fd, &x16, 2, op->addr); + x = __le16_to_cpu(x16); + break; + default: + i = pread(dev->fd, &x32, 4, op->addr); + x = __le32_to_cpu(x32); + break; + } + if (i != (int) op->width) + { + fprintf(stderr, "Error reading from %02x:%02x.%d: %m", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + exit(1); + } + printf(m, x); + } + else + putchar('?'); } + putchar('\n'); } static void @@ -142,17 +216,112 @@ execute(struct op *op) } } +static void +scan_ops(struct op *op) +{ + struct device **pdev, *dev; + + while (op) + { + if (op->num_values >= 0) + { + pdev = op->dev_vector; + while (dev = *pdev++) + dev->need_write = 1; + } + op = op->next; + } +} + +struct reg_name { + int offset; + int width; + char *name; +}; + +static struct reg_name pci_reg_names[] = { + { 0x00, 2, "VENDOR_ID", }, + { 0x02, 2, "DEVICE_ID", }, + { 0x04, 2, "COMMAND", }, + { 0x06, 2, "STATUS", }, + { 0x08, 1, "REVISION", }, + { 0x09, 1, "CLASS_PROG", }, + { 0x0a, 2, "CLASS_DEVICE", }, + { 0x0c, 1, "CACHE_LINE_SIZE", }, + { 0x0d, 1, "LATENCY_TIMER", }, + { 0x0e, 1, "HEADER_TYPE", }, + { 0x0f, 1, "BIST", }, + { 0x10, 4, "BASE_ADDRESS_0", }, + { 0x14, 4, "BASE_ADDRESS_1", }, + { 0x18, 4, "BASE_ADDRESS_2", }, + { 0x1c, 4, "BASE_ADDRESS_3", }, + { 0x20, 4, "BASE_ADDRESS_4", }, + { 0x24, 4, "BASE_ADDRESS_5", }, + { 0x28, 4, "CARDBUS_CIS", }, + { 0x2c, 4, "SUBSYSTEM_VENDOR_ID", }, + { 0x2e, 2, "SUBSYSTEM_ID", }, + { 0x30, 4, "ROM_ADDRESS", }, + { 0x3c, 1, "INTERRUPT_LINE", }, + { 0x3d, 1, "INTERRUPT_PIN", }, + { 0x3e, 1, "MIN_GNT", }, + { 0x3f, 1, "MAX_LAT", }, + { 0x18, 1, "PRIMARY_BUS", }, + { 0x19, 1, "SECONDARY_BUS", }, + { 0x1a, 1, "SUBORDINATE_BUS", }, + { 0x1b, 1, "SEC_LATENCY_TIMER", }, + { 0x1c, 1, "IO_BASE", }, + { 0x1d, 1, "IO_LIMIT", }, + { 0x1e, 2, "SEC_STATUS", }, + { 0x20, 2, "MEMORY_BASE", }, + { 0x22, 2, "MEMORY_LIMIT", }, + { 0x24, 2, "PREF_MEMORY_BASE", }, + { 0x26, 2, "PREF_MEMORY_LIMIT", }, + { 0x28, 4, "PREF_BASE_UPPER32", }, + { 0x2c, 4, "PREF_LIMIT_UPPER32", }, + { 0x30, 2, "IO_BASE_UPPER16", }, + { 0x32, 2, "IO_LIMIT_UPPER16", }, + { 0x38, 4, "BRIDGE_ROM_ADDRESS", }, + { 0x3e, 2, "BRIDGE_CONTROL", }, + { 0x10, 4, "CB_CARDBUS_BASE", }, + { 0x14, 2, "CB_CAPABILITIES", }, + { 0x16, 2, "CB_SEC_STATUS", }, + { 0x18, 1, "CB_BUS_NUMBER", }, + { 0x19, 1, "CB_CARDBUS_NUMBER", }, + { 0x1a, 1, "CB_SUBORDINATE_BUS", }, + { 0x1b, 1, "CB_CARDBUS_LATENCY", }, + { 0x1c, 4, "CB_MEMORY_BASE_0", }, + { 0x20, 4, "CB_MEMORY_LIMIT_0", }, + { 0x24, 4, "CB_MEMORY_BASE_1", }, + { 0x28, 4, "CB_MEMORY_LIMIT_1", }, + { 0x2c, 2, "CB_IO_BASE_0", }, + { 0x2e, 2, "CB_IO_BASE_0_HI", }, + { 0x30, 2, "CB_IO_LIMIT_0", }, + { 0x32, 2, "CB_IO_LIMIT_0_HI", }, + { 0x34, 2, "CB_IO_BASE_1", }, + { 0x36, 2, "CB_IO_BASE_1_HI", }, + { 0x38, 2, "CB_IO_LIMIT_1", }, + { 0x3a, 2, "CB_IO_LIMIT_1_HI", }, + { 0x40, 2, "CB_SUBSYSTEM_VENDOR_ID", }, + { 0x42, 2, "CB_SUBSYSTEM_ID", }, + { 0x44, 4, "CB_LEGACY_MODE_BASE", }, + { 0x00, 0, NULL } +}; + static void usage(void) __attribute__((noreturn)); static void usage(void) { fprintf(stderr, -"Usage: setpci [-f] [-v] (+ [=]*)*\n\ -: -s [[]:][][.[]]\n\ -\t| -d []:[]\n\ -: [.(B|W|L)]\n\ -: [,...]\n\ +"Usage: setpci [-fvD] (+ [=]*)*\n\ +-f\t\tDon't complain if there's nothing to do\n\ +-v\t\tBe verbose\n\ +-D\t\tList changes, don't commit them\n\ +:\t-s [[]:][][.[]]\n\ +\t|\t-d []:[]\n\ +:\t\t[.(B|W|L)]\n\ + |\t\t\n\ +:\t[,...]\n\ "); exit(1); } @@ -181,6 +350,10 @@ main(int argc, char **argv) force++; c++; break; + case 'D': + demo_mode++; + c++; + break; case 0: break; default: @@ -255,6 +428,8 @@ next: if (d) { *d++ = 0; + if (!*d) + usage(); for(e=d, n=1; *e; e++) if (*e == ',') n++; @@ -288,11 +463,28 @@ next: else op->width = 1; ll = strtol(c, &f, 16); - if (ll > 0x100 || ll + op->width*n > 0x100) + if (f && *f) + { + struct reg_name *r; + for(r = pci_reg_names; r->name; r++) + if (!strcasecmp(r->name, c)) + break; + if (!r->name || e) + usage(); + ll = r->offset; + op->width = r->width; + } + if (ll > 0x100 || ll + op->width*((n < 0) ? 1 : n) > 0x100) { fprintf(stderr, "setpci: Register number out of range!\n"); return 1; } + if (ll & (op->width - 1)) + { + fprintf(stderr, "setpci: Unaligned register address!\n"); + return 1; + } + op->addr = ll; for(i=0; i