[patch] PCI fixes for multiple PCI buses and Alpha

Andrea Arcangeli (andrea@suse.de)
Fri, 22 Oct 1999 22:11:50 +0200 (CEST)


Now the cupole of pci bugs that was harming me seems fixed. As last thing
I had to add an hook in the find_resource() to respect the necessary magic
alignments without duplicating lots of code.

Here it is the fixes against 2.3.22 (note I don't know if it will work
with the pre patches, make sure to try them out against 2.3.22 clean). I'd
like to get some feedback from Alpha users.

BTW, if you want a bit more solid kernel probably you want to apply the
patch over 2.3.22aa2:

ftp://ftp.*.kernel.org/pub/linux/kernel/people/andrea/kernels/v2.3/2.3.22aa2/

Have a look at:

ftp://ftp.*.kernel.org/pub/linux/kernel/people/andrea/tools/apply-patches/README

to learn how to go in sync with 2.3.22aa2.

2.3.22aa2 + the pci fixes below is been perfectly stable so far. have fun!

diff -urN 2.3.22/arch/alpha/kernel/core_mcpcia.c 2.3.22-alphapci/arch/alpha/kernel/core_mcpcia.c
--- 2.3.22/arch/alpha/kernel/core_mcpcia.c Tue Oct 12 02:40:34 1999
+++ 2.3.22-alphapci/arch/alpha/kernel/core_mcpcia.c Thu Oct 21 03:55:30 1999
@@ -205,7 +205,7 @@
static int
mcpcia_read_config_byte(struct pci_dev *dev, int where, u8 *value)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr, w;
unsigned char type1;

@@ -221,7 +221,7 @@
static int
mcpcia_read_config_word(struct pci_dev *dev, int where, u16 *value)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr, w;
unsigned char type1;

@@ -237,7 +237,7 @@
static int
mcpcia_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr;
unsigned char type1;

@@ -252,7 +252,7 @@
static int
mcpcia_write_config(struct pci_dev *dev, int where, u32 value, long mask)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr;
unsigned char type1;

diff -urN 2.3.22/arch/alpha/kernel/core_tsunami.c 2.3.22-alphapci/arch/alpha/kernel/core_tsunami.c
--- 2.3.22/arch/alpha/kernel/core_tsunami.c Tue Oct 12 02:40:34 1999
+++ 2.3.22-alphapci/arch/alpha/kernel/core_tsunami.c Thu Oct 21 17:27:37 1999
@@ -84,7 +84,7 @@
mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr,
unsigned char *type1)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr;
u8 bus = dev->bus->number;
u8 device_fn = dev->devfn;
@@ -154,6 +154,7 @@
return PCIBIOS_DEVICE_NOT_FOUND;

__kernel_stb(value, *(vucp)addr);
+ mb();
return PCIBIOS_SUCCESSFUL;
}

@@ -167,6 +168,7 @@
return PCIBIOS_DEVICE_NOT_FOUND;

__kernel_stw(value, *(vusp)addr);
+ mb();
return PCIBIOS_SUCCESSFUL;
}

@@ -180,6 +182,7 @@
return PCIBIOS_DEVICE_NOT_FOUND;

*(vuip)addr = value;
+ mb();
return PCIBIOS_SUCCESSFUL;
}

@@ -259,15 +262,22 @@
hose->index = index;

hose->io_space->start = TSUNAMI_IO(index) - TSUNAMI_IO_BIAS;
- hose->io_space->end = hose->io_space->start + 0xffff;
+ hose->io_space->end = hose->io_space->start + TSUNAMI_IO_SPACE;
hose->io_space->name = pci_io_names[index];
+ hose->io_space->flags = IORESOURCE_IO;

hose->mem_space->start = TSUNAMI_MEM(index) - TSUNAMI_MEM_BIAS;
+ /* the IOMEM address space is larger than 32bit but most pci
+ cars doesn't support 64bit address space so we stick with
+ 32bit here (see the TSUNAMI_MEM_SPACE define). */
hose->mem_space->end = hose->mem_space->start + 0xffffffff;
hose->mem_space->name = pci_mem_names[index];
+ hose->mem_space->flags = IORESOURCE_MEM;

