diff options
author | Johannes Berg <johannes.berg@intel.com> | 2020-12-02 12:59:50 +0100 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2020-12-13 22:22:08 +0100 |
commit | 36d46a5907ba170965307c9d106cc35517acbf33 (patch) | |
tree | 35b1748a7ab1981f00903874a34d68b9977aee60 /arch/um/kernel/irq.c | |
parent | d66c91836b8d7df3b6f0fe7f0c7617d28ebfcb4c (diff) |
um: Support dynamic IRQ allocation
It's cumbersome and error-prone to keep adding fixed IRQ numbers,
and for proper device wakeup support for the virtio/vhost-user
support we need to have different IRQs for each device. Even if
in theory two IRQs (with and without wake) might be sufficient,
it's much easier to reason about it when we have dynamic number
assignment. It also makes it easier to add new devices that may
dynamically exist or depending on the configuration, etc.
Add support for this, up to 64 IRQs (the same limit as epoll FDs
we have right now). Since it's not easy to port all the existing
places to dynamic allocation (some data is statically initialized)
keep the low numbers are reserved for the existing hard-coded IRQ
numbers.
Acked-By: Anton Ivanov <anton.ivanov@cambridgegreys.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Acked-By: Anton Ivanov <anton.ivanov@cambridgegreys.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/kernel/irq.c')
-rw-r--r-- | arch/um/kernel/irq.c | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 3577118bb4a5..b94c72f56617 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -19,6 +19,7 @@ #include <kern_util.h> #include <os.h> #include <irq_user.h> +#include <irq_kern.h> extern void free_irqs(void); @@ -38,6 +39,7 @@ struct irq_entry { static struct irq_entry *active_fds; static DEFINE_SPINLOCK(irq_lock); +static DECLARE_BITMAP(irqs_allocated, NR_IRQS); static void irq_io_loop(struct irq_fd *irq, struct uml_pt_regs *regs) { @@ -421,27 +423,52 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs) return 1; } -void um_free_irq(unsigned int irq, void *dev) +void um_free_irq(int irq, void *dev) { + if (WARN(irq < 0 || irq > NR_IRQS, "freeing invalid irq %d", irq)) + return; + free_irq_by_irq_and_dev(irq, dev); free_irq(irq, dev); + clear_bit(irq, irqs_allocated); } EXPORT_SYMBOL(um_free_irq); -int um_request_irq(unsigned int irq, int fd, int type, +int um_request_irq(int irq, int fd, int type, irq_handler_t handler, unsigned long irqflags, const char * devname, void *dev_id) { int err; + if (irq == UM_IRQ_ALLOC) { + int i; + + for (i = UM_FIRST_DYN_IRQ; i < NR_IRQS; i++) { + if (!test_and_set_bit(i, irqs_allocated)) { + irq = i; + break; + } + } + } + + if (irq < 0) + return -ENOSPC; + if (fd != -1) { err = activate_fd(irq, fd, type, dev_id); if (err) - return err; + goto error; } - return request_irq(irq, handler, irqflags, devname, dev_id); + err = request_irq(irq, handler, irqflags, devname, dev_id); + if (err < 0) + goto error; + + return irq; +error: + clear_bit(irq, irqs_allocated); + return err; } EXPORT_SYMBOL(um_request_irq); @@ -480,7 +507,7 @@ void __init init_IRQ(void) irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq); - for (i = 1; i <= LAST_IRQ; i++) + for (i = 1; i < NR_IRQS; i++) irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq); /* Initialize EPOLL Loop */ os_setup_epoll(); |