Quelle irq.c
Sprache: C
// SPDX-License-Identifier: GPL-2.0
/*
* PCI IRQ handling code
*
* Copyright ( c ) 2008 James Bottomley < James . Bottomley @ HansenPartnership . com >
* Copyright ( C ) 2017 Christoph Hellwig .
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include "pci.h"
/**
* pci_request_irq - allocate an interrupt line for a PCI device
* @ dev : PCI device to operate on
* @ nr : device - relative interrupt vector index ( 0 - based ) .
* @ handler : Function to be called when the IRQ occurs .
* Primary handler for threaded interrupts .
* If NULL and thread_fn ! = NULL the default primary handler is
* installed .
* @ thread_fn : Function called from the IRQ handler thread
* If NULL , no IRQ thread is created
* @ dev_id : Cookie passed back to the handler function
* @ fmt : Printf - like format string naming the handler
*
* This call allocates interrupt resources and enables the interrupt line and
* IRQ handling . From the point this call is made @ handler and @ thread_fn may
* be invoked . All interrupts requested using this function might be shared .
*
* @ dev_id must not be NULL and must be globally unique .
*/
int pci_request_irq(struct pci_dev *dev, unsigned int nr, irq_handler_t handler,
irq_handler_t thread_fn, void *dev_id, const char *fmt, ...)
{
va_list ap;
int ret;
char *devname;
unsigned long irqflags = IRQF_SHARED;
if (!handler)
irqflags |= IRQF_ONESHOT;
va_start(ap, fmt);
devname = kvasprintf(GFP_KERNEL, fmt, ap);
va_end(ap);
if (!devname)
return -ENOMEM;
ret = request_threaded_irq(pci_irq_vector(dev, nr), handler, thread_fn,
irqflags, devname, dev_id);
if (ret)
kfree(devname);
return ret;
}
EXPORT_SYMBOL(pci_request_irq);
/**
* pci_free_irq - free an interrupt allocated with pci_request_irq
* @ dev : PCI device to operate on
* @ nr : device - relative interrupt vector index ( 0 - based ) .
* @ dev_id : Device identity to free
*
* Remove an interrupt handler . The handler is removed and if the interrupt
* line is no longer in use by any driver it is disabled . The caller must
* ensure the interrupt is disabled on the device before calling this function .
* The function does not return until any executing interrupts for this IRQ
* have completed .
*
* This function must not be called from interrupt context .
*/
void pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id)
{
kfree(free_irq(pci_irq_vector(dev, nr), dev_id));
}
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)
{
}
Messung V0.5 in Prozent C=95 H=93 G=93
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland
2026-10-10
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1126438
#Domains=1897691