mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-21 18:06:50 +00:00
lx_emul: implement lookup of dma-addr to virt-addr
* Use the new Lx_kit::Map as lookup structure for virt-to-dma and vice versa, instead of a list-based registry Ref #4268
This commit is contained in:
parent
9bc7ecb605
commit
f8cf0442ed
@ -23,6 +23,7 @@ void * lx_emul_mem_alloc_uncached(unsigned long size);
|
||||
void * lx_emul_mem_alloc_aligned(unsigned long size, unsigned long align);
|
||||
void * lx_emul_mem_alloc_aligned_uncached(unsigned long size, unsigned long align);
|
||||
unsigned long lx_emul_mem_dma_addr(void * addr);
|
||||
unsigned long lx_emul_mem_virt_addr(void * dma_addr);
|
||||
void lx_emul_mem_free(const void * ptr);
|
||||
unsigned long lx_emul_mem_size(const void * ptr);
|
||||
void lx_emul_mem_cache_clean_invalidate(const void * ptr, unsigned long size);
|
||||
|
@ -18,7 +18,8 @@
|
||||
#include <base/cache.h>
|
||||
#include <base/env.h>
|
||||
#include <base/heap.h>
|
||||
#include <base/registry.h>
|
||||
#include <lx_kit/byte_range.h>
|
||||
#include <lx_kit/map.h>
|
||||
|
||||
namespace Platform { class Connection; };
|
||||
namespace Lx_kit {
|
||||
@ -31,7 +32,7 @@ class Lx_kit::Mem_allocator
|
||||
{
|
||||
private:
|
||||
|
||||
class Buffer : Interface
|
||||
class Buffer
|
||||
{
|
||||
private:
|
||||
|
||||
@ -45,18 +46,56 @@ class Lx_kit::Mem_allocator
|
||||
addr_t dma_addr)
|
||||
: _ds(rm, cap), _dma_addr(dma_addr) {}
|
||||
|
||||
addr_t dma_addr() const { return _dma_addr; }
|
||||
Attached_dataspace & ds() { return _ds; }
|
||||
size_t dma_addr() const { return _dma_addr; }
|
||||
size_t size() const { return _ds.size(); }
|
||||
size_t virt_addr() const {
|
||||
return (addr_t) _ds.local_addr<void*>(); }
|
||||
|
||||
Attached_dataspace & ds() { return _ds; }
|
||||
};
|
||||
|
||||
using Buffer_registry = Registry<Registered<Buffer>>;
|
||||
struct Buffer_info
|
||||
{
|
||||
struct Key { addr_t addr; } key;
|
||||
Buffer & buffer;
|
||||
|
||||
size_t size() const { return buffer.size(); }
|
||||
|
||||
bool higher(Key const other_key) const
|
||||
{
|
||||
return key.addr > other_key.addr;
|
||||
}
|
||||
|
||||
struct Query_range
|
||||
{
|
||||
addr_t addr;
|
||||
size_t size;
|
||||
|
||||
bool matches(Buffer_info const & bi) const
|
||||
{
|
||||
Lx_kit::Byte_range buf_range { bi.key.addr, bi.size() };
|
||||
Lx_kit::Byte_range range { addr, size };
|
||||
|
||||
return buf_range.intersects(range);
|
||||
}
|
||||
|
||||
Key key() const { return Key { addr }; }
|
||||
};
|
||||
|
||||
struct Query_addr : Query_range
|
||||
{
|
||||
Query_addr(void const * addr)
|
||||
: Query_range{(addr_t)addr, 1} { }
|
||||
};
|
||||
};
|
||||
|
||||
Env & _env;
|
||||
Heap & _heap;
|
||||
Platform::Connection & _platform;
|
||||
Cache _cache_attr;
|
||||
Allocator_avl _mem;
|
||||
Buffer_registry _buffers {};
|
||||
Map<Buffer_info> _virt_to_dma { _heap };
|
||||
Map<Buffer_info> _dma_to_virt { _heap };
|
||||
|
||||
public:
|
||||
|
||||
@ -69,8 +108,8 @@ class Lx_kit::Mem_allocator
|
||||
|
||||
void * alloc(size_t size, size_t align);
|
||||
addr_t dma_addr(void * addr);
|
||||
addr_t virt_addr(void * dma_addr);
|
||||
size_t size(const void * ptr);
|
||||
void free(Attached_dataspace * ds);
|
||||
bool free(const void * ptr);
|
||||
};
|
||||
|
||||
|
@ -64,6 +64,17 @@ extern "C" unsigned long lx_emul_mem_dma_addr(void * addr)
|
||||
}
|
||||
|
||||
|
||||
extern "C" unsigned long lx_emul_mem_virt_addr(void * dma_addr)
|
||||
{
|
||||
unsigned long ret = Lx_kit::env().memory.virt_addr(dma_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!(ret = Lx_kit::env().uncached_memory.virt_addr(dma_addr)))
|
||||
Genode::error(__func__, " called with invalid addr ", dma_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void lx_emul_mem_free(const void * ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
/* local includes */
|
||||
#include <lx_kit/memory.h>
|
||||
#include <lx_kit/map.h>
|
||||
#include <lx_kit/byte_range.h>
|
||||
|
||||
|
||||
Genode::Attached_dataspace & Lx_kit::Mem_allocator::alloc_dataspace(size_t size)
|
||||
@ -26,17 +28,18 @@ Genode::Attached_dataspace & Lx_kit::Mem_allocator::alloc_dataspace(size_t size)
|
||||
Ram_dataspace_capability ds_cap;
|
||||
|
||||
try {
|
||||
size_t ds_size = align_addr(size, 12);
|
||||
ds_cap = _platform.alloc_dma_buffer(ds_size, _cache_attr);
|
||||
addr_t dma_addr = _platform.dma_addr(ds_cap);
|
||||
Ram_dataspace_capability ds_cap =
|
||||
_platform.alloc_dma_buffer(align_addr(size, 12), _cache_attr);
|
||||
|
||||
Buffer & buffer = *new (_heap)
|
||||
Registered<Buffer>(_buffers, _env.rm(), ds_cap, dma_addr);
|
||||
addr_t addr = (addr_t)buffer.ds().local_addr<void>();
|
||||
Buffer(_env.rm(), ds_cap, _platform.dma_addr(ds_cap));
|
||||
|
||||
/* map eager by touching all pages once */
|
||||
for (size_t sz = 0; sz < ds_size; sz += 4096) {
|
||||
touch_read((unsigned char const volatile*)(addr + sz)); }
|
||||
for (size_t sz = 0; sz < buffer.size(); sz += 4096) {
|
||||
touch_read((unsigned char const volatile*)(buffer.virt_addr() + sz)); }
|
||||
|
||||
_virt_to_dma.insert(buffer.virt_addr(), buffer);
|
||||
_dma_to_virt.insert(buffer.dma_addr(), buffer);
|
||||
|
||||
return buffer.ds();
|
||||
} catch (Out_of_caps) {
|
||||
@ -70,7 +73,8 @@ void * Lx_kit::Mem_allocator::alloc(size_t size, size_t align)
|
||||
* and physical addresses of a multi-page allocation are always
|
||||
* contiguous.
|
||||
*/
|
||||
Attached_dataspace & ds = alloc_dataspace(max(size + 1, min_buffer_size));
|
||||
Attached_dataspace & ds = alloc_dataspace(max(size + 1,
|
||||
min_buffer_size));
|
||||
|
||||
_mem.add_range((addr_t)ds.local_addr<void>(), ds.size() - 1);
|
||||
|
||||
@ -93,15 +97,24 @@ Genode::addr_t Lx_kit::Mem_allocator::dma_addr(void * addr)
|
||||
{
|
||||
addr_t ret = 0UL;
|
||||
|
||||
_buffers.for_each([&] (Buffer & b) {
|
||||
addr_t other = (addr_t)addr;
|
||||
addr_t addr = (addr_t)b.ds().local_addr<void>();
|
||||
if (addr > other || (addr+b.ds().size()) <= other)
|
||||
return;
|
||||
_virt_to_dma.apply(Buffer_info::Query_addr(addr),
|
||||
[&] (Buffer_info const & info) {
|
||||
addr_t const offset = (addr_t)addr - info.buffer.virt_addr();
|
||||
ret = info.buffer.dma_addr() + offset;
|
||||
});
|
||||
|
||||
/* byte offset of 'addr' from start of block */
|
||||
addr_t const offset = other - addr;
|
||||
ret = b.dma_addr() + offset;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Genode::addr_t Lx_kit::Mem_allocator::virt_addr(void * dma_addr)
|
||||
{
|
||||
addr_t ret = 0UL;
|
||||
|
||||
_dma_to_virt.apply(Buffer_info::Query_addr(dma_addr),
|
||||
[&] (Buffer_info const & info) {
|
||||
addr_t const offset = (addr_t)dma_addr - info.buffer.dma_addr();
|
||||
ret = info.buffer.virt_addr() + offset;
|
||||
});
|
||||
|
||||
return ret;
|
||||
@ -118,21 +131,6 @@ bool Lx_kit::Mem_allocator::free(const void * ptr)
|
||||
}
|
||||
|
||||
|
||||
void Lx_kit::Mem_allocator::free(Attached_dataspace * ds)
|
||||
{
|
||||
Dataspace_capability cap = ds->cap();
|
||||
|
||||
Registered<Buffer> * buffer = nullptr;
|
||||
_buffers.for_each([&] (Buffer & b) {
|
||||
if (&b.ds() == ds)
|
||||
buffer = static_cast<Registered<Buffer>*>(&b);
|
||||
});
|
||||
|
||||
destroy(_heap, buffer);
|
||||
_platform.free_dma_buffer(static_cap_cast<Ram_dataspace>(cap));
|
||||
}
|
||||
|
||||
|
||||
Genode::size_t Lx_kit::Mem_allocator::size(const void * ptr)
|
||||
{
|
||||
return ptr ? _mem.size_at(ptr) : 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user