[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH 7/9] cdi: Implementierung von cdi_mem_alloc um Alignments >= 12 erweitert
From: Antoine Kaufmann <toni@xxxxxxxxxx>
* cdi: Sorgt dafuer dass cdi_mem_alloc auch Speicherstuecke allozieren
kann mit einem groesseren Alignment als nur Pagegroesse. Die
Loesung ist zwar nicht wirklich schoen, duerfte aber den Zweck
vorerst erfuellen.
Signed-off-by: Antoine Kaufmann <toni@xxxxxxxxxx>
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/modules/cdi/lib/mem.c | 50 +++++++++++++++++++++++++++++++++++++++++---
1 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/src/modules/cdi/lib/mem.c b/src/modules/cdi/lib/mem.c
index 36ad90d..5597206 100644
--- a/src/modules/cdi/lib/mem.c
+++ b/src/modules/cdi/lib/mem.c
@@ -35,23 +35,65 @@ struct cdi_mem_area* cdi_mem_alloc(size_t size, cdi_mem_flags_t flags)
dma_mem_ptr_t buffer;
struct cdi_mem_area* area;
struct cdi_mem_sg_item* sg_item;
+ size_t alignment = flags & CDI_MEM_ALIGN_MASK;
+ size_t asize;
- // Wir machen im Moment mal nur ganze Pages
- if ((flags & CDI_MEM_ALIGN_MASK) > 12) {
- return NULL;
+ // Wir vergeben nur ganze Pages
+ size = (size + 0xFFF) & (~0xFFF);
+ asize = size;
+
+ // Wenn die physische Adresse nicht intressiert, koennen wir das Alignment
+ // ignorieren.
+ if ((flags & CDI_MEM_VIRT_ONLY)) {
+ alignment = 0;
+ }
+
+ // Quick and dirty Loesung fuer das allozieren von Speicherbereichen mit
+ // einem Alignment von mehr als Page-Size: Wir nehmen einfach die Groesse
+ // plus einmal das Alignment, dann finden wir sicher ein Stueck mit
+ // passendem Alignment innerhalb des allozierten Bereichs. Den Rest geben
+ // wir wieder frei.
+ if (alignment > 12) {
+ // TODO: Momentan unterstuetzen wir das Alignment nur fuer
+ // physisch zusammenhaengende Bereiche.
+ if (!(flags & CDI_MEM_PHYS_CONTIGUOUS)) {
+ return NULL;
+ }
+
+ asize = size + (1ULL << alignment);
}
// Speicher holen
if (flags & CDI_MEM_VIRT_ONLY) {
buffer = mem_dma_allocate(size, 0);
} else {
- buffer = mem_dma_allocate(size, 0x80);
+ buffer = mem_dma_allocate(asize, 0x80);
}
if (buffer.virt == NULL) {
return NULL;
}
+ // Wie oben erwaehnt alignment umsetzen
+ if (alignment > 12) {
+ uintptr_t amask = (1ULL << alignment) - 1;
+ uintptr_t astart = ((uintptr_t) buffer.phys + amask) & (~amask);
+ uintptr_t off = astart - (uintptr_t) buffer.phys;
+
+ // Die beiden Stuecke vor und nach unserem ausgeschnittenen Bereich
+ // freigeben.
+ if (off) {
+ mem_free(buffer.virt, off);
+ }
+ if (asize - size - off) {
+ mem_free((vaddr_t) (((uintptr_t) buffer.virt) + size + off),
+ asize - size - off);
+ }
+
+ buffer.phys = (paddr_t) astart;
+ buffer.virt = (vaddr_t) (((uintptr_t) buffer.virt) + off);
+ }
+
// cdi_mem_area anlegen und befuellen
sg_item = malloc(sizeof(*sg_item));
*sg_item = (struct cdi_mem_sg_item) {
--
1.6.0.2