2012-02-25 21:40:23 +01:00
|
|
|
/*
|
|
|
|
* \brief Service and session interface
|
|
|
|
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
|
|
|
* \date 2012-02-25
|
|
|
|
*
|
|
|
|
* The 'acpi_drv' provides the 'PCI' after rewriting the IRQ information of PCI
|
|
|
|
* devices. For this it uses the 'pci_drv' as a client and forwards the session
|
|
|
|
* capability of the 'pci_drv' afterwards
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2009-2012 Genode Labs GmbH
|
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <os/slave.h>
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <base/env.h>
|
|
|
|
#include <base/sleep.h>
|
|
|
|
#include <cap_session/connection.h>
|
|
|
|
#include <pci_session/client.h>
|
2012-03-15 16:50:09 +01:00
|
|
|
#include <irq_session/connection.h>
|
|
|
|
#include <root/component.h>
|
2012-02-25 21:40:23 +01:00
|
|
|
|
|
|
|
#include "acpi.h"
|
|
|
|
|
2012-03-15 16:50:09 +01:00
|
|
|
/**
|
|
|
|
* IRQ service
|
|
|
|
*/
|
|
|
|
namespace Irq {
|
|
|
|
|
|
|
|
typedef Genode::Rpc_object<Genode::Typed_root<Genode::Irq_session> > Irq_session;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Root interface of IRQ service
|
|
|
|
*/
|
|
|
|
class Root : public Irq_session
|
|
|
|
{
|
2012-10-05 14:23:59 +02:00
|
|
|
private:
|
|
|
|
|
|
|
|
Genode::Irq_session::Trigger _mode2trigger(unsigned mode)
|
|
|
|
{
|
|
|
|
enum { EDGE = 0x4, LEVEL = 0xc };
|
|
|
|
|
|
|
|
switch (mode & 0xc) {
|
|
|
|
case EDGE:
|
|
|
|
return Genode::Irq_session::TRIGGER_EDGE;
|
|
|
|
case LEVEL:
|
|
|
|
return Genode::Irq_session::TRIGGER_LEVEL;
|
|
|
|
default:
|
|
|
|
return Genode::Irq_session::TRIGGER_UNCHANGED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Genode::Irq_session::Polarity _mode2polarity(unsigned mode)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
enum { HIGH = 0x1, LOW = 0x3 };
|
|
|
|
|
|
|
|
switch (mode & 0x3) {
|
|
|
|
case HIGH:
|
|
|
|
return Genode::Irq_session::POLARITY_HIGH;
|
|
|
|
case LOW:
|
|
|
|
return Genode::Irq_session::POLARITY_LOW;
|
|
|
|
default:
|
|
|
|
return Genode::Irq_session::POLARITY_UNCHANGED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-15 16:50:09 +01:00
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remap IRQ number and create IRQ session at parent
|
|
|
|
*/
|
|
|
|
Genode::Session_capability session(Root::Session_args const &args)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
if (!args.is_valid_string()) throw Root::Invalid_args();
|
|
|
|
|
|
|
|
long irq_number = Arg_string::find_arg(args.string(), "irq_number").long_value(-1);
|
|
|
|
|
|
|
|
/* check for 'MADT' overrides */
|
2012-10-05 14:23:59 +02:00
|
|
|
unsigned mode;
|
|
|
|
irq_number = Acpi::override(irq_number, &mode);
|
2012-03-15 16:50:09 +01:00
|
|
|
|
|
|
|
/* allocate IRQ at parent*/
|
|
|
|
try {
|
2012-10-05 14:23:59 +02:00
|
|
|
Irq_connection irq(irq_number, _mode2trigger(mode), _mode2polarity(mode));
|
2012-03-15 16:50:09 +01:00
|
|
|
irq.on_destruction(Irq_connection::KEEP_OPEN);
|
2012-03-16 13:56:34 +01:00
|
|
|
return irq.cap();
|
2012-03-15 16:50:09 +01:00
|
|
|
} catch (...) { throw Root::Unavailable(); }
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Close session at parent
|
|
|
|
*/
|
|
|
|
void close(Genode::Session_capability session) {
|
|
|
|
Genode::env()->parent()->close(session); }
|
|
|
|
|
|
|
|
void upgrade(Genode::Session_capability session, Upgrade_args const &args) { }
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-25 21:40:23 +01:00
|
|
|
namespace Pci {
|
|
|
|
|
|
|
|
struct Provider
|
|
|
|
{
|
|
|
|
bool ready_to_use() { return root().valid(); }
|
|
|
|
|
|
|
|
virtual Genode::Root_capability root() = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Root interface of PCI service
|
|
|
|
*/
|
|
|
|
class Root : public Genode::Rpc_object<Genode::Typed_root<Pci::Session> >
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
Provider &_pci_provider;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2012-03-15 16:50:09 +01:00
|
|
|
Root(Provider &pci_provider) : _pci_provider(pci_provider) { }
|
|
|
|
|
2012-02-25 21:40:23 +01:00
|
|
|
Genode::Session_capability session(Session_args const &args)
|
|
|
|
{
|
|
|
|
if (!args.is_valid_string()) throw Invalid_args();
|
|
|
|
|
|
|
|
if (!_pci_provider.ready_to_use())
|
|
|
|
throw Unavailable();
|
|
|
|
|
|
|
|
try {
|
|
|
|
return Genode::Root_client(_pci_provider.root()).session(args.string());
|
|
|
|
} catch (...) {
|
|
|
|
throw Unavailable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-15 16:50:09 +01:00
|
|
|
void close(Genode::Session_capability session) {
|
|
|
|
Genode::Root_client(_pci_provider.root()).close(session); }
|
2012-02-25 21:40:23 +01:00
|
|
|
|
2012-03-15 16:50:09 +01:00
|
|
|
void upgrade(Genode::Session_capability, Upgrade_args const &) { }
|
2012-02-25 21:40:23 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Pci_policy : public Genode::Slave_policy, public Pci::Provider
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
Genode::Root_capability _cap;
|
2012-03-15 16:50:09 +01:00
|
|
|
Genode::Rpc_entrypoint &_pci_ep;
|
|
|
|
Genode::Rpc_entrypoint &_irq_ep;
|
2012-02-25 21:40:23 +01:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
char const **_permitted_services() const
|
2012-03-15 16:50:09 +01:00
|
|
|
{
|
2012-08-17 12:15:37 +02:00
|
|
|
static char const *permitted_services[] = { "CPU", "CAP", "RM", "LOG", "IO_PORT", 0 };
|
2012-02-25 21:40:23 +01:00
|
|
|
return permitted_services;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse ACPI tables and announce slave PCI service
|
|
|
|
*/
|
|
|
|
void _acpi_session()
|
|
|
|
{
|
|
|
|
Pci::Session_capability session;
|
|
|
|
const char *args = "ram_quota=4K";
|
|
|
|
|
|
|
|
try {
|
|
|
|
using namespace Genode;
|
|
|
|
session = static_cap_cast<Pci::Session>(Root_client(_cap).session(args));
|
|
|
|
} catch (...) { return; }
|
|
|
|
|
|
|
|
Acpi::rewrite_irq(session);
|
|
|
|
|
2012-03-15 16:50:09 +01:00
|
|
|
/* announce PCI/IRQ services to parent */
|
2012-02-25 21:40:23 +01:00
|
|
|
static Pci::Root pci_root(*this);
|
2012-03-15 16:50:09 +01:00
|
|
|
static Irq::Root irq_root;
|
|
|
|
|
|
|
|
Genode::env()->parent()->announce(_pci_ep.manage(&pci_root));
|
|
|
|
Genode::env()->parent()->announce(_irq_ep.manage(&irq_root));
|
2012-02-25 21:40:23 +01:00
|
|
|
|
|
|
|
Genode::Root_client(_cap).close(session);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2012-03-15 16:50:09 +01:00
|
|
|
Pci_policy(Genode::Rpc_entrypoint &slave_ep,
|
|
|
|
Genode::Rpc_entrypoint &pci_ep,
|
|
|
|
Genode::Rpc_entrypoint &irq_ep)
|
|
|
|
: Slave_policy("pci_drv", slave_ep), _pci_ep(pci_ep), _irq_ep(irq_ep)
|
2012-02-25 21:40:23 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
bool announce_service(const char *service_name,
|
|
|
|
Genode::Root_capability root,
|
2012-04-11 18:24:37 +02:00
|
|
|
Genode::Allocator *alloc,
|
|
|
|
Genode::Server *server)
|
2012-02-25 21:40:23 +01:00
|
|
|
{
|
|
|
|
/* wait for 'pci_drv' to announce the PCI service */
|
|
|
|
if (Genode::strcmp(service_name, "PCI"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
_cap = root;
|
|
|
|
|
|
|
|
/* connect session and start ACPI parsing */
|
|
|
|
_acpi_session();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Genode::Root_capability root() { return _cap; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
enum { STACK_SIZE = 2*4096 };
|
|
|
|
static Cap_connection cap;
|
|
|
|
static Rpc_entrypoint ep(&cap, STACK_SIZE, "acpi_ep");
|
|
|
|
|
2012-03-15 16:50:09 +01:00
|
|
|
/* IRQ service */
|
|
|
|
static Cap_connection irq_cap;
|
|
|
|
static Rpc_entrypoint irq_ep(&irq_cap, STACK_SIZE, "acpi_irq_ep");
|
|
|
|
|
2012-02-25 21:40:23 +01:00
|
|
|
/* use 'pci_drv' as slave service */
|
|
|
|
static Rpc_entrypoint pci_ep(&cap, STACK_SIZE, "pci_slave");
|
2012-03-15 16:50:09 +01:00
|
|
|
static Pci_policy pci_policy(pci_ep, ep, irq_ep);
|
2012-07-18 15:46:07 +02:00
|
|
|
static Genode::Slave pci_slave(pci_ep, pci_policy, 1024 * 1024);
|
2012-02-25 21:40:23 +01:00
|
|
|
|
|
|
|
Genode::sleep_forever();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|