x86: support dynamic upgrades for platform driver

and, especially, for the device_pd. Account all resources per platform session
separately.

Fixes #1539
This commit is contained in:
Alexander Boettcher 2015-11-16 14:04:04 +01:00 committed by Christian Helmuth
parent 4c4e7c64d0
commit 92cb9eb06d
16 changed files with 341 additions and 147 deletions

View File

@ -19,6 +19,7 @@
#include <io_mem_session/connection.h>
#include <platform_session/connection.h>
#include <platform_device/client.h>
#include <util/retry.h>
/* local includes */
#include "bsd.h"
@ -120,13 +121,17 @@ class Pci_driver : public Bsd::Bus_driver
*/
Genode::Ram_dataspace_capability _alloc_dma_memory(Genode::size_t size)
{
try {
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%zu", size);
Genode::env()->parent()->upgrade(_pci.cap(), buf);
size_t donate = size;
return _pci.alloc_dma_buffer(size);
} catch (...) { return Genode::Ram_dataspace_capability(); }
return Genode::retry<Platform::Session::Out_of_metadata>(
[&] () { return _pci.alloc_dma_buffer(size); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
Genode::env()->parent()->upgrade(_pci.cap(), quota);
donate = donate * 2 > size ? 4096 : donate * 2;
});
}
public:
@ -374,7 +379,18 @@ extern "C" int pci_mapreg_map(struct pci_attach_args *pa,
}
cmd |= Pci_driver::CMD_MASTER;
device.config_write(Pci_driver::CMD, cmd, Platform::Device::ACCESS_16BIT);
Genode::size_t donate = 4096;
Genode::retry<Platform::Device::Quota_exceeded>(
[&] () { device.config_write(Pci_driver::CMD, cmd,
Platform::Device::ACCESS_16BIT); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
Genode::env()->parent()->upgrade(drv->pci().cap(), quota);
donate *= 2;
});
return 0;
}

View File

@ -35,6 +35,8 @@
#include <rm_session/connection.h>
#include <timer_session/connection.h>
#include <util/misc_math.h>
#include <util/retry.h>
/* local includes */
#include <dde_support.h>
@ -168,7 +170,17 @@ struct Pci_driver
void config_write(unsigned int devfn, T val)
{
Platform::Device_client client(_cap);
client.config_write(devfn, val, _access_size(val));
Genode::size_t donate = 4096;
Genode::retry<Platform::Device::Quota_exceeded>(
[&] () { client.config_write(devfn, val, _access_size(val)); } ,
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
Genode::env()->parent()->upgrade(_pci.cap(), quota);
donate *= 2;
});
}
int first_device(int *bus, int *dev, int *fun)
@ -196,18 +208,26 @@ struct Pci_driver
try {
using namespace Genode;
/* transfer quota to pci driver, otherwise it will give us a exception */
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%zd", size);
Genode::env()->parent()->upgrade(_pci.cap(), buf);
size_t donate = size;
Ram_dataspace_capability ram_cap = _pci.alloc_dma_buffer(size);
Ram_dataspace_capability ram_cap = Genode::retry<Platform::Session::Out_of_metadata>(
[&] () { return _pci.alloc_dma_buffer(size); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
Genode::env()->parent()->upgrade(_pci.cap(), quota);
donate = donate * 2 > size ? 4096 : donate * 2;
});
_region.mapped_base = (Genode::addr_t)env()->rm_session()->attach(ram_cap);
_region.base = Dataspace_client(ram_cap).phys_addr();
return _region.mapped_base;
} catch (...) { return 0; }
} catch (...) {
PERR("failed to allocate dma memory");
return 0;
}
}
Genode::addr_t virt_to_phys(Genode::addr_t virt) {

View File

@ -16,6 +16,7 @@
#include <io_mem_session/client.h>
#include <irq_session/connection.h>
#include <ram_session/client.h>
#include <util/retry.h>
/* Genode os includes */
#include <io_port_session/client.h>
@ -421,7 +422,7 @@ int pci_register_driver(struct pci_driver *drv)
try {
cap = pci.next_device(cap, id->class_, id->class_mask);
} catch (Platform::Device::Quota_exceeded) {
} catch (Platform::Session::Out_of_metadata) {
Genode::env()->parent()->upgrade(pci.cap(), "ram_quota=4096");
cap = pci.next_device(cap, id->class_, id->class_mask);
}
@ -525,12 +526,16 @@ Backend_memory::alloc(Genode::addr_t size, Genode::Cache_attribute cached)
cap = env()->ram_session()->alloc(size);
o = new (env()->heap()) Ram_object(cap);
} else {
/* transfer quota to pci driver, otherwise it will give us a exception */
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%ld", size);
Genode::env()->parent()->upgrade(pci.cap(), buf);
cap = pci.alloc_dma_buffer(size);
size_t donate = size;
cap = Genode::retry<Platform::Session::Out_of_metadata>(
[&] () { return pci.alloc_dma_buffer(size); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
Genode::env()->parent()->upgrade(pci.cap(), quota);
donate = donate * 2 > size ? 4096 : donate * 2;
});
o = new (env()->heap()) Dma_object(cap);
}

