pci: use ram quota upgrade mechanism

Fixes #755
This commit is contained in:
Alexander Boettcher 2015-04-16 15:54:07 +02:00 committed by Christian Helmuth
parent df50d1b29d
commit 06e7c947bc
6 changed files with 87 additions and 47 deletions

View File

@ -24,7 +24,7 @@ struct Pci::Connection : Genode::Connection<Session>, Session_client
{
Connection()
:
Genode::Connection<Session>(session("ram_quota=4K")),
Genode::Connection<Session>(session("ram_quota=12K")),
Session_client(cap())
{ }
};

View File

@ -86,16 +86,20 @@ struct Pci::Session : Genode::Session
** RPC declaration **
*********************/
GENODE_RPC(Rpc_first_device, Device_capability, first_device,
unsigned, unsigned);
GENODE_RPC(Rpc_next_device, Device_capability, next_device,
Device_capability, unsigned, unsigned);
GENODE_RPC_THROW(Rpc_first_device, Device_capability, first_device,
GENODE_TYPE_LIST(Pci::Device::Quota_exceeded),
unsigned, unsigned);
GENODE_RPC_THROW(Rpc_next_device, Device_capability, next_device,
GENODE_TYPE_LIST(Pci::Device::Quota_exceeded),
Device_capability, unsigned, unsigned);
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_THROW(Rpc_config_extended, Genode::Io_mem_dataspace_capability,
config_extended,
GENODE_TYPE_LIST(Pci::Device::Quota_exceeded),
Device_capability);
GENODE_RPC_THROW(Rpc_alloc_dma_buffer, Genode::Ram_dataspace_capability,
alloc_dma_buffer,
GENODE_TYPE_LIST(Genode::Ram_session::Quota_exceeded),
GENODE_TYPE_LIST(Pci::Device::Quota_exceeded),
Genode::size_t);
GENODE_RPC(Rpc_free_dma_buffer, void, free_dma_buffer,
Genode::Ram_dataspace_capability);

View File

