1/*
2 * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6/* Author: alex.kroh@nicta.com.au */
7
8#pragma once
9
10#include <stdint.h>
11#include <stddef.h>
12#include <dma/dma.h>
13#include <platsupport/io.h>
14
15struct dma_allocator;
16typedef struct dma_mem *dma_mem_t;
17
18typedef void *vaddr_t;
19typedef uintptr_t paddr_t;
20
21/**
22 * Describes a chunk of memory for DMA use.
23 */
24struct dma_mem_descriptor {
25    /** The virtual address of the memory.
26        It is the applications responsibility to perform the mapping operation. */
27    uintptr_t vaddr;
28    /// The physical address of the memory.
29    uintptr_t paddr;
30    /** Boolian representation of the cacheability of the frames in this
31        descriptor. */
32    int       cached;
33    /// The size of each frame (2^frame_size_bits bytes)
34    int       size_bits;
35    /// This field is unused and may be used by the bulk allocator
36    void     *alloc_cookie;
37    /// This field is unused and may be used by the application.
38    void     *cookie;
39};
40
41
42/**
43 * DMA access flags.
44 * DMA access patterns are important to the DMA memory manager because cache
45 * maintenance operations may affect (corrupt) adjacent buffers. This is due
46 * to cach line size limits and software flushing granularity (perhaps the OS
47 * interface limits us to perform maintenance operations on a per page basis).
48 *
49 * These flags will generally lead to multiple memory pools where each request
50 * will be allocated from the appropriate pool.
51 */
52enum dma_flags {
53    /// Host always reads, never writes (invalidate only)
54    DMAF_HR,
55    /// Host always writes, never reads (clean only)
56    DMAF_HW,
57    /// Host performs both read and write (clean/invalidate)
58    DMAF_HRW,
59    /// Explicitly request uncached DMA memory
60    DMAF_COHERENT
61};
62
63
64/**
65 * A callback for providing DMA memory to the allocator.
66 * @param[in]  min_size the minimum size for the allocation
67 * @param[in]  cached   0 if the requested memory should not be cached.
68 * @param[out] dma_desc On return, this structure should be filled with a
69 *                      description of the memory that has been provided.
70 * @return              0 on success
71 */
72typedef int (*dma_morecore_fn)(size_t min_size, int cached,
73                               struct dma_mem_descriptor *dma_desc);
74
75/**
76 * Initialises a new DMA allocator for use with io_ops.
77 * @param[in]  morecore A function to use when the allocator requires more DMA
78 *                      memory. NULL if the allocator should not request more
79 *                      memory.
80 * @param[in]  cache_op Operations to use for cleaning/invalidating the cache
81 * @param[out] dma_man  libplatsupport DMA manager structure to populate
82 * @return              0 on success
83 */
84int dma_dmaman_init(dma_morecore_fn morecore, ps_dma_cache_op_fn_t cache_ops,
85                    ps_dma_man_t *dma_man);
86
87
88/**
89 * Explicitly provides memory to the DMA allocator.
90 * @param[in] dma_desc A description of the memory provided.
91 * @return             0 on success
92 */
93int dma_provide_mem(struct dma_allocator *allocator,
94                    struct dma_mem_descriptor dma_desc);
95
96/**
97 * If possible, reclaim some memory from the DMA allocator.
98 * @param[in]  allocator A handle to the allocator to reclaim memory from
99 * @param[out] dma_desc  If the call is successful, this structure will
100 *                       be filled with a description of the memeory that
101 *                       has been released from the allocator.
102 * @return               0 on success, non-zero indicates that a suitable
103 *                       reclaim candidate could not be found.
104 */
105int dma_reclaim_mem(struct dma_allocator *allocator,
106                    struct dma_mem_descriptor *dma_desc);
107
108
109
110/******************
111 * Legacy API
112 ******************/
113
114/**
115 * Initialises a new DMA allocator.
116 * @param[in] morecore A function to use when the allocator requires more DMA
117 *                     memory. NULL if the allocator should not request more
118 *                     memory.
119 * @return             A reference to a new DMA allocator instance.
120 */
121struct dma_allocator *dma_allocator_init(dma_morecore_fn morecore);
122
123/**
124 * Retrieve the virtual address of allocated DMA memory.
125 * @param[in] dma_mem       A handle to DMA memory.
126 * @return                  The virtual address of the DMA memory in question.
127 */
128vaddr_t dma_vaddr(dma_mem_t dma_mem);
129
130/**
131 * Retrieve the physical address of allocated DMA memory.
132 * @param[in] dma_mem       A handle to DMA memory.
133 * @return                  The physical address of the DMA memory in question.
134 */
135paddr_t dma_paddr(dma_mem_t dma_mem);
136
137/**
138 * Flush DMA memory out to RAM by virtual address
139 * @param[in] dma_mem A handle to allocated DMA memory.
140 * @param[in] vstart  The staring virtual address of the flush.
141 * @param[in] vend    One greater than the last virtual address to be
142 *                    flushed.
143 */
144void dma_clean(dma_mem_t dma_mem, vaddr_t vstart, vaddr_t vend);
145
146/**
147 * Invalidate DMA memory from cache by virtual address
148 * @param[in] dma_mem A handle to allocated DMA memory.
149 * @param[in] vstart  The staring virtual address of the invalidation.
150 * @param[in] vend    One greater than the last virtual address to be
151 *                    invalidated.
152 */
153void dma_invalidate(dma_mem_t dma_mem, vaddr_t vstart, vaddr_t vend);
154
155/**
156 * Flush DMA memory out to RAM and invalidate the caches by virtual address.
157 * @param[in] dma_mem A handle to allocated DMA memory.
158 * @param[in] vstart  The staring virtual address of the clean/invalidate.
159 * @param[in] vend    One greater than the last virtual address to be
160 *                          cleaned/invalidated.
161 */
162void dma_cleaninvalidate(dma_mem_t dma_mem, vaddr_t vstart, vaddr_t vend);
163
164/**
165 * Allocate DMA memory.
166 * @param[in]  allocator The DMA allocator instance to use for the allocation.
167 * @param[in]  size      The allocation size.
168 * @param[in]  align     The minimum alignment (in bytes) of the allocated
169 *                       region.
170 * @param[in]  flags     The allocation properties of the request.
171 * @param[out] dma_mem   If the call is successful and dma_mem is not NULL,
172 *                       dma_mem will contain a handle to the allocated memory.
173 * @return               The virtual address of the allocated DMA memory, NULL
174 *                       on failure.
175 */
176vaddr_t dma_alloc(struct dma_allocator *allocator, size_t size, int align,
177                  enum dma_flags flags, dma_mem_t *dma_mem);
178
179/**
180 * Free DMA memory by virtual address.
181 * @param[in] dma_mem   A handle to the DMA memory to free.
182 */
183void dma_free(dma_mem_t dma_mem);
184
185
186/**
187 * Retrieve the DMA memory handle from a given physical address.
188 * The performance of this operation is likely to be poor, but it may be useful
189 * for rapid prototyping or debugging.
190 * @param[in] allocator The allocator managing the memory.
191 * @param[in] paddr     The physical address of the memory in question
192 * @return              The DMA memory handle associated with the
193 *                      provided physical address. NULL if the physical
194 *                      address is not managed by the provided allocator.
195 */
196dma_mem_t dma_plookup(struct dma_allocator *allocator, paddr_t paddr);
197
198/**
199 * Retrieve the DMA memory handle from a given virtual address.
200 * The performance of this operation is likely to be poor, but it may be useful
201 * for rapid prototyping or debugging.
202 * @param[in] allocator The allocator managing the memory.
203 * @param[in] vaddr     The virtual address of the memory in question
204 * @return              The DMA memory handle associated with the
205 *                      provided virtual address. NULL if the physical
206 *                      address is not managed by the provided allocator.
207 */
208dma_mem_t dma_vlookup(struct dma_allocator *allocator, vaddr_t vaddr);
209