- request_resource(&ioport_resource, hose->io_space);
- request_resource(&iomem_resource, hose->mem_space);
+ if (request_resource(&ioport_resource, hose->io_space) < 0)
+ printk(KERN_ERR "failed to request IO on hose %d", index);
+ if (request_resource(&iomem_resource, hose->mem_space) < 0)
+ printk(KERN_ERR "failed to request IOMEM on hose %d", index);

/*
* Set up the PCI->physical memory translation windows.
diff -urN 2.3.22/arch/alpha/kernel/pci.c 2.3.22-alphapci/arch/alpha/kernel/pci.c
--- 2.3.22/arch/alpha/kernel/pci.c Tue Oct 12 02:40:34 1999
+++ 2.3.22-alphapci/arch/alpha/kernel/pci.c Fri Oct 22 21:31:50 1999
@@ -10,6 +10,7 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
+#include <linux/kernel.h>
#include <asm/machvec.h>

#include "proto.h"
@@ -36,7 +37,6 @@
*/

struct pci_controler *hose_head, **hose_tail = &hose_head;
-struct pci_controler *probing_hose;

/*
* Quirks.
@@ -62,24 +62,93 @@
{ 0 }
};

+#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2))
+#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
+#define KB 1024
+#define MB (1024*KB)
+#define GB (1024*MB)
+unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
+ unsigned long start, unsigned long size)
+{
+ unsigned long alignto;
+
+ if (res->flags & IORESOURCE_IO)
+ {
+ /*
+ * Aligning to 0x800 rather than the minimum base of
+ * 0x400 is an attempt to avoid having devices in
+ * any 0x?C?? range, which is where the de4x5 driver
+ * probes for EISA cards.
+ *
+ * Adaptecs, especially, resent such intrusions.
+ */
+ alignto = MAX(0x800, size);
+ start = ALIGN(start, alignto);
+ }
+ else if (res->flags & IORESOURCE_MEM)
+ {
+ /*
+ * The following holds at least for the Low Cost
+ * Alpha implementation of the PCI interface:
+ *
+ * In sparse memory address space, the first
+ * octant (16MB) of every 128MB segment is
+ * aliased to the very first 16 MB of the
+ * address space (i.e., it aliases the ISA
+ * memory address space). Thus, we try to
+ * avoid allocating PCI devices in that range.
+ * Can be allocated in 2nd-7th octant only.
+ * Devices that need more than 112MB of
+ * address space must be accessed through
+ * dense memory space only!
+ */
+ /* align to multiple of size of minimum base */
+ alignto = MAX(0x1000, size);
+ start = ALIGN(start, alignto);
+ if (size > 7 * 16*MB)
+ printk(KERN_WARNING "PCI: dev %s "
+ "requests 0x%ld bytes of contiguous"
+ " address space---don't use sparse"
+ " memory accesses on this device!!\n",
+ dev->name, size);
+ else
+ {
+ if (((start / (16*MB)) & 0x7) == 0) {
+ start &= ~(128*MB - 1);
+ start += 16*MB;
+ start = ALIGN(start, alignto);
+ }
+ if (start/(128*MB) != (start + size)/(128*MB)) {
+ start &= ~(128*MB - 1);
+ start += (128 + 16)*MB;
+ start = ALIGN(start, alignto);
+ }
+ }
+ }
+
+ return start;
+}
+#undef MAX
+#undef ALIGN
+#undef KB
+#undef MB
+#undef GB

/*
* Pre-layout host-independant device initialization.
*/

static void __init
-pcibios_assign_special(void)
+pcibios_assign_special(struct pci_dev * dev)
{
- struct pci_dev *dev;
- int i;
-
/* The first three resources of an IDE controler are often magic,
so leave them unchanged. This is true, for instance, of the
Contaq 82C693 as seen on SX164 and DP264. */

- for (dev = pci_devices; dev; dev = dev->next) {
- if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE)
- continue;
+ if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE)
+ {
+ int i;
+
/* Resource 1 of IDE controller is the address of HD_CMD
register which actually occupies a single byte (0x3f6
for ide0) in reported 0x3f4-3f7 range. We have to fix
@@ -87,10 +156,9 @@
controller. */
dev->resource[1].start += 2;
dev->resource[1].end = dev->resource[1].start;
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- if (dev->resource[i].flags)
+ for (i = 0; i < PCI_NUM_RESOURCES; i++)
+ if (dev->resource[i].flags && dev->resource[i].start)
pci_claim_resource(dev, i);
- }
}
}

@@ -110,31 +178,63 @@
}

