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