acpi: provide pci express style configs to pci_drv

Parse the mcfg table and  provide the extended PCI config space data via
the config file to the pci_drv.
This commit is contained in:
Alexander Boettcher 2013-02-20 13:01:57 +01:00 committed by Norman Feske
parent ba566a1530
commit 822b4f2d96
4 changed files with 133 additions and 19 deletions

View File

@ -114,6 +114,30 @@ class Irq_override : public List<Irq_override>::Element
};
/**
* List that holds the result of the mcfg table parsing which are pointers
* to the extended pci config space - 4k for each device.
*/
class Pci_config_space : public List<Pci_config_space>::Element
{
public:
uint32_t _bdf_start;
uint32_t _func_count;
addr_t _base;
Pci_config_space(uint32_t bdf_start, uint32_t func_count, addr_t base)
:
_bdf_start(bdf_start), _func_count(func_count), _base(base) {}
static List<Pci_config_space> *list()
{
static List<Pci_config_space> _list;
return &_list;
}
};
/**
* ACPI table wrapper that for mapping tables to this address space
*/
@ -235,6 +259,14 @@ class Table_wrapper
for (; mcfg < _table->mcfg_end(); mcfg = mcfg->next()) {
PINF("MCFG BASE 0x%llx seg %02x bus %02x-%02x", mcfg->base,
mcfg->pci_seg, mcfg->pci_bus_start, mcfg->pci_bus_end);
/* bus_count * up to 32 devices * 8 function per device * 4k */
uint32_t bus_count = mcfg->pci_bus_end - mcfg->pci_bus_start + 1;
uint32_t func_count = bus_count * 32 * 8;
uint32_t bus_start = mcfg->pci_bus_start * 32 * 8;
Pci_config_space::list()->insert(
new (env()->heap()) Pci_config_space(bus_start, func_count, mcfg->base));
}
}
@ -867,6 +899,34 @@ class Element : public List<Element>::Element
}
throw -1;
}
static void create_config_file(char * text, size_t max)
{
Pci_config_space *e = Pci_config_space::list()->first();
int len = snprintf(text, max, "<config>");
text += len;
max -= len;
for (; e; e = e->next())
{
using namespace Genode;
len = snprintf(text, max, "<bdf><start>%u</start>", e->_bdf_start);
text += len;
max -= len;
len = snprintf(text, max, "<count>%u</count>" , e->_func_count);
text += len;
max -= len;
len = snprintf(text, max, "<base>0x%lx</base></bdf>" , e->_base);
text += len;
max -= len;
}
len = snprintf(text, max, "</config>");
text += len;
max -= len;
if (max < 2)
PERR("config file could not be generated, buffer to small");
}
};
@ -960,7 +1020,6 @@ class Acpi_table
table.parse_madt();
}
if (table.is_mcfg()) {
PDBG("Found MCFG");
@ -1200,22 +1259,38 @@ static void dump_rewrite(uint32_t bdf, uint8_t line, uint8_t gsi)
(bdf >> 8), (bdf >> 3) & 0x1f, (bdf & 0x7), line, gsi);
}
/**
* Parse acpi table
*/
static void init_acpi_table() {
static Acpi_table table;
}
/**
* Create config file for pci_drv
*/
void Acpi::create_pci_config_file(char * config_space,
Genode::size_t config_space_max)
{
init_acpi_table();
Element::create_config_file(config_space, config_space_max);
}
/**
* Rewrite GSIs of PCI config space
*/
void Acpi::rewrite_irq(Pci::Session_capability &session)
void Acpi::configure_pci_devices(Pci::Session_capability &session)
{
static Acpi_table table;
init_acpi_table();
static Pci_bridge bridge(session);
/* if no _PIC method could be found return */
if (Element::supported_acpi_format())
PINF("ACPI table format is supported by this driver");
else {
PWRN("ACPI table format not supported will not rewrite GSIs");
return;
}
/* if no _PIC method could be found don't rewrite */
bool acpi_rewrite = Element::supported_acpi_format();
if (acpi_rewrite)
PINF("ACPI table format is supported - rewrite GSIs");
else
PWRN("ACPI table format not supported - will not rewrite GSIs");
Pci::Session_client pci(session);
Pci::Device_capability device_cap = pci.first_device(), prev_device_cap;
@ -1224,7 +1299,8 @@ void Acpi::rewrite_irq(Pci::Session_capability &session)
prev_device_cap = device_cap;
Pci_client device(device_cap);
if (!device.is_bridge()) {
/* rewrite IRQs */
if (acpi_rewrite && !device.is_bridge()) {
uint32_t device_bdf = device.bdf();
uint32_t bridge_bdf = Pci_bridge::bridge_bdf(device_bdf);
uint32_t irq_pin = device.irq_pin();
@ -1241,6 +1317,7 @@ void Acpi::rewrite_irq(Pci::Session_capability &session)
device_cap = pci.next_device(device_cap);
pci.release_device(prev_device_cap);
}
}

View File

@ -22,14 +22,27 @@ class Acpi
public:
/**
* Rewrite PCI-config space with GSIs found in ACPI tables
* Constructor
*/
static void rewrite_irq(Pci::Session_capability &session);
Acpi();
/**
* Generate config file for pci_drv containing pointers to the
* extended PCI config space (since PCI Express)
*/
static void create_pci_config_file(char * config_space,
Genode::size_t config_space_max);
/**
* Rewrite PCI-config space with GSIs found in ACPI tables.
*/
static void configure_pci_devices(Pci::Session_capability &session);
/**
* Return override GSI for IRQ
*/
static unsigned override(unsigned irq, unsigned *mode);
};
#endif /* _ACPI_H_ */

