diff --git a/repos/dde_linux/src/drivers/framebuffer/intel/lx_emul.cc b/repos/dde_linux/src/drivers/framebuffer/intel/lx_emul.cc index b2d2072cb9..ca842153ef 100644 --- a/repos/dde_linux/src/drivers/framebuffer/intel/lx_emul.cc +++ b/repos/dde_linux/src/drivers/framebuffer/intel/lx_emul.cc @@ -1094,7 +1094,7 @@ int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, { struct drm_device * drm_dev = (struct drm_device*) dev; Lx::Pci_dev * pci_dev = (Lx::Pci_dev*) drm_dev->pdev->bus; - Lx::Irq::irq().request_irq(pci_dev->client(), handler, dev); + Lx::Irq::irq().request_irq(pci_dev->client(), irq, handler, dev); return 0; } diff --git a/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc b/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc index 9a0c2ea143..7de18beafb 100644 --- a/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc +++ b/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc @@ -586,7 +586,7 @@ int platform_get_irq(struct platform_device * d, unsigned int i) int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id) { - Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), handler, dev_id); + Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), irq, handler, dev_id); return 0; } diff --git a/repos/dde_linux/src/drivers/usb/spec/arm/platform_generic.cc b/repos/dde_linux/src/drivers/usb/spec/arm/platform_generic.cc index d925bed62a..00f39eb7b3 100644 --- a/repos/dde_linux/src/drivers/usb/spec/arm/platform_generic.cc +++ b/repos/dde_linux/src/drivers/usb/spec/arm/platform_generic.cc @@ -45,7 +45,7 @@ void Lx::backend_free(Genode::Ram_dataspace_capability cap) { extern "C" int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) { - Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), handler, dev); + Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), irq, handler, dev); return 0; } diff --git a/repos/dde_linux/src/drivers/usb/spec/x86/pci_driver.cc b/repos/dde_linux/src/drivers/usb/spec/x86/pci_driver.cc index 814d587556..b837dd7b48 100644 --- a/repos/dde_linux/src/drivers/usb/spec/x86/pci_driver.cc +++ b/repos/dde_linux/src/drivers/usb/spec/x86/pci_driver.cc @@ -187,7 +187,7 @@ int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, { for (Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first(); pci_dev; pci_dev = pci_dev->next()) if (pci_dev->irq == irq) { - Lx::Irq::irq().request_irq(pci_dev->client(), handler, dev); + Lx::Irq::irq().request_irq(pci_dev->client(), irq, handler, dev); return 0; } diff --git a/repos/dde_linux/src/drivers/usb_host/spec/arm/platform.cc b/repos/dde_linux/src/drivers/usb_host/spec/arm/platform.cc index 553f76ea8c..067d3530ec 100644 --- a/repos/dde_linux/src/drivers/usb_host/spec/arm/platform.cc +++ b/repos/dde_linux/src/drivers/usb_host/spec/arm/platform.cc @@ -48,7 +48,7 @@ void Lx::backend_free(Genode::Ram_dataspace_capability cap) { extern "C" int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) { - Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), handler, dev); + Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), irq, handler, dev); return 0; } @@ -56,7 +56,7 @@ extern "C" int request_irq(unsigned int irq, irq_handler_t handler, unsigned lon int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id) { - Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), handler, dev_id); + Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), irq, handler, dev_id); return 0; } diff --git a/repos/dde_linux/src/drivers/usb_host/spec/x86/platform.cc b/repos/dde_linux/src/drivers/usb_host/spec/x86/platform.cc index 9d9df2c9bf..ae8acb21a4 100644 --- a/repos/dde_linux/src/drivers/usb_host/spec/x86/platform.cc +++ b/repos/dde_linux/src/drivers/usb_host/spec/x86/platform.cc @@ -194,7 +194,7 @@ int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, if ((is.info().type != Genode::Irq_session::Info::MSI) && !flags) return 1; } - Lx::Irq::irq().request_irq(pci_dev->client(), handler, dev); + Lx::Irq::irq().request_irq(pci_dev->client(), irq, handler, dev); return 0; } diff --git a/repos/dde_linux/src/include/lx_kit/irq.h b/repos/dde_linux/src/include/lx_kit/irq.h index 6f84192637..eff14f27ae 100644 --- a/repos/dde_linux/src/include/lx_kit/irq.h +++ b/repos/dde_linux/src/include/lx_kit/irq.h @@ -32,10 +32,21 @@ class Lx::Irq /** * Request an IRQ */ - virtual void request_irq(Platform::Device &dev, irq_handler_t handler, - void *dev_id, irq_handler_t thread_fn = 0) = 0; + virtual void request_irq(Platform::Device &dev, unsigned int irq, + irq_handler_t handler, void *dev_id, + irq_handler_t thread_fn = 0) = 0; virtual void inject_irq(Platform::Device &dev) = 0; + + /** + * Disable an IRQ + */ + virtual void disable_irq(unsigned int irq) = 0; + + /** + * Enable an IRQ + */ + virtual void enable_irq(unsigned int irq) = 0; }; #endif /* _LX_KIT__IRQ_H_ */ diff --git a/repos/dde_linux/src/lib/wifi/lxcc_emul.cc b/repos/dde_linux/src/lib/wifi/lxcc_emul.cc index d43f20062f..da1152807c 100644 --- a/repos/dde_linux/src/lib/wifi/lxcc_emul.cc +++ b/repos/dde_linux/src/lib/wifi/lxcc_emul.cc @@ -1333,7 +1333,7 @@ int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) { Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first(); - Lx::Irq::irq().request_irq(pci_dev->client(), handler, dev); + Lx::Irq::irq().request_irq(pci_dev->client(), irq, handler, dev); return 0; } @@ -1344,7 +1344,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, void *dev) { Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first(); - Lx::Irq::irq().request_irq(pci_dev->client(), handler, dev, thread_fn); + Lx::Irq::irq().request_irq(pci_dev->client(), irq, handler, dev, thread_fn); return 0; } diff --git a/repos/dde_linux/src/lx_kit/irq.cc b/repos/dde_linux/src/lx_kit/irq.cc index 79e6e0ed92..8353865d4a 100644 --- a/repos/dde_linux/src/lx_kit/irq.cc +++ b/repos/dde_linux/src/lx_kit/irq.cc @@ -58,20 +58,28 @@ class Lx_kit::Irq : public Lx::Irq private: void *_dev; /* Linux device */ + unsigned int _irq; /* Linux IRQ number */ irq_handler_t _handler; /* Linux handler */ irq_handler_t _thread_fn; /* Linux thread function */ public: - Handler(void *dev, irq_handler_t handler, + Handler(void *dev, unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn) - : _dev(dev), _handler(handler), _thread_fn(thread_fn) { } + : _dev(dev), _irq(irq), _handler(handler), + _thread_fn(thread_fn) { } bool handle() { - switch (_handler(0, _dev)) { + if (!_handler) { + /* on Linux, having no handler implies IRQ_WAKE_THREAD */ + _thread_fn(_irq, _dev); + return true; + } + + switch (_handler(_irq, _dev)) { case IRQ_WAKE_THREAD: - _thread_fn(0, _dev); + _thread_fn(_irq, _dev); case IRQ_HANDLED: return true; case IRQ_NONE: @@ -92,9 +100,12 @@ class Lx_kit::Irq : public Lx::Irq Name_composer _name; Platform::Device &_dev; + unsigned int _irq; Genode::Irq_session_client _irq_sess; Lx_kit::List _handler; Lx::Task _task; + bool _irq_enabled; + bool _irq_ack_pending; Genode::Signal_handler _dispatcher; @@ -114,12 +125,16 @@ class Lx_kit::Irq : public Lx::Irq * Constructor */ Context(Genode::Entrypoint &ep, - Platform::Device &dev) + Platform::Device &dev, + unsigned int irq) : _name(dev), _dev(dev), + _irq(irq), _irq_sess(dev.irq(0)), _task(_run_irq, this, _name.name, Lx::Task::PRIORITY_3, Lx::scheduler()), + _irq_enabled(true), + _irq_ack_pending(false), _dispatcher(ep, *this, &Context::unblock) { _irq_sess.sigh(_dispatcher); @@ -144,12 +159,24 @@ class Lx_kit::Irq : public Lx::Irq */ void handle_irq() { - /* report IRQ to all clients */ - for (Handler *h = _handler.first(); h; h = h->next()) { - h->handle(); - } + if (_irq_enabled) { - _irq_sess.ack_irq(); + /* report IRQ to all clients */ + for (Handler *h = _handler.first(); h; h = h->next()) + h->handle(); + + _irq_sess.ack_irq(); + + } else { + + /* + * IRQs are disabled by not acknowledging, so one IRQ + * can still occur in the 'disabled' state. It must be + * acknowledged later by 'enable_irq()'. + */ + + _irq_ack_pending = true; + } } /** @@ -159,6 +186,27 @@ class Lx_kit::Irq : public Lx::Irq bool device(Platform::Device &dev) { return (&dev == &_dev); } + + bool irq(unsigned int irq) { + return (irq == _irq); } + + void disable_irq() + { + _irq_enabled = false; + } + + void enable_irq() + { + if (_irq_enabled) + return; + + if (_irq_ack_pending) { + _irq_sess.ack_irq(); + _irq_ack_pending = false; + } + + _irq_enabled = true; + } }; private: @@ -181,6 +229,16 @@ class Lx_kit::Irq : public Lx::Irq return nullptr; } + /** + * Find context for given IRQ number + */ + Context *_find_context(unsigned int irq) + { + for (Context *i = _list.first(); i; i = i->next()) + if (i->irq(irq)) return i; + return nullptr; + } + Irq(Genode::Entrypoint &ep, Genode::Allocator &alloc) : _ep(ep), _context_alloc(&alloc), @@ -198,20 +256,21 @@ class Lx_kit::Irq : public Lx::Irq ** Lx::Irq interface ** ***********************/ - void request_irq(Platform::Device &dev, irq_handler_t handler, - void *dev_id, irq_handler_t thread_fn = 0) override + void request_irq(Platform::Device &dev, unsigned int irq, + irq_handler_t handler, void *dev_id, + irq_handler_t thread_fn = 0) override { Context *ctx = _find_context(dev); /* if this IRQ is not registered */ if (!ctx) { - ctx = new (&_context_alloc) Context(_ep, dev); + ctx = new (&_context_alloc) Context(_ep, dev, irq); _list.insert(ctx); } /* register Linux handler */ Handler *h = new (&_handler_alloc) - Handler(dev_id, handler, thread_fn); + Handler(dev_id, irq, handler, thread_fn); ctx->add_handler(h); } @@ -220,6 +279,18 @@ class Lx_kit::Irq : public Lx::Irq Context *ctx = _find_context(dev); if (ctx) ctx->unblock(); } + + void disable_irq(unsigned int irq) + { + Context *ctx = _find_context(irq); + if (ctx) ctx->disable_irq(); + } + + void enable_irq(unsigned int irq) + { + Context *ctx = _find_context(irq); + if (ctx) ctx->enable_irq(); + } };