pci: add device_pd functionality

This commit is contained in:
Alexander Boettcher 2013-02-18 10:08:14 +01:00 committed by Norman Feske
parent 2123f3f7e8
commit e05adecfab
6 changed files with 266 additions and 15 deletions

View File

@ -163,8 +163,9 @@ class Pci_policy : public Genode::Slave_policy, public Pci::Provider
char const **_permitted_services() const
{
static char const *permitted_services[] = { "CPU", "CAP", "RM",
"LOG", "IO_PORT",
"SIGNAL", 0};
"LOG", "IO_PORT", "PD",
"ROM", "RAM", "SIGNAL",
"IO_MEM", 0 };
return permitted_services;
};

View File

@ -0,0 +1,95 @@
/*
* \brief Pci device protection domain service for pci_drv
* \author Alexander Boettcher
* \date 2013-02-10
*/
/*
* Copyright (C) 2013-2013 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/static_root.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <cap_session/connection.h>
#include <dataspace/client.h>
#include <pd_session/client.h>
#include <util/touch.h>
#include "../pci_device_pd_ipc.h"
void Pci::Device_pd_component::attach_dma_mem(Genode::Ram_dataspace_capability ds_cap)
{
using namespace Genode;
Dataspace_client ds_client(ds_cap);
addr_t page = env()->rm_session()->attach_at(ds_cap, ds_client.phys_addr());
/* sanity check */
if (page != ds_client.phys_addr())
throw Rm_session::Region_conflict();
/* trigger mapping of whole memory area */
for (size_t rounds = (ds_client.size() + 1) / 4096; rounds;
page += 4096, rounds --)
touch_read(reinterpret_cast<unsigned char *>(page));
}
void Pci::Device_pd_component::assign_pci(Genode::Io_mem_dataspace_capability io_mem_cap)
{
using namespace Genode;
Dataspace_client ds_client(io_mem_cap);
addr_t page = env()->rm_session()->attach(io_mem_cap);
/* sanity check */
if (!page)
throw Rm_session::Region_conflict();
/* trigger mapping of whole memory area */
touch_read(reinterpret_cast<unsigned char *>(page));
/* try to assign pci device to this protection domain */
if (!env()->pd_session()->assign_pci(page))
PERR("assignment of PCI device failed");
/* we don't need the mapping anymore */
env()->rm_session()->detach(page);
}
int main(int argc, char **argv)
{
using namespace Genode;
Genode::printf("PCI device pd starting ...\n");
/*
* Initialize server entry point
*/
enum {
STACK_SIZE = 4096
};
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "pci_device_pd_ep");
static Pci::Device_pd_component pci_device_component;
/*
* Attach input root interface to the entry point
*/
static Static_root<Pci::Device_pd> root(ep.manage(&pci_device_component));
env()->parent()->announce(ep.manage(&root));
printf("PCI device pd started\n");
Genode::sleep_forever();
return 0;
}

View File

@ -0,0 +1,6 @@
TARGET = pci_device_pd
SRC_CC = main.cc
LIBS = base
REQUIRES = nova

View File

@ -16,12 +16,62 @@
#include <base/sleep.h>
#include <cap_session/connection.h>
#include <os/slave.h>
#include "pci_session_component.h"
#include "pci_device_config.h"
using namespace Genode;
using namespace Pci;
class Device_pd_policy : public Genode::Slave_policy
{
private:
Genode::Root_capability _cap;
Genode::Lock _lock;
protected:
char const **_permitted_services() const
{
static char const *permitted_services[] = { "LOG", "CAP", "RM",
"CPU", 0 };
return permitted_services;
};
public:
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep)
:
Slave_policy("pci_device_pd", slave_ep),
_lock(Genode::Lock::LOCKED)
{ }
bool announce_service(const char *service_name,
Genode::Root_capability root,
Genode::Allocator *alloc,
Genode::Server *server)
{
/* wait for 'pci_drv' to announce the PCI service */
if (Genode::strcmp(service_name, "PCI_DEV_PD"))
return false;
_cap = root;
_lock.unlock();
return true;
}
Genode::Root_capability root() {
if (!_cap.valid())
_lock.lock();
return _cap;
}
};
int main(int argc, char **argv)
{
printf("PCI driver started\n");
@ -29,10 +79,26 @@ int main(int argc, char **argv)
/*
* Initialize server entry point
*/
enum { STACK_SIZE = 2 * sizeof(addr_t)*1024 };
enum {
STACK_SIZE = 2 * sizeof(addr_t)*1024,
PCI_DEVICE_PD_RAM_QUOTA = 512 * 1024,
};
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "pci_ep");
/* use 'pci_device_pd' as slave service */
Session_capability session_dev_pd;
try {
static Rpc_entrypoint device_pd_ep(&cap, STACK_SIZE, "device_pd_slave");
static Device_pd_policy device_pd_policy(device_pd_ep);
static Genode::Slave device_pd_slave(device_pd_ep, device_pd_policy,
PCI_DEVICE_PD_RAM_QUOTA);
session_dev_pd = Genode::Root_client(device_pd_policy.root()).session("");
} catch (...) {
PWRN("PCI device protection domain for IOMMU support is not available");
}
/*
* Use sliced heap to allocate each session component at a separate
* dataspace.
@ -42,7 +108,8 @@ int main(int argc, char **argv)
/*
* Let the entry point serve the PCI root interface
*/
static Pci::Root root(&ep, &sliced_heap);
static Pci::Root root(&ep, &sliced_heap, PCI_DEVICE_PD_RAM_QUOTA,
Genode::reinterpret_cap_cast<Device_pd>(session_dev_pd));
env()->parent()->announce(ep.manage(&root));
sleep_forever();