void __init
+pcibios_fixup_resource(struct resource *res, struct resource *root)
+{
+ res->start += root->start;
+ res->end += root->start;
+}
+
+void __init
+pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
+{
+ /* Update device resources. */
+
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (!dev->resource[i].start)
+ continue;
+ if (dev->resource[i].flags & IORESOURCE_IO)
+ pcibios_fixup_resource(&dev->resource[i],
+ bus->resource[0]);
+ else if (dev->resource[i].flags & IORESOURCE_MEM)
+ pcibios_fixup_resource(&dev->resource[i],
+ bus->resource[1]);
+ }
+ pcibios_assign_special(dev);
+}
+
+void __init
pcibios_fixup_bus(struct pci_bus *bus)
{
/* Propogate hose info into the subordinate devices. */

- struct pci_controler *hose = probing_hose;
+ struct pci_controler *hose = (struct pci_controler *) bus->sysdata;
struct pci_dev *dev;

bus->resource[0] = hose->io_space;
bus->resource[1] = hose->mem_space;
for (dev = bus->devices; dev; dev = dev->sibling)
- dev->sysdata = hose;
+ if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ pcibios_fixup_device_resources(dev, bus);
}

void __init
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
- unsigned long where, size;
- u32 reg;
+ int where;
+ u32 reg;

- where = PCI_BASE_ADDRESS_0 + (resource * 4);
- size = res->end - res->start;
- pci_read_config_dword(dev, where, &reg);
- reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
- pci_write_config_dword(dev, where, reg);
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ reg = (res->start - root->start) | (res->flags & 0xf);
+ pci_write_config_dword(dev, where, reg);
+ if ((res->flags & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+ == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64))
+ {
+ pci_write_config_dword(dev, where+4, 0);
+ printk(KERN_WARNING "PCI: dev %s type 64-bit\n", dev->name);
+ }

/* ??? FIXME -- record old value for shutdown. */
}
@@ -170,6 +270,15 @@
}

void __init
+pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
+{
+ ranges->io_start -= bus->resource[0]->start;
+ ranges->io_end -= bus->resource[0]->start;
+ ranges->mem_start -= bus->resource[1]->start;
+ ranges->mem_end -= bus->resource[1]->start;
+}
+
+void __init
common_init_pci(void)
{
struct pci_controler *hose;
@@ -180,15 +289,12 @@
for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
hose->first_busno = next_busno;
hose->last_busno = 0xff;
- probing_hose = hose;
bus = pci_scan_bus(next_busno, alpha_mv.pci_ops, hose);
hose->bus = bus;
next_busno = hose->last_busno = bus->subordinate;
next_busno += 1;
}
- probing_hose = NULL;

- pcibios_assign_special();
pci_assign_unassigned_resources(alpha_mv.min_io_address,
alpha_mv.min_mem_address);
pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
diff -urN 2.3.22/arch/alpha/kernel/pci_impl.h 2.3.22-alphapci/arch/alpha/kernel/pci_impl.h
--- 2.3.22/arch/alpha/kernel/pci_impl.h Tue Sep 14 14:35:30 1999
+++ 2.3.22-alphapci/arch/alpha/kernel/pci_impl.h Thu Oct 21 03:54:44 1999
@@ -125,7 +125,6 @@

/* The hose list. */
extern struct pci_controler *hose_head, **hose_tail;
-extern struct pci_controler *probing_hose;

extern void common_init_pci(void);
extern u8 common_swizzle(struct pci_dev *, u8 *);
diff -urN 2.3.22/arch/i386/kernel/pci-i386.c 2.3.22-alphapci/arch/i386/kernel/pci-i386.c
--- 2.3.22/arch/i386/kernel/pci-i386.c Tue Oct 12 02:40:34 1999
+++ 2.3.22-alphapci/arch/i386/kernel/pci-i386.c Fri Oct 22 21:47:14 1999
@@ -122,12 +122,12 @@
printk(KERN_ERR "PCI: I/O Region %s/%d too large (%ld bytes)\n", dev->slot_name, i, size);
return -EFBIG;
}
- if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) {
+ if (allocate_resource(pr, r, size, 0x1000, ~0, 1024, dev)) {
printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
return -EBUSY;
}
} else {
- if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) {
+ if (allocate_resource(pr, r, size, 0x10000000, ~0, size, dev)) {
printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
return -EBUSY;
}
@@ -309,4 +309,10 @@
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
pcibios_assign_resources();
+}
+
+unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
+ unsigned long start, unsigned long size)
+{
+ return start;
}
diff -urN 2.3.22/drivers/pci/pci.c 2.3.22-alphapci/drivers/pci/pci.c
--- 2.3.22/drivers/pci/pci.c Tue Oct 12 02:40:34 1999
+++ 2.3.22-alphapci/drivers/pci/pci.c Thu Oct 21 03:52:13 1999
@@ -379,6 +379,7 @@
dev = dev_cache;
memset(dev, 0, sizeof(*dev));
dev->bus = bus;
+ dev->sysdata = bus->sysdata;
dev->devfn = devfn;

