mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
PCI: Place interrupt related code into irq.c
Interrupt related code is spread into irq.c, pci.c, and setup-irq.c. Group them into pre-existing irq.c. Link: https://lore.kernel.org/r/20240129113655.3368-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
6613476e22
commit
1e8cc8e6bd
@ -5,7 +5,7 @@
|
|||||||
obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \
|
obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \
|
||||||
remove.o pci.o pci-driver.o search.o \
|
remove.o pci.o pci-driver.o search.o \
|
||||||
pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
|
pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
|
||||||
setup-bus.o vc.o mmap.o setup-irq.o
|
setup-bus.o vc.o mmap.o
|
||||||
|
|
||||||
obj-$(CONFIG_PCI) += msi/
|
obj-$(CONFIG_PCI) += msi/
|
||||||
obj-$(CONFIG_PCI) += pcie/
|
obj-$(CONFIG_PCI) += pcie/
|
||||||
|
@ -8,9 +8,13 @@
|
|||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
#include "pci.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_request_irq - allocate an interrupt line for a PCI device
|
* pci_request_irq - allocate an interrupt line for a PCI device
|
||||||
* @dev: PCI device to operate on
|
* @dev: PCI device to operate on
|
||||||
@ -74,3 +78,203 @@ void pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id)
|
|||||||
kfree(free_irq(pci_irq_vector(dev, nr), dev_id));
|
kfree(free_irq(pci_irq_vector(dev, nr), dev_id));
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pci_free_irq);
|
EXPORT_SYMBOL(pci_free_irq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
|
||||||
|
* @dev: the PCI device
|
||||||
|
* @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
|
||||||
|
*
|
||||||
|
* Perform INTx swizzling for a device behind one level of bridge. This is
|
||||||
|
* required by section 9.1 of the PCI-to-PCI bridge specification for devices
|
||||||
|
* behind bridges on add-in cards. For devices with ARI enabled, the slot
|
||||||
|
* number is always 0 (see the Implementation Note in section 2.2.8.1 of
|
||||||
|
* the PCI Express Base Specification, Revision 2.1)
|
||||||
|
*/
|
||||||
|
u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin)
|
||||||
|
{
|
||||||
|
int slot;
|
||||||
|
|
||||||
|
if (pci_ari_enabled(dev->bus))
|
||||||
|
slot = 0;
|
||||||
|
else
|
||||||
|
slot = PCI_SLOT(dev->devfn);
|
||||||
|
|
||||||
|
return (((pin - 1) + slot) % 4) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
|
||||||
|
{
|
||||||
|
u8 pin;
|
||||||
|
|
||||||
|
pin = dev->pin;
|
||||||
|
if (!pin)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while (!pci_is_root_bus(dev->bus)) {
|
||||||
|
pin = pci_swizzle_interrupt_pin(dev, pin);
|
||||||
|
dev = dev->bus->self;
|
||||||
|
}
|
||||||
|
*bridge = dev;
|
||||||
|
return pin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_common_swizzle - swizzle INTx all the way to root bridge
|
||||||
|
* @dev: the PCI device
|
||||||
|
* @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)
|
||||||
|
*
|
||||||
|
* Perform INTx swizzling for a device. This traverses through all PCI-to-PCI
|
||||||
|
* bridges all the way up to a PCI root bus.
|
||||||
|
*/
|
||||||
|
u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
|
||||||
|
{
|
||||||
|
u8 pin = *pinp;
|
||||||
|
|
||||||
|
while (!pci_is_root_bus(dev->bus)) {
|
||||||
|
pin = pci_swizzle_interrupt_pin(dev, pin);
|
||||||
|
dev = dev->bus->self;
|
||||||
|
}
|
||||||
|
*pinp = pin;
|
||||||
|
return PCI_SLOT(dev->devfn);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pci_common_swizzle);
|
||||||
|
|
||||||
|
void pci_assign_irq(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
u8 pin;
|
||||||
|
u8 slot = -1;
|
||||||
|
int irq = 0;
|
||||||
|
struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
|
||||||
|
|
||||||
|
if (!(hbrg->map_irq)) {
|
||||||
|
pci_dbg(dev, "runtime IRQ mapping not provided by arch\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this device is not on the primary bus, we need to figure out
|
||||||
|
* which interrupt pin it will come in on. We know which slot it
|
||||||
|
* will come in on because that slot is where the bridge is. Each
|
||||||
|
* time the interrupt line passes through a PCI-PCI bridge we must
|
||||||
|
* apply the swizzle function.
|
||||||
|
*/
|
||||||
|
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
|
||||||
|
/* Cope with illegal. */
|
||||||
|
if (pin > 4)
|
||||||
|
pin = 1;
|
||||||
|
|
||||||
|
if (pin) {
|
||||||
|
/* Follow the chain of bridges, swizzling as we go. */
|
||||||
|
if (hbrg->swizzle_irq)
|
||||||
|
slot = (*(hbrg->swizzle_irq))(dev, &pin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a swizzling function is not used, map_irq() must
|
||||||
|
* ignore slot.
|
||||||
|
*/
|
||||||
|
irq = (*(hbrg->map_irq))(dev, slot, pin);
|
||||||
|
if (irq == -1)
|
||||||
|
irq = 0;
|
||||||
|
}
|
||||||
|
dev->irq = irq;
|
||||||
|
|
||||||
|
pci_dbg(dev, "assign IRQ: got %d\n", dev->irq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Always tell the device, so the driver knows what is the real IRQ
|
||||||
|
* to use; the device does not use it.
|
||||||
|
*/
|
||||||
|
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
|
||||||
|
{
|
||||||
|
struct pci_bus *bus = dev->bus;
|
||||||
|
bool mask_updated = true;
|
||||||
|
u32 cmd_status_dword;
|
||||||
|
u16 origcmd, newcmd;
|
||||||
|
unsigned long flags;
|
||||||
|
bool irq_pending;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We do a single dword read to retrieve both command and status.
|
||||||
|
* Document assumptions that make this possible.
|
||||||
|
*/
|
||||||
|
BUILD_BUG_ON(PCI_COMMAND % 4);
|
||||||
|
BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
|
||||||
|
|
||||||
|
raw_spin_lock_irqsave(&pci_lock, flags);
|
||||||
|
|
||||||
|
bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);
|
||||||
|
|
||||||
|
irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check interrupt status register to see whether our device
|
||||||
|
* triggered the interrupt (when masking) or the next IRQ is
|
||||||
|
* already pending (when unmasking).
|
||||||
|
*/
|
||||||
|
if (mask != irq_pending) {
|
||||||
|
mask_updated = false;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
origcmd = cmd_status_dword;
|
||||||
|
newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;
|
||||||
|
if (mask)
|
||||||
|
newcmd |= PCI_COMMAND_INTX_DISABLE;
|
||||||
|
if (newcmd != origcmd)
|
||||||
|
bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);
|
||||||
|
|
||||||
|
done:
|
||||||
|
raw_spin_unlock_irqrestore(&pci_lock, flags);
|
||||||
|
|
||||||
|
return mask_updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_check_and_mask_intx - mask INTx on pending interrupt
|
||||||
|
* @dev: the PCI device to operate on
|
||||||
|
*
|
||||||
|
* Check if the device dev has its INTx line asserted, mask it and return
|
||||||
|
* true in that case. False is returned if no interrupt was pending.
|
||||||
|
*/
|
||||||
|
bool pci_check_and_mask_intx(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
return pci_check_and_set_intx_mask(dev, true);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_check_and_unmask_intx - unmask INTx if no interrupt is pending
|
||||||
|
* @dev: the PCI device to operate on
|
||||||
|
*
|
||||||
|
* Check if the device dev has its INTx line asserted, unmask it if not and
|
||||||
|
* return true. False is returned and the mask remains active if there was
|
||||||
|
* still an interrupt pending.
|
||||||
|
*/
|
||||||
|
bool pci_check_and_unmask_intx(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
return pci_check_and_set_intx_mask(dev, false);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pcibios_penalize_isa_irq - penalize an ISA IRQ
|
||||||
|
* @irq: ISA IRQ to penalize
|
||||||
|
* @active: IRQ active or not
|
||||||
|
*
|
||||||
|
* Permits the platform to provide architecture-specific functionality when
|
||||||
|
* penalizing ISA IRQs. This is the default implementation. Architecture
|
||||||
|
* implementations can override this.
|
||||||
|
*/
|
||||||
|
void __weak pcibios_penalize_isa_irq(int irq, int active) {}
|
||||||
|
|
||||||
|
int __weak pcibios_alloc_irq(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __weak pcibios_free_irq(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -419,15 +419,6 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __weak pcibios_alloc_irq(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __weak pcibios_free_irq(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_IOV
|
#ifdef CONFIG_PCI_IOV
|
||||||
static inline bool pci_device_can_probe(struct pci_dev *pdev)
|
static inline bool pci_device_can_probe(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include <linux/log2.h>
|
#include <linux/log2.h>
|
||||||
#include <linux/logic_pio.h>
|
#include <linux/logic_pio.h>
|
||||||
#include <linux/pm_wakeup.h>
|
#include <linux/pm_wakeup.h>
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/pci_hotplug.h>
|
#include <linux/pci_hotplug.h>
|
||||||
@ -2292,17 +2291,6 @@ void __weak pcibios_release_device(struct pci_dev *dev) {}
|
|||||||
*/
|
*/
|
||||||
void __weak pcibios_disable_device(struct pci_dev *dev) {}
|
void __weak pcibios_disable_device(struct pci_dev *dev) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* pcibios_penalize_isa_irq - penalize an ISA IRQ
|
|
||||||
* @irq: ISA IRQ to penalize
|
|
||||||
* @active: IRQ active or not
|
|
||||||
*
|
|
||||||
* Permits the platform to provide architecture-specific functionality when
|
|
||||||
* penalizing ISA IRQs. This is the default implementation. Architecture
|
|
||||||
* implementations can override this.
|
|
||||||
*/
|
|
||||||
void __weak pcibios_penalize_isa_irq(int irq, int active) {}
|
|
||||||
|
|
||||||
static void do_pci_disable_device(struct pci_dev *dev)
|
static void do_pci_disable_device(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
u16 pci_command;
|
u16 pci_command;
|
||||||
@ -3964,66 +3952,6 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pci_enable_atomic_ops_to_root);
|
EXPORT_SYMBOL(pci_enable_atomic_ops_to_root);
|
||||||
|
|
||||||
/**
|
|
||||||
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
|
|
||||||
* @dev: the PCI device
|
|
||||||
* @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
|
|
||||||
*
|
|
||||||
* Perform INTx swizzling for a device behind one level of bridge. This is
|
|
||||||
* required by section 9.1 of the PCI-to-PCI bridge specification for devices
|
|
||||||
* behind bridges on add-in cards. For devices with ARI enabled, the slot
|
|
||||||
* number is always 0 (see the Implementation Note in section 2.2.8.1 of
|
|
||||||
* the PCI Express Base Specification, Revision 2.1)
|
|
||||||
*/
|
|
||||||
u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin)
|
|
||||||
{
|
|
||||||
int slot;
|
|
||||||
|
|
||||||
if (pci_ari_enabled(dev->bus))
|
|
||||||
slot = 0;
|
|
||||||
else
|
|
||||||
slot = PCI_SLOT(dev->devfn);
|
|
||||||
|
|
||||||
return (((pin - 1) + slot) % 4) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
|
|
||||||
{
|
|
||||||
u8 pin;
|
|
||||||
|
|
||||||
pin = dev->pin;
|
|
||||||
if (!pin)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
while (!pci_is_root_bus(dev->bus)) {
|
|
||||||
pin = pci_swizzle_interrupt_pin(dev, pin);
|
|
||||||
dev = dev->bus->self;
|
|
||||||
}
|
|
||||||
*bridge = dev;
|
|
||||||
return pin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pci_common_swizzle - swizzle INTx all the way to root bridge
|
|
||||||
* @dev: the PCI device
|
|
||||||
* @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)
|
|
||||||
*
|
|
||||||
* Perform INTx swizzling for a device. This traverses through all PCI-to-PCI
|
|
||||||
* bridges all the way up to a PCI root bus.
|
|
||||||
*/
|
|
||||||
u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
|
|
||||||
{
|
|
||||||
u8 pin = *pinp;
|
|
||||||
|
|
||||||
while (!pci_is_root_bus(dev->bus)) {
|
|
||||||
pin = pci_swizzle_interrupt_pin(dev, pin);
|
|
||||||
dev = dev->bus->self;
|
|
||||||
}
|
|
||||||
*pinp = pin;
|
|
||||||
return PCI_SLOT(dev->devfn);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(pci_common_swizzle);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_release_region - Release a PCI bar
|
* pci_release_region - Release a PCI bar
|
||||||
* @pdev: PCI device whose resources were previously reserved by
|
* @pdev: PCI device whose resources were previously reserved by
|
||||||
@ -4737,78 +4665,6 @@ void pci_intx(struct pci_dev *pdev, int enable)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_intx);
|
EXPORT_SYMBOL_GPL(pci_intx);
|
||||||
|
|
||||||
static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
|
|
||||||
{
|
|
||||||
struct pci_bus *bus = dev->bus;
|
|
||||||
bool mask_updated = true;
|
|
||||||
u32 cmd_status_dword;
|
|
||||||
u16 origcmd, newcmd;
|
|
||||||
unsigned long flags;
|
|
||||||
bool irq_pending;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We do a single dword read to retrieve both command and status.
|
|
||||||
* Document assumptions that make this possible.
|
|
||||||
*/
|
|
||||||
BUILD_BUG_ON(PCI_COMMAND % 4);
|
|
||||||
BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
|
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&pci_lock, flags);
|
|
||||||
|
|
||||||
bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);
|
|
||||||
|
|
||||||
irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check interrupt status register to see whether our device
|
|
||||||
* triggered the interrupt (when masking) or the next IRQ is
|
|
||||||
* already pending (when unmasking).
|
|
||||||
*/
|
|
||||||
if (mask != irq_pending) {
|
|
||||||
mask_updated = false;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
origcmd = cmd_status_dword;
|
|
||||||
newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;
|
|
||||||
if (mask)
|
|
||||||
newcmd |= PCI_COMMAND_INTX_DISABLE;
|
|
||||||
if (newcmd != origcmd)
|
|
||||||
bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);
|
|
||||||
|
|
||||||
done:
|
|
||||||
raw_spin_unlock_irqrestore(&pci_lock, flags);
|
|
||||||
|
|
||||||
return mask_updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pci_check_and_mask_intx - mask INTx on pending interrupt
|
|
||||||
* @dev: the PCI device to operate on
|
|
||||||
*
|
|
||||||
* Check if the device dev has its INTx line asserted, mask it and return
|
|
||||||
* true in that case. False is returned if no interrupt was pending.
|
|
||||||
*/
|
|
||||||
bool pci_check_and_mask_intx(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
return pci_check_and_set_intx_mask(dev, true);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pci_check_and_unmask_intx - unmask INTx if no interrupt is pending
|
|
||||||
* @dev: the PCI device to operate on
|
|
||||||
*
|
|
||||||
* Check if the device dev has its INTx line asserted, unmask it if not and
|
|
||||||
* return true. False is returned and the mask remains active if there was
|
|
||||||
* still an interrupt pending.
|
|
||||||
*/
|
|
||||||
bool pci_check_and_unmask_intx(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
return pci_check_and_set_intx_mask(dev, false);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_wait_for_pending_transaction - wait for pending transaction
|
* pci_wait_for_pending_transaction - wait for pending transaction
|
||||||
* @dev: the PCI device to operate on
|
* @dev: the PCI device to operate on
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
|
||||||
/*
|
|
||||||
* Support routines for initializing a PCI subsystem
|
|
||||||
*
|
|
||||||
* Extruded from code written by
|
|
||||||
* Dave Rusling (david.rusling@reo.mts.dec.com)
|
|
||||||
* David Mosberger (davidm@cs.arizona.edu)
|
|
||||||
* David Miller (davem@redhat.com)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/pci.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/ioport.h>
|
|
||||||
#include <linux/cache.h>
|
|
||||||
#include "pci.h"
|
|
||||||
|
|
||||||
void pci_assign_irq(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
u8 pin;
|
|
||||||
u8 slot = -1;
|
|
||||||
int irq = 0;
|
|
||||||
struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
|
|
||||||
|
|
||||||
if (!(hbrg->map_irq)) {
|
|
||||||
pci_dbg(dev, "runtime IRQ mapping not provided by arch\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If this device is not on the primary bus, we need to figure out
|
|
||||||
* which interrupt pin it will come in on. We know which slot it
|
|
||||||
* will come in on because that slot is where the bridge is. Each
|
|
||||||
* time the interrupt line passes through a PCI-PCI bridge we must
|
|
||||||
* apply the swizzle function.
|
|
||||||
*/
|
|
||||||
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
|
|
||||||
/* Cope with illegal. */
|
|
||||||
if (pin > 4)
|
|
||||||
pin = 1;
|
|
||||||
|
|
||||||
if (pin) {
|
|
||||||
/* Follow the chain of bridges, swizzling as we go. */
|
|
||||||
if (hbrg->swizzle_irq)
|
|
||||||
slot = (*(hbrg->swizzle_irq))(dev, &pin);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If a swizzling function is not used, map_irq() must
|
|
||||||
* ignore slot.
|
|
||||||
*/
|
|
||||||
irq = (*(hbrg->map_irq))(dev, slot, pin);
|
|
||||||
if (irq == -1)
|
|
||||||
irq = 0;
|
|
||||||
}
|
|
||||||
dev->irq = irq;
|
|
||||||
|
|
||||||
pci_dbg(dev, "assign IRQ: got %d\n", dev->irq);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Always tell the device, so the driver knows what is the real IRQ
|
|
||||||
* to use; the device does not use it.
|
|
||||||
*/
|
|
||||||
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user