mirror of
https://github.com/torvalds/linux.git
synced 2025-11-03 01:59:51 +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;
|
return this->irq == match->irq && this->dev_id == match->dev_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int devm_request_result(struct device *dev, int rc, unsigned int irq,
|
||||||
* devm_request_threaded_irq - allocate an interrupt line for a managed device
|
irq_handler_t handler, irq_handler_t thread_fn,
|
||||||
* @dev: device to request interrupt for
|
const char *devname)
|
||||||
* @irq: Interrupt line to allocate
|
{
|
||||||
* @handler: Function to be called when the IRQ occurs
|
if (rc >= 0)
|
||||||
* @thread_fn: function to be called in a threaded interrupt context. NULL
|
return rc;
|
||||||
* for devices which handle everything in @handler
|
|
||||||
* @irqflags: Interrupt type flags
|
return dev_err_probe(dev, rc, "request_irq(%u) %ps %ps %s\n",
|
||||||
* @devname: An ascii name for the claiming device, dev_name(dev) if NULL
|
irq, handler, thread_fn, devname ? : "");
|
||||||
* @dev_id: A cookie passed back to the handler function
|
}
|
||||||
*
|
|
||||||
* Except for the extra @dev argument, this function takes the
|
static int __devm_request_threaded_irq(struct device *dev, unsigned int irq,
|
||||||
* same arguments and performs the same function as
|
irq_handler_t handler,
|
||||||
* request_threaded_irq(). IRQs requested with this function will be
|
irq_handler_t thread_fn,
|
||||||
* automatically freed on driver detach.
|
unsigned long irqflags,
|
||||||
*
|
const char *devname, void *dev_id)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
struct irq_devres *dr;
|
struct irq_devres *dr;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
@ -78,28 +71,48 @@ int devm_request_threaded_irq(struct device *dev, unsigned int irq,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(devm_request_threaded_irq);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* devm_request_any_context_irq - allocate an interrupt line for a managed device
|
* devm_request_threaded_irq - allocate an interrupt line for a managed device with error logging
|
||||||
* @dev: device to request interrupt for
|
* @dev: Device to request interrupt for
|
||||||
* @irq: Interrupt line to allocate
|
* @irq: Interrupt line to allocate
|
||||||
* @handler: Function to be called when the IRQ occurs
|
* @handler: Function to be called when the interrupt occurs
|
||||||
* @irqflags: Interrupt type flags
|
* @thread_fn: Function to be called in a threaded interrupt context. NULL
|
||||||
* @devname: An ascii name for the claiming device, dev_name(dev) if NULL
|
* for devices which handle everything in @handler
|
||||||
* @dev_id: A cookie passed back to the handler function
|
* @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
|
* Except for the extra @dev argument, this function takes the same
|
||||||
* same arguments and performs the same function as
|
* arguments and performs the same function as request_threaded_irq().
|
||||||
* request_any_context_irq(). IRQs requested with this function will be
|
* Interrupts requested with this function will be automatically freed on
|
||||||
* automatically freed on driver detach.
|
* driver detach.
|
||||||
*
|
*
|
||||||
* If an IRQ allocated with this function needs to be freed
|
* If an interrupt allocated with this function needs to be freed
|
||||||
* separately, devm_free_irq() must be used.
|
* 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,
|
int devm_request_threaded_irq(struct device *dev, unsigned int irq,
|
||||||
irq_handler_t handler, unsigned long irqflags,
|
irq_handler_t handler, irq_handler_t thread_fn,
|
||||||
const char *devname, void *dev_id)
|
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;
|
struct irq_devres *dr;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
@ -124,6 +137,40 @@ int devm_request_any_context_irq(struct device *dev, unsigned int irq,
|
||||||
|
|
||||||
return rc;
|
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);
|
EXPORT_SYMBOL(devm_request_any_context_irq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue