aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/kernel/bios32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/bios32.c')
-rw-r--r--arch/arm/kernel/bios32.c318
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);
+}