block: free packet stream dataspace on destruction

Fixes #1033
This commit is contained in:
Stefan Kalkowski 2014-01-24 11:54:51 +01:00 committed by Christian Helmuth
parent c888ff0d76
commit 7876dfcb5e
9 changed files with 138 additions and 29 deletions

View File

@ -21,6 +21,9 @@ class Backend_memory {
static Genode::Ram_dataspace_capability alloc(Genode::addr_t size,
bool cached) {
return Genode::env()->ram_session()->alloc(size, cached); }
static void free(Genode::Ram_dataspace_capability cap) {
return Genode::env()->ram_session()->free(cap); }
};
#endif /* _ARM__PLATFORM__LX_MEM_ */

View File

@ -1,6 +1,6 @@
/*
* \brief Platform specific part of memory allocation
* \author Alexander Boettcher
* \author Alexander Boettcher
* \date 2013-03-18
*/
@ -20,6 +20,8 @@ class Backend_memory {
static Genode::Ram_dataspace_capability alloc(Genode::addr_t size,
bool cached);
static void free(Genode::Ram_dataspace_capability cap);
};
#endif /* _X86__PLATFORM__LX_MEM_ */

View File

@ -12,6 +12,8 @@
*/
/* Genode inludes */
#include <ram_session/client.h>
#include <base/object_pool.h>
#include <pci_session/connection.h>
#include <pci_device/client.h>
@ -175,12 +177,51 @@ class Pci_driver
};
/********************************
** Backend memory definitions **
********************************/
struct Memory_object_base : Genode::Object_pool<Memory_object_base>::Entry
{
Memory_object_base(Genode::Ram_dataspace_capability cap)
: Genode::Object_pool<Memory_object_base>::Entry(cap) {}
virtual ~Memory_object_base() {};
virtual void free() = 0;
Genode::Ram_dataspace_capability ram_cap()
{
using namespace Genode;
return reinterpret_cap_cast<Ram_dataspace>(cap());
}
};
struct Ram_object : Memory_object_base
{
Ram_object(Genode::Ram_dataspace_capability cap)
: Memory_object_base(cap) {}
void free();
};
struct Dma_object : Memory_object_base
{
Dma_object(Genode::Ram_dataspace_capability cap)
: Memory_object_base(cap) {}
void free();
};
/*********************
** Linux interface **
*********************/
static Pci::Device_capability pci_device_cap;
static Pci::Connection pci;
static Genode::Object_pool<Memory_object_base> memory_pool;
int pci_register_driver(struct pci_driver *drv)
{
@ -319,13 +360,42 @@ const char *pci_name(const struct pci_dev *pdev)
return "dummy";
}
void Ram_object::free() { Genode::env()->ram_session()->free(ram_cap()); }
void Dma_object::free() { pci.free_dma_buffer(pci_device_cap, ram_cap()); }
Genode::Ram_dataspace_capability Backend_memory::alloc(Genode::addr_t size,
bool cached)
{
using namespace Genode;
if (cached)
return env()->ram_session()->alloc(size, cached);
else
return pci.alloc_dma_buffer(pci_device_cap, size);
Memory_object_base *o;
Genode::Ram_dataspace_capability cap;
if (cached) {
cap = env()->ram_session()->alloc(size, cached);
o = new (env()->heap()) Ram_object(cap);
} else {
cap = pci.alloc_dma_buffer(pci_device_cap, size);
o = new (env()->heap()) Dma_object(cap);
}
memory_pool.insert(o);
return cap;
}
void Backend_memory::free(Genode::Ram_dataspace_capability cap)
{
using namespace Genode;
Memory_object_base *o = memory_pool.lookup_and_lock(cap);
if (!o)
return;
o->free();
memory_pool.remove_locked(o);
destroy(env()->heap(), o);
}

View File

@ -177,6 +177,9 @@ class Storage_device : public Genode::List<Storage_device>::Element,
Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t size) {
return Backend_memory::alloc(size, false); }
void free_dma_buffer(Genode::Ram_dataspace_capability cap) {
return Backend_memory::free(cap); }
};

View File

