+2004-06-27 Martin Mares <mj@ucw.cz>
+
+ * lspci.c (check_root): Gone. No explicit checks for root are needed,
+ report correct errors reported by the libpci instead.
+
+ * lspci.c: Added dumping of the extended config space on "-xxxx".
+ Better caching of config registers.
+
+ * setpci.c (main): Allow access to whole 4096 bytes of the config space.
+
+ * lib/sysfs.c, lib/proc.c: Don't print error messages on short reads,
+ just return the appropriate error code.
+
+ * lib: Added support for extended (4096-byte) configuration space,
+ currently implemented only in Linux proc and sysfs access methods
+ and of course in the dump reader.
+
2004-05-29 Martin Mares <mj@ucw.cz>
* Released as 2.1.99-test5.
aix_read(struct pci_dev *d, int pos, byte *buf, int len)
{
struct mdio mdio;
- int fd = aix_bus_open(d->access, d->bus);
+ int fd;
+ if (pos + len > 256)
+ return 0;
+
+ fd = aix_bus_open(d->access, d->bus);
mdio.md_addr = (ulong) pos;
mdio.md_size = len;
mdio.md_incr = MV_BYTE;
aix_write(struct pci_dev *d, int pos, byte *buf, int len)
{
struct mdio mdio;
- int fd = aix_bus_open(d->access, d->bus);
+ int fd;
+
+ if (pos + len > 256)
+ return 0;
+ fd = aix_bus_open(d->access, d->bus);
mdio.md_addr = (ulong) pos;
mdio.md_size = len;
mdio.md_incr = MV_BYTE;
/*
* The PCI Library -- Reading of Bus Dumps
*
- * Copyright (c) 1997--2003 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 1997--2004 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "internal.h"
+struct dump_data {
+ int len;
+ byte data[1];
+};
+
static int
dump_detect(struct pci_access *a)
{
return !!a->method_params[PCI_ACCESS_DUMP];
}
+static void
+dump_alloc_data(struct pci_dev *dev, int len)
+{
+ struct dump_data *dd = pci_malloc(dev->access, sizeof(struct dump_data) + len - 1);
+ dd->len = len;
+ memset(dd->data, 0xff, len);
+ dev->aux = dd;
+}
+
static void
dump_init(struct pci_access *a)
{
sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4))
{
dev = pci_get_dev(a, mn, bn, dn, fn);
- dev->aux = pci_malloc(a, 256);
- memset(dev->aux, 0xff, 256);
+ dump_alloc_data(dev, 256);
pci_link_dev(a, dev);
}
else if (!len)
dev = NULL;
- else if (dev && len >= 51 && buf[2] == ':' && buf[3] == ' ' &&
+ else if (dev &&
+ (len >= 51 && buf[2] == ':' && buf[3] == ' ' || len >= 52 && buf[3] == ':' && buf[4] == ' ') &&
sscanf(buf, "%x: ", &i) == 1)
{
- z = buf+3;
+ struct dump_data *dd = dev->aux;
+ z = strchr(buf, ' ') + 1;
while (isspace(z[0]) && isxdigit(z[1]) && isxdigit(z[2]))
{
z++;
if (sscanf(z, "%x", &j) != 1 || i >= 256)
a->error("dump: Malformed line");
- ((byte *) dev->aux)[i++] = j;
+ if (i >= 4096)
+ break;
+ if (i > dd->len) /* Need to re-allocate the buffer */
+ {
+ dump_alloc_data(dev, 4096);
+ memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256);
+ pci_mfree(dd);
+ dd = dev->aux;
+ }
+ dd->data[i++] = j;
z += 2;
}
}
static int
dump_read(struct pci_dev *d, int pos, byte *buf, int len)
{
- if (!d->aux)
+ struct dump_data *dd;
+ if (!(dd = d->aux))
{
struct pci_dev *e = d->access->devices;
while (e && (e->bus != d->bus || e->dev != d->dev || e->func != d->func))
e = e->next;
- if (e)
- d = e;
- else
+ if (!e)
return 0;
+ dd = e->aux;
}
- memcpy(buf, (byte *) d->aux + pos, len);
+ if (pos + len > dd->len)
+ return 0;
+ memcpy(buf, dd->data + pos, len);
return 1;
}
return pci_generic_block_read(d, pos, buf, len);
}
+ if (pos >= 256)
+ return 0;
+
pi.pi_sel.pc_bus = d->bus;
pi.pi_sel.pc_dev = d->dev;
pi.pi_sel.pc_func = d->func;
return pci_generic_block_write(d, pos, buf, len);
}
+ if (pos >= 256)
+ return 0;
+
pi.pi_sel.pc_bus = d->bus;
pi.pi_sel.pc_dev = d->dev;
pi.pi_sel.pc_func = d->func;
conf1_read(struct pci_dev *d, int pos, byte *buf, int len)
{
int addr = 0xcfc + (pos&3);
+
+ if (pos >= 256)
+ return 0;
+
outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
switch (len)
conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
{
int addr = 0xcfc + (pos&3);
+
+ if (pos >= 256)
+ return 0;
+
outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
switch (len)
{
int addr = 0xc000 | (d->dev << 8) | pos;
+ if (pos >= 256)
+ return 0;
+
if (d->dev >= 16)
/* conf2 supports only 16 devices per bus */
return 0;
{
int addr = 0xc000 | (d->dev << 8) | pos;
+ if (pos >= 256)
+ return 0;
+
if (d->dev >= 16)
d->access->error("conf2_write: only first 16 devices exist.");
outb((d->func << 1) | 0xf0, 0xcf8);
if (!(len == 1 || len == 2 || len == 4))
return pci_generic_block_read(d, pos, buf, len);
+ if (pos >= 256)
+ return 0;
+
shift = 8*(pos % 4);
pos &= ~3;
if (!(len == 1 || len == 2 || len == 4))
return pci_generic_block_write(d, pos, buf, len);
+ if (pos >= 256)
+ return 0;
+
/*
* BEWARE: NetBSD seems to support only 32-bit access, so we have
* to emulate byte and word writes by read-modify-write, possibly
return 0;
}
else if (res != len)
- {
- d->access->warning("proc_read: tried to read %d bytes at %d, but got only %d", len, pos, res);
- return 0;
- }
+ d->access->warning("proc_read: tried to read %d bytes at %d, but got only %d", len, pos, res);
return 1;
}
}
else if (res != len)
{
- d->access->warning("proc_write: tried to write %d bytes at %d, but got only %d", len, pos, res);
+ d->access->warning("proc_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res);
return 0;
}
return 1;
return 0;
}
else if (res != len)
- {
- d->access->warning("sysfs_read: tried to read %d bytes at %d, but got only %d", len, pos, res);
- return 0;
- }
+ return 0;
return 1;
}
}
else if (res != len)
{
- d->access->warning("sysfs_write: tried to write %d bytes at %d, but got only %d", len, pos, res);
+ d->access->warning("sysfs_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res);
return 0;
}
return 1;
-b\t\tBus-centric view (PCI addresses and IRQ's instead of those seen by the CPU)\n\
-x\t\tShow hex-dump of the standard portion of config space\n\
-xxx\t\tShow hex-dump of the whole config space (dangerous; root only)\n\
+-xxxx\t\tShow hex-dump of the 4096-byte extended config space (root only)\n\
-s [[[[<domain>]:]<bus>]:][<slot>][.[<func>]]\tShow only devices in selected slots\n\
-d [<vendor>]:[<device>]\tShow only selected devices\n\
-t\t\tShow bus tree\n\
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))
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)
+ d->config_cnt = 64;
+ if (!pci_read_block(p, 0, d->config, 64))
+ die("Unable to read the 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 (!pci_read_block(p, 64, d->config+64, 64))
die("Unable to read cardbus bridge extension data.");
- how_much = 128;
+ d->config_cnt = 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 | PCI_FILL_SIZES);
return d;
}
}
-static int
-check_root(void)
-{
-#ifdef OS_WINDOWS
- return 1;
-#else
- static int is_root = -1;
-
- if (is_root < 0)
- is_root = !geteuid();
- return is_root;
-#endif
-}
-
static int
config_fetch(struct device *d, unsigned int pos, unsigned int len)
{
if (pos + len < d->config_cnt)
return 1;
- if (pacc->method != PCI_ACCESS_DUMP && !check_root())
- return 0;
return pci_read_block(d->dev, pos, d->config + pos, len);
}
static void
show_hex_dump(struct device *d)
{
- unsigned int i;
+ unsigned int i, cnt;
- for(i=0; i<d->config_cnt; i++)
+ cnt = d->config_cnt;
+ if (show_hex >= 3 && config_fetch(d, cnt, 256-cnt))
+ {
+ cnt = 256;
+ if (show_hex >= 4 && config_fetch(d, 256, 4096-256))
+ cnt = 4096;
+ }
+
+ for(i=0; i<cnt; i++)
{
if (! (i & 15))
printf("%02x:", i);
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)
/*
* The PCI Utilities -- Manipulate PCI Configuration Registers
*
- * Copyright (c) 1998--2003 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 1998--2004 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
ll = r->offset;
op->width = r->width;
}
- if (ll > 0x100 || ll + op->width*((n < 0) ? 1 : n) > 0x100)
+ if (ll > 0x1000 || ll + op->width*((n < 0) ? 1 : n) > 0x1000)
die("Register number out of range!");
if (ll & (op->width - 1))
die("Unaligned register address!");