1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#pragma once
14
15#include <platsupport/io.h>
16#include <stddef.h>
17#include <stdint.h>
18#include <utils/util.h>
19#include <sel4/sel4.h>
20#include <utils/attribute.h>
21
22/* Add memory to the dma allocator. This function must be called before using any
23 * of the functions below. Pass in the pool to allocate from, the size of this
24 * pool in bytes, the page size of the associated mappings and a function to
25 * reverse mappings. Callers may pass 0 as the page_size to force the allocator
26 * itself to determine it automatically. Returns 0 on success.
27 *
28 * This function is intended to be called by the CAmkES backend and not by a user.
29 */
30int camkes_dma_init(void *dma_pool, size_t dma_pool_sz, size_t page_size)
31NONNULL(1) WARN_UNUSED_RESULT;
32
33/**
34 * Allocate memory to be used for DMA.
35 *
36 * @param size Size in bytes to allocate
37 * @param align Alignment constraint in bytes (0 == none)
38 *
39 * @return Virtual address of allocation or NULL on failure
40 */
41void *camkes_dma_alloc(size_t size, int align, bool cached) ALLOC_SIZE(1) ALLOC_ALIGN(2)
42MALLOC WARN_UNUSED_RESULT;
43
44/**
45 * Free previously allocated DMA memory.
46 *
47 * @param ptr Virtual address that was allocated (passing NULL is treated as a
48 *    no-op)
49 * @param size Size that was given in the allocation request
50 */
51void camkes_dma_free(void *ptr, size_t size);
52
53/* Return the physical address of a pointer into a DMA buffer. Returns NULL if
54 * you pass a pointer into memory that is not part of a DMA buffer. Behaviour
55 * is undefined if you pass a pointer into memory that is part of a DMA buffer,
56 * but not one currently allocated to you by camkes_dma_alloc_page.
57 */
58uintptr_t camkes_dma_get_paddr(void *ptr);
59
60/* Return the cap to a frame backing part of the DMA buffer. Returns seL4_CapNull
61 * if passed a pointer into memory that is not part of a DMA buffer. */
62seL4_CPtr camkes_dma_get_cptr(void *ptr);
63
64/* Initialise a DMA manager for use with libplatsupport. This manager will be
65 * backed by the (generated) CAmkES DMA pool. Returns 0 on success.
66 *
67 * If you only need simple DMA allocation, prefer the alloc_page and free_page
68 * functions above, but if you need a more interoperable DMA interface then use
69 * this function. Note that you can mix calls to alloc_page, free_page and the
70 * manager initialised by this function with no adverse effects.
71 */
72int camkes_dma_manager(ps_dma_man_t *man) NONNULL_ALL WARN_UNUSED_RESULT;
73
74/* Debug functionality for profiling DMA heap usage. This information is
75 * returned from a call to `camkes_dma_stats`. Note that this functionality is
76 * only available when NDEBUG is not defined.
77 */
78typedef struct {
79
80    /* The total size of the heap in bytes. */
81    size_t heap_size;
82
83    /* The low water mark of available bytes the heap has ever reached. */
84    size_t minimum_heap_size;
85
86    /* The current live (allocated) heap space in bytes. Note that the
87     * currently available bytes in the heap can be calculated as
88     * `heap_size - current_outstanding`
89     */
90    size_t current_outstanding;
91
92    /* The number of defragmentation attempts that have been performed. Note
93     * that no information is provided as to which of these defragmentation
94     * operations did useful work.
95     */
96    uint64_t defragmentations;
97
98    /* Number of coalescing operations that were performed during
99     * defragmentations.
100     */
101    uint64_t coalesces;
102
103    /* Total number of allocation requests (succeeded or failed) that have been
104     * performed.
105     */
106    uint64_t total_allocations;
107
108    /* Number of allocations that initially failed, but then succeeded on
109     * retrying after defragmenting the heap.
110     */
111    uint64_t succeeded_allocations_on_defrag;
112
113    /* Number of failed allocations. This is separated into those that failed
114     * because the heap was exhausted and for some other reason. The total
115     * failures is calculable by summing them. The succeeded allocations are
116     * available by subtracting their sum from `total_allocations`.
117     */
118    uint64_t failed_allocations_out_of_memory;
119    uint64_t failed_allocations_other;
120
121    /* Average allocation request (succeeded or failed) in bytes. */
122    size_t average_allocation;
123
124    /* Minimum allocation request (succeeded or failed) in bytes. */
125    size_t minimum_allocation;
126
127    /* Maximum allocation request (succeeded or failed) in bytes. */
128    size_t maximum_allocation;
129
130    /* Maximum alignment constraint (succeeded or failed) in bytes. */
131    int maximum_alignment;
132
133    /* Minimum alignment constraint (succeeded or failed) in bytes. */
134    int minimum_alignment;
135
136} camkes_dma_stats_t;
137
138/* Retrieve the above statistics for the current DMA heap. This function is
139 * only provided when NDEBUG is not defined. The caller should not modify or
140 * free the returned value that may be a static resource.
141 */
142const camkes_dma_stats_t *camkes_dma_stats(void) RETURNS_NONNULL;
143
144/* Legacy functionality. Use the general allocation and free functions above in
145 * preference to these.
146 */
147void *camkes_dma_alloc_page(void)
148DEPRECATED("use camkes_dma_alloc(PAGE_SIZE_4K, PAGE_SIZE_4K) instead");
149void camkes_dma_free_page(void *ptr)
150DEPRECATED("use camkes_dma_free(ptr, PAGE_SIZE_4K) instead");
151
152/*
153 * This struct describes the information about a frame in a component's DMA pool.
154 */
155struct dma_frame {
156    seL4_CPtr cap;
157    size_t size;
158    uintptr_t vaddr;
159    bool cached;
160};
161typedef struct dma_frame dma_frame_t;
162