View File

@ -454,12 +454,16 @@ Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached)
cap = env()->ram_session()->alloc(size);
o = new (env()->heap()) Ram_object(cap);
} else {
/* transfer quota to pci driver, otherwise it will give us a exception */
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%ld", size);
Genode::env()->parent()->upgrade(pci()->cap(), buf);
cap = pci()->alloc_dma_buffer(size);
size_t donate = size;
cap = Genode::retry<Platform::Session::Out_of_metadata>(
[&] () { return pci()->alloc_dma_buffer(size); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
Genode::env()->parent()->upgrade(pci()->cap(), quota);
donate = donate * 2 > size ? 4096 : donate * 2;
});
o = new (env()->heap()) Dma_object(cap);
}

View File

@ -234,8 +234,9 @@ struct Platform::Device : Platform::Abstract_device
GENODE_RPC(Rpc_resource, Resource, resource, int);
GENODE_RPC(Rpc_config_read, unsigned, config_read,
unsigned char, Access_size);
GENODE_RPC(Rpc_config_write, void, config_write,
unsigned char, unsigned, Access_size);
GENODE_RPC_THROW(Rpc_config_write, void, config_write,
GENODE_TYPE_LIST(Quota_exceeded),
unsigned char, unsigned, Access_size);
GENODE_RPC(Rpc_irq, Genode::Irq_session_capability, irq, Genode::uint8_t);
GENODE_RPC_THROW(Rpc_io_port, Genode::Io_port_session_capability, io_port,
GENODE_TYPE_LIST(Quota_exceeded),

View File

@ -38,9 +38,6 @@ struct Platform::Client : public Genode::Rpc_client<Session>
void release_device(Device_capability device) override {
call<Rpc_release_device>(device); }
Genode::Io_mem_dataspace_capability config_extended(Device_capability device_cap) override {
return call<Rpc_config_extended>(device_cap); }
Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t size) override {
return call<Rpc_alloc_dma_buffer>(size); }

View File

@ -26,6 +26,14 @@ namespace Platform { struct Session; }
struct Platform::Session : Genode::Session
{
/*********************
** Exception types **
*********************/
class Alloc_failed : public Genode::Exception { };
class Out_of_metadata : public Alloc_failed { };
class Fatal : public Alloc_failed { };
static const char *service_name() { return "Platform"; }
virtual ~Session() { }
@ -53,12 +61,6 @@ struct Platform::Session : Genode::Session
*/
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;
typedef Genode::Rpc_in_buffer<8> String;
/**
@ -82,28 +84,23 @@ struct Platform::Session : Genode::Session
*********************/
GENODE_RPC_THROW(Rpc_first_device, Device_capability, first_device,
GENODE_TYPE_LIST(Platform::Device::Quota_exceeded),
GENODE_TYPE_LIST(Out_of_metadata),
unsigned, unsigned);
GENODE_RPC_THROW(Rpc_next_device, Device_capability, next_device,
GENODE_TYPE_LIST(Platform::Device::Quota_exceeded),
GENODE_TYPE_LIST(Out_of_metadata),
Device_capability, unsigned, unsigned);
GENODE_RPC(Rpc_release_device, void, release_device, Device_capability);
GENODE_RPC_THROW(Rpc_config_extended, Genode::Io_mem_dataspace_capability,
config_extended,
GENODE_TYPE_LIST(Platform::Device::Quota_exceeded),
Device_capability);
GENODE_RPC_THROW(Rpc_alloc_dma_buffer, Genode::Ram_dataspace_capability,
alloc_dma_buffer,
GENODE_TYPE_LIST(Platform::Device::Quota_exceeded),
GENODE_TYPE_LIST(Out_of_metadata, Fatal),
Genode::size_t);
GENODE_RPC(Rpc_free_dma_buffer, void, free_dma_buffer,
Genode::Ram_dataspace_capability);
GENODE_RPC_THROW(Rpc_device, Device_capability, device,
GENODE_TYPE_LIST(Platform::Device::Quota_exceeded),
GENODE_TYPE_LIST(Out_of_metadata),
String const &);
GENODE_RPC_INTERFACE(Rpc_first_device, Rpc_next_device,
Rpc_release_device, Rpc_config_extended,
Rpc_alloc_dma_buffer, Rpc_free_dma_buffer,
Rpc_device);
Rpc_release_device, Rpc_alloc_dma_buffer,
Rpc_free_dma_buffer, Rpc_device);
};

