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
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2009-2013 Genode Labs GmbH
|
2012-02-25 21:40:23 +01:00
|
|
|
*
|
|
|
|
* 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;
|
2013-02-20 13:01:57 +01:00
|
|
|
Genode::Lock _lock;
|
2012-02-25 21:40:23 +01:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
char const **_permitted_services() const
|
2012-03-15 16:50:09 +01:00
|
|
|
{
|
2013-02-20 13:01:57 +01:00
|
|
|
static char const *permitted_services[] = { "CPU", "CAP", "RM",
|
2013-02-18 10:08:14 +01:00
|
|
|
"LOG", "IO_PORT", "PD",
|
|
|
|
"ROM", "RAM", "SIGNAL",
|
|
|
|
"IO_MEM", 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; }
|
|
|
|
|
2013-02-20 13:01:57 +01:00
|
|
|
Acpi::configure_pci_devices(session);
|
2012-02-25 21:40:23 +01:00
|
|
|
|
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)
|
2013-02-20 13:01:57 +01:00
|
|
|
:
|
|
|
|
Slave_policy("pci_drv", slave_ep, Genode::env()->ram_session()),
|
|
|
|
_pci_ep(pci_ep), _irq_ep(irq_ep), _lock(Genode::Lock::LOCKED)
|
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;
|
|
|
|
|
2013-02-20 13:01:57 +01:00
|
|
|
/* unblock main thread blocked in wait_for_pci_drv */
|
|
|
|
_lock.unlock();
|
2012-02-25 21:40:23 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-02-20 13:01:57 +01:00
|
|
|
void wait_for_pci_drv() {
|
|
|
|
/* wait until pci drv is ready */
|
|
|
|
_lock.lock();
|
|
|
|
|
|
|
|
/* connect session and start ACPI parsing */
|
|
|
|
_acpi_session();
|
|
|
|
}
|
|
|
|
|
2012-02-25 21:40:23 +01:00
|
|
|
Genode::Root_capability root() { return _cap; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
|
2013-02-20 08:56:08 +01:00
|
|
|
enum { STACK_SIZE = 2*4096, ACPI_MEMORY_SIZE = 2 * 1024 * 1024 };
|
|
|
|
|
|
|
|
/* reserve portion for acpi and give rest to pci_drv */
|
|
|
|
Genode::addr_t avail_size = Genode::env()->ram_session()->avail();
|
|
|
|
if (avail_size < ACPI_MEMORY_SIZE) {
|
|
|
|
PERR("not enough memory");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
avail_size -= ACPI_MEMORY_SIZE;
|
|
|
|
PINF("available memory for ACPI %d kiB, for PCI_DRV %lu kiB",
|
|
|
|
ACPI_MEMORY_SIZE / 1024, avail_size / 1024);
|
2013-02-20 13:01:57 +01:00
|
|
|
|
2012-02-25 21:40:23 +01:00
|
|
|
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);
|
2013-02-20 13:01:57 +01:00
|
|
|
|
|
|
|
/* generate config file for pci_drv */
|
|
|
|
char buf[256];
|
|
|
|
Acpi::create_pci_config_file(buf, sizeof(buf));
|
|
|
|
pci_policy.configure(buf);
|
|
|
|
|
|
|
|
/* use 'pci_drv' as slave service */
|
2013-02-20 08:56:08 +01:00
|
|
|
static Genode::Slave pci_slave(pci_ep, pci_policy, avail_size);
|
2012-02-25 21:40:23 +01:00
|
|
|
|
2013-02-20 13:01:57 +01:00
|
|
|
/* wait until pci drv is online and then make the acpi work */
|
|
|
|
pci_policy.wait_for_pci_drv();
|
|
|
|
|
2012-02-25 21:40:23 +01:00
|
|
|
Genode::sleep_forever();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|