irq/irq_sim: store multiple interrupt offsets in a bitmap
PATCH 1/1 irq/irq_sim: store multiple interrupt offsets in a bitmap
Two threads can try to fire the irq_sim with different offsets and will end up fighting for the irq_work asignment. Thomas Gleixner suggested a solution based on a bitfield where we set a bit for every offset associated with an interrupt that should be fired and then iterate over all set bits in the interrupt handler.
This is a slightly modified solution using a bitmap so that we don't impose a limit on the number of interrupts one can allocate with irq_sim.
--- include/linux/irq_sim.h | 2 +- kernel/irq/irq_sim.c | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-)
include/linux/irq_sim.h +1 -1
@@ -16,7 +16,7 @@struct irq_sim_work_ctx {struct irq_work work; -int irq; +unsigned long *pending; };struct irq_sim_irq_ctx {
kernel/irq/irq_sim.c +21 -2
@@ -34,9 +34,20 @@ static struct irq_chip irq_sim_irqchip = {static void irq_sim_handle_irq (struct irq_work *work) {struct irq_sim_work_ctx *work_ctx; +unsigned int offset =0 ; +struct irq_sim *sim; +int irqnum; work_ctx = container_of(work, struct irq_sim_work_ctx, work); -handle_simple_irq (irq_to_desc (work_ctx->irq)); + sim = container_of(work_ctx, struct irq_sim, work_ctx); + +while (!bitmap_empty (work_ctx->pending, sim->irq_count)) { + offset =find_next_bit (work_ctx->pending, + sim->irq_count, offset); +clear_bit (offset, work_ctx->pending); + irqnum =irq_sim_irqnum (sim, offset); +handle_simple_irq (irq_to_desc (irqnum)); + } }/**
@@ -63,6 +74,13 @@ int irq_sim_init(struct irq_sim *sim, unsigned int num_irqs)return sim->irq_base; } + sim->work_ctx.pending =bitmap_zalloc (num_irqs,GFP_KERNEL ); +if (!sim->work_ctx.pending) { +kfree (sim->irqs); +irq_free_descs (sim->irq_base, num_irqs); +return -ENOMEM ; + } +for (i =0 ; i < num_irqs; i++) { sim->irqs[i].irqnum = sim->irq_base + i; sim->irqs[i].enabled = false;
@@ -89,6 +107,7 @@ EXPORT_SYMBOL_GPL(irq_sim_init);void irq_sim_fini (struct irq_sim *sim) {irq_work_sync (&sim->work_ctx.work); +bitmap_free (sim->work_ctx.pending);irq_free_descs (sim->irq_base, sim->irq_count);kfree (sim->irqs); }
@@ -143,7 +162,7 @@ EXPORT_SYMBOL_GPL(devm_irq_sim_init);void irq_sim_fire (struct irq_sim *sim,unsigned int offset) {if (sim->irqs[offset].enabled) { - sim->work_ctx.irq =irq_sim_irqnum (sim, offset); +set_bit (offset, sim->work_ctx.pending);irq_work_queue (&sim->work_ctx.work); } }
Signature · 1 line
2.19.1
pt., 9 lis 2018 o 18:21 Bartosz Golaszewski <[email protected]> napisał(a):
Quoted 89 lines
Two threads can try to fire the
irq_simwith different offsets and will end up fighting for theirq_workasignment. Thomas Gleixner suggested a solution based on a bitfield where we set a bit for every offset associated with an interrupt that should be fired and then iterate over all set bits in the interrupt handler.This is a slightly modified solution using a bitmap so that we don't impose a limit on the number of interrupts one can allocate with
irq_sim.Suggested-by Thomas Gleixner <[email protected]>Signed-off-by Bartosz Golaszewski <[email protected]>--- include/linux/irq_sim.h | 2 +- kernel/irq/irq_sim.c | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-)include/linux/irq_sim.h +1
-1@@ -16,7 +16,7 @@struct irq_sim_work_ctx {struct irq_work work; -int irq; +unsigned long *pending; };struct irq_sim_irq_ctx {kernel/irq/irq_sim.c +21
-3@@ -34,9 +34,20 @@ static struct irq_chip irq_sim_irqchip = {static void irq_sim_handle_irq (struct irq_work *work) {struct irq_sim_work_ctx *work_ctx; +unsigned int offset =0 ; +struct irq_sim *sim; +int irqnum; work_ctx = container_of(work, struct irq_sim_work_ctx, work); -handle_simple_irq (irq_to_desc (work_ctx->irq)); + sim = container_of(work_ctx, struct irq_sim, work_ctx); + +while (!bitmap_empty (work_ctx->pending, sim->irq_count)) { + offset =find_next_bit (work_ctx->pending, + sim->irq_count, offset); +clear_bit (offset, work_ctx->pending); + irqnum =irq_sim_irqnum (sim, offset); +handle_simple_irq (irq_to_desc (irqnum)); + } }/** @@ -63,6 +74,13 @@ int irq_sim_init(struct irq_sim *sim, unsigned int num_irqs)return sim->irq_base; } + sim->work_ctx.pending =bitmap_zalloc (num_irqs,GFP_KERNEL ); +if (!sim->work_ctx.pending) { +kfree (sim->irqs); +irq_free_descs (sim->irq_base, num_irqs); +return -ENOMEM ; + } +for (i =0 ; i < num_irqs; i++) { sim->irqs[i].irqnum = sim->irq_base + i; sim->irqs[i].enabled = false;@@ -89,6 +107,7 @@ EXPORT_SYMBOL_GPL(irq_sim_init);void irq_sim_fini (struct irq_sim *sim) {irq_work_sync (&sim->work_ctx.work); +bitmap_free (sim->work_ctx.pending);irq_free_descs (sim->irq_base, sim->irq_count);kfree (sim->irqs); }@@ -143,7 +162,7 @@ EXPORT_SYMBOL_GPL(devm_irq_sim_init);void irq_sim_fire (struct irq_sim *sim,unsigned int offset) {if (sim->irqs[offset].enabled) { - sim->work_ctx.irq =irq_sim_irqnum (sim, offset); +set_bit (offset, sim->work_ctx.pending);irq_work_queue (&sim->work_ctx.work); } } --
Quoted 2 lines
2.19.1
Ping and Cc'ing Marc Zyngier. Any chance of getting this in for 4.21?
Bart
Quoted 86 lines · Bartosz Golaszewski
pt., 9 lis 2018 o 18:21 Bartosz Golaszewski <[email protected]> napisał(a):
Quoted 85 lines
Two threads can try to fire the
irq_simwith different offsets and will end up fighting for theirq_workasignment. Thomas Gleixner suggested a solution based on a bitfield where we set a bit for every offset associated with an interrupt that should be fired and then iterate over all set bits in the interrupt handler.This is a slightly modified solution using a bitmap so that we don't impose a limit on the number of interrupts one can allocate with
irq_sim.Suggested-by Thomas Gleixner <[email protected]>Signed-off-by Bartosz Golaszewski <[email protected]>--- include/linux/irq_sim.h | 2 +- kernel/irq/irq_sim.c | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-)include/linux/irq_sim.h +1
-1@@ -16,7 +16,7 @@struct irq_sim_work_ctx {struct irq_work work; -int irq; +unsigned long *pending; };struct irq_sim_irq_ctx {kernel/irq/irq_sim.c +21
-2@@ -34,9 +34,20 @@ static struct irq_chip irq_sim_irqchip = {static void irq_sim_handle_irq (struct irq_work *work) {struct irq_sim_work_ctx *work_ctx; +unsigned int offset =0 ; +struct irq_sim *sim; +int irqnum; work_ctx = container_of(work, struct irq_sim_work_ctx, work); -handle_simple_irq (irq_to_desc (work_ctx->irq)); + sim = container_of(work_ctx, struct irq_sim, work_ctx); + +while (!bitmap_empty (work_ctx->pending, sim->irq_count)) { + offset =find_next_bit (work_ctx->pending, + sim->irq_count, offset); +clear_bit (offset, work_ctx->pending); + irqnum =irq_sim_irqnum (sim, offset); +handle_simple_irq (irq_to_desc (irqnum)); + } }/** @@ -63,6 +74,13 @@ int irq_sim_init(struct irq_sim *sim, unsigned int num_irqs)return sim->irq_base; } + sim->work_ctx.pending =bitmap_zalloc (num_irqs,GFP_KERNEL ); +if (!sim->work_ctx.pending) { +kfree (sim->irqs); +irq_free_descs (sim->irq_base, num_irqs); +return -ENOMEM ; + } +for (i =0 ; i < num_irqs; i++) { sim->irqs[i].irqnum = sim->irq_base + i; sim->irqs[i].enabled = false;@@ -89,6 +107,7 @@ EXPORT_SYMBOL_GPL(irq_sim_init);void irq_sim_fini (struct irq_sim *sim) {irq_work_sync (&sim->work_ctx.work); +bitmap_free (sim->work_ctx.pending);irq_free_descs (sim->irq_base, sim->irq_count);kfree (sim->irqs); }@@ -143,7 +162,7 @@ EXPORT_SYMBOL_GPL(devm_irq_sim_init);void irq_sim_fire (struct irq_sim *sim,unsigned int offset) {if (sim->irqs[offset].enabled) { - sim->work_ctx.irq =irq_sim_irqnum (sim, offset); +set_bit (offset, sim->work_ctx.pending);
Quoted 8 lines
Quoted 6 lines
kernel/irq/irq_sim.c +0
-1irq_work_queue (&sim->work_ctx.work); } } --2.19.1
Ping and Cc'ing Marc Zyngier. Any chance of getting this in for 4.21?
Bizarrely, I can't find any trace of this patch in my Inbox. I've now cherry-picked from https://lore.kernel.org/patchwork/patch/1009297/ .
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
wt., 11 gru 2018 o 15:42 Marc Zyngier <[email protected]> napisał(a):
Quoted 97 lines · Bartosz Golaszewski
Quoted 86 lines
pt., 9 lis 2018 o 18:21 Bartosz Golaszewski <[email protected]> napisał(a):
Quoted 85 lines
Two threads can try to fire the
irq_simwith different offsets and will end up fighting for theirq_workasignment. Thomas Gleixner suggested a solution based on a bitfield where we set a bit for every offset associated with an interrupt that should be fired and then iterate over all set bits in the interrupt handler.This is a slightly modified solution using a bitmap so that we don't impose a limit on the number of interrupts one can allocate with
irq_sim.Suggested-by Thomas Gleixner <[email protected]>Signed-off-by Bartosz Golaszewski <[email protected]>--- include/linux/irq_sim.h | 2 +- kernel/irq/irq_sim.c | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-)include/linux/irq_sim.h +1
-1@@ -16,7 +16,7 @@struct irq_sim_work_ctx {struct irq_work work; -int irq; +unsigned long *pending; };struct irq_sim_irq_ctx {kernel/irq/irq_sim.c +21
-2@@ -34,9 +34,20 @@ static struct irq_chip irq_sim_irqchip = {static void irq_sim_handle_irq (struct irq_work *work) {struct irq_sim_work_ctx *work_ctx; +unsigned int offset =0 ; +struct irq_sim *sim; +int irqnum; work_ctx = container_of(work, struct irq_sim_work_ctx, work); -handle_simple_irq (irq_to_desc (work_ctx->irq)); + sim = container_of(work_ctx, struct irq_sim, work_ctx); + +while (!bitmap_empty (work_ctx->pending, sim->irq_count)) { + offset =find_next_bit (work_ctx->pending, + sim->irq_count, offset); +clear_bit (offset, work_ctx->pending); + irqnum =irq_sim_irqnum (sim, offset); +handle_simple_irq (irq_to_desc (irqnum)); + } }/** @@ -63,6 +74,13 @@ int irq_sim_init(struct irq_sim *sim, unsigned int num_irqs)return sim->irq_base; } + sim->work_ctx.pending =bitmap_zalloc (num_irqs,GFP_KERNEL ); +if (!sim->work_ctx.pending) { +kfree (sim->irqs); +irq_free_descs (sim->irq_base, num_irqs); +return -ENOMEM ; + } +for (i =0 ; i < num_irqs; i++) { sim->irqs[i].irqnum = sim->irq_base + i; sim->irqs[i].enabled = false;@@ -89,6 +107,7 @@ EXPORT_SYMBOL_GPL(irq_sim_init);void irq_sim_fini (struct irq_sim *sim) {irq_work_sync (&sim->work_ctx.work); +bitmap_free (sim->work_ctx.pending);irq_free_descs (sim->irq_base, sim->irq_count);kfree (sim->irqs); }@@ -143,7 +162,7 @@ EXPORT_SYMBOL_GPL(devm_irq_sim_init);void irq_sim_fire (struct irq_sim *sim,unsigned int offset) {if (sim->irqs[offset].enabled) { - sim->work_ctx.irq =irq_sim_irqnum (sim, offset); +set_bit (offset, sim->work_ctx.pending);Quoted 8 lines
Quoted 6 lines
kernel/irq/irq_sim.c +0
-1irq_work_queue (&sim->work_ctx.work); } } --2.19.1
Ping and Cc'ing Marc Zyngier. Any chance of getting this in for 4.21?
Quoted 3 lines
Bizarrely, I can't find any trace of this patch in my Inbox. I've now cherry-picked from https://lore.kernel.org/patchwork/patch/1009297/ .
Your e-mail doesn't pop up with get_maintainer on this patch. That's why you didn't get it initially.
Bart