View File

@ -41,17 +41,15 @@ struct X86_hba : Platform::Hba
X86_hba()
{
for (unsigned i = 0; i < 2; i++)
try {
if (!(pci_device_cap =
pci.next_device(pci_device_cap, AHCI_DEVICE, CLASS_MASK)).valid()) {
PERR("No AHCI controller found");
throw -1;
}
break;
} catch (Platform::Device::Quota_exceeded) {
Genode::env()->parent()->upgrade(pci.cap(), "ram_quota=4096");
}
pci_device_cap = retry<Platform::Session::Out_of_metadata>(
[&] () { return pci.next_device(pci_device_cap, AHCI_DEVICE,
CLASS_MASK); },
[&] () { env()->parent()->upgrade(pci.cap(), "ram_quota=4096"); });
if (!pci_device_cap.valid()) {
PERR("No AHCI controller found");
throw -1;
}
/* construct pci client */
pci_device.construct(pci_device_cap);
@ -70,7 +68,7 @@ struct X86_hba : Platform::Hba
/* enable bus master */
uint16_t cmd = pci_device->config_read(PCI_CMD, Platform::Device::ACCESS_16BIT);
cmd |= 0x4;
pci_device->config_write(PCI_CMD, cmd, Platform::Device::ACCESS_16BIT);
_config_write(PCI_CMD, cmd, Platform::Device::ACCESS_16BIT);
irq.construct(pci_device->irq(0));
}
@ -90,12 +88,28 @@ struct X86_hba : Platform::Hba
uint16_t msi = pci_device->config_read(cap + 2, Platform::Device::ACCESS_16BIT);
if (msi & MSI_ENABLED) {
pci_device->config_write(cap + 2, msi ^ MSI_CAP, Platform::Device::ACCESS_8BIT);
_config_write(cap + 2, msi ^ MSI_CAP,
Platform::Device::ACCESS_8BIT);
PINF("Disabled MSIs %x", msi);
}
}
}
void _config_write(uint8_t op, uint16_t cmd,
Platform::Device::Access_size width)
{
Genode::size_t donate = 4096;
Genode::retry<Platform::Device::Quota_exceeded>(
[&] () { pci_device->config_write(op, cmd, width); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
Genode::env()->parent()->upgrade(pci.cap(), quota);
donate *= 2;
});
}
/*******************
** Hba interface **
@ -115,12 +129,16 @@ struct X86_hba : Platform::Hba
Ram_dataspace_capability
alloc_dma_buffer(Genode::size_t size) override
{
/* transfer quota to pci driver, otherwise we get a exception */
char quota[32];
snprintf(quota, sizeof(quota), "ram_quota=%zd", size);
env()->parent()->upgrade(pci.cap(), quota);
size_t donate = size;
return pci.alloc_dma_buffer(size);
return retry<Platform::Session::Out_of_metadata>(
[&] () { return pci.alloc_dma_buffer(size); },
[&] () {
char quota[32];
snprintf(quota, sizeof(quota), "ram_quota=%zd", donate);
env()->parent()->upgrade(pci.cap(), quota);
donate = donate * 2 > size ? 4096 : donate * 2;
});
}
void free_dma_buffer(Genode::Ram_dataspace_capability ds)

View File