if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
@@ -498,6 +499,7 @@
child->self = dev;
child->parent = bus;
child->ops = bus->ops;
+ child->sysdata = bus->sysdata;

/*
* Set up the primary, secondary and subordinate
diff -urN 2.3.22/drivers/pci/setup.c 2.3.22-alphapci/drivers/pci/setup.c
--- 2.3.22/drivers/pci/setup.c Tue Oct 12 02:40:34 1999
+++ 2.3.22-alphapci/drivers/pci/setup.c Fri Oct 22 21:50:59 1999
@@ -33,15 +33,8 @@
int err;

err = -EINVAL;
- if (root != NULL) {
- /* If `dev' is on a secondary pci bus, `root' may not be
- at the origin. In that case, adjust the resource into
- range. */
- res->start += root->start;
- res->end += root->start;
-
+ if (root != NULL)
err = request_resource(root, res);
- }
if (err) {
printk(KERN_ERR "PCI: Address space collision on region %d "
"of device %s\n", resource, dev->name);
@@ -89,7 +82,7 @@
DBGC((" for root[%lx:%lx] min[%lx] size[%lx]\n",
root->start, root->end, min, size));

- if (allocate_resource(root, res, size, min, -1, size) < 0) {
+ if (allocate_resource(root, res, size, min, -1, size, dev) < 0) {
printk(KERN_ERR
"PCI: Failed to allocate resource %d for %s\n",
i, dev->name);
@@ -148,13 +141,6 @@
pdev_assign_unassigned_resources(dev, min_io, min_mem);
}

-struct pbus_set_ranges_data
-{
- int found_vga;
- unsigned int io_start, io_end;
- unsigned int mem_start, mem_end;
-};
-
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define ROUND_DOWN(x, a) ((x) & ~((a) - 1))

@@ -166,7 +152,7 @@
struct pci_dev *dev;

inner.found_vga = 0;
- inner.mem_start = inner.io_start = ~0;
+ inner.mem_start = inner.io_start = ~0UL;
inner.mem_end = inner.io_end = 0;

/* Collect information about how our direct children are layed out. */
@@ -200,6 +186,8 @@

inner.mem_start = ROUND_DOWN(inner.mem_start, 1*1024*1024);
inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024);
+
+ pcibios_fixup_pbus_ranges(bus, &inner);

/* Configure the bridge, if possible. */
if (bus->self) {
diff -urN 2.3.22/drivers/video/tgafb.c 2.3.22-alphapci/drivers/video/tgafb.c
--- 2.3.22/drivers/video/tgafb.c Tue Sep 14 14:35:13 1999
+++ 2.3.22-alphapci/drivers/video/tgafb.c Tue Oct 19 19:00:13 1999
@@ -937,7 +937,7 @@
static void tgafb_set_disp(const void *fb_par, struct display *disp,
struct fb_info_gen *info)
{
- disp->screen_base = ioremap(fb_info.tga_fb_base);
+ disp->screen_base = ioremap(fb_info.tga_fb_base, 0);
switch (fb_info.tga_type) {
#ifdef FBCON_HAS_CFB8
case 0: /* 8-plane */
diff -urN 2.3.22/include/asm-alpha/core_tsunami.h 2.3.22-alphapci/include/asm-alpha/core_tsunami.h
--- 2.3.22/include/asm-alpha/core_tsunami.h Tue Oct 12 18:16:42 1999
+++ 2.3.22-alphapci/include/asm-alpha/core_tsunami.h Thu Oct 21 17:25:02 1999
@@ -291,6 +291,9 @@
#define TSUNAMI_IO_BIAS TSUNAMI_IO(0)
#define TSUNAMI_MEM_BIAS TSUNAMI_MEM(0)

+/* The IO address space is larger than 0xffff */
+#define TSUNAMI_IO_SPACE (TSUNAMI_CONF(0) - TSUNAMI_IO(0))
+#define TSUNAMI_MEM_SPACE (_TSUNAMI_IACK_SC(0) - TSUNAMI_MEM(0))

/*
* Data structure for handling TSUNAMI machine checks:
diff -urN 2.3.22/include/asm-alpha/pgtable.h 2.3.22-alphapci/include/asm-alpha/pgtable.h
--- 2.3.22/include/asm-alpha/pgtable.h Tue Oct 19 03:16:25 1999
+++ 2.3.22-alphapci/include/asm-alpha/pgtable.h Fri Oct 22 21:25:54 1999
@@ -622,6 +622,6 @@
#define kern_addr_valid(addr) (1)

#define io_remap_page_range(start, busaddr, size, prot) \
- remap_page_range(start, virt_to_phys(__ioremap(busaddr)), size, prot)
+ remap_page_range(start, virt_to_phys(__ioremap(busaddr), 0), size, prot)

#endif /* _ALPHA_PGTABLE_H */
diff -urN 2.3.22/include/linux/ioport.h 2.3.22-alphapci/include/linux/ioport.h
--- 2.3.22/include/linux/ioport.h Tue Sep 14 14:35:32 1999
+++ 2.3.22-alphapci/include/linux/ioport.h Fri Oct 22 21:25:50 1999
@@ -80,10 +80,11 @@

extern int request_resource(struct resource *root, struct resource *new);
extern int release_resource(struct resource *new);
+struct pci_dev;
extern int allocate_resource(struct resource *root, struct resource *new,
unsigned long size,
unsigned long min, unsigned long max,
- unsigned long align);
+ unsigned long align, struct pci_dev *);

/* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
@@ -106,5 +107,8 @@
#define HAVE_AUTOIRQ
extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime);
+
+extern unsigned long resource_fixup(struct pci_dev *, struct resource *,
+ unsigned long, unsigned long);

#endif /* _LINUX_IOPORT_H */
diff -urN 2.3.22/include/linux/pci.h 2.3.22-alphapci/include/linux/pci.h
--- 2.3.22/include/linux/pci.h Fri Oct 22 17:06:36 1999
+++ 2.3.22-alphapci/include/linux/pci.h Fri Oct 22 21:41:26 1999
@@ -404,8 +404,16 @@
int (*write_dword)(struct pci_dev *, int where, u32 val);
};

+struct pbus_set_ranges_data
+{
+ int found_vga;
+ unsigned long io_start, io_end;
+ unsigned long mem_start, mem_end;
+};
+
void pcibios_init(void);
void pcibios_fixup_bus(struct pci_bus *);
+void pcibios_fixup_pbus_ranges(struct pci_bus *, struct pbus_set_ranges_data *);
char *pcibios_setup (char *str);

void pcibios_update_resource(struct pci_dev *, struct resource *,
diff -urN 2.3.22/kernel/resource.c 2.3.22-alphapci/kernel/resource.c
--- 2.3.22/kernel/resource.c Tue Sep 14 14:35:58 1999
+++ 2.3.22-alphapci/kernel/resource.c Fri Oct 22 21:25:06 1999
@@ -126,7 +126,7 @@
static int find_resource(struct resource *root, struct resource *new,
unsigned long size,
unsigned long min, unsigned long max,
- unsigned long align)
+ unsigned long align, struct pci_dev * dev)
{
struct resource *this = root->child;
unsigned long start, end;
@@ -142,6 +142,7 @@
if (end > max)
end = max;
start = (start + align - 1) & ~(align - 1);
+ start = resource_fixup (dev, new, start, size);
if (start < end && end - start + 1 >= size) {
new->start = start;
new->end = start + size - 1;
@@ -161,12 +162,12 @@
int allocate_resource(struct resource *root, struct resource *new,
unsigned long size,
unsigned long min, unsigned long max,
- unsigned long align)
+ unsigned long align, struct pci_dev * dev)
{
int err;

write_lock(&resource_lock);
- err = find_resource(root, new, size, min, max, align);
+ err = find_resource(root, new, size, min, max, align, dev);
if (err >= 0 && __request_resource(root, new))
err = -EBUSY;
write_unlock(&resource_lock);

Andrea

-
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/