162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCI IRQ handling code 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> 662306a36Sopenharmony_ci * Copyright (C) 2017 Christoph Hellwig. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/device.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/export.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/** 1562306a36Sopenharmony_ci * pci_request_irq - allocate an interrupt line for a PCI device 1662306a36Sopenharmony_ci * @dev: PCI device to operate on 1762306a36Sopenharmony_ci * @nr: device-relative interrupt vector index (0-based). 1862306a36Sopenharmony_ci * @handler: Function to be called when the IRQ occurs. 1962306a36Sopenharmony_ci * Primary handler for threaded interrupts. 2062306a36Sopenharmony_ci * If NULL and thread_fn != NULL the default primary handler is 2162306a36Sopenharmony_ci * installed. 2262306a36Sopenharmony_ci * @thread_fn: Function called from the IRQ handler thread 2362306a36Sopenharmony_ci * If NULL, no IRQ thread is created 2462306a36Sopenharmony_ci * @dev_id: Cookie passed back to the handler function 2562306a36Sopenharmony_ci * @fmt: Printf-like format string naming the handler 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * This call allocates interrupt resources and enables the interrupt line and 2862306a36Sopenharmony_ci * IRQ handling. From the point this call is made @handler and @thread_fn may 2962306a36Sopenharmony_ci * be invoked. All interrupts requested using this function might be shared. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * @dev_id must not be NULL and must be globally unique. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ciint pci_request_irq(struct pci_dev *dev, unsigned int nr, irq_handler_t handler, 3462306a36Sopenharmony_ci irq_handler_t thread_fn, void *dev_id, const char *fmt, ...) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci va_list ap; 3762306a36Sopenharmony_ci int ret; 3862306a36Sopenharmony_ci char *devname; 3962306a36Sopenharmony_ci unsigned long irqflags = IRQF_SHARED; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (!handler) 4262306a36Sopenharmony_ci irqflags |= IRQF_ONESHOT; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci va_start(ap, fmt); 4562306a36Sopenharmony_ci devname = kvasprintf(GFP_KERNEL, fmt, ap); 4662306a36Sopenharmony_ci va_end(ap); 4762306a36Sopenharmony_ci if (!devname) 4862306a36Sopenharmony_ci return -ENOMEM; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci ret = request_threaded_irq(pci_irq_vector(dev, nr), handler, thread_fn, 5162306a36Sopenharmony_ci irqflags, devname, dev_id); 5262306a36Sopenharmony_ci if (ret) 5362306a36Sopenharmony_ci kfree(devname); 5462306a36Sopenharmony_ci return ret; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ciEXPORT_SYMBOL(pci_request_irq); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * pci_free_irq - free an interrupt allocated with pci_request_irq 6062306a36Sopenharmony_ci * @dev: PCI device to operate on 6162306a36Sopenharmony_ci * @nr: device-relative interrupt vector index (0-based). 6262306a36Sopenharmony_ci * @dev_id: Device identity to free 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * Remove an interrupt handler. The handler is removed and if the interrupt 6562306a36Sopenharmony_ci * line is no longer in use by any driver it is disabled. The caller must 6662306a36Sopenharmony_ci * ensure the interrupt is disabled on the device before calling this function. 6762306a36Sopenharmony_ci * The function does not return until any executing interrupts for this IRQ 6862306a36Sopenharmony_ci * have completed. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * This function must not be called from interrupt context. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_civoid pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci kfree(free_irq(pci_irq_vector(dev, nr), dev_id)); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ciEXPORT_SYMBOL(pci_free_irq); 77