View File

@ -156,12 +156,15 @@ class Pci_policy : public Genode::Slave_policy, public Pci::Provider
Genode::Root_capability _cap;
Genode::Rpc_entrypoint &_pci_ep;
Genode::Rpc_entrypoint &_irq_ep;
Genode::Lock _lock;
protected:
char const **_permitted_services() const
{
static char const *permitted_services[] = { "CPU", "CAP", "RM", "LOG", "IO_PORT", 0 };
static char const *permitted_services[] = { "CPU", "CAP", "RM",
"LOG", "IO_PORT",
"SIGNAL", 0};
return permitted_services;
};
@ -178,7 +181,7 @@ class Pci_policy : public Genode::Slave_policy, public Pci::Provider
session = static_cap_cast<Pci::Session>(Root_client(_cap).session(args));
} catch (...) { return; }
Acpi::rewrite_irq(session);
Acpi::configure_pci_devices(session);
/* announce PCI/IRQ services to parent */
static Pci::Root pci_root(*this);
@ -195,7 +198,9 @@ class Pci_policy : public Genode::Slave_policy, public Pci::Provider
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)
:
Slave_policy("pci_drv", slave_ep, Genode::env()->ram_session()),
_pci_ep(pci_ep), _irq_ep(irq_ep), _lock(Genode::Lock::LOCKED)
{ }
bool announce_service(const char *service_name,
@ -209,12 +214,20 @@ class Pci_policy : public Genode::Slave_policy, public Pci::Provider
_cap = root;
/* connect session and start ACPI parsing */
_acpi_session();
/* unblock main thread blocked in wait_for_pci_drv */
_lock.unlock();
return true;
}
void wait_for_pci_drv() {
/* wait until pci drv is ready */
_lock.lock();
/* connect session and start ACPI parsing */
_acpi_session();
}
Genode::Root_capability root() { return _cap; }
};
@ -224,6 +237,7 @@ 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");
@ -234,8 +248,18 @@ int main(int argc, char **argv)
/* use 'pci_drv' as slave service */
static Rpc_entrypoint pci_ep(&cap, STACK_SIZE, "pci_slave");
static Pci_policy pci_policy(pci_ep, ep, irq_ep);
/* 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 */
static Genode::Slave pci_slave(pci_ep, pci_policy, 1024 * 1024);
/* wait until pci drv is online and then make the acpi work */
pci_policy.wait_for_pci_drv();
Genode::sleep_forever();
return 0;
}

View File

@ -1,4 +1,4 @@
TARGET = acpi_drv
TARGET = acpi_drv
REQUIRES = x86
SRC_CC = main.cc acpi.cc
LIBS = base