1/*
2 * Copyright (c) 2014 ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <string.h>
11#include <barrelfish/barrelfish.h>
12#include "dma_mem.h"
13
14errval_t dma_mem_from_capref(struct capref frame, struct dma_mem *mem)
15{
16    errval_t err = SYS_ERR_OK;
17    if (mem == NULL) {
18        return DMA_ERR_ARG_INVALID;
19    }
20
21    struct frame_identity id;
22    err = invoke_frame_identify(frame, &id);
23    if (err_is_fail(err)) {
24        DEBUG_ERR(err, "invoke frame id");
25        return err;
26    }
27
28    mem->paddr = id.base;
29    mem->bytes = id.bytes;
30    mem->requested = id.bytes;
31    mem->frame = frame;
32
33    void *addr;
34    err = vspace_map_one_frame_attr(&addr, mem->bytes, mem->frame, VREGION_FLAGS_READ_WRITE,
35                                    NULL, NULL);
36    if (err_is_fail(err)) {
37        dma_mem_free(mem);
38        return err;
39    }
40
41    mem->vaddr = (lvaddr_t)addr;
42
43    return SYS_ERR_OK;
44}
45
46/**
47 * \brief allocates and maps a memory region to be used for DMA purposes
48 *
49 * \param bytes minimum size of the memory region in bytes
50 * \param flags VREGION flags how the region gets mapped
51 * \param mem   returns the mapping information
52 *
53 * \returns SYS_ERR_OK on success
54 *          errval on error
55 */
56errval_t dma_mem_alloc(size_t bytes, struct dma_mem *mem)
57{
58    errval_t err = SYS_ERR_OK;
59    mem->requested = bytes;
60    bytes = ROUND_UP(BASE_PAGE_SIZE, bytes);
61
62    if (mem == NULL) {
63        return DMA_ERR_ARG_INVALID;
64    }
65
66    err = frame_alloc(&mem->frame, bytes, &mem->bytes);
67    if (err_is_fail(err)) {
68        return err;
69    }
70
71    struct frame_identity id;
72    err = invoke_frame_identify(mem->frame, &id);
73    if (err_is_fail(err)) {
74        dma_mem_free(mem);
75        return err;
76    }
77
78    mem->paddr = id.base;
79
80    void *addr;
81    err = vspace_map_one_frame_attr(&addr, mem->bytes, mem->frame, VREGION_FLAGS_READ_WRITE,
82                                    NULL, NULL);
83    if (err_is_fail(err)) {
84        dma_mem_free(mem);
85        return err;
86    }
87
88    mem->vaddr = (lvaddr_t)addr;
89
90    return SYS_ERR_OK;
91}
92
93/**
94 * \brief tries to free the allocated memory region
95 *
96 * \returns SYS_ERR_OK on success
97 *          errval on error
98 */
99errval_t dma_mem_free(struct dma_mem *mem)
100{
101    errval_t err;
102
103    if (mem->vaddr) {
104        err = vspace_unmap((void*)mem->vaddr);
105        if (err_is_fail(err)) {
106            USER_PANIC_ERR(err, "call failed.");
107        }
108    }
109
110    if (!capref_is_null(mem->frame)) {
111        err = cap_destroy(mem->frame);
112        if (err_is_fail(err)) {
113            if (err_is_fail(err)) {
114                USER_PANIC_ERR(err, "call failed.");
115            }
116        }
117    }
118
119    memset(mem, 0, sizeof(*mem));
120
121    return SYS_ERR_OK;
122}
123