summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/pci_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/pci_32.c')
-rw-r--r--arch/powerpc/kernel/pci_32.c246
1 files changed, 3 insertions, 243 deletions
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 717c554..ce7c20c 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -35,13 +35,9 @@ unsigned long isa_io_base = 0;
unsigned long pci_dram_offset = 0;
int pcibios_assign_bus_offset = 1;
-/* Default PCI flags is 0 */
-unsigned int ppc_pci_flags;
-
void pcibios_make_OF_bus_map(void);
static void fixup_broken_pcnet32(struct pci_dev* dev);
-static int reparent_resources(struct resource *parent, struct resource *res);
static void fixup_cpc710_pci64(struct pci_dev* dev);
#ifdef CONFIG_PPC_OF
static u8* pci_to_OF_bus_map;
@@ -97,170 +93,6 @@ fixup_cpc710_pci64(struct pci_dev* dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64);
-static int skip_isa_ioresource_align(struct pci_dev *dev)
-{
- if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) &&
- !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
- return 1;
- return 0;
-}
-
-/*
- * We need to avoid collisions with `mirrored' VGA ports
- * and other strange ISA hardware, so we always want the
- * addresses to be allocated in the 0x000-0x0ff region
- * modulo 0x400.
- *
- * Why? Because some silly external IO cards only decode
- * the low 10 bits of the IO address. The 0x00-0xff region
- * is reserved for motherboard devices that decode all 16
- * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
- * but we want to try to avoid allocating at 0x2900-0x2bff
- * which might have be mirrored at 0x0100-0x03ff..
- */
-void pcibios_align_resource(void *data, struct resource *res,
- resource_size_t size, resource_size_t align)
-{
- struct pci_dev *dev = data;
-
- if (res->flags & IORESOURCE_IO) {
- resource_size_t start = res->start;
-
- if (skip_isa_ioresource_align(dev))
- return;
- if (start & 0x300) {
- start = (start + 0x3ff) & ~0x3ff;
- res->start = start;
- }
- }
-}
-EXPORT_SYMBOL(pcibios_align_resource);
-
-/*
- * Handle resources of PCI devices. If the world were perfect, we could
- * just allocate all the resource regions and do nothing more. It isn't.
- * On the other hand, we cannot just re-allocate all devices, as it would
- * require us to know lots of host bridge internals. So we attempt to
- * keep as much of the original configuration as possible, but tweak it
- * when it's found to be wrong.
- *
- * Known BIOS problems we have to work around:
- * - I/O or memory regions not configured
- * - regions configured, but not enabled in the command register
- * - bogus I/O addresses above 64K used
- * - expansion ROMs left enabled (this may sound harmless, but given
- * the fact the PCI specs explicitly allow address decoders to be
- * shared between expansion ROMs and other resource regions, it's
- * at least dangerous)
- *
- * Our solution:
- * (1) Allocate resources for all buses behind PCI-to-PCI bridges.
- * This gives us fixed barriers on where we can allocate.
- * (2) Allocate resources for all enabled devices. If there is
- * a collision, just mark the resource as unallocated. Also
- * disable expansion ROMs during this step.
- * (3) Try to allocate resources for disabled devices. If the
- * resources were assigned correctly, everything goes well,
- * if they weren't, they won't disturb allocation of other
- * resources.
- * (4) Assign new addresses to resources which were either
- * not configured at all or misconfigured. If explicitly
- * requested by the user, configure expansion ROM address
- * as well.
- */
-
-static void __init
-pcibios_allocate_bus_resources(struct list_head *bus_list)
-{
- struct pci_bus *bus;
- int i;
- struct resource *res, *pr;
-
- /* Depth-First Search on bus tree */
- list_for_each_entry(bus, bus_list, node) {
- for (i = 0; i < 4; ++i) {
- if ((res = bus->resource[i]) == NULL || !res->flags
- || res->start > res->end)
- continue;
- if (bus->parent == NULL)
- pr = (res->flags & IORESOURCE_IO)?
- &ioport_resource : &iomem_resource;
- else {
- /* Don't bother with non-root busses when
- * re-assigning all resources.
- */
- if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)
- continue;
- pr = pci_find_parent_resource(bus->self, res);
- if (pr == res) {
- /* this happens when the generic PCI
- * code (wrongly) decides that this
- * bridge is transparent -- paulus
- */
- continue;
- }
- }
-
- DBG("PCI: dev %s (bus 0x%02x) bridge rsrc %d: %016llx..%016llx "
- "(f:0x%08lx), parent %p\n",
- bus->self ? pci_name(bus->self) : "PHB", bus->number, i,
- (u64)res->start, (u64)res->end, res->flags, pr);
-
- if (pr && !(pr->flags & IORESOURCE_UNSET)) {
- if (request_resource(pr, res) == 0)
- continue;
- /*
- * Must be a conflict with an existing entry.
- * Move that entry (or entries) under the
- * bridge resource and try again.
- */
- if (reparent_resources(pr, res) == 0)
- continue;
- }
- printk(KERN_WARNING
- "PCI: Cannot allocate resource region "
- "%d of PCI bridge %d, will remap\n",
- i, bus->number);
- res->flags |= IORESOURCE_UNSET;
- }
- pcibios_allocate_bus_resources(&bus->children);
- }
-}
-
-/*
- * Reparent resource children of pr that conflict with res
- * under res, and make res replace those children.
- */
-static int __init
-reparent_resources(struct resource *parent, struct resource *res)
-{
- struct resource *p, **pp;
- struct resource **firstpp = NULL;
-
- for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) {
- if (p->end < res->start)
- continue;
- if (res->end < p->start)
- break;
- if (p->start < res->start || p->end > res->end)
- return -1; /* not completely contained */
- if (firstpp == NULL)
- firstpp = pp;
- }
- if (firstpp == NULL)
- return -1; /* didn't find any conflicting entries? */
- res->parent = parent;
- res->child = *firstpp;
- res->sibling = *pp;
- *firstpp = res;
- *pp = NULL;
- for (p = res->child; p != NULL; p = p->sibling) {
- p->parent = res;
- DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
- p->name, (u64)p->start, (u64)p->end, res->name);
- }
- return 0;
-}
void __init
update_bridge_resource(struct pci_dev *dev, struct resource *res)
@@ -318,63 +150,6 @@ update_bridge_resource(struct pci_dev *dev, struct resource *res)
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
-static inline void alloc_resource(struct pci_dev *dev, int idx)
-{
- struct resource *pr, *r = &dev->resource[idx];
-
- DBG("PCI: Allocating %s: Resource %d: %016llx..%016llx (f=%lx)\n",
- pci_name(dev), idx, (u64)r->start, (u64)r->end, r->flags);
- pr = pci_find_parent_resource(dev, r);
- if (!pr || (pr->flags & IORESOURCE_UNSET) || request_resource(pr, r) < 0) {
- printk(KERN_WARNING "PCI: Cannot allocate resource region %d"
- " of device %s, will remap\n", idx, pci_name(dev));
- if (pr)
- DBG("PCI: parent is %p: %016llx-%016llx (f=%lx)\n",
- pr, (u64)pr->start, (u64)pr->end, pr->flags);
- /* We'll assign a new address later */
- r->flags |= IORESOURCE_UNSET;
- r->end -= r->start;
- r->start = 0;
- }
-}
-
-static void __init
-pcibios_allocate_resources(int pass)
-{
- struct pci_dev *dev = NULL;
- int idx, disabled;
- u16 command;
- struct resource *r;
-
- for_each_pci_dev(dev) {
- pci_read_config_word(dev, PCI_COMMAND, &command);
- for (idx = 0; idx < 6; idx++) {
- r = &dev->resource[idx];
- if (r->parent) /* Already allocated */
- continue;
- if (!r->flags || (r->flags & IORESOURCE_UNSET))
- continue; /* Not assigned at all */
- if (r->flags & IORESOURCE_IO)
- disabled = !(command & PCI_COMMAND_IO);
- else
- disabled = !(command & PCI_COMMAND_MEMORY);
- if (pass == disabled)
- alloc_resource(dev, idx);
- }
- if (pass)
- continue;
- r = &dev->resource[PCI_ROM_RESOURCE];
- if (r->flags & IORESOURCE_ROM_ENABLE) {
- /* Turn the ROM off, leave the resource region, but keep it unregistered. */
- u32 reg;
- DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
- r->flags &= ~IORESOURCE_ROM_ENABLE;
- pci_read_config_dword(dev, dev->rom_base_reg, &reg);
- pci_write_config_dword(dev, dev->rom_base_reg,
- reg & ~PCI_ROM_ADDRESS_ENABLE);
- }
- }
-}
#ifdef CONFIG_PPC_OF
/*
@@ -649,8 +424,7 @@ void pcibios_make_OF_bus_map(void)
}
#endif /* CONFIG_PPC_OF */
-static int __init
-pcibios_init(void)
+static int __init pcibios_init(void)
{
struct pci_controller *hose, *tmp;
struct pci_bus *bus;
@@ -683,22 +457,8 @@ pcibios_init(void)
if (pci_assign_all_buses && have_of)
pcibios_make_OF_bus_map();
- /* Call machine dependent fixup */
- if (ppc_md.pcibios_fixup)
- ppc_md.pcibios_fixup();
-
- /* Allocate and assign resources. If we re-assign everything, then
- * we skip the allocate phase
- */
- pcibios_allocate_bus_resources(&pci_root_buses);
- if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) {
- pcibios_allocate_resources(0);
- pcibios_allocate_resources(1);
- }
- if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
- DBG("PCI: Assigning unassigned resouces...\n");
- pci_assign_unassigned_resources();
- }
+ /* Call common code to handle resource allocation */
+ pcibios_resource_survey();
/* Call machine dependent post-init code */
if (ppc_md.pcibios_after_init)
OpenPOWER on IntegriCloud