xref: /openbmc/linux/drivers/pci/setup-irq.c (revision 47a650f2795b00297a5a3eab7aaa46bdb2bbe304)
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>
18*47a650f2SMatthew Minter #include "pci.h"
191da177e4SLinus Torvalds 
208885b7b6SThierry Reding void __weak pcibios_update_irq(struct pci_dev *dev, int irq)
218885b7b6SThierry Reding {
228885b7b6SThierry Reding 	dev_dbg(&dev->dev, "assigning IRQ %02d\n", irq);
238885b7b6SThierry Reding 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
248885b7b6SThierry Reding }
251da177e4SLinus Torvalds 
26*47a650f2SMatthew Minter void pci_assign_irq(struct pci_dev *dev)
271da177e4SLinus Torvalds {
28*47a650f2SMatthew Minter 	u8 pin;
29*47a650f2SMatthew Minter 	u8 slot = -1;
30691cd0c2SAndreas Block 	int irq = 0;
31*47a650f2SMatthew Minter 	struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
32*47a650f2SMatthew Minter 
33*47a650f2SMatthew Minter 	if (!(hbrg->map_irq)) {
34*47a650f2SMatthew Minter 		dev_dbg(&dev->dev, "runtime IRQ mapping not provided by arch\n");
35*47a650f2SMatthew Minter 		return;
36*47a650f2SMatthew Minter 	}
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 	/* If this device is not on the primary bus, we need to figure out
391da177e4SLinus Torvalds 	   which interrupt pin it will come in on.   We know which slot it
401da177e4SLinus Torvalds 	   will come in on 'cos that slot is where the bridge is.   Each
411da177e4SLinus Torvalds 	   time the interrupt line passes through a PCI-PCI bridge we must
421da177e4SLinus Torvalds 	   apply the swizzle function.  */
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
45691cd0c2SAndreas Block 	/* Cope with illegal. */
46691cd0c2SAndreas Block 	if (pin > 4)
471da177e4SLinus Torvalds 		pin = 1;
481da177e4SLinus Torvalds 
49*47a650f2SMatthew Minter 	if (pin) {
501da177e4SLinus Torvalds 		/* Follow the chain of bridges, swizzling as we go.  */
51*47a650f2SMatthew Minter 		if (hbrg->swizzle_irq)
52*47a650f2SMatthew Minter 			slot = (*(hbrg->swizzle_irq))(dev, &pin);
531da177e4SLinus Torvalds 
54*47a650f2SMatthew Minter 		/*
55*47a650f2SMatthew Minter 		 * If a swizzling function is not used map_irq must
56*47a650f2SMatthew Minter 		 * ignore slot
57*47a650f2SMatthew Minter 		 */
58*47a650f2SMatthew Minter 		irq = (*(hbrg->map_irq))(dev, slot, pin);
591da177e4SLinus Torvalds 		if (irq == -1)
601da177e4SLinus Torvalds 			irq = 0;
61691cd0c2SAndreas Block 	}
621da177e4SLinus Torvalds 	dev->irq = irq;
631da177e4SLinus Torvalds 
64*47a650f2SMatthew Minter 	dev_dbg(&dev->dev, "assign IRQ: got %d\n", dev->irq);
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	/* Always tell the device, so the driver knows what is
671da177e4SLinus Torvalds 	   the real IRQ to use; the device does not use it. */
681da177e4SLinus Torvalds 	pcibios_update_irq(dev, irq);
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds 
713c78bc61SRyan Desfosses void pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
72d5341942SRalf Baechle 		    int (*map_irq)(const struct pci_dev *, u8, u8))
731da177e4SLinus Torvalds {
74*47a650f2SMatthew Minter 	/*
75*47a650f2SMatthew Minter 	 * Implement pci_fixup_irqs() through pci_assign_irq().
76*47a650f2SMatthew Minter 	 * This code should be remove eventually, it is a wrapper
77*47a650f2SMatthew Minter 	 * around pci_assign_irq() interface to keep current
78*47a650f2SMatthew Minter 	 * pci_fixup_irqs() behaviour unchanged on architecture
79*47a650f2SMatthew Minter 	 * code still relying on its interface.
80*47a650f2SMatthew Minter 	 */
811da177e4SLinus Torvalds 	struct pci_dev *dev = NULL;
82*47a650f2SMatthew Minter 	struct pci_host_bridge *hbrg = NULL;
833c78bc61SRyan Desfosses 
84*47a650f2SMatthew Minter 	for_each_pci_dev(dev) {
85*47a650f2SMatthew Minter 		hbrg = pci_find_host_bridge(dev->bus);
86*47a650f2SMatthew Minter 		hbrg->swizzle_irq = swizzle;
87*47a650f2SMatthew Minter 		hbrg->map_irq = map_irq;
88*47a650f2SMatthew Minter 		pci_assign_irq(dev);
89*47a650f2SMatthew Minter 		hbrg->swizzle_irq = NULL;
90*47a650f2SMatthew Minter 		hbrg->map_irq = NULL;
91*47a650f2SMatthew Minter 	}
921da177e4SLinus Torvalds }
93e6b29deaSRay Jui EXPORT_SYMBOL_GPL(pci_fixup_irqs);
94