mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 03:45:24 +00:00
usb: Rewrote back-end allocators
Allocate back-end memory dynamically.
This commit is contained in:
parent
87f83c1cff
commit
78c752b1c7
@ -1,6 +1,4 @@
|
||||
SRC_C += platform_device.c
|
||||
SRC_CC += mem.cc
|
||||
INC_DIR += $(LIB_INC_DIR)/arm
|
||||
|
||||
vpath platform_device.c $(LIB_DIR)/arm
|
||||
vpath mem.cc $(LIB_DIR)/arm
|
||||
|
@ -17,6 +17,9 @@ build {
|
||||
test/lwip/http_srv
|
||||
}
|
||||
|
||||
lappend_if [have_spec acpi] build_components drivers/acpi
|
||||
lappend_if [have_spec pci] build_components drivers/pci/device_pd
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
@ -58,7 +61,29 @@ set config {
|
||||
</start>
|
||||
<start name="test-lwip_httpsrv">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
</start>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec acpi] config {
|
||||
<start name="acpi">
|
||||
<resource name="RAM" quantum="5M"/>
|
||||
<binary name="acpi_drv"/>
|
||||
<provides>
|
||||
<service name="PCI"/>
|
||||
<service name="IRQ" />
|
||||
</provides>
|
||||
<route>
|
||||
<service name="PCI"> <any-child /> </service>
|
||||
<any-service> <parent/> <any-child /> </any-service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append_if [expr ![have_spec acpi] && [have_spec pci]] config {
|
||||
<start name="pci_drv">
|
||||
<resource name="RAM" quantum="3M"/>
|
||||
<provides> <service name="PCI"/> </provides>
|
||||
</start> }
|
||||
|
||||
append config {
|
||||
</config>
|
||||
}
|
||||
|
||||
@ -75,6 +100,10 @@ set boot_modules {
|
||||
ld.lib.so libc.lib.so libc_log.lib.so lwip.lib.so test-lwip_httpsrv
|
||||
}
|
||||
|
||||
lappend_if [have_spec acpi] boot_modules acpi_drv
|
||||
lappend_if [have_spec pci] boot_modules pci_drv
|
||||
lappend_if [have_spec nova] boot_modules pci_device_pd
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
# vi: set ft=tcl :
|
||||
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* \brief Backend for allocating DMA memory on ARM
|
||||
* \author Alexander Boettcher
|
||||
* \date 2013-02-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/env.h>
|
||||
#include "mem.h"
|
||||
|
||||
Genode::Ram_dataspace_capability Genode::Mem::alloc_dma_buffer(size_t size) {
|
||||
return Genode::env()->ram_session()->alloc(size, false); }
|
26
dde_linux/src/lib/usb/include/arm/platform/lx_mem.h
Normal file
26
dde_linux/src/lib/usb/include/arm/platform/lx_mem.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* \brief Platform specific part of memory allocation
|
||||
* \author Alexander Boettcher
|
||||
* \date 2013-03-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _ARM__PLATFORM__LX_MEM_
|
||||
#define _ARM__PLATFORM__LX_MEM_
|
||||
|
||||
class Backend_memory {
|
||||
|
||||
public:
|
||||
|
||||
static Genode::Ram_dataspace_capability alloc(Genode::addr_t size,
|
||||
bool cached) {
|
||||
return Genode::env()->ram_session()->alloc(size, cached); }
|
||||
};
|
||||
|
||||
#endif /* _ARM__PLATFORM__LX_MEM_ */
|
@ -1,251 +0,0 @@
|
||||
/*
|
||||
* \brief Memory pool
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-06-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _MEM_H_
|
||||
#define _MEM_H_
|
||||
|
||||
#include <base/allocator_avl.h>
|
||||
#include <dataspace/client.h>
|
||||
#include <lx_emul.h>
|
||||
|
||||
/*********************
|
||||
** linux/dmapool.h **
|
||||
*********************/
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* Memory back-end
|
||||
*/
|
||||
class Mem
|
||||
{
|
||||
/* configurable sizes of memory pools */
|
||||
enum
|
||||
{
|
||||
MEM_POOL_SHARE = 3
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
addr_t _base; /* virt base of pool */
|
||||
addr_t _base_phys; /* phys base of pool */
|
||||
size_t _size; /* size of backng store */
|
||||
Allocator_avl _range; /* range allocator for pool */
|
||||
addr_t *_zones; /* bases of zones */
|
||||
int _zone_count; /* number of zones */
|
||||
int _zone_alloc; /* currently allocated zones */
|
||||
|
||||
Ram_dataspace_capability _ds_cap; /* backing store */
|
||||
|
||||
/**
|
||||
* Allocates memory which can be used for DMA.
|
||||
*/
|
||||
Genode::Ram_dataspace_capability alloc_dma_buffer(size_t size);
|
||||
|
||||
/**
|
||||
* Private constructor
|
||||
*/
|
||||
Mem(size_t size, bool cached = true)
|
||||
: _size(size), _range(env()->heap()),_zone_count(0), _zone_alloc(0)
|
||||
{
|
||||
if (cached)
|
||||
_ds_cap = env()->ram_session()->alloc(_size, cached);
|
||||
else
|
||||
_ds_cap = alloc_dma_buffer(_size);
|
||||
|
||||
_base_phys = Dataspace_client(_ds_cap).phys_addr();
|
||||
_base = (addr_t)env()->rm_session()->attach(_ds_cap);
|
||||
|
||||
dde_kit_log(DEBUG_DMA, "New DMA range [%lx-%lx)", _base, _base + _size);
|
||||
_range.add_range(_base, _size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert 'Mem' addres to zone address
|
||||
*/
|
||||
void *_to_zone(void const *addr, int i)
|
||||
{
|
||||
if (i < 0)
|
||||
return (void *)addr;
|
||||
|
||||
addr_t zone_base = _zones[i];
|
||||
addr_t offset = (addr_t)addr - _base;
|
||||
return (void *)(zone_base + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert zone addres to 'Mem' address
|
||||
*/
|
||||
void *_from_zone(void const *addr, int i)
|
||||
{
|
||||
if (i < 0)
|
||||
return (void *)addr;
|
||||
|
||||
addr_t zone_base = _zones[i];
|
||||
addr_t offset = (addr_t)addr - zone_base;
|
||||
return (void *)(_base + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory usable by back-end allocators
|
||||
*/
|
||||
static size_t _mem_avail() {
|
||||
return env()->ram_session()->avail() - (1024 * 1024); }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Memory zone within Mem allocator
|
||||
*/
|
||||
class Zone_alloc : public Allocator
|
||||
{
|
||||
private:
|
||||
|
||||
Mem *_pool; /* pool of zone */
|
||||
int _zone; /* zone number */
|
||||
addr_t _base; /* base address of zone */
|
||||
size_t _size; /* size of zone */
|
||||
|
||||
public:
|
||||
|
||||
Zone_alloc(Mem *pool, int zone, addr_t base, size_t size)
|
||||
: _pool(pool), _zone(zone), _base(base), _size(size) { }
|
||||
|
||||
|
||||
/*************************
|
||||
** Alocator interface **
|
||||
*************************/
|
||||
|
||||
bool alloc(size_t size, void **out_addr)
|
||||
{
|
||||
*out_addr = _pool->alloc(size, _zone);
|
||||
if (!*out_addr) {
|
||||
PERR("Zone of %zu bytes allocation failed", size);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void free(void *addr, size_t /* size */) { _pool->free(addr, _zone); }
|
||||
size_t overhead(size_t size) { return 0; }
|
||||
|
||||
/**
|
||||
* Check if address matches zone
|
||||
*/
|
||||
bool match(void const *addr)
|
||||
{
|
||||
addr_t a = (addr_t)addr;
|
||||
bool ret = ((a >= _base) && (a < (_base + _size)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve virt to phys mapping
|
||||
*/
|
||||
addr_t phys_addr(void const *addr) { return _pool->phys_addr(addr, _zone); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Gernal purpose memory pool
|
||||
*/
|
||||
static Mem* pool()
|
||||
{
|
||||
static Mem _p(_mem_avail() / MEM_POOL_SHARE);
|
||||
return &_p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DMA memory pool
|
||||
*/
|
||||
static Mem* dma()
|
||||
{
|
||||
static Mem _p(_mem_avail() - (_mem_avail() / MEM_POOL_SHARE), false);
|
||||
return &_p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocator interface
|
||||
*/
|
||||
void *alloc(size_t size, int zone = -1, int align = 2)
|
||||
{
|
||||
void *addr;
|
||||
if (_range.alloc_aligned(size, &addr, align).is_error()) {
|
||||
PERR("Memory allocation of %zu bytes failed", size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _to_zone(addr, zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free addr in zone
|
||||
*/
|
||||
void free(void *addr, int zone = -1) { _range.free(_from_zone(addr, zone)); }
|
||||
|
||||
/**
|
||||
* Get phys for virt address
|
||||
*/
|
||||
addr_t phys_addr(void const *addr, int zone = - 1)
|
||||
{
|
||||
addr_t a = (addr_t)_from_zone(addr, zone);
|
||||
if (a < _base || a >= _base + _size) {
|
||||
PERR("No DMA phys addr for %lx zone: %d", a, zone);
|
||||
return 0;
|
||||
}
|
||||
return (a - _base) + _base_phys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iinit allocator with count zones
|
||||
*/
|
||||
void init_zones(int count)
|
||||
{
|
||||
if (_zone_count)
|
||||
return;
|
||||
|
||||
_zones = (addr_t *)env()->heap()->alloc(count * sizeof(addr_t));
|
||||
_zone_count = count;
|
||||
|
||||
for (int i = 0; i < _zone_count; i++) {
|
||||
_zones[i] = (addr_t)env()->rm_session()->attach(_ds_cap);
|
||||
dde_kit_log(DEBUG_DMA, "Zone %d: base: %lx end %lx", i, _zones[i], _zones[i] + _size);
|
||||
}
|
||||
|
||||
PINF("Registered %d zone allocators", count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new zone allocator
|
||||
*
|
||||
* 'init_zones' must have been called beforehand
|
||||
*/
|
||||
Zone_alloc *new_zone_allocator()
|
||||
{
|
||||
if(_zone_alloc >= _zone_count) {
|
||||
PERR("Zone allocators exhausted");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Zone_alloc *zone = new(env()->heap()) Zone_alloc(this,
|
||||
_zone_alloc,
|
||||
_zones[_zone_alloc],
|
||||
_size);
|
||||
_zone_alloc++;
|
||||
return zone;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _MEM_H_ */
|
25
dde_linux/src/lib/usb/include/x86/platform/lx_mem.h
Normal file
25
dde_linux/src/lib/usb/include/x86/platform/lx_mem.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* \brief Platform specific part of memory allocation
|
||||
* \author Alexander Boettcher
|
||||
* \date 2013-03-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _X86__PLATFORM__LX_MEM_
|
||||
#define _X86__PLATFORM__LX_MEM_
|
||||
|
||||
class Backend_memory {
|
||||
|
||||
public:
|
||||
|
||||
static Genode::Ram_dataspace_capability alloc(Genode::addr_t size,
|
||||
bool cached);
|
||||
};
|
||||
|
||||
#endif /* _X86__PLATFORM__LX_MEM_ */
|
@ -20,10 +20,10 @@
|
||||
#include <util/string.h>
|
||||
|
||||
/* Local includes */
|
||||
#include "mem.h"
|
||||
#include "routine.h"
|
||||
#include "signal.h"
|
||||
#include "lx_emul.h"
|
||||
#include "platform/lx_mem.h"
|
||||
|
||||
/* DDE kit includes */
|
||||
extern "C" {
|
||||
@ -38,121 +38,217 @@ extern "C" {
|
||||
|
||||
#if VERBOSE_LX_EMUL
|
||||
#define TRACE dde_kit_printf("\033[35m%s\033[0m called\n", __PRETTY_FUNCTION__)
|
||||
#define UNSUPPORTED dde_kit_printf("\033[31m%s\033[0m unsupported arguments\n", __PRETTY_FUNCTION__)
|
||||
#else
|
||||
#define TRACE
|
||||
#define UNSUPPORTED
|
||||
#endif
|
||||
|
||||
namespace Genode {
|
||||
|
||||
class Slab_alloc : public Slab
|
||||
{
|
||||
private:
|
||||
|
||||
Mem::Zone_alloc *_allocator;
|
||||
|
||||
size_t _calculate_block_size(size_t object_size)
|
||||
{
|
||||
size_t block_size = 8 * (object_size + sizeof(Slab_entry)) + sizeof(Slab_block);
|
||||
return align_addr(block_size, 12);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Slab_alloc(size_t object_size, Mem::Zone_alloc *allocator)
|
||||
: Slab(object_size, _calculate_block_size(object_size), 0, allocator),
|
||||
_allocator(allocator) { }
|
||||
|
||||
inline void *alloc()
|
||||
{
|
||||
void *result;
|
||||
return (Slab::alloc(slab_size(), &result) ? result : 0);
|
||||
}
|
||||
|
||||
bool match(void const *addr) { return _allocator->match(addr); }
|
||||
addr_t phys_addr(void const *addr) { return _allocator->phys_addr(addr); }
|
||||
};
|
||||
class Slab_backend_alloc;
|
||||
class Slab_alloc;
|
||||
}
|
||||
|
||||
|
||||
class Malloc
|
||||
/**
|
||||
* Back-end allocator for Genode's slab allocator
|
||||
*/
|
||||
class Genode::Slab_backend_alloc : public Genode::Allocator,
|
||||
public Genode::Rm_connection
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Mem *_pool;
|
||||
|
||||
enum {
|
||||
SLAB_START_LOG2 = 3, /* 8 B */
|
||||
SLAB_STOP_LOG2 = 16, /* 64 KB */
|
||||
NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1
|
||||
enum {
|
||||
VM_SIZE = 10 * 1024 * 1024, /* size of VM region to reserve */
|
||||
BLOCK_SIZE = 768 * 1024, /* 1 MB */
|
||||
ELEMENTS = VM_SIZE / BLOCK_SIZE, /* MAX number of dataspaces in VM */
|
||||
};
|
||||
|
||||
/* slab allocator using Mem as back-end */
|
||||
Genode::Slab_alloc *_allocator[NUM_SLABS];
|
||||
addr_t _base; /* virt. base address */
|
||||
bool _cached; /* non-/cached RAM */
|
||||
Ram_dataspace_capability _ds_cap[ELEMENTS]; /* dataspaces to put in VM */
|
||||
addr_t _ds_phys[ELEMENTS]; /* physical bases of dataspaces */
|
||||
int _index; /* current index in ds_cap */
|
||||
Allocator_avl _range; /* manage allocations */
|
||||
|
||||
void _init_slabs()
|
||||
bool _alloc_block()
|
||||
{
|
||||
using namespace Genode;
|
||||
_pool->init_zones(NUM_SLABS);
|
||||
for (unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++) {
|
||||
Mem::Zone_alloc *allocator = _pool->new_zone_allocator();
|
||||
_allocator[i - SLAB_START_LOG2] = new (env()->heap()) Slab_alloc(1U << i, allocator);
|
||||
if (_index == ELEMENTS) {
|
||||
PERR("Slab-backend exhausted!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return slab for 'struct dma_pool' of size
|
||||
*/
|
||||
int _dma_pool_slab(Genode::size_t size)
|
||||
{
|
||||
int msb = Genode::log2(size);
|
||||
if (size > (1U << msb))
|
||||
msb++;
|
||||
try {
|
||||
_ds_cap[_index] = Backend_memory::alloc(BLOCK_SIZE, _cached);
|
||||
/* attach at index * BLOCK_SIZE */
|
||||
Rm_connection::attach_at(_ds_cap[_index], _index * BLOCK_SIZE, BLOCK_SIZE, 0);
|
||||
|
||||
/* take next chunk */
|
||||
return msb++;
|
||||
/* lookup phys. address */
|
||||
_ds_phys[_index] = Dataspace_client(_ds_cap[_index]).phys_addr();
|
||||
} catch (...) { return false; }
|
||||
|
||||
/* return base + offset in VM area */
|
||||
addr_t block_base = _base + (_index * BLOCK_SIZE);
|
||||
++_index;
|
||||
|
||||
_range.add_range(block_base, BLOCK_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Malloc(Genode::Mem *pool) : _pool(pool) { _init_slabs(); }
|
||||
|
||||
/**
|
||||
* General purpose allcator
|
||||
*/
|
||||
static Malloc *mem()
|
||||
Slab_backend_alloc(bool cached)
|
||||
: Rm_connection(0, VM_SIZE), _cached(cached), _index(0),
|
||||
_range(env()->heap())
|
||||
{
|
||||
static Malloc _m(Genode::Mem::pool());
|
||||
return &_m;
|
||||
/* reserver attach us, anywere */
|
||||
_base = env()->rm_session()->attach(dataspace());
|
||||
}
|
||||
|
||||
/**
|
||||
* DMA allocator
|
||||
* Allocate
|
||||
*/
|
||||
static Malloc *dma()
|
||||
bool alloc(size_t size, void **out_addr)
|
||||
{
|
||||
static Malloc _m(Genode::Mem::dma());
|
||||
return &_m;
|
||||
bool done = _range.alloc(size, out_addr);
|
||||
|
||||
if (done)
|
||||
return done;
|
||||
|
||||
done = _alloc_block();
|
||||
if (!done) {
|
||||
PERR("Backend allocator exhausted\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return _range.alloc(size, out_addr);
|
||||
}
|
||||
|
||||
void free(void *addr, size_t /* size */) { }
|
||||
size_t overhead(size_t size) { return 0; }
|
||||
|
||||
/**
|
||||
* Alloc with alignment (uses back-end when alingment is > 2)
|
||||
* Return phys address for given virtual addr.
|
||||
*/
|
||||
void *alloc(Genode::size_t size, int align)
|
||||
addr_t phys_addr(addr_t addr)
|
||||
{
|
||||
if (align <= 2)
|
||||
return alloc(size);
|
||||
if (addr < _base || addr >= (_base + VM_SIZE))
|
||||
return ~0UL;
|
||||
|
||||
return _pool->alloc(size, -1, align);
|
||||
int index = (addr - _base) / BLOCK_SIZE;
|
||||
|
||||
/* physical base of dataspace */
|
||||
addr_t phys = _ds_phys[index];
|
||||
|
||||
if (!phys)
|
||||
return ~0UL;
|
||||
|
||||
/* add offset */
|
||||
phys += (addr - _base - (index * BLOCK_SIZE));
|
||||
return phys;
|
||||
}
|
||||
|
||||
addr_t start() const { return _base; }
|
||||
addr_t end() const { return _base + VM_SIZE - 1; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Slab allocator using our back-end allocator
|
||||
*/
|
||||
class Genode::Slab_alloc : public Genode::Slab
|
||||
{
|
||||
private:
|
||||
|
||||
Slab_backend_alloc *_allocator;
|
||||
|
||||
size_t _calculate_block_size(size_t object_size)
|
||||
{
|
||||
size_t block_size = 8 * (object_size + sizeof(Slab_entry)) + sizeof(Slab_block);
|
||||
return align_addr(block_size, 12);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Slab_alloc(size_t object_size, Slab_backend_alloc *allocator)
|
||||
: Slab(object_size, _calculate_block_size(object_size), 0, allocator),
|
||||
_allocator(allocator) { }
|
||||
|
||||
inline addr_t alloc()
|
||||
{
|
||||
addr_t result;
|
||||
return (Slab::alloc(slab_size(), (void **)&result) ? result : 0);
|
||||
}
|
||||
|
||||
addr_t phys_addr(addr_t addr) { return _allocator->phys_addr(addr); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Memory interface used used for Linux emulation
|
||||
*/
|
||||
class Malloc
|
||||
{
|
||||
private:
|
||||
|
||||
enum {
|
||||
SLAB_START_LOG2 = 3, /* 8 B */
|
||||
SLAB_STOP_LOG2 = 16, /* 64 KB */
|
||||
NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1,
|
||||
};
|
||||
|
||||
typedef Genode::addr_t addr_t;
|
||||
typedef Genode::Slab_alloc Slab_alloc;
|
||||
typedef Genode::Slab_backend_alloc Slab_backend_alloc;
|
||||
|
||||
Slab_alloc *_allocator[NUM_SLABS];
|
||||
bool _cached; /* cached or un-cached memory */
|
||||
addr_t _start; /* VM region of this allocator */
|
||||
addr_t _end;
|
||||
|
||||
/**
|
||||
* Set 'value' at 'addr'
|
||||
*/
|
||||
void _set_at(addr_t addr, addr_t value) { *((addr_t *)addr) = value; }
|
||||
|
||||
/**
|
||||
* Retrieve slab index belonging to given address
|
||||
*/
|
||||
unsigned _slab_index(Genode::addr_t **addr)
|
||||
{
|
||||
using namespace Genode;
|
||||
/* get index */
|
||||
addr_t index = *(*addr - 1);
|
||||
|
||||
/*
|
||||
* If index large, we use aligned memory, retrieve beginning of slab entry
|
||||
* and read index from there
|
||||
*/
|
||||
if (index > 32) {
|
||||
*addr = (addr_t *)*(*addr - 1);
|
||||
index = *(*addr - 1);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Malloc(Slab_backend_alloc *alloc, bool cached)
|
||||
: _cached(cached), _start(alloc->start()), _end(alloc->end())
|
||||
{
|
||||
/* init slab allocators */
|
||||
for (unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++)
|
||||
_allocator[i - SLAB_START_LOG2] = new (Genode::env()->heap())
|
||||
Slab_alloc(1U << i, alloc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alloc in slabs
|
||||
*/
|
||||
void *alloc(Genode::size_t size)
|
||||
void *alloc(Genode::size_t size, int align = 0, Genode::addr_t *phys = 0)
|
||||
{
|
||||
using namespace Genode;
|
||||
/* += slab index + aligment size */
|
||||
size += sizeof(addr_t) + (align > 2 ? (1 << align) : 0);
|
||||
|
||||
int msb = Genode::log2(size);
|
||||
|
||||
if (size > (1U << msb))
|
||||
@ -162,86 +258,74 @@ class Malloc
|
||||
msb = SLAB_STOP_LOG2;
|
||||
|
||||
if (msb > SLAB_STOP_LOG2) {
|
||||
PINF("Slab too large %u", 1U << msb);
|
||||
return _pool->alloc(size);
|
||||
PERR("Slab too large %u reqested %zu cached %d", 1U << msb, size, _cached);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _allocator[msb - SLAB_START_LOG2]->alloc();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free from slabs
|
||||
*/
|
||||
void free(void const *addr)
|
||||
{
|
||||
|
||||
for (register unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++) {
|
||||
Genode::Slab_alloc *slab = _allocator[i - SLAB_START_LOG2];
|
||||
|
||||
if (!slab->match(addr))
|
||||
continue;
|
||||
|
||||
slab->free((void *)addr);
|
||||
return;
|
||||
addr_t addr = _allocator[msb - SLAB_START_LOG2]->alloc();
|
||||
if (!addr) {
|
||||
PERR("Failed to get slab for %u", 1 << msb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_pool->free((void *)addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get phys addr
|
||||
*/
|
||||
Genode::addr_t phys_addr(void *addr)
|
||||
{
|
||||
for (register unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++) {
|
||||
Genode::Slab_alloc *slab = _allocator[i - SLAB_START_LOG2];
|
||||
|
||||
if (!slab->match(addr))
|
||||
continue;
|
||||
_set_at(addr, msb - SLAB_START_LOG2);
|
||||
addr += sizeof(addr_t);
|
||||
|
||||
return slab->phys_addr(addr);
|
||||
if (align > 2) {
|
||||
/* save */
|
||||
addr_t ptr = addr;
|
||||
addr_t align_val = (1U << align);
|
||||
addr_t align_mask = align_val - 2;
|
||||
/* align */
|
||||
addr = (addr + align_val) & ~align_mask;
|
||||
/* write start address before aligned address */
|
||||
_set_at(addr - sizeof(addr_t), ptr);
|
||||
}
|
||||
/* not found in slabs, try in back-end */
|
||||
return _pool->phys_addr(addr);
|
||||
|
||||
if (phys)
|
||||
*phys = _allocator[msb - SLAB_START_LOG2]->phys_addr(addr);
|
||||
return (addr_t *)addr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocate aligned memory in slabs
|
||||
*/
|
||||
void *dma_pool_alloc(size_t size, int align, Genode::addr_t *dma)
|
||||
void free(void const *a)
|
||||
{
|
||||
using namespace Genode;
|
||||
addr_t *addr = (addr_t *)a;
|
||||
|
||||
int msb = _dma_pool_slab(size);
|
||||
addr_t base = (addr_t)_allocator[msb - SLAB_START_LOG2]->alloc();
|
||||
unsigned nr = _slab_index(&addr);
|
||||
_allocator[nr]->free((void *)(addr - 1));
|
||||
}
|
||||
|
||||
unsigned align_val = (1U << align);
|
||||
unsigned align_mask = align_val - 1;
|
||||
|
||||
/* make room for pointer */
|
||||
addr_t addr = base + sizeof(Genode::addr_t);
|
||||
|
||||
/* align */
|
||||
addr = (addr + align_val - 1) & ~align_mask;
|
||||
addr_t *ptr = (addr_t *)addr - 1;
|
||||
*ptr = base;
|
||||
|
||||
*dma = phys_addr((void *)addr);
|
||||
return (void *)addr;
|
||||
Genode::addr_t phys_addr(void *a)
|
||||
{
|
||||
using namespace Genode;
|
||||
addr_t *addr = (addr_t *)a;
|
||||
return _allocator[_slab_index(&addr)]->phys_addr((addr_t)a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free memory allocted with 'dma_pool_alloc'
|
||||
* Belongs given address to this allocator
|
||||
*/
|
||||
void dma_pool_free(size_t size, void *addr)
|
||||
{
|
||||
using namespace Genode;
|
||||
bool inside(addr_t const addr) const { return (addr > _start) && (addr <= _end); }
|
||||
|
||||
int msb = _dma_pool_slab(size);
|
||||
addr_t base = *((addr_t *)addr - 1);
|
||||
_allocator[msb - SLAB_START_LOG2]->free((void *)base);
|
||||
/**
|
||||
* Cached memory allocator
|
||||
*/
|
||||
static Malloc *mem()
|
||||
{
|
||||
static Slab_backend_alloc _b(true);
|
||||
static Malloc _m(&_b, true);
|
||||
return &_m;
|
||||
}
|
||||
|
||||
/**
|
||||
* DMA allocator
|
||||
*/
|
||||
static Malloc *dma()
|
||||
{
|
||||
static Slab_backend_alloc _b(false);
|
||||
static Malloc _m(&_b, false);
|
||||
return &_m;
|
||||
}
|
||||
};
|
||||
|
||||
@ -280,6 +364,11 @@ void mutex_unlock(struct mutex *m) { if (m->lock) dde_kit_lock_unlock( m->lock);
|
||||
void *kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
void *addr = flags & GFP_NOIO ? Malloc::dma()->alloc(size) : Malloc::mem()->alloc(size);
|
||||
|
||||
unsigned long a = (unsigned long)addr;
|
||||
|
||||
if (a & 0x3)
|
||||
PERR("Unaligned kmalloc %lx", a);
|
||||
return addr;
|
||||
}
|
||||
|
||||
@ -304,8 +393,11 @@ void *kcalloc(size_t n, size_t size, gfp_t flags)
|
||||
|
||||
void kfree(const void *p)
|
||||
{
|
||||
Malloc::mem()->free(p);
|
||||
Malloc::dma()->free(p);
|
||||
if (Malloc::mem()->inside((Genode::addr_t)p))
|
||||
Malloc::mem()->free(p);
|
||||
|
||||
if (Malloc::dma()->inside((Genode::addr_t)p))
|
||||
Malloc::dma()->free(p);
|
||||
}
|
||||
|
||||
|
||||
@ -756,7 +848,7 @@ static Timer::Connection _timer;
|
||||
|
||||
void udelay(unsigned long usecs)
|
||||
{
|
||||
_timer.msleep(usecs < 1000 ? 1 : usecs / 1000);
|
||||
_timer.usleep(usecs);
|
||||
}
|
||||
|
||||
|
||||
@ -807,25 +899,24 @@ void dma_pool_destroy(struct dma_pool *d)
|
||||
|
||||
void *dma_pool_alloc(struct dma_pool *d, gfp_t f, dma_addr_t *dma)
|
||||
{
|
||||
return Malloc::dma()->dma_pool_alloc(d->size, d->align, (Genode::addr_t*)dma);
|
||||
return Malloc::dma()->alloc(d->size, d->align, (Genode::addr_t*)dma);
|
||||
}
|
||||
|
||||
|
||||
void dma_pool_free(struct dma_pool *d, void *vaddr, dma_addr_t a)
|
||||
{
|
||||
dde_kit_log(DEBUG_DMA, "free: addr %p, size: %zx", vaddr, d->size);
|
||||
Malloc::dma()->dma_pool_free(d->size, vaddr);
|
||||
Malloc::dma()->free(vaddr);
|
||||
}
|
||||
|
||||
|
||||
void *dma_alloc_coherent(struct device *, size_t size, dma_addr_t *dma, gfp_t)
|
||||
{
|
||||
void *addr = Malloc::dma()->alloc(size, PAGE_SHIFT);
|
||||
void *addr = Malloc::dma()->alloc(size, PAGE_SHIFT, dma);
|
||||
|
||||
if (!addr)
|
||||
return 0;
|
||||
|
||||
*dma = (dma_addr_t)Malloc::dma()->phys_addr(addr);
|
||||
dde_kit_log(DEBUG_DMA, "DMA pool alloc addr: %p size %zx align: %d, phys: %lx",
|
||||
addr, size, PAGE_SHIFT, *dma);
|
||||
return addr;
|
||||
@ -853,6 +944,10 @@ dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
|
||||
{
|
||||
dma_addr_t phys = (dma_addr_t)Malloc::dma()->phys_addr(ptr);
|
||||
|
||||
if (phys == ~0UL)
|
||||
PERR("translation virt->phys %p->%lx failed, return ip %p", ptr, phys,
|
||||
__builtin_return_address(0));
|
||||
|
||||
dde_kit_log(DEBUG_DMA, "virt: %p phys: %lx", ptr, phys);
|
||||
return phys;
|
||||
}
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <util/xml_node.h>
|
||||
|
||||
#include <lx_emul.h>
|
||||
#include <mem.h>
|
||||
|
||||
#include <nic/component.h>
|
||||
#include "signal.h"
|
||||
@ -69,7 +68,7 @@ class Skb
|
||||
Genode::memset(_free, 0xff, sizeof(_free));
|
||||
|
||||
for (unsigned i = 0; i < ENTRIES; i++)
|
||||
_buf[i].start = (unsigned char *)Genode::Mem::dma()->alloc(BUFFER);;
|
||||
_buf[i].start = (unsigned char *)kmalloc(BUFFER, GFP_NOIO);
|
||||
}
|
||||
|
||||
sk_buff *alloc()
|
||||
|
@ -17,8 +17,7 @@
|
||||
|
||||
/* Linux includes */
|
||||
#include <lx_emul.h>
|
||||
|
||||
#include "mem.h"
|
||||
#include <platform/lx_mem.h>
|
||||
|
||||
struct bus_type pci_bus_type;
|
||||
|
||||
@ -311,10 +310,14 @@ const char *pci_name(const struct pci_dev *pdev)
|
||||
return "dummy";
|
||||
}
|
||||
|
||||
Genode::Ram_dataspace_capability Genode::Mem::alloc_dma_buffer(size_t size)
|
||||
Genode::Ram_dataspace_capability Backend_memory::alloc(Genode::addr_t size,
|
||||
bool cached)
|
||||
{
|
||||
using namespace Genode;
|
||||
Ram_dataspace_capability ram_cap = pci.alloc_dma_buffer(pci_device_cap,
|
||||
size);
|
||||
return ram_cap;
|
||||
|
||||
PERR("use it here %u", cached);
|
||||
if (cached)
|
||||
return env()->ram_session()->alloc(size, cached);
|
||||
else
|
||||
return pci.alloc_dma_buffer(pci_device_cap, size);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user