PATCH: PCI changes for pre-2.3.16-1

Martin Mares (mj@ucw.cz)
Tue, 31 Aug 1999 16:05:47 +0200


Hi Linus,

This patch (against pre-2.3.16-1) contains a few more steps of my
PCI subsystem changes.

Have a nice day
Martin

Summary:

o Updated Documentation/Changes.
o Added pcibios_assign_resource() to arch-dependent code. This function
should handle address assignment when a new device (or, more frequently,
a new [read: misconfigured] region on an old device) is found.
o Changed i386 bios32.c to use pcibios_assign_resource() for all
allocations.
o Distinguish between pci_dev->name (only bus/slot/function, used for
PCI subsystem initialization messages) and pci_dev->full_name
(used for resource management stuff).
o Added pci_find_capability which is a library function to be used
by drivers whenever they need to walk the PCI capability lists.
o Removed pci_dev->master flag.
o pci_scan_bus: If the bus already exists, don't attempt to scan it
again (yes, there really exist machines with a single bus behind
two different bridges [a host bridge and a fake PCI-to-PCI bridge], argh).
o /proc/pci works again.
o Modified the /proc/pci output format. I've left out several non-interesting
status bits like devsel timing, but I tried to keep as close to the
original format as possible not to break programs parsing this file (ugh!).
o Removed PCI_REGION_* macros.
o Added fixup for broken S3 cards reporting 32M region sizes instead of 64M.
o Changed allocation of PCI resources -- we really need to know about
address ranges assigned to individual PCI buses to be sure which addresses
are free and which are routed to which bus. Each bus now has four pointers
to resources from which are all resources of devices on this bus allocated
(see pci_find_parent_resource() for a matching algorithm). As usually,
everything can be overriden in arch-specific code.
o Removed the i448BX fixup as it was superseded by the bus resource
management changes.
o resource.c: ioport_resource should have IORESOURCE_IO flag set,
iomem_resource likewise.

diff -uN linux-2.3.16-pre1/Documentation/Changes rsrc/Documentation/Changes
--- linux-2.3.16-pre1/Documentation/Changes Tue Aug 31 15:31:40 1999
+++ rsrc/Documentation/Changes Tue Aug 31 11:39:50 1999
@@ -419,9 +419,16 @@
=========

Linux PCI utils are available; these include lspci, which displays
-the detailed information about your system's PCI devices which used to
-be in /proc/pci, and setpci, which allws you to read and write
-configuration registers on your PCI devices.
+detailed information about your system's PCI devices (much more than
+the basic things in /proc/pci), and setpci, which allows you to read
+and write PCI configuration registers of your devices.
+
+Powertweak
+==========
+
+ The PCI Bridge Optimization has been removed from the kernel. If you
+think your BIOS does a poor job when setting up your chipset, there
+is a utility called PowerTweak whose job is to tune chipset parameters.

Xosview
=======
@@ -734,9 +741,16 @@
PCI utils
=========

-The 1.09 release:
-ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-1.09.tar.gz
-ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-1.09.tar.gz
+The 2.0 release:
+ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.0.tar.gz
+ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.0.tar.gz
+
+Powertweak
+==========
+
+The 0.1.2 release:
+http://linux.powertweak.com/files/powertweak-0.1.2.tgz
+ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/powertweak/powertweak-0.1.2.tgz

Tunelp
======
diff -uN linux-2.3.16-pre1/arch/i386/kernel/bios32.c rsrc/arch/i386/kernel/bios32.c
--- linux-2.3.16-pre1/arch/i386/kernel/bios32.c Mon Aug 30 11:28:23 1999
+++ rsrc/arch/i386/kernel/bios32.c Tue Aug 31 15:22:39 1999
@@ -760,6 +760,36 @@
#endif

