11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers/pci/setup-irq.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Extruded from code written by 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dave Rusling (david.rusling@reo.mts.dec.com) 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * David Mosberger (davidm@cs.arizona.edu) 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * David Miller (davem@redhat.com) 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Support routines for initializing a PCI subsystem. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cache.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 198885b7b637fa9aca7e1b00581a0173c6956966d3Thierry Redingvoid __weak pcibios_update_irq(struct pci_dev *dev, int irq) 208885b7b637fa9aca7e1b00581a0173c6956966d3Thierry Reding{ 218885b7b637fa9aca7e1b00581a0173c6956966d3Thierry Reding dev_dbg(&dev->dev, "assigning IRQ %02d\n", irq); 228885b7b637fa9aca7e1b00581a0173c6956966d3Thierry Reding pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); 238885b7b637fa9aca7e1b00581a0173c6956966d3Thierry Reding} 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 253c78bc61f5ef3bc87e7f94f67ec737d2273f120bRyan Desfossesstatic void pdev_fixup_irq(struct pci_dev *dev, 263c78bc61f5ef3bc87e7f94f67ec737d2273f120bRyan Desfosses u8 (*swizzle)(struct pci_dev *, u8 *), 273c78bc61f5ef3bc87e7f94f67ec737d2273f120bRyan Desfosses int (*map_irq)(const struct pci_dev *, u8, u8)) 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 pin, slot; 30691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block int irq = 0; 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If this device is not on the primary bus, we need to figure out 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds which interrupt pin it will come in on. We know which slot it 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds will come in on 'cos that slot is where the bridge is. Each 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds time the interrupt line passes through a PCI-PCI bridge we must 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds apply the swizzle function. */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); 39691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block /* Cope with illegal. */ 40691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block if (pin > 4) 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pin = 1; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block if (pin != 0) { 44691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block /* Follow the chain of bridges, swizzling as we go. */ 45691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block slot = (*swizzle)(dev, &pin); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block irq = (*map_irq)(dev, slot, pin); 48691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block if (irq == -1) 49691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block irq = 0; 50691cd0c2ee2d4d6dff652627fca1b2d4f1377d58Andreas Block } 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5380ccba1186d48fa728dc4b1456cc07ffb07da501Bjorn Helgaas dev_dbg(&dev->dev, "fixup irq: got %d\n", dev->irq); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Always tell the device, so the driver knows what is 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the real IRQ to use; the device does not use it. */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcibios_update_irq(dev, irq); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 603c78bc61f5ef3bc87e7f94f67ec737d2273f120bRyan Desfossesvoid pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), 613c78bc61f5ef3bc87e7f94f67ec737d2273f120bRyan Desfosses int (*map_irq)(const struct pci_dev *, u8, u8)) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev = NULL; 643c78bc61f5ef3bc87e7f94f67ec737d2273f120bRyan Desfosses 654e344b1cc53989e8ecc1140e9346f657d7c8aa9eKulikov Vasiliy for_each_pci_dev(dev) 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pdev_fixup_irq(dev, swizzle, map_irq); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 68