mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 00:24:51 +00:00
lx_kit: support enable/disable IRQ and pass IRQ number to handler
Fixes #3589
This commit is contained in:
parent
18f90ca1e3
commit
0eaa1f7a08
@ -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;
|
struct drm_device * drm_dev = (struct drm_device*) dev;
|
||||||
Lx::Pci_dev * pci_dev = (Lx::Pci_dev*) drm_dev->pdev->bus;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
extern "C" int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
|
||||||
const char *name, void *dev)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -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())
|
for (Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first(); pci_dev; pci_dev = pci_dev->next())
|
||||||
if (pci_dev->irq == irq) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
extern "C" int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
|
||||||
const char *name, void *dev)
|
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;
|
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)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
if ((is.info().type != Genode::Irq_session::Info::MSI)
|
||||||
&& !flags) return 1;
|
&& !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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,10 +32,21 @@ class Lx::Irq
|
|||||||
/**
|
/**
|
||||||
* Request an IRQ
|
* Request an IRQ
|
||||||
*/
|
*/
|
||||||
virtual void request_irq(Platform::Device &dev, irq_handler_t handler,
|
virtual void request_irq(Platform::Device &dev, unsigned int irq,
|
||||||
void *dev_id, irq_handler_t thread_fn = 0) = 0;
|
irq_handler_t handler, void *dev_id,
|
||||||
|
irq_handler_t thread_fn = 0) = 0;
|
||||||
|
|
||||||
virtual void inject_irq(Platform::Device &dev) = 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_ */
|
#endif /* _LX_KIT__IRQ_H_ */
|
||||||
|
@ -1333,7 +1333,7 @@ int request_irq(unsigned int irq, irq_handler_t handler,
|
|||||||
unsigned long flags, const char *name, void *dev)
|
unsigned long flags, const char *name, void *dev)
|
||||||
{
|
{
|
||||||
Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1344,7 +1344,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
|
|||||||
void *dev)
|
void *dev)
|
||||||
{
|
{
|
||||||
Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,20 +58,28 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
void *_dev; /* Linux device */
|
void *_dev; /* Linux device */
|
||||||
|
unsigned int _irq; /* Linux IRQ number */
|
||||||
irq_handler_t _handler; /* Linux handler */
|
irq_handler_t _handler; /* Linux handler */
|
||||||
irq_handler_t _thread_fn; /* Linux thread function */
|
irq_handler_t _thread_fn; /* Linux thread function */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Handler(void *dev, irq_handler_t handler,
|
Handler(void *dev, unsigned int irq, irq_handler_t handler,
|
||||||
irq_handler_t thread_fn)
|
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()
|
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:
|
case IRQ_WAKE_THREAD:
|
||||||
_thread_fn(0, _dev);
|
_thread_fn(_irq, _dev);
|
||||||
case IRQ_HANDLED:
|
case IRQ_HANDLED:
|
||||||
return true;
|
return true;
|
||||||
case IRQ_NONE:
|
case IRQ_NONE:
|
||||||
@ -92,9 +100,12 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
|
|
||||||
Name_composer _name;
|
Name_composer _name;
|
||||||
Platform::Device &_dev;
|
Platform::Device &_dev;
|
||||||
|
unsigned int _irq;
|
||||||
Genode::Irq_session_client _irq_sess;
|
Genode::Irq_session_client _irq_sess;
|
||||||
Lx_kit::List<Handler> _handler;
|
Lx_kit::List<Handler> _handler;
|
||||||
Lx::Task _task;
|
Lx::Task _task;
|
||||||
|
bool _irq_enabled;
|
||||||
|
bool _irq_ack_pending;
|
||||||
|
|
||||||
Genode::Signal_handler<Context> _dispatcher;
|
Genode::Signal_handler<Context> _dispatcher;
|
||||||
|
|
||||||
@ -114,12 +125,16 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Context(Genode::Entrypoint &ep,
|
Context(Genode::Entrypoint &ep,
|
||||||
Platform::Device &dev)
|
Platform::Device &dev,
|
||||||
|
unsigned int irq)
|
||||||
:
|
:
|
||||||
_name(dev),
|
_name(dev),
|
||||||
_dev(dev),
|
_dev(dev),
|
||||||
|
_irq(irq),
|
||||||
_irq_sess(dev.irq(0)),
|
_irq_sess(dev.irq(0)),
|
||||||
_task(_run_irq, this, _name.name, Lx::Task::PRIORITY_3, Lx::scheduler()),
|
_task(_run_irq, this, _name.name, Lx::Task::PRIORITY_3, Lx::scheduler()),
|
||||||
|
_irq_enabled(true),
|
||||||
|
_irq_ack_pending(false),
|
||||||
_dispatcher(ep, *this, &Context::unblock)
|
_dispatcher(ep, *this, &Context::unblock)
|
||||||
{
|
{
|
||||||
_irq_sess.sigh(_dispatcher);
|
_irq_sess.sigh(_dispatcher);
|
||||||
@ -144,12 +159,24 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
*/
|
*/
|
||||||
void handle_irq()
|
void handle_irq()
|
||||||
{
|
{
|
||||||
/* report IRQ to all clients */
|
if (_irq_enabled) {
|
||||||
for (Handler *h = _handler.first(); h; h = h->next()) {
|
|
||||||
h->handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
_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) {
|
bool device(Platform::Device &dev) {
|
||||||
return (&dev == &_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:
|
private:
|
||||||
@ -181,6 +229,16 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
return nullptr;
|
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)
|
Irq(Genode::Entrypoint &ep, Genode::Allocator &alloc)
|
||||||
: _ep(ep),
|
: _ep(ep),
|
||||||
_context_alloc(&alloc),
|
_context_alloc(&alloc),
|
||||||
@ -198,20 +256,21 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
** Lx::Irq interface **
|
** Lx::Irq interface **
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
void request_irq(Platform::Device &dev, irq_handler_t handler,
|
void request_irq(Platform::Device &dev, unsigned int irq,
|
||||||
void *dev_id, irq_handler_t thread_fn = 0) override
|
irq_handler_t handler, void *dev_id,
|
||||||
|
irq_handler_t thread_fn = 0) override
|
||||||
{
|
{
|
||||||
Context *ctx = _find_context(dev);
|
Context *ctx = _find_context(dev);
|
||||||
|
|
||||||
/* if this IRQ is not registered */
|
/* if this IRQ is not registered */
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
ctx = new (&_context_alloc) Context(_ep, dev);
|
ctx = new (&_context_alloc) Context(_ep, dev, irq);
|
||||||
_list.insert(ctx);
|
_list.insert(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register Linux handler */
|
/* register Linux handler */
|
||||||
Handler *h = new (&_handler_alloc)
|
Handler *h = new (&_handler_alloc)
|
||||||
Handler(dev_id, handler, thread_fn);
|
Handler(dev_id, irq, handler, thread_fn);
|
||||||
ctx->add_handler(h);
|
ctx->add_handler(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +279,18 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
Context *ctx = _find_context(dev);
|
Context *ctx = _find_context(dev);
|
||||||
if (ctx) ctx->unblock();
|
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();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user