/*
+ * Assign new address to PCI resource. We hope our resource information
+ * is complete. On the PC, we don't re-assign resources unless we are
+ * forced to do so.
+ *
+ * Expects start=0, end=size-1, flags=resource type.
+ */
+
+int __init pcibios_assign_resource(struct pci_dev *dev, int i)
+{
+ struct resource *r = &dev->resource[i];
+ struct resource *pr = pci_find_parent_resource(dev, r);
+ unsigned long size = r->end + 1;
+
+ if (!pr)
+ return -EINVAL;
+ if (r->flags & IORESOURCE_IO) {
+ if (size > 0x100)
+ return -EFBIG;
+ if (allocate_resource(pr, r, size, 0x1000, ~0, 1024))
+ return -EBUSY;
+ } else {
+ if (allocate_resource(pr, r, size, 0x10000000, ~0, size))
+ return -EBUSY;
+ }
+ if (i < 6)
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start);
+ return 0;
+}
+
+/*
* Several BIOS'es forget to assign addresses to I/O ranges. Try to fix it.
*/

@@ -792,12 +822,13 @@
} else {
u32 try;

- if (allocate_resource(&ioport_resource, r, size, 0x1000, ~0, 1024)) {
+ r->start = 0;
+ r->end = size - 1;
+ if (pcibios_assign_resource(dev, idx)) {
printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O space for device %s.\n", size, dev->name);
return;
}
- printk("PCI: Assigning I/O space %04lx-%04lx to device %s\n", r->start, r->end, dev->name);
- pci_write_config_dword(dev, reg, r->start | PCI_BASE_ADDRESS_SPACE_IO);
+ printk("PCI: Assigned I/O space %04lx-%04lx to device %s\n", r->start, r->end, dev->name);
pci_read_config_dword(dev, reg, &try);
if ((try & PCI_BASE_ADDRESS_IO_MASK) != r->start) {
r->start = 0;
@@ -819,12 +850,12 @@
struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
unsigned long rom_size = r->end - r->start + 1;

- if (allocate_resource(&iomem_resource, r, rom_size, 0xf0000000, ~0, rom_size) < 0) {
+ r->start = 0;
+ r->end = rom_size - 1;
+ if (pcibios_assign_resource(dev, PCI_ROM_RESOURCE))
printk(KERN_ERR "PCI: Unable to find free space for expansion ROM of device %s (0x%lx bytes)\n",
dev->name, rom_size);
- r->start = 0;
- r->end = rom_size - 1;
- } else {
+ else {
DBG("PCI: Assigned address %08lx to expansion ROM of %s (0x%lx bytes)\n", r->start, dev->name, rom_size);
pci_write_config_dword(dev, reg, r->start | PCI_ROM_ADDRESS_ENABLE);
r->flags |= PCI_ROM_ADDRESS_ENABLE;
@@ -947,7 +978,8 @@
if (found) {
printk("PCI: Discovered primary peer bus %02x\n", n);
b = pci_scan_bus(n, ops, NULL);
- n = b->subordinate;
+ if (b)
+ n = b->subordinate;
}
n++;
}
@@ -979,33 +1011,6 @@
pci_probe |= PCI_NO_PEER_FIXUP;
}

-static void __init pci_fixup_i440bx(struct pci_dev *d)
-{
-#if 0 /* Temporarily disabled FIXME */
- /*
- * i440BX/ZX -- Occupy the AGP bridge windows.
- */
- u16 a, b;
- u8 u, v;
- pci_read_config_byte(d, 0x1c, &u);
- pci_read_config_byte(d, 0x1d, &v);
- if (v >= u) {
- a = u<<8;
- b = ((v-u)<<8) + 0x100;
- occupy_region(a, a+b, b, 1, &d->dev);
- }
- for (u = 0; u < 2; u++) {
- pci_read_config_word(d, 0x20+(u*4), &a);
- pci_read_config_word(d, 0x22+(u*4), &b);
- if (b >= a) {
- u32 m = a<<16;
- u32 n = ((b-a)<<16) + 0x100000;
- occupy_mem_region(m, m+n, n, 1, &d->dev);
- }
- }
-#endif
-}
-
static void __init pci_fixup_umc_ide(struct pci_dev *d)
{
/*
@@ -1021,7 +1026,6 @@

struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx },
- { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, pci_fixup_i440bx },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide },
{ 0 }
};
@@ -1031,20 +1035,28 @@
* we try to fix up anything.
*/

-static void __init pcibios_claim_resources(void)
+static void __init pcibios_claim_resources(struct pci_bus *bus)
{
struct pci_dev *dev;
int idx;

- for (dev=pci_devices; dev; dev=dev->next)
- for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
- struct resource *r = &dev->resource[idx];
- if (!r->start)
- continue;
- if (request_resource((r->flags & PCI_BASE_ADDRESS_SPACE_IO) ? &ioport_resource : &iomem_resource, r) < 0)
- printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name);
- /* We probably should disable the region, shouldn't we? */
+ while (bus) {
+ for (dev=bus->devices; dev; dev=dev->sibling)
+ for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
+ struct resource *r = &dev->resource[idx];
+ struct resource *pr;
+ if (!r->start)
+ continue;
+ pr = pci_find_parent_resource(dev, r);
+ if (!pr || request_resource(pr, r) < 0) {
+ printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name);
+ /* We probably should disable the region, shouldn't we? */
+ }
}
+ if (bus->children)
+ pcibios_claim_resources(bus->children);
+ bus = bus->next;
+ }
}

/*
@@ -1190,7 +1202,7 @@

if (!(pci_probe & PCI_NO_PEER_FIXUP))
pcibios_fixup_peer_bridges();
- pcibios_claim_resources();
+ pcibios_claim_resources(pci_root);
pcibios_fixup_devices();

#ifdef CONFIG_PCI_BIOS
diff -uN linux-2.3.16-pre1/drivers/pci/names.c rsrc/drivers/pci/names.c
--- linux-2.3.16-pre1/drivers/pci/names.c Mon Aug 30 11:28:26 1999
+++ rsrc/drivers/pci/names.c Tue Aug 31 12:56:27 1999
@@ -55,7 +55,7 @@
{
const struct pci_vendor_info *vendor_p = pci_vendor_list;
int i = VENDORS;
- char *name = dev->name;
+ char *name = dev->full_name;

do {
if (vendor_p->vendor == dev->vendor)
@@ -79,12 +79,12 @@
}

/* Ok, found the vendor, but unknown device */
- sprintf(name, " PCI device %04x:%04x (%s)", dev->vendor, dev->device, vendor_p->name);
+ sprintf(name, "PCI device %04x:%04x (%s)", dev->vendor, dev->device, vendor_p->name);
return;

/* Full match */
match_device: {
- char *n = name + sprintf(name, " %s %s", vendor_p->name, device_p->name);
+ char *n = name + sprintf(name, "%s %s", vendor_p->name, device_p->name);
int nr = device_p->seen + 1;
device_p->seen = nr;
if (nr > 1)
diff -uN linux-2.3.16-pre1/drivers/pci/pci.c rsrc/drivers/pci/pci.c
--- linux-2.3.16-pre1/drivers/pci/pci.c Tue Aug 31 15:31:48 1999
+++ rsrc/drivers/pci/pci.c Tue Aug 31 15:26:54 1999
@@ -88,6 +88,65 @@
}


+int
+pci_find_capability(struct pci_dev *dev, int cap)
+{
+ u16 status;
+ u8 pos, id;
+ int ttl = 48;
+
+ pci_read_config_word(dev, PCI_STATUS, &status);
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+ pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos);
+ while (ttl-- && pos >= 0x40) {
+ pos &= ~3;
+ pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+ pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos);
+ }
+ return 0;
+}
+
+
+/*
+ * For given resource region of given device, return the resource
+ * region of parent bus the given region is contained in or where
+ * it should be allocated from.
+ */
+struct resource *
+pci_find_parent_resource(struct pci_dev *dev, struct resource *res)
+{
+ struct pci_bus *bus = dev->bus;
+ int i;
+ struct resource *best = NULL;
+
+ while (bus) {
+ for(i=0; i<4; i++) {
+ struct resource *r = bus->resource[i];
+ if (!r)
+ continue;
+ if (res->start && !(res->start >= r->start && res->end <= r->end))
+ continue; /* Not contained */
+ if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
+ continue; /* Wrong type */
+ if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
+ return r; /* Exact match */
+ if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))
+ best = r; /* Approximating prefetchable by non-prefetchable */
+ }
+ if (best)
+ return best;
+ bus = bus->parent;
+ }
+ printk(KERN_ERR "PCI: Bug: Parent resource not found!\n");
+ return NULL;
+}
+
+
/*
* This interrupt-safe spinlock protects all accesses to PCI
* configuration space.
@@ -174,7 +233,7 @@
for(pos=0; pos<howmany; pos = next) {
next = pos+1;
res = &dev->resource[pos];
- res->name = dev->name;
+ res->name = dev->full_name;
reg = PCI_BASE_ADDRESS_0 + (pos << 2);
pci_read_config_dword(dev, reg, &l);
pci_write_config_dword(dev, reg, ~0);
@@ -207,7 +266,7 @@
res->end = res->start + (((unsigned long) ~l) << 32);
#else
if (l) {
- printk("PCI: Unable to handle 64-bit address for device %s\n", dev->name);
+ printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->name);
res->start = 0;
res->flags = 0;
continue;
@@ -229,15 +288,77 @@
res->start = l & PCI_ROM_ADDRESS_MASK;
res->end = res->start + (~(sz & PCI_ROM_ADDRESS_MASK));
}
- res->name = dev->name;
+ res->name = dev->full_name;
}
pci_write_config_word(dev, PCI_COMMAND, cmd);
}

+static void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
+{
+ u8 io_base_lo, io_limit_lo;
+ u16 mem_base_lo, mem_limit_lo, io_base_hi, io_limit_hi;
+ u32 mem_base_hi, mem_limit_hi;
+ unsigned long base, limit;
+ struct resource *res;
+ int i;
+
+ for(i=0; i<3; i++)
+ child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
+ res = child->resource[0];
+ pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
+ pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
+ pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
+ pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
+ base = ((io_base_lo & PCI_IO_RANGE_MASK) << 8) | (io_base_hi << 16);
+ limit = ((io_limit_lo & PCI_IO_RANGE_MASK) << 8) | (io_limit_hi << 16);
+ if (base && base <= limit) {
+ res->flags |= (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+ res->start = base;
+ res->end = limit + 0xfff;
+ res->name = child->name;
+ }
+
+ res = child->resource[1];
+ pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
+ pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
+ base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
+ limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
+ if (base && base <= limit) {
+ res->flags |= (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
+ res->start = base;
+ res->end = limit + 0xfffff;
+ res->name = child->name;
+ }
+
+ res = child->resource[2];
+ pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
+ pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
+ pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
+ pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
+ base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
+ limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
+#if BITS_PER_LONG == 64
+ base |= ((long) mem_base_hi) << 32;
+ limit |= ((long) mem_limit_hi) << 32;
+#else
+ if (mem_base_hi || mem_limit_hi) {
+ printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name);
+ return;
+ }
+#endif
+ if (base && base <= limit) {
+ res->flags |= (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
+ res->start = base;
+ res->end = limit + 0xfffff;
+ res->name = child->name;
+ }
+}
+
static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
{
unsigned int devfn, l, max, class;
- unsigned char cmd, irq, tmp, hdr_type, is_multi = 0;
+ unsigned char irq, hdr_type, is_multi = 0;
struct pci_dev *dev, **bus_last;
struct pci_bus *child;
struct pci_dev *dev_cache = NULL;
@@ -273,15 +394,9 @@
dev_cache = NULL;
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
+ sprintf(dev->name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
pci_name_device(dev);

- /* non-destructively determine if device can be a master: */
- pci_read_config_byte(dev, PCI_COMMAND, &cmd);
- pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
- pci_read_config_byte(dev, PCI_COMMAND, &tmp);
- dev->master = ((tmp & PCI_COMMAND_MASTER) != 0);
- pci_write_config_byte(dev, PCI_COMMAND, cmd);
-
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
class >>= 8; /* upper 3 bytes */
dev->class = class;
@@ -390,11 +505,13 @@

