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() Connection()
: :
Genode::Connection<Session>(session("ram_quota=4K")), Genode::Connection<Session>(session("ram_quota=12K")),
Session_client(cap()) Session_client(cap())
{ } { }
}; };

View File

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

View File

@ -147,7 +147,11 @@ namespace Pci {
void close(Genode::Session_capability session) { void close(Genode::Session_capability session) {
Genode::Root_client(_pci_provider.root()).close(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() void _acpi_session()
{ {
Pci::Session_capability session; Pci::Session_capability session;
const char *args = "label=\"acpi_drv\", ram_quota=4K"; const char *args = "label=\"acpi_drv\", ram_quota=16K";
try { try {
using namespace Genode; 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 */ /* return invalid resource if device is invalid */
if (!_device_config.valid()) if (!_device_config.valid())
Resource(0, 0); return Resource(0, 0);
return _device_config.resource(resource_id); return _device_config.resource(resource_id);
} }

View File

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

View File

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