162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Support routines for initializing a PCI subsystem
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Extruded from code written by
662306a36Sopenharmony_ci *      Dave Rusling (david.rusling@reo.mts.dec.com)
762306a36Sopenharmony_ci *      David Mosberger (davidm@cs.arizona.edu)
862306a36Sopenharmony_ci *	David Miller (davem@redhat.com)
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/pci.h>
1362306a36Sopenharmony_ci#include <linux/errno.h>
1462306a36Sopenharmony_ci#include <linux/ioport.h>
1562306a36Sopenharmony_ci#include <linux/cache.h>
1662306a36Sopenharmony_ci#include "pci.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_civoid pci_assign_irq(struct pci_dev *dev)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	u8 pin;
2162306a36Sopenharmony_ci	u8 slot = -1;
2262306a36Sopenharmony_ci	int irq = 0;
2362306a36Sopenharmony_ci	struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if (!(hbrg->map_irq)) {
2662306a36Sopenharmony_ci		pci_dbg(dev, "runtime IRQ mapping not provided by arch\n");
2762306a36Sopenharmony_ci		return;
2862306a36Sopenharmony_ci	}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/*
3162306a36Sopenharmony_ci	 * If this device is not on the primary bus, we need to figure out
3262306a36Sopenharmony_ci	 * which interrupt pin it will come in on. We know which slot it
3362306a36Sopenharmony_ci	 * will come in on because that slot is where the bridge is. Each
3462306a36Sopenharmony_ci	 * time the interrupt line passes through a PCI-PCI bridge we must
3562306a36Sopenharmony_ci	 * apply the swizzle function.
3662306a36Sopenharmony_ci	 */
3762306a36Sopenharmony_ci	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
3862306a36Sopenharmony_ci	/* Cope with illegal. */
3962306a36Sopenharmony_ci	if (pin > 4)
4062306a36Sopenharmony_ci		pin = 1;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (pin) {
4362306a36Sopenharmony_ci		/* Follow the chain of bridges, swizzling as we go. */
4462306a36Sopenharmony_ci		if (hbrg->swizzle_irq)
4562306a36Sopenharmony_ci			slot = (*(hbrg->swizzle_irq))(dev, &pin);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		/*
4862306a36Sopenharmony_ci		 * If a swizzling function is not used, map_irq() must
4962306a36Sopenharmony_ci		 * ignore slot.
5062306a36Sopenharmony_ci		 */
5162306a36Sopenharmony_ci		irq = (*(hbrg->map_irq))(dev, slot, pin);
5262306a36Sopenharmony_ci		if (irq == -1)
5362306a36Sopenharmony_ci			irq = 0;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci	dev->irq = irq;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	pci_dbg(dev, "assign IRQ: got %d\n", dev->irq);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/*
6062306a36Sopenharmony_ci	 * Always tell the device, so the driver knows what is the real IRQ
6162306a36Sopenharmony_ci	 * to use; the device does not use it.
6262306a36Sopenharmony_ci	 */
6362306a36Sopenharmony_ci	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
6462306a36Sopenharmony_ci}
65