Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * PCI IRQ handling code 4 : : * 5 : : * Copyright (c) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> 6 : : * Copyright (C) 2017 Christoph Hellwig. 7 : : */ 8 : : 9 : : #include <linux/acpi.h> 10 : : #include <linux/device.h> 11 : : #include <linux/kernel.h> 12 : : #include <linux/export.h> 13 : : #include <linux/pci.h> 14 : : 15 : 0 : static void pci_note_irq_problem(struct pci_dev *pdev, const char *reason) 16 : : { 17 : 0 : struct pci_dev *parent = to_pci_dev(pdev->dev.parent); 18 : : 19 [ # # ]: 0 : pci_err(pdev, "Potentially misrouted IRQ (Bridge %s %04x:%04x)\n", 20 : : dev_name(&parent->dev), parent->vendor, parent->device); 21 : 0 : pci_err(pdev, "%s\n", reason); 22 : 0 : pci_err(pdev, "Please report to linux-kernel@vger.kernel.org\n"); 23 : 0 : WARN_ON(1); 24 : 0 : } 25 : : 26 : : /** 27 : : * pci_lost_interrupt - reports a lost PCI interrupt 28 : : * @pdev: device whose interrupt is lost 29 : : * 30 : : * The primary function of this routine is to report a lost interrupt 31 : : * in a standard way which users can recognise (instead of blaming the 32 : : * driver). 33 : : * 34 : : * Returns: 35 : : * a suggestion for fixing it (although the driver is not required to 36 : : * act on this). 37 : : */ 38 : 0 : enum pci_lost_interrupt_reason pci_lost_interrupt(struct pci_dev *pdev) 39 : : { 40 [ # # ]: 0 : if (pdev->msi_enabled || pdev->msix_enabled) { 41 : 0 : enum pci_lost_interrupt_reason ret; 42 : : 43 [ # # ]: 0 : if (pdev->msix_enabled) { 44 : 0 : pci_note_irq_problem(pdev, "MSIX routing failure"); 45 : 0 : ret = PCI_LOST_IRQ_DISABLE_MSIX; 46 : : } else { 47 : 0 : pci_note_irq_problem(pdev, "MSI routing failure"); 48 : 0 : ret = PCI_LOST_IRQ_DISABLE_MSI; 49 : : } 50 : 0 : return ret; 51 : : } 52 : : #ifdef CONFIG_ACPI 53 [ # # # # ]: 0 : if (!(acpi_disabled || acpi_noirq)) { 54 : 0 : pci_note_irq_problem(pdev, "Potential ACPI misrouting please reboot with acpi=noirq"); 55 : : /* currently no way to fix acpi on the fly */ 56 : 0 : return PCI_LOST_IRQ_DISABLE_ACPI; 57 : : } 58 : : #endif 59 : 0 : pci_note_irq_problem(pdev, "unknown cause (not MSI or ACPI)"); 60 : 0 : return PCI_LOST_IRQ_NO_INFORMATION; 61 : : } 62 : : EXPORT_SYMBOL(pci_lost_interrupt); 63 : : 64 : : /** 65 : : * pci_request_irq - allocate an interrupt line for a PCI device 66 : : * @dev: PCI device to operate on 67 : : * @nr: device-relative interrupt vector index (0-based). 68 : : * @handler: Function to be called when the IRQ occurs. 69 : : * Primary handler for threaded interrupts. 70 : : * If NULL and thread_fn != NULL the default primary handler is 71 : : * installed. 72 : : * @thread_fn: Function called from the IRQ handler thread 73 : : * If NULL, no IRQ thread is created 74 : : * @dev_id: Cookie passed back to the handler function 75 : : * @fmt: Printf-like format string naming the handler 76 : : * 77 : : * This call allocates interrupt resources and enables the interrupt line and 78 : : * IRQ handling. From the point this call is made @handler and @thread_fn may 79 : : * be invoked. All interrupts requested using this function might be shared. 80 : : * 81 : : * @dev_id must not be NULL and must be globally unique. 82 : : */ 83 : 0 : int pci_request_irq(struct pci_dev *dev, unsigned int nr, irq_handler_t handler, 84 : : irq_handler_t thread_fn, void *dev_id, const char *fmt, ...) 85 : : { 86 : 0 : va_list ap; 87 : 0 : int ret; 88 : 0 : char *devname; 89 : 0 : unsigned long irqflags = IRQF_SHARED; 90 : : 91 [ # # ]: 0 : if (!handler) 92 : 0 : irqflags |= IRQF_ONESHOT; 93 : : 94 : 0 : va_start(ap, fmt); 95 : 0 : devname = kvasprintf(GFP_KERNEL, fmt, ap); 96 : 0 : va_end(ap); 97 : : 98 : 0 : ret = request_threaded_irq(pci_irq_vector(dev, nr), handler, thread_fn, 99 : : irqflags, devname, dev_id); 100 [ # # ]: 0 : if (ret) 101 : 0 : kfree(devname); 102 : 0 : return ret; 103 : : } 104 : : EXPORT_SYMBOL(pci_request_irq); 105 : : 106 : : /** 107 : : * pci_free_irq - free an interrupt allocated with pci_request_irq 108 : : * @dev: PCI device to operate on 109 : : * @nr: device-relative interrupt vector index (0-based). 110 : : * @dev_id: Device identity to free 111 : : * 112 : : * Remove an interrupt handler. The handler is removed and if the interrupt 113 : : * line is no longer in use by any driver it is disabled. The caller must 114 : : * ensure the interrupt is disabled on the device before calling this function. 115 : : * The function does not return until any executing interrupts for this IRQ 116 : : * have completed. 117 : : * 118 : : * This function must not be called from interrupt context. 119 : : */ 120 : 0 : void pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id) 121 : : { 122 : 0 : kfree(free_irq(pci_irq_vector(dev, nr), dev_id)); 123 : 0 : } 124 : : EXPORT_SYMBOL(pci_free_irq);