/*
* Set up the primary, secondary and subordinate
- * bus numbers.
+ * bus numbers. Read resource ranges behind the bridge.
*/
child->number = child->secondary = ++max;
child->primary = bus->secondary;
child->subordinate = 0xff;
+ sprintf(child->name, "PCI Bus #%02x", child->number);
+ pci_read_bridge_bases(dev, child);
/*
* Clear all status bits and turn off memory,
* I/O and master enables.
@@ -458,10 +575,28 @@
return max;
}

+static int __init pci_bus_exists(struct pci_bus *b, int nr)
+{
+ while (b) {
+ if (b->number == nr)
+ return 1;
+ if (b->children && pci_bus_exists(b->children, nr))
+ return 1;
+ b = b->next;
+ }
+ return 0;
+}
+
struct pci_bus * __init pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
{
struct pci_bus *b;

+ if (pci_bus_exists(pci_root, bus)) {
+ /* If we already got to this bus through a different bridge, ignore it */
+ DBG("PCI: Bus %02x already known\n", bus);
+ return NULL;
+ }
+
b = kmalloc(sizeof(*b), GFP_KERNEL);
memset(b, 0, sizeof(*b));
if (pci_root) {
@@ -472,6 +607,8 @@
b->number = b->secondary = bus;
b->sysdata = sysdata;
b->ops = ops;
+ b->resource[0] = &ioport_resource;
+ b->resource[1] = &iomem_resource;
b->subordinate = pci_do_scan_bus(b);
return b;
}
diff -uN linux-2.3.16-pre1/drivers/pci/proc.c rsrc/drivers/pci/proc.c
--- linux-2.3.16-pre1/drivers/pci/proc.c Mon Aug 30 11:28:26 1999
+++ rsrc/drivers/pci/proc.c Tue Aug 31 11:16:58 1999
@@ -418,78 +418,33 @@
*/
static int sprint_dev_config(struct pci_dev *dev, char *buf, int size)
{
- unsigned int class_rev, bus, devfn;
- unsigned short vendor, device, status;
- unsigned char bist, latency, min_gnt, max_lat;
+ unsigned int class_rev;
+ unsigned char latency, min_gnt, max_lat;
int reg, len = 0;
- const char *str;

- bus = dev->bus->number;
- devfn = dev->devfn;
-
- pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev);
- pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device);
- pcibios_read_config_word (bus, devfn, PCI_STATUS, &status);
- pcibios_read_config_byte (bus, devfn, PCI_BIST, &bist);
- pcibios_read_config_byte (bus, devfn, PCI_LATENCY_TIMER, &latency);
- pcibios_read_config_byte (bus, devfn, PCI_MIN_GNT, &min_gnt);
- pcibios_read_config_byte (bus, devfn, PCI_MAX_LAT, &max_lat);
- if (len + 80 > size) {
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+ pci_read_config_byte (dev, PCI_MIN_GNT, &min_gnt);
+ pci_read_config_byte (dev, PCI_MAX_LAT, &max_lat);
+ if (len + 160 > size)
return -1;
- }
len += sprintf(buf + len, " Bus %2d, device %3d, function %2d:\n",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-
- if (len + 80 > size) {
- return -1;
- }
- len += sprintf(buf + len, " %s: %s (rev %d).\n ",
+ dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ len += sprintf(buf + len, " %s: %s (rev %d).\n",
pci_strclass(class_rev >> 8),
dev->name,
class_rev & 0xff);

- switch (status & PCI_STATUS_DEVSEL_MASK) {
- case PCI_STATUS_DEVSEL_FAST: str = "Fast devsel. "; break;
- case PCI_STATUS_DEVSEL_MEDIUM: str = "Medium devsel. "; break;
- case PCI_STATUS_DEVSEL_SLOW: str = "Slow devsel. "; break;
- default: str = "Unknown devsel. ";
- }
- if (len + strlen(str) > size) {
- return -1;
- }
- len += sprintf(buf + len, str);
-
- if (status & PCI_STATUS_FAST_BACK) {
-# define fast_b2b_capable "Fast back-to-back capable. "
- if (len + strlen(fast_b2b_capable) > size) {
- return -1;
- }
- len += sprintf(buf + len, fast_b2b_capable);
-# undef fast_b2b_capable
- }
-
- if (bist & PCI_BIST_CAPABLE) {
-# define BIST_capable "BIST capable. "
- if (len + strlen(BIST_capable) > size) {
- return -1;
- }
- len += sprintf(buf + len, BIST_capable);
-# undef BIST_capable
- }
-
if (dev->irq) {
- if (len + 40 > size) {
+ if (len + 40 > size)
return -1;
- }
- len += sprintf(buf + len, "IRQ %d. ", dev->irq);
+ len += sprintf(buf + len, " IRQ %d.\n", dev->irq);
}

- if (dev->master) {
- if (len + 80 > size) {
+ if (latency || min_gnt || max_lat) {
+ if (len + 80 > size)
return -1;
- }
- len += sprintf(buf + len, "Master Capable. ");
+ len += sprintf(buf + len, " Master Capable. ");
if (latency)
len += sprintf(buf + len, "Latency=%d. ", latency);
else
@@ -498,15 +453,15 @@
len += sprintf(buf + len, "Min Gnt=%d.", min_gnt);
if (max_lat)
len += sprintf(buf + len, "Max Lat=%d.", max_lat);
+ len += sprintf(buf + len, "\n");
}

for (reg = 0; reg < 6; reg++) {
struct resource *res = dev->resource + reg;
unsigned long base, end, flags;

- if (len + 40 > size) {
+ if (len + 40 > size)
return -1;
- }
base = res->start;
end = res->end;
flags = res->flags;
@@ -515,16 +470,15 @@

if (flags & PCI_BASE_ADDRESS_SPACE_IO) {
len += sprintf(buf + len,
- "\n I/O at 0x%lx [0x%lx].",
+ " I/O at 0x%lx [0x%lx].\n",
base, end);
} else {
const char *pref, *type = "unknown";

- if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+ if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
pref = "P";
- } else {
+ else
pref = "Non-p";
- }
switch (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
case PCI_BASE_ADDRESS_MEM_TYPE_32:
type = "32 bit"; break;
@@ -534,14 +488,13 @@
type = "64 bit"; break;
}
len += sprintf(buf + len,
- "\n %srefetchable %s memory at "
- "0x%lx [0x%lx].", pref, type,
+ " %srefetchable %s memory at "
+ "0x%lx [0x%lx].\n", pref, type,
base,
end);
}
}

- len += sprintf(buf + len, "\n");
return len;
}

diff -uN linux-2.3.16-pre1/drivers/pci/quirks.c rsrc/drivers/pci/quirks.c
--- linux-2.3.16-pre1/drivers/pci/quirks.c Mon Aug 30 11:28:26 1999
+++ rsrc/drivers/pci/quirks.c Tue Aug 31 15:01:44 1999
@@ -58,6 +58,27 @@


/*
+ * S3 868 and 968 chips report region size equal to 32M, but they decode 64M.
+ * If it's needed, re-allocate the region.
+ */
+
+static void __init quirk_s3_64M(struct pci_dev *dev)
+{
+ struct resource *r = &dev->resource[0];
+
+ if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) {
+ printk("PCI: Re-allocating buggy S3 card at %s: ", dev->name);
+ r->start = 0;
+ r->end = 0x3ffffff;
+ if (pcibios_assign_resource(dev, 0))
+ printk("FAILED\n");
+ else
+ printk("moved to %08lx\n", r->start);
+ }
+}
+
+
+/*
* The main table of quirks.
*/

