diff --git a/dde_linux/src/lib/usb/include/arm/platform/lx_mem.h b/dde_linux/src/lib/usb/include/arm/platform/lx_mem.h index 30fcfda91..9ac672a17 100644 --- a/dde_linux/src/lib/usb/include/arm/platform/lx_mem.h +++ b/dde_linux/src/lib/usb/include/arm/platform/lx_mem.h @@ -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_ */ diff --git a/dde_linux/src/lib/usb/include/x86/platform/lx_mem.h b/dde_linux/src/lib/usb/include/x86/platform/lx_mem.h index 45530b100..106984947 100644 --- a/dde_linux/src/lib/usb/include/x86/platform/lx_mem.h +++ b/dde_linux/src/lib/usb/include/x86/platform/lx_mem.h @@ -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_ */ diff --git a/dde_linux/src/lib/usb/pci_driver.cc b/dde_linux/src/lib/usb/pci_driver.cc index 913195919..92b923a2a 100644 --- a/dde_linux/src/lib/usb/pci_driver.cc +++ b/dde_linux/src/lib/usb/pci_driver.cc @@ -12,6 +12,8 @@ */ /* Genode inludes */ +#include +#include #include #include @@ -175,12 +177,51 @@ class Pci_driver }; +/******************************** + ** Backend memory definitions ** + ********************************/ + +struct Memory_object_base : Genode::Object_pool::Entry +{ + Memory_object_base(Genode::Ram_dataspace_capability cap) + : Genode::Object_pool::Entry(cap) {} + virtual ~Memory_object_base() {}; + + virtual void free() = 0; + + Genode::Ram_dataspace_capability ram_cap() + { + using namespace Genode; + return reinterpret_cap_cast(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_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); } diff --git a/dde_linux/src/lib/usb/storage/storage.cc b/dde_linux/src/lib/usb/storage/storage.cc index 70a3fb0ce..9e39631e2 100644 --- a/dde_linux/src/lib/usb/storage/storage.cc +++ b/dde_linux/src/lib/usb/storage/storage.cc @@ -177,6 +177,9 @@ class Storage_device : public Genode::List::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); } }; diff --git a/os/include/block/component.h b/os/include/block/component.h index 8db9cbb05..548d4d9c8 100644 --- a/os/include/block/component.h +++ b/os/include/block/component.h @@ -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 _sink_ack; Signal_rpc_member _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_componentalloc_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: diff --git a/os/include/block/driver.h b/os/include/block/driver.h index aa22f41ec..af0e2c159 100644 --- a/os/include/block/driver.h +++ b/os/include/block/driver.h @@ -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. * diff --git a/os/src/drivers/ahci/include/ahci_device_base.h b/os/src/drivers/ahci/include/ahci_device_base.h index 15071dfe6..d487755e9 100644 --- a/os/src/drivers/ahci/include/ahci_device_base.h +++ b/os/src/drivers/ahci/include/ahci_device_base.h @@ -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_ */ diff --git a/os/src/drivers/ahci/include/ahci_driver_base.h b/os/src/drivers/ahci/include/ahci_driver_base.h index 5a2f050d7..2f0b3c52e 100644 --- a/os/src/drivers/ahci/include/ahci_driver_base.h +++ b/os/src/drivers/ahci/include/ahci_driver_base.h @@ -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_ */ diff --git a/os/src/drivers/ahci/x86/ahci_device.h b/os/src/drivers/ahci/x86/ahci_device.h index 9bb3928f2..366482b49 100644 --- a/os/src/drivers/ahci/x86/ahci_device.h +++ b/os/src/drivers/ahci/x86/ahci_device.h @@ -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_ */