@ -147,7 +147,11 @@ namespace Pci {
void close(Genode::Session_capability session) {
Genode::Root_client(_pci_provider.root()).close(session); }
void upgrade(Genode::Session_capability, Upgrade_args const &) { }
void upgrade(Genode::Session_capability s, Upgrade_args const & u)
{
try { Genode::Root_client(_pci_provider.root()).upgrade(s, u); }
catch (...) { throw Invalid_args(); }
}
};
}
@ -178,7 +182,7 @@ class Pci_policy : public Genode::Slave_policy, public Pci::Provider
void _acpi_session()
{
Pci::Session_capability session;
const char *args = "label=\"acpi_drv\", ram_quota=4K";
const char *args = "label=\"acpi_drv\", ram_quota=16K";
try {
using namespace Genode;

View File

@ -114,7 +114,7 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
{
/* return invalid resource if device is invalid */
if (!_device_config.valid())
Resource(0, 0);
return Resource(0, 0);
return _device_config.resource(resource_id);
}

View File

@ -56,6 +56,8 @@ namespace Pci {
return resource_id >= 0 && resource_id < max_num;
}
enum { INVALID_VENDOR = 0xffffU };
public:
enum { MAX_BUSES = 256, MAX_DEVICES = 32, MAX_FUNCTIONS = 8 };
@ -63,7 +65,8 @@ namespace Pci {
/**
* Constructor
*/
Device_config() { }
Device_config() : _vendor_id(INVALID_VENDOR) { }
Device_config(int bus, int device, int function,
Config_access *pci_config):
_bus(bus), _device(device), _function(function)
@ -71,7 +74,7 @@ namespace Pci {
_vendor_id = pci_config->read(bus, device, function, 0, Device::ACCESS_16BIT);
/* break here if device is invalid */
if (_vendor_id == 0xffff)
if (_vendor_id == INVALID_VENDOR)
return;
_device_id = pci_config->read(bus, device, function, 2, Device::ACCESS_16BIT);
@ -88,7 +91,7 @@ namespace Pci {
*/
if (function != 0
&& !(pci_config->read(bus, device, 0, 0xe, Device::ACCESS_8BIT) & 0x80)) {
_vendor_id = 0xffff;
_vendor_id = INVALID_VENDOR;
return;
}
@ -152,7 +155,7 @@ namespace Pci {
/**
* Return true if device is valid
*/
bool valid() { return _vendor_id != 0xffff; }
bool valid() { return _vendor_id != INVALID_VENDOR; }
/**
* Return resource description by resource ID

View File

@ -15,7 +15,10 @@
#define _PCI_SESSION_COMPONENT_H_
/* base */
#include <base/allocator_guard.h>
#include <base/rpc_server.h>
#include <base/tslab.h>
#include <ram_session/connection.h>
#include <root/component.h>
@ -40,13 +43,14 @@ namespace Pci {
{
private:
Genode::Rpc_entrypoint *_ep;
Genode::Allocator *_md_alloc;
Genode::List<Device_component> _device_list;
Device_pd_client *_child;
Genode::Ram_connection *_ram;
Genode::Session_label _label;
Genode::Session_policy _policy;
Genode::Rpc_entrypoint *_ep;
Genode::Allocator_guard _md_alloc;
Genode::Tslab<Device_component, 4096 - 64> _device_slab;
Genode::List<Device_component> _device_list;
Device_pd_client *_child;
Genode::Ram_connection *_ram;
Genode::Session_label _label;
Genode::Session_policy _policy;
/**
* Scan PCI buses for a device
@ -296,7 +300,9 @@ namespace Pci {
Genode::Ram_connection *ram,
const char *args)
:
_ep(ep), _md_alloc(md_alloc),
_ep(ep),
_md_alloc(md_alloc, Genode::Arg_string::find_arg(args, "ram_quota").long_value(0)),
_device_slab(&_md_alloc),
_child(child), _ram(ram), _label(args), _policy(_label)
{
/* non-pci devices */
@ -403,6 +409,10 @@ namespace Pci {
release_device(_device_list.first()->cap());
}
void upgrade_ram_quota(long quota) { _md_alloc.upgrade(quota); }
static void add_config_space(Genode::uint32_t bdf_start,
Genode::uint32_t func_count,
Genode::addr_t base)
@ -484,17 +494,14 @@ namespace Pci {
/*
* 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, config_space, _ep, this);
if (!device_component)
return Device_capability();
_device_list.insert(device_component);
return _ep->manage(device_component);
try {
Device_component * dev = new (_device_slab) Device_component(config, config_space, _ep, this);
_device_list.insert(dev);
return _ep->manage(dev);
} catch (Genode::Allocator::Out_of_memory) {
throw Device::Quota_exceeded();
}
}
void release_device(Device_capability device_cap)
@ -509,11 +516,14 @@ namespace Pci {
_device_list.remove(device);
_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);
if (device->config().valid())
destroy(_device_slab, device);
else
destroy(_md_alloc, device);
}
Genode::Io_mem_dataspace_capability config_extended(Device_capability device_cap)
@ -533,6 +543,8 @@ namespace Pci {
try {
io_mem = new (_md_alloc) Io_mem_connection(device->config_space(),
0x1000);
} catch (Genode::Allocator::Out_of_memory) {
throw Device::Quota_exceeded();
} catch (Parent::Service_denied) {
return Io_mem_dataspace_capability();
}
@ -552,17 +564,30 @@ namespace Pci {
Ram_capability alloc_dma_buffer(Genode::size_t size)
{
if (Genode::env()->ram_session()->transfer_quota(_ram->cap(),
size))
if (!_md_alloc.withdraw(size))
throw Device::Quota_exceeded();
Genode::Ram_session * const rs = Genode::env()->ram_session();
if (rs->transfer_quota(_ram->cap(), size)) {
_md_alloc.upgrade(size);
return Ram_capability();
}
Ram_capability ram = _ram->alloc(size, Genode::UNCACHED);
if (!ram.valid() || !_child)
return ram;
Ram_capability ram_cap;
try {
_child->attach_dma_mem(ram);
ram_cap = _ram->alloc(size, Genode::UNCACHED);
} catch (Genode::Ram_session::Quota_exceeded) {
_md_alloc.upgrade(size);
return Ram_capability();
}
return ram;
if (!ram_cap.valid() || !_child)
return ram_cap;
_child->attach_dma_mem(ram_cap);
return ram_cap;
}
void free_dma_buffer(Ram_capability ram)
@ -623,9 +648,6 @@ namespace Pci {
Session_component *_create_session(const char *args)
{
/* FIXME: extract quota from args */
/* FIXME: pass quota to session-component constructor */
try {
return new (md_alloc()) Session_component(ep(), md_alloc(),
_pd_device_client,
@ -637,6 +659,14 @@ namespace Pci {
}
}
void _upgrade_session(Session_component *s, const char *args) override
{
long ram_quota = Genode::Arg_string::find_arg(args, "ram_quota").long_value(0);
s->upgrade_ram_quota(ram_quota);
}
public:
/**
@ -653,7 +683,6 @@ namespace Pci {
:
Genode::Root_component<Session_component>(ep, md_alloc),
_pd_device_client(0),
/* restrict physical address to 4G on 32/64bit in general XXX */
/* restrict physical address to 3G on 32bit with device_pd */
_ram("dma", 0, (pci_device_pd.valid() && sizeof(void *) == 4) ?
0xc0000000UL : 0x100000000ULL)
@ -661,7 +690,7 @@ namespace Pci {
_parse_config();
if (pci_device_pd.valid())
_pd_device_client = new (md_alloc) Device_pd_client(pci_device_pd);
_pd_device_client = new (Genode::env()->heap()) Device_pd_client(pci_device_pd);
/* associate _ram session with ram_session of process */
_ram.ref_account(Genode::env()->ram_session_cap());