brintos

brintos / linux-shallow public Read only

0
0
Text · 7.6 KiB · 4555630 Raw
281 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * PCI IRQ handling code4 *5 * Copyright (c) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>6 * Copyright (C) 2017 Christoph Hellwig.7 */8 9#include <linux/device.h>10#include <linux/kernel.h>11#include <linux/errno.h>12#include <linux/export.h>13#include <linux/interrupt.h>14#include <linux/pci.h>15 16#include "pci.h"17 18/**19 * pci_request_irq - allocate an interrupt line for a PCI device20 * @dev:	PCI device to operate on21 * @nr:		device-relative interrupt vector index (0-based).22 * @handler:	Function to be called when the IRQ occurs.23 *		Primary handler for threaded interrupts.24 *		If NULL and thread_fn != NULL the default primary handler is25 *		installed.26 * @thread_fn:	Function called from the IRQ handler thread27 *		If NULL, no IRQ thread is created28 * @dev_id:	Cookie passed back to the handler function29 * @fmt:	Printf-like format string naming the handler30 *31 * This call allocates interrupt resources and enables the interrupt line and32 * IRQ handling. From the point this call is made @handler and @thread_fn may33 * be invoked.  All interrupts requested using this function might be shared.34 *35 * @dev_id must not be NULL and must be globally unique.36 */37int pci_request_irq(struct pci_dev *dev, unsigned int nr, irq_handler_t handler,38		irq_handler_t thread_fn, void *dev_id, const char *fmt, ...)39{40	va_list ap;41	int ret;42	char *devname;43	unsigned long irqflags = IRQF_SHARED;44 45	if (!handler)46		irqflags |= IRQF_ONESHOT;47 48	va_start(ap, fmt);49	devname = kvasprintf(GFP_KERNEL, fmt, ap);50	va_end(ap);51	if (!devname)52		return -ENOMEM;53 54	ret = request_threaded_irq(pci_irq_vector(dev, nr), handler, thread_fn,55				   irqflags, devname, dev_id);56	if (ret)57		kfree(devname);58	return ret;59}60EXPORT_SYMBOL(pci_request_irq);61 62/**63 * pci_free_irq - free an interrupt allocated with pci_request_irq64 * @dev:	PCI device to operate on65 * @nr:		device-relative interrupt vector index (0-based).66 * @dev_id:	Device identity to free67 *68 * Remove an interrupt handler. The handler is removed and if the interrupt69 * line is no longer in use by any driver it is disabled.  The caller must70 * ensure the interrupt is disabled on the device before calling this function.71 * The function does not return until any executing interrupts for this IRQ72 * have completed.73 *74 * This function must not be called from interrupt context.75 */76void pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id)77{78	kfree(free_irq(pci_irq_vector(dev, nr), dev_id));79}80EXPORT_SYMBOL(pci_free_irq);81 82/**83 * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge84 * @dev: the PCI device85 * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)86 *87 * Perform INTx swizzling for a device behind one level of bridge.  This is88 * required by section 9.1 of the PCI-to-PCI bridge specification for devices89 * behind bridges on add-in cards.  For devices with ARI enabled, the slot90 * number is always 0 (see the Implementation Note in section 2.2.8.1 of91 * the PCI Express Base Specification, Revision 2.1)92 */93u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin)94{95	int slot;96 97	if (pci_ari_enabled(dev->bus))98		slot = 0;99	else100		slot = PCI_SLOT(dev->devfn);101 102	return (((pin - 1) + slot) % 4) + 1;103}104 105int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)106{107	u8 pin;108 109	pin = dev->pin;110	if (!pin)111		return -1;112 113	while (!pci_is_root_bus(dev->bus)) {114		pin = pci_swizzle_interrupt_pin(dev, pin);115		dev = dev->bus->self;116	}117	*bridge = dev;118	return pin;119}120 121/**122 * pci_common_swizzle - swizzle INTx all the way to root bridge123 * @dev: the PCI device124 * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)125 *126 * Perform INTx swizzling for a device.  This traverses through all PCI-to-PCI127 * bridges all the way up to a PCI root bus.128 */129u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)130{131	u8 pin = *pinp;132 133	while (!pci_is_root_bus(dev->bus)) {134		pin = pci_swizzle_interrupt_pin(dev, pin);135		dev = dev->bus->self;136	}137	*pinp = pin;138	return PCI_SLOT(dev->devfn);139}140EXPORT_SYMBOL_GPL(pci_common_swizzle);141 142void pci_assign_irq(struct pci_dev *dev)143{144	u8 pin;145	u8 slot = -1;146	int irq = 0;147	struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);148 149	if (!(hbrg->map_irq)) {150		pci_dbg(dev, "runtime IRQ mapping not provided by arch\n");151		return;152	}153 154	/*155	 * If this device is not on the primary bus, we need to figure out156	 * which interrupt pin it will come in on. We know which slot it157	 * will come in on because that slot is where the bridge is. Each158	 * time the interrupt line passes through a PCI-PCI bridge we must159	 * apply the swizzle function.160	 */161	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);162	/* Cope with illegal. */163	if (pin > 4)164		pin = 1;165 166	if (pin) {167		/* Follow the chain of bridges, swizzling as we go. */168		if (hbrg->swizzle_irq)169			slot = (*(hbrg->swizzle_irq))(dev, &pin);170 171		/*172		 * If a swizzling function is not used, map_irq() must173		 * ignore slot.174		 */175		irq = (*(hbrg->map_irq))(dev, slot, pin);176		if (irq == -1)177			irq = 0;178	}179	dev->irq = irq;180 181	pci_dbg(dev, "assign IRQ: got %d\n", dev->irq);182 183	/*184	 * Always tell the device, so the driver knows what is the real IRQ185	 * to use; the device does not use it.186	 */187	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);188}189 190static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)191{192	struct pci_bus *bus = dev->bus;193	bool mask_updated = true;194	u32 cmd_status_dword;195	u16 origcmd, newcmd;196	unsigned long flags;197	bool irq_pending;198 199	/*200	 * We do a single dword read to retrieve both command and status.201	 * Document assumptions that make this possible.202	 */203	BUILD_BUG_ON(PCI_COMMAND % 4);204	BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);205 206	raw_spin_lock_irqsave(&pci_lock, flags);207 208	bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);209 210	irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;211 212	/*213	 * Check interrupt status register to see whether our device214	 * triggered the interrupt (when masking) or the next IRQ is215	 * already pending (when unmasking).216	 */217	if (mask != irq_pending) {218		mask_updated = false;219		goto done;220	}221 222	origcmd = cmd_status_dword;223	newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;224	if (mask)225		newcmd |= PCI_COMMAND_INTX_DISABLE;226	if (newcmd != origcmd)227		bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);228 229done:230	raw_spin_unlock_irqrestore(&pci_lock, flags);231 232	return mask_updated;233}234 235/**236 * pci_check_and_mask_intx - mask INTx on pending interrupt237 * @dev: the PCI device to operate on238 *239 * Check if the device dev has its INTx line asserted, mask it and return240 * true in that case. False is returned if no interrupt was pending.241 */242bool pci_check_and_mask_intx(struct pci_dev *dev)243{244	return pci_check_and_set_intx_mask(dev, true);245}246EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);247 248/**249 * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending250 * @dev: the PCI device to operate on251 *252 * Check if the device dev has its INTx line asserted, unmask it if not and253 * return true. False is returned and the mask remains active if there was254 * still an interrupt pending.255 */256bool pci_check_and_unmask_intx(struct pci_dev *dev)257{258	return pci_check_and_set_intx_mask(dev, false);259}260EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);261 262/**263 * pcibios_penalize_isa_irq - penalize an ISA IRQ264 * @irq: ISA IRQ to penalize265 * @active: IRQ active or not266 *267 * Permits the platform to provide architecture-specific functionality when268 * penalizing ISA IRQs. This is the default implementation. Architecture269 * implementations can override this.270 */271void __weak pcibios_penalize_isa_irq(int irq, int active) {}272 273int __weak pcibios_alloc_irq(struct pci_dev *dev)274{275	return 0;276}277 278void __weak pcibios_free_irq(struct pci_dev *dev)279{280}281