mirror of
https://github.com/torvalds/linux.git
synced 2025-11-02 17:49:03 +02:00
genirq/devres: Add error handling in devm_request_*_irq()
devm_request_threaded_irq() and devm_request_any_context_irq() currently don't print any error message when interrupt registration fails. This forces each driver to implement redundant error logging - over 2,000 lines of error messages exist across drivers. Additionally, when upper-layer functions propagate these errors without logging, critical debugging information is lost. Add devm_request_result() helper to unify error reporting via dev_err_probe(), Use it in devm_request_threaded_irq() and devm_request_any_context_irq() printing device name, IRQ number, handler functions, and error code on failure automatically. Co-developed-by: Yangtao Li <frank.li@vivo.com> Signed-off-by: Yangtao Li <frank.li@vivo.com> Signed-off-by: Pan Chuang <panchuang@vivo.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/all/20250805092922.135500-2-panchuang@vivo.com
This commit is contained in:
parent
7a721a2fee
commit
55b48e23f5
1 changed files with 87 additions and 40 deletions
|
|
@ -30,29 +30,22 @@ static int devm_irq_match(struct device *dev, void *res, void *data)
|
|||
return this->irq == match->irq && this->dev_id == match->dev_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_request_threaded_irq - allocate an interrupt line for a managed device
|
||||
* @dev: device to request interrupt for
|
||||
* @irq: Interrupt line to allocate
|
||||
* @handler: Function to be called when the IRQ occurs
|
||||
* @thread_fn: function to be called in a threaded interrupt context. NULL
|
||||
* for devices which handle everything in @handler
|
||||
* @irqflags: Interrupt type flags
|
||||
* @devname: An ascii name for the claiming device, dev_name(dev) if NULL
|
||||
* @dev_id: A cookie passed back to the handler function
|
||||
*
|
||||
* Except for the extra @dev argument, this function takes the
|
||||
* same arguments and performs the same function as
|
||||
* request_threaded_irq(). IRQs requested with this function will be
|
||||
* automatically freed on driver detach.
|
||||
*
|
||||
* If an IRQ allocated with this function needs to be freed
|
||||
* separately, devm_free_irq() must be used.
|
||||
*/
|
||||
int devm_request_threaded_irq(struct device *dev, unsigned int irq,
|
||||
irq_handler_t handler, irq_handler_t thread_fn,
|
||||
unsigned long irqflags, const char *devname,
|
||||
void *dev_id)
|
||||
static int devm_request_result(struct device *dev, int rc, unsigned int irq,
|
||||
irq_handler_t handler, irq_handler_t thread_fn,
|
||||
const char *devname)
|
||||
{
|
||||
if (rc >= 0)
|
||||
return rc;
|
||||
|
||||
return dev_err_probe(dev, rc, "request_irq(%u) %ps %ps %s\n",
|
||||
irq, handler, thread_fn, devname ? : "");
|
||||
}
|
||||
|
||||
static int __devm_request_threaded_irq(struct device *dev, unsigned int irq,
|
||||
irq_handler_t handler,
|
||||
irq_handler_t thread_fn,
|
||||
unsigned long irqflags,
|
||||
const char *devname, void *dev_id)
|
||||
{
|
||||
struct irq_devres *dr;
|
||||
int rc;
|
||||
|
|
@ -78,28 +71,48 @@ int devm_request_threaded_irq(struct device *dev, unsigned int irq,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_request_threaded_irq);
|
||||
|
||||
/**
|
||||
* devm_request_any_context_irq - allocate an interrupt line for a managed device
|
||||
* @dev: device to request interrupt for
|
||||
* @irq: Interrupt line to allocate
|
||||
* @handler: Function to be called when the IRQ occurs
|
||||
* @irqflags: Interrupt type flags
|
||||
* @devname: An ascii name for the claiming device, dev_name(dev) if NULL
|
||||
* @dev_id: A cookie passed back to the handler function
|
||||
* devm_request_threaded_irq - allocate an interrupt line for a managed device with error logging
|
||||
* @dev: Device to request interrupt for
|
||||
* @irq: Interrupt line to allocate
|
||||
* @handler: Function to be called when the interrupt occurs
|
||||
* @thread_fn: Function to be called in a threaded interrupt context. NULL
|
||||
* for devices which handle everything in @handler
|
||||
* @irqflags: Interrupt type flags
|
||||
* @devname: An ascii name for the claiming device, dev_name(dev) if NULL
|
||||
* @dev_id: A cookie passed back to the handler function
|
||||
*
|
||||
* Except for the extra @dev argument, this function takes the
|
||||
* same arguments and performs the same function as
|
||||
* request_any_context_irq(). IRQs requested with this function will be
|
||||
* automatically freed on driver detach.
|
||||
* Except for the extra @dev argument, this function takes the same
|
||||
* arguments and performs the same function as request_threaded_irq().
|
||||
* Interrupts requested with this function will be automatically freed on
|
||||
* driver detach.
|
||||
*
|
||||
* If an IRQ allocated with this function needs to be freed
|
||||
* separately, devm_free_irq() must be used.
|
||||
* If an interrupt allocated with this function needs to be freed
|
||||
* separately, devm_free_irq() must be used.
|
||||
*
|
||||
* When the request fails, an error message is printed with contextual
|
||||
* information (device name, interrupt number, handler functions and
|
||||
* error code). Don't add extra error messages at the call sites.
|
||||
*
|
||||
* Return: 0 on success or a negative error number.
|
||||
*/
|
||||
int devm_request_any_context_irq(struct device *dev, unsigned int irq,
|
||||
irq_handler_t handler, unsigned long irqflags,
|
||||
const char *devname, void *dev_id)
|
||||
int devm_request_threaded_irq(struct device *dev, unsigned int irq,
|
||||
irq_handler_t handler, irq_handler_t thread_fn,
|
||||
unsigned long irqflags, const char *devname,
|
||||
void *dev_id)
|
||||
{
|
||||
int rc = __devm_request_threaded_irq(dev, irq, handler, thread_fn,
|
||||
irqflags, devname, dev_id);
|
||||
|
||||
return devm_request_result(dev, rc, irq, handler, thread_fn, devname);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_request_threaded_irq);
|
||||
|
||||
static int __devm_request_any_context_irq(struct device *dev, unsigned int irq,
|
||||
irq_handler_t handler,
|
||||
unsigned long irqflags,
|
||||
const char *devname, void *dev_id)
|
||||
{
|
||||
struct irq_devres *dr;
|
||||
int rc;
|
||||
|
|
@ -124,6 +137,40 @@ int devm_request_any_context_irq(struct device *dev, unsigned int irq,
|
|||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_request_any_context_irq - allocate an interrupt line for a managed device with error logging
|
||||
* @dev: Device to request interrupt for
|
||||
* @irq: Interrupt line to allocate
|
||||
* @handler: Function to be called when the interrupt occurs
|
||||
* @irqflags: Interrupt type flags
|
||||
* @devname: An ascii name for the claiming device, dev_name(dev) if NULL
|
||||
* @dev_id: A cookie passed back to the handler function
|
||||
*
|
||||
* Except for the extra @dev argument, this function takes the same
|
||||
* arguments and performs the same function as request_any_context_irq().
|
||||
* Interrupts requested with this function will be automatically freed on
|
||||
* driver detach.
|
||||
*
|
||||
* If an interrupt allocated with this function needs to be freed
|
||||
* separately, devm_free_irq() must be used.
|
||||
*
|
||||
* When the request fails, an error message is printed with contextual
|
||||
* information (device name, interrupt number, handler functions and
|
||||
* error code). Don't add extra error messages at the call sites.
|
||||
*
|
||||
* Return: IRQC_IS_HARDIRQ or IRQC_IS_NESTED on success, or a negative error
|
||||
* number.
|
||||
*/
|
||||
int devm_request_any_context_irq(struct device *dev, unsigned int irq,
|
||||
irq_handler_t handler, unsigned long irqflags,
|
||||
const char *devname, void *dev_id)
|
||||
{
|
||||
int rc = __devm_request_any_context_irq(dev, irq, handler, irqflags,
|
||||
devname, dev_id);
|
||||
|
||||
return devm_request_result(dev, rc, irq, handler, NULL, devname);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_request_any_context_irq);
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue