sh: pci: New-style controller registration.
This moves off of the board_pci_channels[] approach for bus registration and over to a cleaner register_pci_controller(), all derived from the MIPS code. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
parent
99f95f1178
commit
e79066a659
3 changed files with 132 additions and 85 deletions
|
@ -13,40 +13,90 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/dma-debug.h>
|
#include <linux/dma-debug.h>
|
||||||
#include <linux/io.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;
|
struct pci_bus *bus;
|
||||||
int busno;
|
|
||||||
|
|
||||||
/* init channels */
|
/* Catch botched conversion attempts */
|
||||||
busno = 0;
|
BUG_ON(hose->init);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* scan the buses */
|
bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
|
||||||
busno = 0;
|
if (bus) {
|
||||||
for (p = board_pci_channels; p->init; p++) {
|
next_busno = bus->subordinate + 1;
|
||||||
if (p->enabled) {
|
/* Don't allow 8-bit bus number overflow inside the hose -
|
||||||
bus = pci_scan_bus(busno, p->pci_ops, p);
|
reserve some space for bridges. */
|
||||||
busno = bus->subordinate + 1;
|
if (next_busno > 224)
|
||||||
|
next_busno = 0;
|
||||||
|
|
||||||
pci_bus_size_bridges(bus);
|
pci_bus_size_bridges(bus);
|
||||||
pci_bus_assign_resources(bus);
|
pci_bus_assign_resources(bus);
|
||||||
pci_enable_bridges(bus);
|
pci_enable_bridges(bus);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(pci_scan_mutex);
|
||||||
|
|
||||||
|
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);
|
pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
|
||||||
|
|
||||||
dma_debug_add_bus(&pci_bus_type);
|
dma_debug_add_bus(&pci_bus_type);
|
||||||
|
|
||||||
|
pci_initialized = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
subsys_initcall(pcibios_init);
|
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
|
* Called after each bus is probed, but before its children
|
||||||
* are examined.
|
* 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);
|
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(board_pci_channels);
|
|
||||||
|
|
|
@ -15,11 +15,47 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include "pci-sh4.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;
|
unsigned int id;
|
||||||
const char *type = NULL;
|
const char *type = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
u32 word;
|
||||||
|
|
||||||
printk(KERN_NOTICE "PCI: Starting intialization.\n");
|
printk(KERN_NOTICE "PCI: Starting intialization.\n");
|
||||||
|
|
||||||
|
@ -54,52 +90,6 @@ static int __init sh7780_pci_init(struct pci_channel *chan)
|
||||||
if ((ret = sh4_pci_check_direct(chan)) != 0)
|
if ((ret = sh4_pci_check_direct(chan)) != 0)
|
||||||
return ret;
|
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.
|
* Set the class and sub-class codes.
|
||||||
*/
|
*/
|
||||||
|
@ -153,5 +143,8 @@ int __init pcibios_init_platform(void)
|
||||||
|
|
||||||
__set_io_port_base(SH7780_PCI_IO_BASE);
|
__set_io_port_base(SH7780_PCI_IO_BASE);
|
||||||
|
|
||||||
|
register_pci_controller(chan);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
arch_initcall(sh7780_pci_init);
|
||||||
|
|
|
@ -17,13 +17,18 @@
|
||||||
* external) PCI controllers.
|
* external) PCI controllers.
|
||||||
*/
|
*/
|
||||||
struct pci_channel {
|
struct pci_channel {
|
||||||
|
struct pci_channel *next;
|
||||||
|
|
||||||
int (*init)(struct pci_channel *chan);
|
int (*init)(struct pci_channel *chan);
|
||||||
|
|
||||||
struct pci_ops *pci_ops;
|
struct pci_ops *pci_ops;
|
||||||
struct resource *io_resource;
|
struct resource *io_resource;
|
||||||
struct resource *mem_resource;
|
struct resource *mem_resource;
|
||||||
|
|
||||||
int first_devfn;
|
int first_devfn;
|
||||||
int last_devfn;
|
int last_devfn;
|
||||||
int enabled;
|
int enabled;
|
||||||
|
|
||||||
unsigned long reg_base;
|
unsigned long reg_base;
|
||||||
unsigned long io_base;
|
unsigned long io_base;
|
||||||
|
|
||||||
|
@ -35,6 +40,8 @@ struct pci_channel {
|
||||||
*/
|
*/
|
||||||
extern struct pci_channel board_pci_channels[];
|
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;
|
extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM;
|
||||||
|
|
||||||
struct pci_dev;
|
struct pci_dev;
|
||||||
|
|
Reference in a new issue