@ -25,18 +25,49 @@ namespace Block {
using namespace Genode;
class Session_component_base;
class Session_component;
class Root;
};
class Block::Session_component : public Block::Session_rpc_object
/**
* We have a hen and egg situation that makes this base class necessary.
* The Block::Session_rpc_object construction depends on a dataspace for
* the packet stream. The dataspace on the other hand is constructed by
* the driver, which is created on demand when creating a session.
* When creating the driver, and dataspace outside the Session_component
* constructor within _create_session of the root component, we would have
* to destroy the driver and dataspace within the destructor body of
* Session_component, which will lead to problems, because the packet stream
* destructors will be called after the shared memory already vanished.
*/
class Block::Session_component_base
{
protected:
Driver_factory &_driver_factory;
Driver &_driver;
Ram_dataspace_capability _rq_ds;
Session_component_base(Driver_factory &factory, size_t tx_buf_size)
: _driver_factory(factory),
_driver(*factory.create()),
_rq_ds(_driver.alloc_dma_buffer(tx_buf_size)) {}
~Session_component_base()
{
_driver.free_dma_buffer(_rq_ds);
_driver_factory.destroy(&_driver);
}
};
class Block::Session_component : public Block::Session_component_base,
public Block::Session_rpc_object
{
private:
Driver_factory &_driver_factory;
Driver &_driver;
Ram_dataspace_capability _rq_ds;
addr_t _rq_phys;
Signal_rpc_member<Session_component> _sink_ack;
Signal_rpc_member<Session_component> _sink_submit;
@ -149,14 +180,10 @@ class Block::Session_component : public Block::Session_rpc_object
* \param driver_factory factory to create and destroy driver objects
* \param ep entrypoint handling this session component
*/
Session_component(Ram_dataspace_capability rq_ds,
Driver &driver,
Driver_factory &driver_factory,
Server::Entrypoint &ep)
: Session_rpc_object(rq_ds, ep.rpc_ep()),
_driver_factory(driver_factory),
_driver(driver),
_rq_ds(rq_ds),
Session_component(Driver_factory &driver_factory,
Server::Entrypoint &ep, size_t buf_size)
: Session_component_base(driver_factory, buf_size),
Session_rpc_object(_rq_ds, ep.rpc_ep()),
_rq_phys(Dataspace_client(_rq_ds).phys_addr()),
_sink_ack(ep, *this, &Session_component::_ready_to_ack),
_sink_submit(ep, *this, &Session_component::_packet_avail),
@ -166,7 +193,7 @@ class Block::Session_component : public Block::Session_rpc_object
_tx.sigh_ready_to_ack(_sink_ack);
_tx.sigh_packet_avail(_sink_submit);
driver.session = this;
_driver.session = this;
}
/**
@ -198,12 +225,6 @@ class Block::Session_component : public Block::Session_rpc_object
_packet_avail(0);
}
/**
* Destructor
*/
~Session_component() {
_driver_factory.destroy(&_driver); }
/*******************************
** Block session interface **
@ -262,11 +283,8 @@ class Block::Root : public Genode::Root_component<Block::Session_component,
throw Root::Quota_exceeded();
}
Driver * driver = _driver_factory.create();
Ram_dataspace_capability ds_cap;
ds_cap = driver->alloc_dma_buffer(tx_buf_size);
return new (md_alloc())
Session_component(ds_cap, *driver, _driver_factory, _ep);
return new (md_alloc()) Session_component(_driver_factory,
_ep, tx_buf_size);
}
public:

View File

@ -147,6 +147,12 @@ struct Block::Driver
alloc_dma_buffer(Genode::size_t size) {
return Genode::env()->ram_session()->alloc(size, false); }
/**
* Free buffer which is suitable for DMA.
*/
virtual void free_dma_buffer(Genode::Ram_dataspace_capability c) {
return Genode::env()->ram_session()->free(c); }
/**
* Synchronize with device.
*

View File

@ -563,6 +563,7 @@ class Ahci_device_base
}
virtual Ram_dataspace_capability alloc_dma_buffer(size_t size) = 0;
virtual void free_dma_buffer(Ram_dataspace_capability cap) = 0;
};
#endif /* _AHCI_DEVICE_BASE_H_ */

View File

@ -81,6 +81,9 @@ class Ahci_driver_base : public Block::Driver
Ram_dataspace_capability alloc_dma_buffer(size_t size) {
return _device->alloc_dma_buffer(size); }
void free_dma_buffer(Ram_dataspace_capability cap) {
return _device->free_dma_buffer(cap); }
};
#endif /* _AHCI_DRIVER_BASE_H_ */

View File

@ -205,6 +205,9 @@ class Ahci_device : public Ahci_device_base
Ram_dataspace_capability alloc_dma_buffer(size_t size) {
return _pci.alloc_dma_buffer(_pci_device_cap, size); }
void free_dma_buffer(Ram_dataspace_capability cap) {
return _pci.free_dma_buffer(_pci_device_cap, cap); }
};
#endif /* _AHCI_DEVICE_H_ */