diff options
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/drivers/pci/pci-new.c | 97 | ||||
-rw-r--r-- | arch/sh/drivers/pci/pci-sh7780.c | 87 | ||||
-rw-r--r-- | arch/sh/include/asm/pci.h | 29 |
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; |