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