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
12#include <barrelfish/barrelfish.h>
13
14#include <dma_internal.h>
15#include <dma_mem_utils.h>
16#include <driverkit/iommu.h>
17
18static lvaddr_t addr_start = (256UL << 30);
19
20/**
21 * \brief allocates and maps a memory region to be used for DMA purposes
22 *
23 * \param bytes minimum size of the memory region in bytes
24 * \param flags VREGION flags how the region gets mapped
25 * \param cl    IOMMU client if IOMMU is present
26 * \param mem   returns the mapping information
27 *
28 * \returns SYS_ERR_OK on success
29 *          errval on error
30 */
31errval_t dma_mem_alloc(size_t bytes,
32                       vregion_flags_t flags,
33                       struct iommu_client *cl,
34                       struct dmem *mem)
35{
36    // TODO might also include allocation with IOMMU present
37    errval_t err;
38
39    if (mem == NULL) {
40        return DMA_ERR_ARG_INVALID;
41    }
42
43    if (cl != NULL) {
44        err = driverkit_iommu_mmap_cl(cl, bytes, flags, mem);
45        return err;
46    }
47
48    uint64_t base, limit;
49    ram_get_affinity(&base, &limit);
50    ram_set_affinity(4UL << 30, 128UL << 32);
51    err = frame_alloc(&mem->mem, bytes, &mem->size);
52    if (err_is_fail(err)) {
53        return err;
54    }
55    ram_set_affinity(base, limit);
56
57    struct frame_identity id;
58    err = frame_identify(mem->mem, &id);
59    if (err_is_fail(err)) {
60        dma_mem_free(mem);
61        return err;
62    }
63
64    mem->devaddr = id.base;
65
66
67    void *addr;
68    err = vspace_map_one_frame_fixed_attr(addr_start, mem->size, mem->mem, flags, NULL,
69                                          NULL);
70    if (err_is_fail(err)) {
71        dma_mem_free(mem);
72        return err;
73    }
74
75    addr = (void *)addr_start;
76    addr_start += mem->size;
77
78    mem->vbase = (lvaddr_t)addr;
79
80    return SYS_ERR_OK;
81}
82
83/**
84 * \brief tries to free the allocated memory region
85 *
86 * \returns SYS_ERR_OK on success
87 *          errval on error
88 */
89errval_t dma_mem_free(struct dmem *mem)
90{
91    errval_t err;
92
93    if (mem->vbase) {
94        err = vspace_unmap((void*)mem->vbase);
95        if (err_is_fail(err)) {
96            /* todo: error handling ignoring for now */
97        }
98    }
99
100    if (!capref_is_null(mem->mem)) {
101        err = cap_destroy(mem->mem);
102        if (err_is_fail(err)) {
103            /* todo: error handling ignoring for now */
104
105        }
106    }
107
108    memset(mem, 0, sizeof(*mem));
109
110    return SYS_ERR_OK;
111}
112
113