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