View File

@ -0,0 +1,57 @@
/*
* \brief IPC interface between pci_drv and pci_device_pd
* \author Alexander Boettcher
* \date 2013-02-15
*/
/*
* Copyright (C) 2013-2013 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.
*/
#ifndef _PCI_DEVICE_PD_IPC_H_
#define _PCI_DEVICE_PD_IPC_H_
#include <base/rpc_server.h>
#include <io_mem_session/capability.h>
#include <ram_session/ram_session.h>
namespace Pci {
struct Device_pd : Genode::Session
{
static const char *service_name() { return "PCI_DEV_PD"; }
GENODE_RPC(Rpc_attach_dma_mem, void, attach_dma_mem,
Genode::Ram_dataspace_capability);
GENODE_RPC(Rpc_assign_pci, void, assign_pci,
Genode::Io_mem_dataspace_capability);
GENODE_RPC_INTERFACE(Rpc_attach_dma_mem, Rpc_assign_pci);
};
struct Device_pd_client : Genode::Rpc_client<Device_pd>
{
Device_pd_client(Capability<Device_pd> cap)
:
Rpc_client<Device_pd>(cap) { }
void attach_dma_mem(Genode::Ram_dataspace_capability cap) {
call<Rpc_attach_dma_mem>(cap); }
void assign_pci(Genode::Io_mem_dataspace_capability cap) {
call<Rpc_assign_pci>(cap); }
};
struct Device_pd_component : Genode::Rpc_object<Device_pd,
Device_pd_component>
{
void attach_dma_mem(Genode::Ram_dataspace_capability);
void assign_pci(Genode::Io_mem_dataspace_capability);
};
}
#endif /* _PCI_DEVICE_PD_IPC_H_ */

View File

@ -24,11 +24,12 @@
#include "pci_device_component.h"
#include "pci_config_access.h"
#include "pci_device_pd_ipc.h"
namespace Pci {
/**
* Check if given PCI bus was found on inital scan
* Check if given PCI bus was found on initial scan
*
* This tremendously speeds up further scans by other drivers.
*/
@ -80,9 +81,10 @@ namespace Pci {
Genode::Rpc_entrypoint *_ep;
Genode::Allocator *_md_alloc;
Genode::List<Device_component> _device_list;
Device_pd_client *_child;
/**
* Scan PCI busses for a device
* Scan PCI buses for a device
*
* \param bus start scanning at bus number
* \param device start scanning at device number
@ -157,8 +159,10 @@ namespace Pci {
* Constructor
*/
Session_component(Genode::Rpc_entrypoint *ep,
Genode::Allocator *md_alloc):
_ep(ep), _md_alloc(md_alloc) { }
Genode::Allocator *md_alloc,
Device_pd_client *child)
:
_ep(ep), _md_alloc(md_alloc), _child(child) { }
/**
* Destructor
@ -231,6 +235,7 @@ namespace Pci {
/* 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.
@ -289,12 +294,25 @@ namespace Pci {
device->set_config_space(io_mem);
if (_child)
_child->assign_pci(io_mem->dataspace());
return io_mem->dataspace();
}
Genode::Ram_dataspace_capability alloc_dma_buffer(Device_capability device_cap,
Genode::size_t size) {
return Genode::env()->ram_session()->alloc(size, false); }
Genode::size_t size)
{
Genode::Ram_dataspace_capability ram =
Genode::env()->ram_session()->alloc(size, false);
if (!ram.valid() || !_child)
return ram;
_child->attach_dma_mem(ram);
return ram;
}
};
@ -302,7 +320,8 @@ namespace Pci {
{
private:
Genode::Cap_session *_cap_session;
/* for now we have only one device pd for all pci devices */
Device_pd_client *_pd_device_client;
void _parse_config()
@ -340,7 +359,8 @@ namespace Pci {
/* FIXME: extract quota from args */
/* FIXME: pass quota to session-component constructor */
return new (md_alloc()) Session_component(ep(), md_alloc());
return new (md_alloc()) Session_component(ep(), md_alloc(),
_pd_device_client);
}
public:
@ -353,13 +373,18 @@ namespace Pci {
* \param md_alloc meta-data allocator for allocating PCI-session
* components and PCI-device components
*/
Root(Genode::Rpc_entrypoint *ep,
Genode::Allocator *md_alloc)
Root(Genode::Rpc_entrypoint *ep, Genode::Allocator *md_alloc,
Genode::size_t pci_device_pd_ram_quota,
Genode::Capability <Device_pd> pci_device_pd)
:
Genode::Root_component<Session_component>(ep, md_alloc)
Genode::Root_component<Session_component>(ep, md_alloc),
_pd_device_client(0)
{
_parse_config();
if (pci_device_pd.valid())
_pd_device_client = new (md_alloc) Device_pd_client(pci_device_pd);
/* enforce initial bus scan */
bus_valid();
}