|
@@ -35,13 +35,9 @@ unsigned long isa_io_base = 0;
|
|
unsigned long pci_dram_offset = 0;
|
|
unsigned long pci_dram_offset = 0;
|
|
int pcibios_assign_bus_offset = 1;
|
|
int pcibios_assign_bus_offset = 1;
|
|
|
|
|
|
-/* Default PCI flags is 0 */
|
|
|
|
-unsigned int ppc_pci_flags;
|
|
|
|
-
|
|
|
|
void pcibios_make_OF_bus_map(void);
|
|
void pcibios_make_OF_bus_map(void);
|
|
|
|
|
|
static void fixup_broken_pcnet32(struct pci_dev* dev);
|
|
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);
|
|
static void fixup_cpc710_pci64(struct pci_dev* dev);
|
|
#ifdef CONFIG_PPC_OF
|
|
#ifdef CONFIG_PPC_OF
|
|
static u8* pci_to_OF_bus_map;
|
|
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);
|
|
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
|
|
void __init
|
|
update_bridge_resource(struct pci_dev *dev, struct resource *res)
|
|
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);
|
|
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, ®);
|
|
|
|
- pci_write_config_dword(dev, dev->rom_base_reg,
|
|
|
|
- reg & ~PCI_ROM_ADDRESS_ENABLE);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_OF
|
|
#ifdef CONFIG_PPC_OF
|
|
/*
|
|
/*
|
|
@@ -649,8 +424,7 @@ void pcibios_make_OF_bus_map(void)
|
|
}
|
|
}
|
|
#endif /* CONFIG_PPC_OF */
|
|
#endif /* CONFIG_PPC_OF */
|
|
|
|
|
|
-static int __init
|
|
|
|
-pcibios_init(void)
|
|
|
|
|
|
+static int __init pcibios_init(void)
|
|
{
|
|
{
|
|
struct pci_controller *hose, *tmp;
|
|
struct pci_controller *hose, *tmp;
|
|
struct pci_bus *bus;
|
|
struct pci_bus *bus;
|
|
@@ -683,22 +457,8 @@ pcibios_init(void)
|
|
if (pci_assign_all_buses && have_of)
|
|
if (pci_assign_all_buses && have_of)
|
|
pcibios_make_OF_bus_map();
|
|
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 */
|
|
/* Call machine dependent post-init code */
|
|
if (ppc_md.pcibios_after_init)
|
|
if (ppc_md.pcibios_after_init)
|