18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCI IRQ handling code
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
68c2ecf20Sopenharmony_ci * Copyright (C) 2017 Christoph Hellwig.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/device.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/export.h>
128c2ecf20Sopenharmony_ci#include <linux/pci.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/**
158c2ecf20Sopenharmony_ci * pci_request_irq - allocate an interrupt line for a PCI device
168c2ecf20Sopenharmony_ci * @dev:	PCI device to operate on
178c2ecf20Sopenharmony_ci * @nr:		device-relative interrupt vector index (0-based).
188c2ecf20Sopenharmony_ci * @handler:	Function to be called when the IRQ occurs.
198c2ecf20Sopenharmony_ci *		Primary handler for threaded interrupts.
208c2ecf20Sopenharmony_ci *		If NULL and thread_fn != NULL the default primary handler is
218c2ecf20Sopenharmony_ci *		installed.
228c2ecf20Sopenharmony_ci * @thread_fn:	Function called from the IRQ handler thread
238c2ecf20Sopenharmony_ci *		If NULL, no IRQ thread is created
248c2ecf20Sopenharmony_ci * @dev_id:	Cookie passed back to the handler function
258c2ecf20Sopenharmony_ci * @fmt:	Printf-like format string naming the handler
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * This call allocates interrupt resources and enables the interrupt line and
288c2ecf20Sopenharmony_ci * IRQ handling. From the point this call is made @handler and @thread_fn may
298c2ecf20Sopenharmony_ci * be invoked.  All interrupts requested using this function might be shared.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * @dev_id must not be NULL and must be globally unique.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ciint pci_request_irq(struct pci_dev *dev, unsigned int nr, irq_handler_t handler,
348c2ecf20Sopenharmony_ci		irq_handler_t thread_fn, void *dev_id, const char *fmt, ...)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	va_list ap;
378c2ecf20Sopenharmony_ci	int ret;
388c2ecf20Sopenharmony_ci	char *devname;
398c2ecf20Sopenharmony_ci	unsigned long irqflags = IRQF_SHARED;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (!handler)
428c2ecf20Sopenharmony_ci		irqflags |= IRQF_ONESHOT;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	va_start(ap, fmt);
458c2ecf20Sopenharmony_ci	devname = kvasprintf(GFP_KERNEL, fmt, ap);
468c2ecf20Sopenharmony_ci	va_end(ap);
478c2ecf20Sopenharmony_ci	if (!devname)
488c2ecf20Sopenharmony_ci		return -ENOMEM;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	ret = request_threaded_irq(pci_irq_vector(dev, nr), handler, thread_fn,
518c2ecf20Sopenharmony_ci				   irqflags, devname, dev_id);
528c2ecf20Sopenharmony_ci	if (ret)
538c2ecf20Sopenharmony_ci		kfree(devname);
548c2ecf20Sopenharmony_ci	return ret;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_request_irq);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/**
598c2ecf20Sopenharmony_ci * pci_free_irq - free an interrupt allocated with pci_request_irq
608c2ecf20Sopenharmony_ci * @dev:	PCI device to operate on
618c2ecf20Sopenharmony_ci * @nr:		device-relative interrupt vector index (0-based).
628c2ecf20Sopenharmony_ci * @dev_id:	Device identity to free
638c2ecf20Sopenharmony_ci *
648c2ecf20Sopenharmony_ci * Remove an interrupt handler. The handler is removed and if the interrupt
658c2ecf20Sopenharmony_ci * line is no longer in use by any driver it is disabled.  The caller must
668c2ecf20Sopenharmony_ci * ensure the interrupt is disabled on the device before calling this function.
678c2ecf20Sopenharmony_ci * The function does not return until any executing interrupts for this IRQ
688c2ecf20Sopenharmony_ci * have completed.
698c2ecf20Sopenharmony_ci *
708c2ecf20Sopenharmony_ci * This function must not be called from interrupt context.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_civoid pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	kfree(free_irq(pci_irq_vector(dev, nr), dev_id));
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_free_irq);
77