@ -15,10 +15,7 @@
#include <os/slave.h>
enum {
DEVICE_PD_RAM_QUOTA = 256 * 4096,
STACK_SIZE = 2 * sizeof(void *)*1024
};
enum { STACK_SIZE = 2 * sizeof(void *) * 1024 };
namespace Platform { class Device_pd_policy; }
@ -29,7 +26,8 @@ class Platform::Device_pd_policy : public Genode::Slave_policy
Genode::Root_capability _cap;
Genode::Lock _lock;
Genode::Slave _device_pd_slave;
Genode::Ram_session_capability _ram_ref_cap;
Genode::Slave _device_pd_slave;
protected:
@ -41,11 +39,14 @@ class Platform::Device_pd_policy : public Genode::Slave_policy
public:
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep)
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep,
Genode::Ram_session_capability ram_ref_cap,
Genode::addr_t device_pd_ram_quota)
:
Slave_policy("device_pd", slave_ep),
_lock(Genode::Lock::LOCKED),
_device_pd_slave(slave_ep, *this, DEVICE_PD_RAM_QUOTA)
_ram_ref_cap(ram_ref_cap),
_device_pd_slave(slave_ep, *this, device_pd_ram_quota, ram_ref_cap)
{ }
bool announce_service(const char *service_name,
@ -69,6 +70,15 @@ class Platform::Device_pd_policy : public Genode::Slave_policy
_lock.lock();
return _cap;
}
Genode::Ram_connection &ram_slave() { return _device_pd_slave.ram(); }
/**
* Override struct Genode::Child_policy::ref_ram_cap with our ram cap
*/
Genode::Ram_session_capability ref_ram_cap() const override {
return _ram_ref_cap; }
};

View File

