mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
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:
parent
4c4e7c64d0
commit
92cb9eb06d
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user