mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
genirq: Add rcuref count to struct irq_desc
Prepare for a smarter iterator for /proc/interrupts so that the next interrupt descriptor can be cached after lookup. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Tested-by: Michael Kelley <mhklinux@outlook.com> Reviewed-by: Dmitry Ilvokhin <d@ilvokhin.com> Link: https://patch.msgid.link/20260517194931.917415190@kernel.org
This commit is contained in:
@@ -70,6 +70,7 @@ struct irq_redirect {
|
||||
* IRQF_NO_SUSPEND set
|
||||
* @force_resume_depth: number of irqactions on a irq descriptor with
|
||||
* IRQF_FORCE_RESUME set
|
||||
* @refcnt: Reference count mainly for /proc/interrupts
|
||||
* @rcu: rcu head for delayed free
|
||||
* @kobj: kobject used to represent this struct in sysfs
|
||||
* @request_mutex: mutex to protect request/free before locking desc->lock
|
||||
@@ -119,6 +120,7 @@ struct irq_desc {
|
||||
struct dentry *debugfs_file;
|
||||
const char *dev_name;
|
||||
#endif
|
||||
rcuref_t refcnt;
|
||||
#ifdef CONFIG_SPARSE_IRQ
|
||||
struct rcu_head rcu;
|
||||
struct kobject kobj;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/irqdesc.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/rcuref.h>
|
||||
#include <linux/sched/clock.h>
|
||||
|
||||
#ifdef CONFIG_SPARSE_IRQ
|
||||
@@ -101,9 +102,23 @@ extern void unmask_irq(struct irq_desc *desc);
|
||||
extern void unmask_threaded_irq(struct irq_desc *desc);
|
||||
|
||||
#ifdef CONFIG_SPARSE_IRQ
|
||||
static inline void irq_mark_irq(unsigned int irq) { }
|
||||
static __always_inline void irq_mark_irq(unsigned int irq) { }
|
||||
void irq_desc_free_rcu(struct irq_desc *desc);
|
||||
|
||||
static __always_inline bool irq_desc_get_ref(struct irq_desc *desc)
|
||||
{
|
||||
return rcuref_get(&desc->refcnt);
|
||||
}
|
||||
|
||||
static __always_inline void irq_desc_put_ref(struct irq_desc *desc)
|
||||
{
|
||||
if (rcuref_put(&desc->refcnt))
|
||||
irq_desc_free_rcu(desc);
|
||||
}
|
||||
#else
|
||||
extern void irq_mark_irq(unsigned int irq);
|
||||
static __always_inline bool irq_desc_get_ref(struct irq_desc *desc) { return true; }
|
||||
static __always_inline void irq_desc_put_ref(struct irq_desc *desc) { }
|
||||
#endif
|
||||
|
||||
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc);
|
||||
|
||||
@@ -137,6 +137,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
|
||||
desc->tot_count = 0;
|
||||
desc->name = NULL;
|
||||
desc->owner = owner;
|
||||
rcuref_init(&desc->refcnt, 1);
|
||||
desc_smp_init(desc, node, affinity);
|
||||
}
|
||||
|
||||
@@ -465,6 +466,17 @@ static void delayed_free_desc(struct rcu_head *rhp)
|
||||
kobject_put(&desc->kobj);
|
||||
}
|
||||
|
||||
void irq_desc_free_rcu(struct irq_desc *desc)
|
||||
{
|
||||
/*
|
||||
* We free the descriptor, masks and stat fields via RCU. That
|
||||
* allows demultiplex interrupts to do rcu based management of
|
||||
* the child interrupts.
|
||||
* This also allows us to use rcu in kstat_irqs_usr().
|
||||
*/
|
||||
call_rcu(&desc->rcu, delayed_free_desc);
|
||||
}
|
||||
|
||||
static void free_desc(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
@@ -483,14 +495,7 @@ static void free_desc(unsigned int irq)
|
||||
*/
|
||||
irq_sysfs_del(desc);
|
||||
delete_irq_desc(irq);
|
||||
|
||||
/*
|
||||
* We free the descriptor, masks and stat fields via RCU. That
|
||||
* allows demultiplex interrupts to do rcu based management of
|
||||
* the child interrupts.
|
||||
* This also allows us to use rcu in kstat_irqs_usr().
|
||||
*/
|
||||
call_rcu(&desc->rcu, delayed_free_desc);
|
||||
irq_desc_put_ref(desc);
|
||||
}
|
||||
|
||||
static int alloc_descs(unsigned int start, unsigned int cnt, int node,
|
||||
|
||||
Reference in New Issue
Block a user