@@ -69,6 +90,8 @@
* quantity.
*/
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs },
+ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M },
+ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M },
{ 0 }
};

diff -uN linux-2.3.16-pre1/fs/proc/array.c rsrc/fs/proc/array.c
--- linux-2.3.16-pre1/fs/proc/array.c Tue Aug 31 15:31:54 1999
+++ rsrc/fs/proc/array.c Tue Aug 31 12:54:09 1999
@@ -1350,7 +1350,7 @@
case PROC_MEMINFO:
return get_meminfo(page);

-#ifdef CONFIG_PCI_OLD_PROC
+#ifdef CONFIG_PCI
case PROC_PCI:
return get_pci_list(page);
#endif
diff -uN linux-2.3.16-pre1/include/linux/pci.h rsrc/include/linux/pci.h
--- linux-2.3.16-pre1/include/linux/pci.h Tue Aug 31 15:31:55 1999
+++ rsrc/include/linux/pci.h Tue Aug 31 14:46:48 1999
@@ -1334,7 +1334,6 @@
unsigned short subsystem_device;
unsigned int class; /* 3 bytes: (base,sub,prog-if) */
unsigned int hdr_type; /* PCI header type */
- unsigned int master : 1; /* set if device is master capable */

unsigned short regs;

@@ -1351,19 +1350,26 @@
struct resource dma_resource[DEVICE_COUNT_DMA];
struct resource irq_resource[DEVICE_COUNT_IRQ];

- char name[48]; /* Device name */
+ char name[8]; /* short name (bus:slot.func) */
+ char full_name[48]; /* verbose name (vendor & device) */

int (*prepare)(struct pci_dev *dev);
int (*activate)(struct pci_dev *dev);
int (*deactivate)(struct pci_dev *dev);
};

+/*
+ * For PCI devices, the region numbers are assigned this way:
+ *
+ * 0-5 standard PCI regions
+ * 6 expansion ROM
+ * 7-10 bridges: address space assigned to buses behind the bridge
+ */
+
#define PCI_ROM_RESOURCE 6
-#define PCI_NUM_RESOURCES 7
+#define PCI_BRIDGE_RESOURCES 7
+#define PCI_NUM_RESOURCES 11

-#define PCI_REGION_EXISTS(dev, r) (dev)->resource[r].start
-#define PCI_REGION_IS_IO(dev, r) (PCI_REGION_EXISTS(dev,r) && ((dev)->resource[r].flags & PCI_BASE_ADDRESS_SPACE_IO))
-#define PCI_REGION_IS_MEM(dev, r) (PCI_REGION_EXISTS(dev,r) && !((dev)->resource[r].flags & PCI_BASE_ADDRESS_SPACE_IO))
#define PCI_REGION_FLAG_MASK 0x0f /* These bits of resource flags tell us the PCI region flags */

struct pci_bus {
@@ -1374,6 +1380,7 @@

struct pci_dev *self; /* bridge device as seen by parent */
struct pci_dev *devices; /* devices behind this bridge */
+ struct resource *resource[4]; /* address space routed to this bus */

void *sysdata; /* hook for sys-specific extension */
struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */
@@ -1421,6 +1428,7 @@
void pcibios_init(void);
void pcibios_fixup_bus(struct pci_bus *);
char *pcibios_setup (char *str);
+int pcibios_assign_resource(struct pci_dev *, int i);


/* Backward compatibility, don't use in new code! */
@@ -1452,6 +1460,7 @@
int pci_proc_attach_device(struct pci_dev *dev);
int pci_proc_detach_device(struct pci_dev *dev);
void pci_name_device(struct pci_dev *dev);
+struct resource *pci_find_parent_resource(struct pci_dev *dev, struct resource *res);

struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
struct pci_dev *pci_find_subsys (unsigned int vendor, unsigned int device,
@@ -1459,6 +1468,7 @@
struct pci_dev *from);
struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from);
struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
+int pci_find_capability (struct pci_dev *dev, int cap);

#define PCI_ANY_ID (~0)

diff -uN linux-2.3.16-pre1/kernel/resource.c rsrc/kernel/resource.c
--- linux-2.3.16-pre1/kernel/resource.c Mon Aug 30 11:28:39 1999
+++ rsrc/kernel/resource.c Tue Aug 31 15:23:11 1999
@@ -15,8 +15,8 @@

#include <asm/spinlock.h>

-struct resource ioport_resource = { "PCI IO", 0x0000, 0xFFFF };
-struct resource iomem_resource = { "PCI mem", 0x00000000, 0xFFFFFFFF };
+struct resource ioport_resource = { "PCI IO", 0x0000, 0xFFFF, IORESOURCE_IO };
+struct resource iomem_resource = { "PCI mem", 0x00000000, 0xFFFFFFFF, IORESOURCE_MEM };

static rwlock_t resource_lock = RW_LOCK_UNLOCKED;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/