|
@@ -348,3 +348,156 @@ void pcibios_fixup_bus(struct pci_bus *bus)
|
|
|
/*
|
|
|
* Propagate the flags to the PCI bridge.
|
|
|
*/
|
|
|
+ if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
|
|
|
+ if (features & PCI_COMMAND_FAST_BACK)
|
|
|
+ bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK;
|
|
|
+ if (features & PCI_COMMAND_PARITY)
|
|
|
+ bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Report what we did for this 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);
|
|
|
+
|
|
|
+/*
|
|
|
+ * 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 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
|
|
|
+{
|
|
|
+ struct pci_sys_data *sys = dev->sysdata;
|
|
|
+ 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",
|
|
|
+ pci_name(dev), oldpin, *pin, slot);
|
|
|
+
|
|
|
+ return slot;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Map a slot/pin to an IRQ.
|
|
|
+ */
|
|
|
+static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|
|
+{
|
|
|
+ struct pci_sys_data *sys = dev->sysdata;
|
|
|
+ int irq = -1;
|
|
|
+
|
|
|
+ if (sys->map_irq)
|
|
|
+ irq = sys->map_irq(dev, slot, pin);
|
|
|
+
|
|
|
+ if (debug_pci)
|
|
|
+ printk("PCI: %s mapping slot %d pin %d => irq %d\n",
|
|
|
+ pci_name(dev), slot, pin, irq);
|
|
|
+
|
|
|
+ return irq;
|
|
|
+}
|
|
|
+
|
|
|
+static int __init 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 __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
|
|
|
+{
|
|
|
+ struct pci_sys_data *sys = NULL;
|
|
|
+ int ret;
|
|
|
+ int nr, busnr;
|
|
|
+
|
|
|
+ for (nr = busnr = 0; nr < hw->nr_controllers; nr++) {
|
|
|
+ sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL);
|
|
|
+ if (!sys)
|
|
|
+ panic("PCI: unable to allocate sys data!");
|
|
|
+
|
|
|
+#ifdef CONFIG_PCI_DOMAINS
|
|
|
+ sys->domain = hw->domain;
|
|
|
+#endif
|
|
|
+ sys->busnr = busnr;
|
|
|
+ sys->swizzle = hw->swizzle;
|
|
|
+ sys->map_irq = hw->map_irq;
|
|
|
+ INIT_LIST_HEAD(&sys->resources);
|
|
|
+
|
|
|
+ ret = hw->setup(nr, sys);
|
|
|
+
|
|
|
+ if (ret > 0) {
|
|
|
+ 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(NULL, sys->busnr,
|
|
|
+ hw->ops, sys, &sys->resources);
|
|
|
+
|
|
|
+ if (!sys->bus)
|
|
|
+ panic("PCI: unable to scan bus!");
|
|
|
+
|
|
|
+ busnr = sys->bus->busn_res.end + 1;
|
|
|
+
|
|
|
+ list_add(&sys->node, head);
|
|
|
+ } else {
|
|
|
+ kfree(sys);
|
|
|
+ if (ret < 0)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void __init pci_common_init(struct hw_pci *hw)
|
|
|
+{
|
|
|
+ struct pci_sys_data *sys;
|
|
|
+ LIST_HEAD(head);
|
|
|
+
|
|
|
+ pci_add_flags(PCI_REASSIGN_ALL_RSRC);
|
|
|
+ if (hw->preinit)
|
|
|
+ hw->preinit();
|