diff options
Diffstat (limited to 'arch/arm/kernel/bios32.c')
| -rw-r--r-- | arch/arm/kernel/bios32.c | 318 |
1 files changed, 139 insertions, 179 deletions
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index c6273a3bfc2..17a26c17f7f 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -5,7 +5,7 @@ * * Bits taken from various places. */ -#include <linux/module.h> +#include <linux/export.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/slab.h> @@ -13,13 +13,13 @@ #include <linux/io.h> #include <asm/mach-types.h> +#include <asm/mach/map.h> #include <asm/mach/pci.h> static int debug_pci; -static int use_firmware; /* - * We can't use pci_find_device() here since we are + * We can't use pci_get_device() here since we are * called from interrupt context. */ static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, int warn) @@ -57,13 +57,10 @@ static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, in void pcibios_report_status(u_int status_mask, int warn) { - struct list_head *l; - - list_for_each(l, &pci_root_buses) { - struct pci_bus *bus = pci_bus_b(l); + struct pci_bus *bus; + list_for_each_entry(bus, &pci_root_buses, node) pcibios_bus_report_status(bus, status_mask, warn); - } } /* @@ -78,7 +75,7 @@ void pcibios_report_status(u_int status_mask, int warn) * Bug 3 is responsible for the sound DMA grinding to a halt. We now * live with bug 2. */ -static void __devinit pci_fixup_83c553(struct pci_dev *dev) +static void pci_fixup_83c553(struct pci_dev *dev) { /* * Set memory region to start at address 0, and enable IO @@ -130,7 +127,7 @@ static void __devinit pci_fixup_83c553(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, pci_fixup_83c553); -static void __devinit pci_fixup_unassign(struct pci_dev *dev) +static void pci_fixup_unassign(struct pci_dev *dev) { dev->resource[0].end -= dev->resource[0].start; dev->resource[0].start = 0; @@ -142,7 +139,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940F, * if it is the host bridge by marking it as such. These resources are of * no consequence to the PCI layer (they are handled elsewhere). */ -static void __devinit pci_fixup_dec21285(struct pci_dev *dev) +static void pci_fixup_dec21285(struct pci_dev *dev) { int i; @@ -159,34 +156,9 @@ static void __devinit pci_fixup_dec21285(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, pci_fixup_dec21285); /* - * Same as above. The PrPMC800 carrier board for the PrPMC1100 - * card maps the host-bridge @ 00:01:00 for some reason and it - * ends up getting scanned. Note that we only want to do this - * fixup when we find the IXP4xx on a PrPMC system, which is why - * we check the machine type. We could be running on a board - * with an IXP4xx target device and we don't want to kill the - * resources in that case. - */ -static void __devinit pci_fixup_prpmc1100(struct pci_dev *dev) -{ - int i; - - if (machine_is_prpmc1100()) { - dev->class &= 0xff; - dev->class |= PCI_CLASS_BRIDGE_HOST << 8; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; - } - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IXP4XX, pci_fixup_prpmc1100); - -/* * PCI IDE controllers use non-standard I/O port decoding, respect it. */ -static void __devinit pci_fixup_ide_bases(struct pci_dev *dev) +static void pci_fixup_ide_bases(struct pci_dev *dev) { struct resource *r; int i; @@ -207,7 +179,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); /* * Put the DEC21142 to sleep */ -static void __devinit pci_fixup_dec21142(struct pci_dev *dev) +static void pci_fixup_dec21142(struct pci_dev *dev) { pci_write_config_dword(dev, 0x40, 0x80000000); } @@ -229,7 +201,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, pci_fixup_d * functional. However, The CY82C693U _does not work_ in bus * master mode without locking the PCI bus solid. */ -static void __devinit pci_fixup_cy82c693(struct pci_dev *dev) +static void pci_fixup_cy82c693(struct pci_dev *dev) { if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { u32 base0, base1; @@ -279,7 +251,7 @@ static void __devinit pci_fixup_cy82c693(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, pci_fixup_cy82c693); -static void __init pci_fixup_it8152(struct pci_dev *dev) +static void pci_fixup_it8152(struct pci_dev *dev) { int i; /* fixup for ITE 8152 devices */ @@ -296,15 +268,6 @@ static void __init pci_fixup_it8152(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8152, pci_fixup_it8152); - - -void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) -{ - if (debug_pci) - printk("PCI: Assigning IRQ %02d to %s\n", irq, pci_name(dev)); - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); -} - /* * If the bus contains any of these devices, then we must not turn on * parity checking of any kind. Currently this is CyberPro 20x0 only. @@ -320,54 +283,14 @@ static inline int pdev_bad_for_parity(struct pci_dev *dev) } /* - * Adjust the device resources from bus-centric to Linux-centric. - */ -static void __devinit -pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev) -{ - resource_size_t offset; - int i; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (dev->resource[i].start == 0) - continue; - if (dev->resource[i].flags & IORESOURCE_MEM) - offset = root->mem_offset; - else - offset = root->io_offset; - - dev->resource[i].start += offset; - dev->resource[i].end += offset; - } -} - -static void __devinit -pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root) -{ - struct pci_dev *dev = bus->self; - int i; - - if (!dev) { - /* - * Assign root bus resources. - */ - for (i = 0; i < 3; i++) - bus->resource[i] = root->resource[i]; - } -} - -/* * pcibios_fixup_bus - Called after each bus is probed, * but before its children are examined. */ void pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_sys_data *root = bus->sysdata; struct pci_dev *dev; u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK; - pbus_assign_bus_resources(bus, root); - /* * Walk the devices on this bus, working out what we can * and can't support. @@ -375,8 +298,6 @@ void pcibios_fixup_bus(struct pci_bus *bus) list_for_each_entry(dev, &bus->devices, bus_list) { u16 status; - pdev_fixup_device_resources(root, dev); - pci_read_config_word(dev, PCI_STATUS, &status); /* @@ -437,59 +358,46 @@ void pcibios_fixup_bus(struct pci_bus *bus) printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n", bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); } +EXPORT_SYMBOL(pcibios_fixup_bus); -/* - * Convert from Linux-centric to bus-centric addresses for bridge devices. - */ -void -pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, - struct resource *res) +void pcibios_add_bus(struct pci_bus *bus) { - struct pci_sys_data *root = dev->sysdata; - unsigned long offset = 0; - - if (res->flags & IORESOURCE_IO) - offset = root->io_offset; - if (res->flags & IORESOURCE_MEM) - offset = root->mem_offset; - - region->start = res->start - offset; - region->end = res->end - offset; + struct pci_sys_data *sys = bus->sysdata; + if (sys->add_bus) + sys->add_bus(bus); } -void __devinit -pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, - struct pci_bus_region *region) +void pcibios_remove_bus(struct pci_bus *bus) { - struct pci_sys_data *root = dev->sysdata; - unsigned long offset = 0; - - if (res->flags & IORESOURCE_IO) - offset = root->io_offset; - if (res->flags & IORESOURCE_MEM) - offset = root->mem_offset; - - res->start = region->start + offset; - res->end = region->end + offset; + struct pci_sys_data *sys = bus->sysdata; + if (sys->remove_bus) + sys->remove_bus(bus); } -#ifdef CONFIG_HOTPLUG -EXPORT_SYMBOL(pcibios_fixup_bus); -EXPORT_SYMBOL(pcibios_resource_to_bus); -EXPORT_SYMBOL(pcibios_bus_to_resource); -#endif - /* - * Swizzle the device pin each time we cross a bridge. - * This might update pin and returns the slot number. + * Swizzle the device pin each time we cross a bridge. If a platform does + * not provide a swizzle function, we perform the standard PCI swizzling. + * + * The default swizzling walks up the bus tree one level at a time, applying + * the standard swizzle function at each step, stopping when it finds the PCI + * root bus. This will return the slot number of the bridge device on the + * root bus and the interrupt pin on that device which should correspond + * with the downstream device interrupt. + * + * Platforms may override this, in which case the slot and pin returned + * depend entirely on the platform code. However, please note that the + * PCI standard swizzle is implemented on plug-in cards and Cardbus based + * PCI extenders, so it can not be ignored. */ -static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 *pin) +static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin) { struct pci_sys_data *sys = dev->sysdata; - int slot = 0, oldpin = *pin; + int slot, oldpin = *pin; if (sys->swizzle) slot = sys->swizzle(dev, pin); + else + slot = pci_common_swizzle(dev, pin); if (debug_pci) printk("PCI: %s swizzling pin %d => pin %d slot %d\n", @@ -501,7 +409,7 @@ static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 *pin) /* * Map a slot/pin to an IRQ. */ -static int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct pci_sys_data *sys = dev->sysdata; int irq = -1; @@ -516,7 +424,40 @@ static int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return irq; } -static void __init pcibios_init_hw(struct hw_pci *hw) +static int pcibios_init_resources(int busnr, struct pci_sys_data *sys) +{ + int ret; + struct pci_host_bridge_window *window; + + if (list_empty(&sys->resources)) { + pci_add_resource_offset(&sys->resources, + &iomem_resource, sys->mem_offset); + } + + list_for_each_entry(window, &sys->resources, list) { + if (resource_type(window->res) == IORESOURCE_IO) + return 0; + } + + sys->io_res.start = (busnr * SZ_64K) ? : pcibios_min_io; + sys->io_res.end = (busnr + 1) * SZ_64K - 1; + sys->io_res.flags = IORESOURCE_IO; + sys->io_res.name = sys->io_res_name; + sprintf(sys->io_res_name, "PCI%d I/O", busnr); + + ret = request_resource(&ioport_resource, &sys->io_res); + if (ret) { + pr_err("PCI: unable to allocate I/O port region (%d)\n", ret); + return ret; + } + pci_add_resource_offset(&sys->resources, &sys->io_res, + sys->io_offset); + + return 0; +} + +static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, + struct list_head *head) { struct pci_sys_data *sys = NULL; int ret; @@ -530,24 +471,38 @@ static void __init pcibios_init_hw(struct hw_pci *hw) #ifdef CONFIG_PCI_DOMAINS sys->domain = hw->domain; #endif - sys->hw = hw; sys->busnr = busnr; sys->swizzle = hw->swizzle; sys->map_irq = hw->map_irq; - sys->resource[0] = &ioport_resource; - sys->resource[1] = &iomem_resource; + sys->align_resource = hw->align_resource; + sys->add_bus = hw->add_bus; + sys->remove_bus = hw->remove_bus; + INIT_LIST_HEAD(&sys->resources); + + if (hw->private_data) + sys->private_data = hw->private_data[nr]; ret = hw->setup(nr, sys); if (ret > 0) { - sys->bus = hw->scan(nr, sys); + ret = pcibios_init_resources(nr, sys); + if (ret) { + kfree(sys); + break; + } + + if (hw->scan) + sys->bus = hw->scan(nr, sys); + else + sys->bus = pci_scan_root_bus(parent, sys->busnr, + hw->ops, sys, &sys->resources); if (!sys->bus) panic("PCI: unable to scan bus!"); - busnr = sys->bus->subordinate + 1; + busnr = sys->bus->busn_res.end + 1; - list_add(&sys->node, &hw->buses); + list_add(&sys->node, head); } else { kfree(sys); if (ret < 0) @@ -556,24 +511,24 @@ static void __init pcibios_init_hw(struct hw_pci *hw) } } -void __init pci_common_init(struct hw_pci *hw) +void pci_common_init_dev(struct device *parent, struct hw_pci *hw) { struct pci_sys_data *sys; + LIST_HEAD(head); - INIT_LIST_HEAD(&hw->buses); - + pci_add_flags(PCI_REASSIGN_ALL_RSRC); if (hw->preinit) hw->preinit(); - pcibios_init_hw(hw); + pcibios_init_hw(parent, hw, &head); if (hw->postinit) hw->postinit(); pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); - list_for_each_entry(sys, &hw->buses, node) { + list_for_each_entry(sys, &head, node) { struct pci_bus *bus = sys->bus; - if (!use_firmware) { + if (!pci_has_flag(PCI_PROBE_ONLY)) { /* * Size the bridge windows. */ @@ -590,15 +545,34 @@ void __init pci_common_init(struct hw_pci *hw) */ pci_bus_add_devices(bus); } + + list_for_each_entry(sys, &head, node) { + struct pci_bus *bus = sys->bus; + + /* Configure PCI Express settings */ + if (bus && !pci_has_flag(PCI_PROBE_ONLY)) { + struct pci_bus *child; + + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + } + } } +#ifndef CONFIG_PCI_HOST_ITE8152 +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} +#endif + char * __init pcibios_setup(char *str) { if (!strcmp(str, "debug")) { debug_pci = 1; return NULL; } else if (!strcmp(str, "firmware")) { - use_firmware = 1; + pci_add_flags(PCI_PROBE_ONLY); return NULL; } return str; @@ -622,6 +596,8 @@ char * __init pcibios_setup(char *str) resource_size_t pcibios_align_resource(void *data, const struct resource *res, resource_size_t size, resource_size_t align) { + struct pci_dev *dev = data; + struct pci_sys_data *sys = dev->sysdata; resource_size_t start = res->start; if (res->flags & IORESOURCE_IO && start & 0x300) @@ -629,6 +605,9 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, start = (start + align - 1) & ~(align - 1); + if (sys->align_resource) + return sys->align_resource(dev, res, start, size, align); + return start; } @@ -638,41 +617,10 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, */ int pcibios_enable_device(struct pci_dev *dev, int mask) { - u16 cmd, old_cmd; - int idx; - struct resource *r; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - for (idx = 0; idx < 6; idx++) { - /* Only set up the requested stuff */ - if (!(mask & (1 << idx))) - continue; + if (pci_has_flag(PCI_PROBE_ONLY)) + return 0; - r = dev->resource + idx; - if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available because" - " of resource collisions\n", pci_name(dev)); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - - /* - * Bridges (eg, cardbus bridges) need to be fully enabled - */ - if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) - cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - - if (cmd != old_cmd) { - printk("PCI: enabling device %s (%04x -> %04x)\n", - pci_name(dev), old_cmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; + return pci_enable_resources(dev, mask); } int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, @@ -699,3 +647,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, return 0; } + +void __init pci_map_io_early(unsigned long pfn) +{ + struct map_desc pci_io_desc = { + .virtual = PCI_IO_VIRT_BASE, + .type = MT_DEVICE, + .length = SZ_64K, + }; + + pci_io_desc.pfn = pfn; + iotable_init(&pci_io_desc, 1); +} |
