[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH 2/5] cdi: mem.h implementiert
+ cdi: mem.h implementiert
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/modules/cdi/include/cdi-osdep.h | 1 +
src/modules/cdi/lib/mem.c | 215 +++++++++++++++++++++++++++++++++++
2 files changed, 216 insertions(+), 0 deletions(-)
create mode 100644 src/modules/cdi/lib/mem.c
diff --git a/src/modules/cdi/include/cdi-osdep.h b/src/modules/cdi/include/cdi-osdep.h
index 0d052fe..204793b 100644
--- a/src/modules/cdi/include/cdi-osdep.h
+++ b/src/modules/cdi/include/cdi-osdep.h
@@ -77,6 +77,7 @@ typedef struct
* \endenglish
*/
typedef struct {
+ int mapped;
} cdi_mem_osdep;
#endif
diff --git a/src/modules/cdi/lib/mem.c b/src/modules/cdi/lib/mem.c
new file mode 100644
index 0000000..36ad90d
--- /dev/null
+++ b/src/modules/cdi/lib/mem.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2010 Kevin Wolf
+ *
+ * This program is free software. It comes without any warranty, to
+ * the extent permitted by applicable law. You can redistribute it
+ * and/or modify it under the terms of the Do What The Fuck You Want
+ * To Public License, Version 2, as published by Sam Hocevar. See
+ * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <string.h>
+
+#include "cdi.h"
+#include "cdi/mem.h"
+
+/**
+ * \german
+ * Reserviert einen Speicherbereich.
+ *
+ * @param size Grö�e des Speicherbereichs in Bytes
+ * @param flags Flags, die zusätzliche Anforderungen beschreiben
+ * \endgerman
+ * \english
+ * Allocates a memory area.
+ *
+ * @param size Size of the memory area in bytes
+ * @param flags Flags that describe additional requirements
+ * \endenglish
+ */
+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;
+
+ // Wir machen im Moment mal nur ganze Pages
+ if ((flags & CDI_MEM_ALIGN_MASK) > 12) {
+ return NULL;
+ }
+
+ // Speicher holen
+ if (flags & CDI_MEM_VIRT_ONLY) {
+ buffer = mem_dma_allocate(size, 0);
+ } else {
+ buffer = mem_dma_allocate(size, 0x80);
+ }
+
+ if (buffer.virt == NULL) {
+ return NULL;
+ }
+
+ // cdi_mem_area anlegen und befuellen
+ sg_item = malloc(sizeof(*sg_item));
+ *sg_item = (struct cdi_mem_sg_item) {
+ .start = (uintptr_t) buffer.phys,
+ .size = size,
+ };
+
+ area = malloc(sizeof(*area));
+ *area = (struct cdi_mem_area) {
+ .size = size,
+ .vaddr = buffer.virt,
+ .paddr = {
+ .num = 1,
+ .items = sg_item,
+ },
+ };
+
+ return area;
+}
+
+/**
+ * Reserviert physisch zusammenhägenden Speicher an einer definierten Adresse
+ *
+ * @param paddr Physische Adresse des angeforderten Speicherbereichs
+ * @param size Grö�e des benötigten Speichers in Bytes
+ *
+ * @return Eine cdi_mem_area bei Erfolg, NULL im Fehlerfall
+ */
+struct cdi_mem_area* cdi_mem_map(uintptr_t paddr, size_t size)
+{
+ struct cdi_mem_area* area;
+ struct cdi_mem_sg_item* sg_item;
+ void* vaddr = mem_allocate_physical(size, paddr, 0);
+
+ if (vaddr == NULL) {
+ return NULL;
+ }
+
+ // cdi_mem_area anlegen und befuellen
+ sg_item = malloc(sizeof(*sg_item));
+ *sg_item = (struct cdi_mem_sg_item) {
+ .start = paddr,
+ .size = size,
+ };
+
+ area = malloc(sizeof(*area));
+ *area = (struct cdi_mem_area) {
+ .size = size,
+ .vaddr = vaddr,
+ .paddr = {
+ .num = 1,
+ .items = sg_item,
+ },
+ .osdep = {
+ .mapped = 1,
+ },
+ };
+
+ return area;
+}
+
+
+/**
+ * \german
+ * Gibt einen durch cdi_mem_alloc oder cdi_mem_map reservierten Speicherbereich
+ * frei
+ * \endgerman
+ * \english
+ * Frees a memory area that was previously allocated by cdi_mem_alloc or
+ * cdi_mem_map
+ * \endenglish
+ */
+void cdi_mem_free(struct cdi_mem_area* p)
+{
+ if (p->osdep.mapped) {
+ mem_free_physical(p->vaddr, p->size);
+ } else {
+ mem_free(p->vaddr, p->size);
+ }
+
+ free(p->paddr.items);
+ free(p);
+}
+
+/**
+ * \german
+ * Gibt einen Speicherbereich zurück, der dieselben Daten wie @a p beschreibt,
+ * aber mindestens die gegebenen Flags gesetzt hat.
+ *
+ * Diese Funktion kann denselben virtuellen und physischen Speicherbereich wie
+ * @p benutzen oder sogar @p selbst zurückzugeben, solange der gemeinsam
+ * benutzte Speicher erst dann freigegeben wird, wenn sowohl @a p als auch der
+ * Rückgabewert durch cdi_mem_free freigegeben worden sind.
+ *
+ * Ansonsten wird ein neuer Speicherbereich reserviert und (auÃ?er wenn das
+ * Flag CDI_MEM_NOINIT gesetzt ist) die Daten werden aus @a p in den neu
+ * reservierten Speicher kopiert.
+ * \endgerman
+ * \english
+ * Returns a memory area that describes the same data as @a p does, but for
+ * which at least the given flags are set.
+ *
+ * This function may use the same virtual and physical memory areas as used in
+ * @a p, or it may even return @a p itself. In this case it must ensure that
+ * the commonly used memory is only freed when both @a p and the return value
+ * of this function have been freed by cdi_mem_free.
+ *
+ * Otherwise, a new memory area is allocated and data is copied from @a p into
+ * the newly allocated memory (unless CDI_MEM_NOINIT is set).
+ * \endenglish
+ */
+struct cdi_mem_area* cdi_mem_require_flags(struct cdi_mem_area* p,
+ cdi_mem_flags_t flags)
+{
+ // TODO Das geht unter Umstaenden effizienter
+ struct cdi_mem_area* new = cdi_mem_alloc(p->size, flags);
+ if (new == NULL) {
+ return NULL;
+ }
+
+ memcpy(new->vaddr, p->vaddr, new->size);
+ return new;
+}
+
+/**
+ * \german
+ * Kopiert die Daten von @a src nach @a dest. Beide Speicherbereiche müssen
+ * gleich groÃ? sein.
+ *
+ * Das bedeutet nicht unbedingt eine physische Kopie: Wenn beide
+ * Speicherbereiche auf denselben physischen Speicher zeigen, macht diese
+ * Funktion nichts. Sie kann auch andere Methoden verwenden, um den Speicher
+ * effektiv zu kopieren, z.B. durch geeignetes Ummappen von Pages.
+ *
+ * @return 0 bei Erfolg, -1 sonst
+ * \endgerman
+ * \english
+ * Copies data from @a src to @a dest. Both memory areas must be of the same
+ * size.
+ *
+ * This does not necessarily involve a physical copy: If both memory areas
+ * point to the same physical memory, this function does nothing. It can also
+ * use other methods to achieve the same visible effect, e.g. by remapping
+ * pages.
+ *
+ * @return 0 on success, -1 otherwise
+ * \endenglish
+ */
+int cdi_mem_copy(struct cdi_mem_area* dest, struct cdi_mem_area* src)
+{
+ // TODO Das geht unter Umstaenden effizienter
+ if (dest->size != src->size) {
+ return -1;
+ }
+
+ if (dest->vaddr != src->vaddr) {
+ memcpy(dest->vaddr, src->vaddr, dest->size);
+ }
+
+ return 0;
+}
--
1.6.0.2