aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sh/drivers/pci/pci-new.c97
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.c87
-rw-r--r--arch/sh/include/asm/pci.h29
3 files changed, 130 insertions, 83 deletions
diff --git a/arch/sh/drivers/pci/pci-new.c b/arch/sh/drivers/pci/pci-new.c
index c92e65045c6..78b7292c6aa 100644
--- a/arch/sh/drivers/pci/pci-new.c
+++ b/arch/sh/drivers/pci/pci-new.c
@@ -13,40 +13,90 @@
#include <linux/init.h>
#include <linux/dma-debug.h>
#include <linux/io.h>
+#include <linux/mutex.h>
-static int __init pcibios_init(void)
+/*
+ * The PCI controller list.
+ */
+static struct pci_channel *hose_head, **hose_tail = &hose_head;
+
+static int pci_initialized;
+
+static void __devinit pcibios_scanbus(struct pci_channel *hose)
{
- struct pci_channel *p;
+ static int next_busno;
struct pci_bus *bus;
- int busno;
-
- /* init channels */
- busno = 0;
- for (p = board_pci_channels; p->init; p++) {
- if (p->init(p) == 0)
- p->enabled = 1;
- else
- pr_err("Unable to init pci channel %d\n", busno);
- busno++;
+
+ /* Catch botched conversion attempts */
+ BUG_ON(hose->init);
+
+ bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
+ if (bus) {
+ next_busno = bus->subordinate + 1;
+ /* Don't allow 8-bit bus number overflow inside the hose -
+ reserve some space for bridges. */
+ if (next_busno > 224)
+ next_busno = 0;
+
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
+ pci_enable_bridges(bus);
}
+}
- /* scan the buses */
- busno = 0;
- for (p = board_pci_channels; p->init; p++) {
- if (p->enabled) {
- bus = pci_scan_bus(busno, p->pci_ops, p);
- busno = bus->subordinate + 1;
+static DEFINE_MUTEX(pci_scan_mutex);
- pci_bus_size_bridges(bus);
- pci_bus_assign_resources(bus);
- pci_enable_bridges(bus);
- }
+void __devinit register_pci_controller(struct pci_channel *hose)
+{
+ if (request_resource(&iomem_resource, hose->mem_resource) < 0)
+ goto out;
+ if (request_resource(&ioport_resource, hose->io_resource) < 0) {
+ release_resource(hose->mem_resource);
+ goto out;
+ }
+
+ *hose_tail = hose;
+ hose_tail = &hose->next;
+
+ /*
+ * Do not panic here but later - this might hapen before console init.
+ */
+ if (!hose->io_map_base) {
+ printk(KERN_WARNING
+ "registering PCI controller with io_map_base unset\n");
+ }
+
+ /*
+ * Scan the bus if it is register after the PCI subsystem
+ * initialization.
+ */
+ if (pci_initialized) {
+ mutex_lock(&pci_scan_mutex);
+ pcibios_scanbus(hose);
+ mutex_unlock(&pci_scan_mutex);
}
+ return;
+
+out:
+ printk(KERN_WARNING
+ "Skipping PCI bus scan due to resource conflict\n");
+}
+
+static int __init pcibios_init(void)
+{
+ struct pci_channel *hose;
+
+ /* Scan all of the recorded PCI controllers. */
+ for (hose = hose_head; hose; hose = hose->next)
+ pcibios_scanbus(hose);
+
pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
dma_debug_add_bus(&pci_bus_type);
+ pci_initialized = 1;
+
return 0;
}
subsys_initcall(pcibios_init);
@@ -74,7 +124,6 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev,
}
}
-
/*
* Called after each bus is probed, but before its children
* are examined.
@@ -186,5 +235,3 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
{
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
-
-EXPORT_SYMBOL(board_pci_channels);
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index f02d9dfcf25..4dd6e3b94a6 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -15,11 +15,47 @@
#include <linux/delay.h>
#include "pci-sh4.h"
-static int __init sh7780_pci_init(struct pci_channel *chan)
+extern u8 pci_cache_line_size;
+
+static struct resource sh7785_io_resource = {
+ .name = "SH7785_IO",
+ .start = SH7780_PCI_IO_BASE,
+ .end = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource sh7785_mem_resource = {
+ .name = "SH7785_mem",
+ .start = SH7780_PCI_MEMORY_BASE,
+ .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+static struct pci_channel sh7780_pci_controller = {
+ .pci_ops = &sh4_pci_ops,
+ .mem_resource = &sh7785_mem_resource,
+ .io_resource = &sh7785_io_resource,
+};
+
+static struct sh4_pci_address_map sh7780_pci_map = {
+ .window0 = {
+#if defined(CONFIG_32BIT)
+ .base = SH7780_32BIT_DDR_BASE_ADDR,
+ .size = 0x40000000,
+#else
+ .base = SH7780_CS0_BASE_ADDR,
+ .size = 0x20000000,
+#endif
+ },
+};
+
+static int __init sh7780_pci_init(void)
{
+ struct pci_channel *chan = &sh7780_pci_controller;
unsigned int id;
const char *type = NULL;
int ret;
+ u32 word;
printk(KERN_NOTICE "PCI: Starting intialization.\n");
@@ -55,52 +91,6 @@ static int __init sh7780_pci_init(struct pci_channel *chan)
return ret;
/*
- * Platform specific initialization (BSC registers, and memory space
- * mapping) will be called via the platform defined function
- * pcibios_init_platform().
- */
- return pcibios_init_platform();
-}
-
-extern u8 pci_cache_line_size;
-
-static struct resource sh7785_io_resource = {
- .name = "SH7785_IO",
- .start = SH7780_PCI_IO_BASE,
- .end = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
- .flags = IORESOURCE_IO
-};
-
-static struct resource sh7785_mem_resource = {
- .name = "SH7785_mem",
- .start = SH7780_PCI_MEMORY_BASE,
- .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
- .flags = IORESOURCE_MEM
-};
-
-struct pci_channel board_pci_channels[] = {
- { sh7780_pci_init, &sh4_pci_ops, &sh7785_io_resource, &sh7785_mem_resource, 0, 0xff },
- { NULL, NULL, NULL, 0, 0 },
-};
-
-static struct sh4_pci_address_map sh7780_pci_map = {
- .window0 = {
-#if defined(CONFIG_32BIT)
- .base = SH7780_32BIT_DDR_BASE_ADDR,
- .size = 0x40000000,
-#else
- .base = SH7780_CS0_BASE_ADDR,
- .size = 0x20000000,
-#endif
- },
-};
-
-int __init pcibios_init_platform(void)
-{
- struct pci_channel *chan = &board_pci_channels[0];
- u32 word;
-
- /*
* Set the class and sub-class codes.
*/
__raw_writeb(PCI_CLASS_BRIDGE_HOST >> 8,
@@ -153,5 +143,8 @@ int __init pcibios_init_platform(void)
__set_io_port_base(SH7780_PCI_IO_BASE);
+ register_pci_controller(chan);
+
return 0;
}
+arch_initcall(sh7780_pci_init);
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 82a9369511b..e057ebdb461 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -17,17 +17,22 @@
* external) PCI controllers.
*/
struct pci_channel {
- int (*init)(struct pci_channel *chan);
- struct pci_ops *pci_ops;
- struct resource *io_resource;
- struct resource *mem_resource;
- int first_devfn;
- int last_devfn;
- int enabled;
- unsigned long reg_base;
- unsigned long io_base;
-
- unsigned long io_map_base;
+ struct pci_channel *next;
+
+ int (*init)(struct pci_channel *chan);
+
+ struct pci_ops *pci_ops;
+ struct resource *io_resource;
+ struct resource *mem_resource;
+
+ int first_devfn;
+ int last_devfn;
+ int enabled;
+
+ unsigned long reg_base;
+ unsigned long io_base;
+
+ unsigned long io_map_base;
};
/*
@@ -35,6 +40,8 @@ struct pci_channel {
*/
extern struct pci_channel board_pci_channels[];
+extern void register_pci_controller(struct pci_channel *hose);
+
extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM;
struct pci_dev;