xref: /openbmc/linux/drivers/pci/setup-irq.c (revision 9a0a1417)
17328c8f4SBjorn Helgaas // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
3df62ab5eSBjorn Helgaas  * Support routines for initializing a PCI subsystem
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Extruded from code written by
61da177e4SLinus Torvalds  *      Dave Rusling (david.rusling@reo.mts.dec.com)
71da177e4SLinus Torvalds  *      David Mosberger (davidm@cs.arizona.edu)
81da177e4SLinus Torvalds  *	David Miller (davem@redhat.com)
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/pci.h>
131da177e4SLinus Torvalds #include <linux/errno.h>
141da177e4SLinus Torvalds #include <linux/ioport.h>
151da177e4SLinus Torvalds #include <linux/cache.h>
1647a650f2SMatthew Minter #include "pci.h"
171da177e4SLinus Torvalds 
pci_assign_irq(struct pci_dev * dev)1847a650f2SMatthew Minter void pci_assign_irq(struct pci_dev *dev)
191da177e4SLinus Torvalds {
2047a650f2SMatthew Minter 	u8 pin;
2147a650f2SMatthew Minter 	u8 slot = -1;
22691cd0c2SAndreas Block 	int irq = 0;
2347a650f2SMatthew Minter 	struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
2447a650f2SMatthew Minter 
2547a650f2SMatthew Minter 	if (!(hbrg->map_irq)) {
267506dc79SFrederick Lawler 		pci_dbg(dev, "runtime IRQ mapping not provided by arch\n");
2747a650f2SMatthew Minter 		return;
2847a650f2SMatthew Minter 	}
291da177e4SLinus Torvalds 
30*9a0a1417SPranay Sanghai 	/*
31*9a0a1417SPranay Sanghai 	 * If this device is not on the primary bus, we need to figure out
32*9a0a1417SPranay Sanghai 	 * which interrupt pin it will come in on. We know which slot it
33*9a0a1417SPranay Sanghai 	 * will come in on because that slot is where the bridge is. Each
34*9a0a1417SPranay Sanghai 	 * time the interrupt line passes through a PCI-PCI bridge we must
35*9a0a1417SPranay Sanghai 	 * apply the swizzle function.
36*9a0a1417SPranay Sanghai 	 */
371da177e4SLinus Torvalds 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
38691cd0c2SAndreas Block 	/* Cope with illegal. */
39691cd0c2SAndreas Block 	if (pin > 4)
401da177e4SLinus Torvalds 		pin = 1;
411da177e4SLinus Torvalds 
4247a650f2SMatthew Minter 	if (pin) {
431da177e4SLinus Torvalds 		/* Follow the chain of bridges, swizzling as we go. */
4447a650f2SMatthew Minter 		if (hbrg->swizzle_irq)
4547a650f2SMatthew Minter 			slot = (*(hbrg->swizzle_irq))(dev, &pin);
461da177e4SLinus Torvalds 
4747a650f2SMatthew Minter 		/*
48*9a0a1417SPranay Sanghai 		 * If a swizzling function is not used, map_irq() must
49*9a0a1417SPranay Sanghai 		 * ignore slot.
5047a650f2SMatthew Minter 		 */
5147a650f2SMatthew Minter 		irq = (*(hbrg->map_irq))(dev, slot, pin);
521da177e4SLinus Torvalds 		if (irq == -1)
531da177e4SLinus Torvalds 			irq = 0;
54691cd0c2SAndreas Block 	}
551da177e4SLinus Torvalds 	dev->irq = irq;
561da177e4SLinus Torvalds 
577506dc79SFrederick Lawler 	pci_dbg(dev, "assign IRQ: got %d\n", dev->irq);
581da177e4SLinus Torvalds 
59*9a0a1417SPranay Sanghai 	/*
60*9a0a1417SPranay Sanghai 	 * Always tell the device, so the driver knows what is the real IRQ
61*9a0a1417SPranay Sanghai 	 * to use; the device does not use it.
62*9a0a1417SPranay Sanghai 	 */
63606799ccSBjorn Helgaas 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
641da177e4SLinus Torvalds }
65