@ -17,12 +17,58 @@
#include <cap_session/connection.h>
#include <dataspace/client.h>
#include <rm_session/client.h>
#include <pd_session/client.h>
#include <util/flex_iterator.h>
#include <util/retry.h>
#include "../pci_device_pd_ipc.h"
/**
*
*/
struct Expanding_rm_session_client : Genode::Rm_session_client
{
Genode::Rm_session_capability _cap;
Expanding_rm_session_client(Genode::Rm_session_capability cap)
: Rm_session_client(cap), _cap(cap) { }
Local_addr attach(Genode::Dataspace_capability ds,
Genode::size_t size, Genode::off_t offset,
bool use_local_addr,
Local_addr local_addr,
bool executable) override
{
return Genode::retry<Rm_session::Out_of_metadata>(
[&] () {
return Rm_session_client::attach(ds, size, offset,
use_local_addr,
local_addr,
executable); },
[&] () {
enum { UPGRADE_QUOTA = 4096 };
if (Genode::env()->ram_session()->avail() < UPGRADE_QUOTA)
throw;
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%u",
UPGRADE_QUOTA);
Genode::env()->parent()->upgrade(_cap, buf);
});
}
};
static Genode::Rm_session *rm_session() {
using namespace Genode;
static Expanding_rm_session_client rm (static_cap_cast<Rm_session>(env()->parent()->session("Env::rm_session", "")));
return &rm;
}
static bool map_eager(Genode::addr_t const page, unsigned log2_order)
{
using Genode::addr_t;
@ -56,13 +102,15 @@ void Platform::Device_pd_component::attach_dma_mem(Genode::Dataspace_capability
addr_t page = ~0UL;
try {
page = env()->rm_session()->attach_at(ds_cap, phys);
page = rm_session()->attach_at(ds_cap, phys);
} catch (Rm_session::Out_of_metadata) {
throw;
} catch (...) { }
/* sanity check */
if ((page == ~0UL) || (page != phys)) {
if (page != ~0UL)
env()->rm_session()->detach(page);
rm_session()->detach(page);
PERR("attachment of DMA memory @ %lx+%zx failed", phys, size);
return;
@ -85,7 +133,7 @@ void Platform::Device_pd_component::assign_pci(Genode::Io_mem_dataspace_capabili
Dataspace_client ds_client(io_mem_cap);
addr_t page = env()->rm_session()->attach(io_mem_cap);
addr_t page = rm_session()->attach(io_mem_cap);
/* sanity check */
if (!page)
throw Rm_session::Region_conflict();
@ -99,7 +147,7 @@ void Platform::Device_pd_component::assign_pci(Genode::Io_mem_dataspace_capabili
PERR("assignment of PCI device failed");
/* we don't need the mapping anymore */
env()->rm_session()->detach(page);
rm_session()->detach(page);
}
int main(int argc, char **argv)

View File

@ -125,7 +125,7 @@ Platform::Device_capability Platform::Session_component::device(String const &na
_device_list.insert(dev);
return _ep->manage(dev);
} catch (Genode::Allocator::Out_of_memory) {
throw Platform::Device::Quota_exceeded();
throw Out_of_metadata();
} catch (Genode::Parent::Service_denied) {
return Device_capability();
}

View File

@ -73,7 +73,7 @@ Genode::Io_mem_session_capability Platform::Device_component::io_mem(Genode::uin
_io_mem[i].insert(io_mem);
return io_mem->cap();
} catch (Genode::Allocator::Out_of_memory) {
throw Platform::Device::Quota_exceeded();
throw Quota_exceeded();
} catch (...) {
return Genode::Io_mem_session_capability();
}
@ -115,8 +115,15 @@ void Platform::Device_component::config_write(unsigned char address,
}
/* assign device to device_pd */
if (address == PCI_CMD_REG && value & PCI_CMD_DMA && _session)
_session->assign_device(this);
if (address == PCI_CMD_REG && value & PCI_CMD_DMA && _session) {
try {
_session->assign_device(this);
} catch (Platform::Session::Out_of_metadata) {
throw Quota_exceeded();
} catch (...) {
PERR("assignment to device failed");
}
}
_device_config.write(&_config_access, address, value, size,
_device_config.DONT_TRACK_ACCESS);

View File

@ -27,10 +27,13 @@ struct Platform::Device_pd : Genode::Session
{
static const char *service_name() { return "DEVICE_PD"; }
GENODE_RPC(Rpc_attach_dma_mem, void, attach_dma_mem,
Genode::Dataspace_capability);
GENODE_RPC(Rpc_assign_pci, void, assign_pci,
Genode::Io_mem_dataspace_capability);
GENODE_RPC_THROW(Rpc_attach_dma_mem, void, attach_dma_mem,
GENODE_TYPE_LIST(Genode::Rm_session::Out_of_metadata),
Genode::Dataspace_capability);
GENODE_RPC_THROW(Rpc_assign_pci, void, assign_pci,
GENODE_TYPE_LIST(Genode::Rm_session::Out_of_metadata,
Genode::Rm_session::Region_conflict),
Genode::Io_mem_dataspace_capability);
GENODE_RPC_INTERFACE(Rpc_attach_dma_mem, Rpc_assign_pci);
};

View File

@ -24,6 +24,7 @@
#include <root/client.h>
#include <util/retry.h>
#include <util/volatile_object.h>
/* os */
#include <io_mem_session/connection.h>
@ -118,20 +119,49 @@ namespace Platform {
Genode::Allocator_guard _md_alloc;
Genode::Tslab<Device_component, 4096 - 64> _device_slab;
Genode::List<Device_component> _device_list;
Genode::Rpc_entrypoint &_device_pd_ep;
struct Resources {
Genode::Ram_connection _ram;
Resources() :
/* restrict physical address to 3G on 32bit */
_ram("dma", 0, (sizeof(void *) == 4)
? 0xc0000000UL : 0x100000000ULL)
{
/* associate _ram session with platform_drv _ram session */
_ram.ref_account(Genode::env()->ram_session_cap());
}
Genode::Ram_connection &ram() { return _ram; }
} _resources;
struct Devicepd {
Platform::Device_pd_policy *policy;
Device_pd_client child;
Device_pd_policy *policy;
Device_pd_client child;
Genode::Allocator_guard &_md_alloc;
enum { DEVICE_PD_RAM_QUOTA = 160 * 4096 };
Devicepd (Genode::Rpc_entrypoint &ep,
Genode::Allocator_guard &md_alloc)
Genode::Allocator_guard &md_alloc,
Genode::Ram_session_capability ram_ref_cap)
:
policy(nullptr),
child(Genode::reinterpret_cap_cast<Device_pd>(Genode::Native_capability()))
child(Genode::reinterpret_cap_cast<Device_pd>(Genode::Native_capability())),
_md_alloc(md_alloc)
{
if (!md_alloc.withdraw(DEVICE_PD_RAM_QUOTA))
throw Out_of_metadata();
if (Genode::env()->ram_session()->transfer_quota(ram_ref_cap, DEVICE_PD_RAM_QUOTA)) {
PERR("Transferring quota for device pd failed");
md_alloc.upgrade(DEVICE_PD_RAM_QUOTA);
throw Platform::Session::Fatal();
}
try {
policy = new (md_alloc) Device_pd_policy(ep);
policy = new (md_alloc) Device_pd_policy(ep, ram_ref_cap, DEVICE_PD_RAM_QUOTA);
using Genode::Session_capability;
using Genode::Affinity;
@ -141,13 +171,36 @@ namespace Platform {
} catch (Genode::Rom_connection::Rom_connection_failed) {
PWRN("PCI device protection domain for IOMMU support "
"is not available");
if (policy) {
destroy(md_alloc, policy);
policy = nullptr;
}
md_alloc.upgrade(DEVICE_PD_RAM_QUOTA);
} catch (Genode::Allocator::Out_of_memory) {
md_alloc.upgrade(DEVICE_PD_RAM_QUOTA);
throw Out_of_metadata();
} catch(...) {
PERR("unknown exception");
md_alloc.upgrade(DEVICE_PD_RAM_QUOTA);
throw Platform::Session::Fatal();
}
}
bool valid() { return policy && policy->root().valid(); }
} _device_pd;
~Devicepd() {
if (!policy)
return;
destroy(_md_alloc, policy);
_md_alloc.upgrade(DEVICE_PD_RAM_QUOTA);
}
bool valid() { return policy && policy->root().valid() && child.valid(); }
};
Genode::Lazy_volatile_object<struct Devicepd> _device_pd;
Genode::Ram_connection _ram;
Genode::Session_label _label;
Genode::Session_policy _policy;
@ -413,16 +466,9 @@ namespace Platform {
_ep(ep),
_md_alloc(md_alloc, Genode::Arg_string::find_arg(args, "ram_quota").long_value(0)),
_device_slab(&_md_alloc),
_device_pd(device_pd_ep, _md_alloc),
/* restrict physical address to 3G on 32bit with device_pd */
_ram("dma", 0, (_device_pd.valid() && sizeof(void *) == 4)
? 0xc0000000UL : 0x100000000ULL),
_device_pd_ep(device_pd_ep),
_label(args), _policy(_label)
{
/* associate _ram session with platform_drv _ram session */
_ram.ref_account(Genode::env()->ram_session_cap());
Genode::env()->ram_session()->transfer_quota(_ram.cap(), 0x1000);
/* non-pci devices */
_policy.for_each_sub_node("device", [&] (Genode::Xml_node device_node) {
try {
@ -650,7 +696,7 @@ namespace Platform {
_device_list.insert(dev);
return _ep->manage(dev);
} catch (Genode::Allocator::Out_of_memory) {
throw Device::Quota_exceeded();
throw Out_of_metadata();
}
};
return _ep->apply(prev_device, lambda);
@ -690,40 +736,33 @@ namespace Platform {
destroy(_md_alloc, device);
}
Genode::Io_mem_dataspace_capability assign_device(Device_component * device)
void assign_device(Device_component * device)
{
using namespace Genode;
if (!device || !device->get_config_space().valid())
return Io_mem_dataspace_capability();
return;
Io_mem_dataspace_capability io_mem = device->get_config_space();
if (!_device_pd.child.valid())
return Io_mem_dataspace_capability();
if (!_device_pd.is_constructed())
_device_pd.construct(_device_pd_ep, _md_alloc,
_resources.ram().cap());
_device_pd.child.assign_pci(io_mem);
if (!_device_pd->valid())
return;
for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) {
Io_mem_dataspace_capability rmrr_cap = r->match(device->config());
if (rmrr_cap.valid())
_device_pd.child.attach_dma_mem(rmrr_cap);
try {
_device_pd->child.assign_pci(io_mem);
for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) {
Io_mem_dataspace_capability rmrr_cap = r->match(device->config());
if (rmrr_cap.valid())
_device_pd->child.attach_dma_mem(rmrr_cap);
}
} catch (...) {
PERR("assignment to device pd or of RMRR region failed");
}
/*
* By now forbid usage of extended pci config space dataspace,
* - until required.
*/
// return io_mem;
return Io_mem_dataspace_capability();
}
Genode::Io_mem_dataspace_capability config_extended(Device_capability device_cap)
{
using namespace Genode;
return _ep->apply(device_cap, [&] (Device_component *device) {
return assign_device(device);});
}
/**
@ -731,34 +770,63 @@ namespace Platform {
*/
typedef Genode::Ram_dataspace_capability Ram_capability;
Ram_capability alloc_dma_buffer(Genode::size_t size)
Ram_capability alloc_dma_buffer(Genode::size_t const size)
{
if (!_device_pd.is_constructed())
_device_pd.construct(_device_pd_ep, _md_alloc,
_resources.ram().cap());
if (!_md_alloc.withdraw(size))
throw Device::Quota_exceeded();
throw Out_of_metadata();
/* transfer ram quota to session specific ram session */
Genode::Ram_session * const rs = Genode::env()->ram_session();
if (rs->transfer_quota(_ram.cap(), size)) {
if (rs->transfer_quota(_resources.ram().cap(), size)) {
_md_alloc.upgrade(size);
return Ram_capability();
throw Fatal();
}
Ram_capability ram_cap;
try {
ram_cap = Genode::retry<Genode::Ram_session::Out_of_metadata>(
[&] () { return _ram.alloc(size, Genode::UNCACHED); },
[&] () { Genode::env()->parent()->upgrade(_ram.cap(), "ram_quota=4K"); });
} catch (Genode::Ram_session::Quota_exceeded) { }
enum { UPGRADE_QUOTA = 4096 };
if (!ram_cap.valid()) {
_ram.transfer_quota(Genode::env()->ram_session_cap(), size);
_md_alloc.upgrade(size);
return ram_cap;
}
/* allocate dataspace from session specific ram session */
Ram_capability ram_cap = Genode::retry<Genode::Ram_session::Out_of_metadata>(
[&] () { return _resources.ram().alloc(size, Genode::UNCACHED); },
[&] () {
if (!_md_alloc.withdraw(UPGRADE_QUOTA)) {
/* role-back */
if (_resources.ram().transfer_quota(Genode::env()->ram_session_cap(), size))
throw Fatal();
_md_alloc.upgrade(size);
throw Out_of_metadata();
}
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%u",
UPGRADE_QUOTA);
Genode::env()->parent()->upgrade(_resources.ram().cap(), buf);
});
if (!_device_pd.child.valid())
if (!_device_pd->valid())
return ram_cap;
_device_pd.child.attach_dma_mem(ram_cap);
Genode::retry<Genode::Rm_session::Out_of_metadata>(
[&] () { _device_pd->child.attach_dma_mem(ram_cap); },
[&] () {
if (!_md_alloc.withdraw(UPGRADE_QUOTA)) {
/* role-back */
_resources.ram().free(ram_cap);
if (_resources.ram().transfer_quota(Genode::env()->ram_session_cap(), size))
throw Fatal();
_md_alloc.upgrade(size);
throw Out_of_metadata();
}
if (rs->transfer_quota(_resources.ram().cap(), UPGRADE_QUOTA))
throw Fatal();
Genode::Ram_connection &slave = _device_pd->policy->ram_slave();
if (_resources.ram().transfer_quota(slave.cap(), UPGRADE_QUOTA))
throw Fatal();
});
return ram_cap;
}
@ -766,7 +834,7 @@ namespace Platform {
void free_dma_buffer(Ram_capability ram)
{
if (ram.valid())
_ram.free(ram);
_resources.ram().free(ram);
}
Device_capability device(String const &name) override;

View File

@ -214,7 +214,7 @@ append_platform_drv_config
append_if $use_nic_session config {
<start name="nic_drv" priority="-2">
<resource name="RAM" quantum="3M"/>
<resource name="RAM" quantum="4M"/>
<provides><service name="Nic"/></provides>
<route> <any-service><any-child/><parent/></any-service> </route>
</start>

View File

@ -75,7 +75,7 @@ append config_of_app {
(Recording is configured to use the external mic.)
-->
<start name="audio_drv">
<resource name="RAM" quantum="8M"/>
<resource name="RAM" quantum="9M"/>
<provides>
<service name="Audio_out"/>
<service name="Audio_in"/>