pci: add support to provide PCI ECMA config

This commit is contained in:
Alexander Boettcher 2013-02-18 10:06:34 +01:00 committed by Norman Feske
parent 822b4f2d96
commit c374f294c8
9 changed files with 174 additions and 11 deletions

View File

@ -52,7 +52,7 @@ namespace Genode {
void _out_char(char c)
{
/* ensure to leave space for null-termination */
if (_w_offset > _dst_len - 2)
if (_w_offset + 2 > _dst_len)
return;
_dst[_w_offset++] = c;

View File

@ -17,6 +17,7 @@
#include <pci_session/pci_session.h>
#include <pci_device/pci_device.h>
#include <base/rpc_client.h>
#include <io_mem_session/io_mem_session.h>
namespace Pci {

View File

@ -15,6 +15,7 @@
#define _INCLUDE__PCI_DEVICE__PCI_DEVICE_H_
#include <base/rpc.h>
#include <io_mem_session/io_mem_session.h>
namespace Pci {

View File

@ -32,6 +32,9 @@ namespace Pci {
void release_device(Device_capability device) {
call<Rpc_release_device>(device); }
Genode::Io_mem_dataspace_capability config_extended(Device_capability device_cap) {
return call<Rpc_config_extended>(device_cap); }
};
}

View File

@ -49,16 +49,25 @@ namespace Pci {
*/
virtual void release_device(Device_capability device) = 0;
/**
* Provide mapping to device configuration space of 4k, known as
* "Enhanced Configuration Access Mechanism (ECAM) for PCI Express
*/
virtual Genode::Io_mem_dataspace_capability config_extended(Device_capability) = 0;
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_first_device, Device_capability, first_device);
GENODE_RPC(Rpc_next_device, Device_capability, next_device, Device_capability);
GENODE_RPC(Rpc_next_device, Device_capability, next_device,
Device_capability);
GENODE_RPC(Rpc_release_device, void, release_device, Device_capability);
GENODE_RPC(Rpc_config_extended, Genode::Io_mem_dataspace_capability,
config_extended, Device_capability);
GENODE_RPC_INTERFACE(Rpc_first_device, Rpc_next_device, Rpc_release_device);
GENODE_RPC_INTERFACE(Rpc_first_device, Rpc_next_device,
Rpc_release_device, Rpc_config_extended);
};
}

View File

@ -22,7 +22,6 @@
using namespace Genode;
using namespace Pci;
int main(int argc, char **argv)
{
printf("PCI driver started\n");
@ -30,7 +29,7 @@ int main(int argc, char **argv)
/*
* Initialize server entry point
*/
enum { STACK_SIZE = sizeof(addr_t)*1024 };
enum { STACK_SIZE = 2 * sizeof(addr_t)*1024 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "pci_ep");
@ -46,6 +45,6 @@ int main(int argc, char **argv)
static Pci::Root root(&ep, &sliced_heap);
env()->parent()->announce(ep.manage(&root));
Genode::sleep_forever();
sleep_forever();
return 0;
}

View File

@ -19,6 +19,8 @@
#include <base/rpc_server.h>
#include <base/printf.h>
#include <io_mem_session/io_mem_session.h>
#include "pci_device_config.h"
namespace Pci {
@ -28,18 +30,32 @@ namespace Pci {
{
private:
Device_config _device_config;
Device_config _device_config;
Genode::addr_t _config_space;
Genode::Io_mem_connection *_io_mem;
public:
/**
* Constructor
*/
Device_component(Device_config device_config):
_device_config(device_config) { }
Device_component(Device_config device_config, Genode::addr_t addr)
:
_device_config(device_config), _config_space(addr),
_io_mem(0) { }
/****************************************
** Methods used solely by pci session **
****************************************/
Device_config config() { return _device_config; }
Genode::addr_t config_space() { return _config_space; }
void set_config_space(Genode::Io_mem_connection * io_mem) {
_io_mem = io_mem; }
Genode::Io_mem_connection * get_config_space() { return _io_mem; }
/**************************
** PCI-device interface **

View File

@ -184,6 +184,29 @@ namespace Pci {
pci_config->write(_bus, _device, _function, address, value, size);
}
};
class Config_space : public Genode::List<Config_space>::Element
{
private:
Genode::uint32_t _bdf_start;
Genode::uint32_t _func_count;
Genode::addr_t _base;
public:
Config_space(Genode::uint32_t bdf_start,
Genode::uint32_t func_count, Genode::addr_t base)
:
_bdf_start(bdf_start), _func_count(func_count), _base(base) {}
Genode::addr_t lookup_config_space(Genode::uint32_t bdf)
{
if ((_bdf_start <= bdf) && (bdf <= _bdf_start + _func_count - 1))
return _base + (bdf << 12);
return 0;
}
};
}
#endif /* _DEVICE_CONFIG_H_ */

View File

@ -18,6 +18,10 @@
#include <pci_session/pci_session.h>
#include <root/component.h>
#include <io_mem_session/connection.h>
#include <os/config.h>
#include "pci_device_component.h"
#include "pci_config_access.h"
@ -77,7 +81,6 @@ namespace Pci {
Genode::Allocator *_md_alloc;
Genode::List<Device_component> _device_list;
/**
* Scan PCI busses for a device
*
@ -119,6 +122,34 @@ namespace Pci {
return false;
}
/**
* List containing extended PCI config space information
*/
static Genode::List<Config_space> &config_space_list() {
static Genode::List<Config_space> config_space;
return config_space;
}
/**
* Find for a given PCI device described by the bus:dev:func triple
* the corresponding extended 4K PCI config space address.
* A io mem dataspace is created and returned.
*/
Genode::addr_t
lookup_config_space(Genode::uint8_t bus, Genode::uint8_t dev,
Genode::uint8_t func)
{
using namespace Genode;
uint32_t bdf = (bus << 8) | ((dev & 0x1f) << 3) | (func & 0x7);
addr_t config_space = ~0UL; /* invalid */
Config_space *e = config_space_list().first();
for (; e && (config_space == ~0UL); e = e->next())
config_space = e->lookup_config_space(bdf);
return config_space;
}
public:
@ -139,6 +170,17 @@ namespace Pci {
release_device(_device_list.first()->cap());
}
static void add_config_space(Genode::uint32_t bdf_start,
Genode::uint32_t func_count,
Genode::addr_t base)
{
using namespace Genode;
Config_space * space =
new (env()->heap()) Config_space(bdf_start, func_count,
base);
config_space_list().insert(space);
}
/***************************
** PCI session interface **
@ -181,13 +223,22 @@ namespace Pci {
if (!_find_next(bus, device, function, &config, &config_access))
return Device_capability();
/* get new bdf values */
bus = config.bus_number();
device = config.device_number();
function = config.function_number();
/* lookup if we have a extended pci config space */
Genode::addr_t config_space = lookup_config_space(bus, device,
function);
/*
* A device was found. Create a new device component for the
* device and return its capability.
*
* FIXME: check and adjust session quota
*/
Device_component *device_component = new (_md_alloc) Device_component(config);
Device_component *device_component =
new (_md_alloc) Device_component(config, config_space);
if (!device_component)
return Device_capability();
@ -209,8 +260,37 @@ namespace Pci {
_ep->dissolve(device);
/* FIXME: adjust quota */
Genode::Io_mem_connection * io_mem = device->get_config_space();
if (io_mem)
destroy(_md_alloc, io_mem);
destroy(_md_alloc, device);
}
Genode::Io_mem_dataspace_capability config_extended(Device_capability device_cap)
{
using namespace Genode;
Object_pool<Device_component>::Guard
device(_ep->lookup_and_lock(device_cap));
if (!device || device->config_space() == ~0UL)
return Io_mem_dataspace_capability();
Io_mem_connection * io_mem = device->get_config_space();
if (io_mem)
return io_mem->dataspace();
try {
io_mem = new (_md_alloc) Io_mem_connection(device->config_space(),
0x1000);
} catch (Parent::Service_denied) {
return Io_mem_dataspace_capability();
}
device->set_config_space(io_mem);
return io_mem->dataspace();
}
};
@ -220,6 +300,35 @@ namespace Pci {
Genode::Cap_session *_cap_session;
void _parse_config()
{
using namespace Genode;
try {
unsigned i;
for (i = 0; i < config()->xml_node().num_sub_nodes(); i++)
{
Xml_node node = config()->xml_node().sub_node(i);
uint32_t bdf_start = 0;
uint32_t func_count = 0;
addr_t base = 0;
node.sub_node("start").value(&bdf_start);
node.sub_node("count").value(&func_count);
node.sub_node("base").value(&base);
PINF("%2u BDF start %x, functions: 0x%x, physical base "
"0x%lx", i, bdf_start, func_count, base);
Session_component::add_config_space(bdf_start,
func_count, base);
}
} catch (...) {
PERR("PCI config space data could not be parsed.");
}
}
protected:
Session_component *_create_session(const char *args)
@ -245,6 +354,8 @@ namespace Pci {
:
Genode::Root_component<Session_component>(ep, md_alloc)
{
_parse_config();
/* enforce initial bus scan */
bus_valid();
}