1 | /* |
2 | * DMA helper functions |
3 | * |
4 | * Copyright (c) 2009 Red Hat |
5 | * |
6 | * This work is licensed under the terms of the GNU General Public License |
7 | * (GNU GPL), version 2 or later. |
8 | */ |
9 | |
10 | #ifndef DMA_H |
11 | #define DMA_H |
12 | |
13 | #include "exec/memory.h" |
14 | #include "exec/address-spaces.h" |
15 | #include "block/block.h" |
16 | #include "block/accounting.h" |
17 | |
18 | typedef struct ScatterGatherEntry ScatterGatherEntry; |
19 | |
20 | typedef enum { |
21 | DMA_DIRECTION_TO_DEVICE = 0, |
22 | DMA_DIRECTION_FROM_DEVICE = 1, |
23 | } DMADirection; |
24 | |
25 | struct QEMUSGList { |
26 | ScatterGatherEntry *sg; |
27 | int nsg; |
28 | int nalloc; |
29 | size_t size; |
30 | DeviceState *dev; |
31 | AddressSpace *as; |
32 | }; |
33 | |
34 | #ifndef CONFIG_USER_ONLY |
35 | |
36 | /* |
37 | * When an IOMMU is present, bus addresses become distinct from |
38 | * CPU/memory physical addresses and may be a different size. Because |
39 | * the IOVA size depends more on the bus than on the platform, we more |
40 | * or less have to treat these as 64-bit always to cover all (or at |
41 | * least most) cases. |
42 | */ |
43 | typedef uint64_t dma_addr_t; |
44 | |
45 | #define DMA_ADDR_BITS 64 |
46 | #define DMA_ADDR_FMT "%" PRIx64 |
47 | |
48 | static inline void dma_barrier(AddressSpace *as, DMADirection dir) |
49 | { |
50 | /* |
51 | * This is called before DMA read and write operations |
52 | * unless the _relaxed form is used and is responsible |
53 | * for providing some sane ordering of accesses vs |
54 | * concurrently running VCPUs. |
55 | * |
56 | * Users of map(), unmap() or lower level st/ld_* |
57 | * operations are responsible for providing their own |
58 | * ordering via barriers. |
59 | * |
60 | * This primitive implementation does a simple smp_mb() |
61 | * before each operation which provides pretty much full |
62 | * ordering. |
63 | * |
64 | * A smarter implementation can be devised if needed to |
65 | * use lighter barriers based on the direction of the |
66 | * transfer, the DMA context, etc... |
67 | */ |
68 | smp_mb(); |
69 | } |
70 | |
71 | /* Checks that the given range of addresses is valid for DMA. This is |
72 | * useful for certain cases, but usually you should just use |
73 | * dma_memory_{read,write}() and check for errors */ |
74 | static inline bool dma_memory_valid(AddressSpace *as, |
75 | dma_addr_t addr, dma_addr_t len, |
76 | DMADirection dir) |
77 | { |
78 | return address_space_access_valid(as, addr, len, |
79 | dir == DMA_DIRECTION_FROM_DEVICE, |
80 | MEMTXATTRS_UNSPECIFIED); |
81 | } |
82 | |
83 | static inline int dma_memory_rw_relaxed(AddressSpace *as, dma_addr_t addr, |
84 | void *buf, dma_addr_t len, |
85 | DMADirection dir) |
86 | { |
87 | return (bool)address_space_rw(as, addr, MEMTXATTRS_UNSPECIFIED, |
88 | buf, len, dir == DMA_DIRECTION_FROM_DEVICE); |
89 | } |
90 | |
91 | static inline int dma_memory_read_relaxed(AddressSpace *as, dma_addr_t addr, |
92 | void *buf, dma_addr_t len) |
93 | { |
94 | return dma_memory_rw_relaxed(as, addr, buf, len, DMA_DIRECTION_TO_DEVICE); |
95 | } |
96 | |
97 | static inline int dma_memory_write_relaxed(AddressSpace *as, dma_addr_t addr, |
98 | const void *buf, dma_addr_t len) |
99 | { |
100 | return dma_memory_rw_relaxed(as, addr, (void *)buf, len, |
101 | DMA_DIRECTION_FROM_DEVICE); |
102 | } |
103 | |
104 | static inline int dma_memory_rw(AddressSpace *as, dma_addr_t addr, |
105 | void *buf, dma_addr_t len, |
106 | DMADirection dir) |
107 | { |
108 | dma_barrier(as, dir); |
109 | |
110 | return dma_memory_rw_relaxed(as, addr, buf, len, dir); |
111 | } |
112 | |
113 | static inline int dma_memory_read(AddressSpace *as, dma_addr_t addr, |
114 | void *buf, dma_addr_t len) |
115 | { |
116 | return dma_memory_rw(as, addr, buf, len, DMA_DIRECTION_TO_DEVICE); |
117 | } |
118 | |
119 | static inline int dma_memory_write(AddressSpace *as, dma_addr_t addr, |
120 | const void *buf, dma_addr_t len) |
121 | { |
122 | return dma_memory_rw(as, addr, (void *)buf, len, |
123 | DMA_DIRECTION_FROM_DEVICE); |
124 | } |
125 | |
126 | int dma_memory_set(AddressSpace *as, dma_addr_t addr, uint8_t c, dma_addr_t len); |
127 | |
128 | static inline void *dma_memory_map(AddressSpace *as, |
129 | dma_addr_t addr, dma_addr_t *len, |
130 | DMADirection dir) |
131 | { |
132 | hwaddr xlen = *len; |
133 | void *p; |
134 | |
135 | p = address_space_map(as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE, |
136 | MEMTXATTRS_UNSPECIFIED); |
137 | *len = xlen; |
138 | return p; |
139 | } |
140 | |
141 | static inline void dma_memory_unmap(AddressSpace *as, |
142 | void *buffer, dma_addr_t len, |
143 | DMADirection dir, dma_addr_t access_len) |
144 | { |
145 | address_space_unmap(as, buffer, (hwaddr)len, |
146 | dir == DMA_DIRECTION_FROM_DEVICE, access_len); |
147 | } |
148 | |
149 | #define DEFINE_LDST_DMA(_lname, _sname, _bits, _end) \ |
150 | static inline uint##_bits##_t ld##_lname##_##_end##_dma(AddressSpace *as, \ |
151 | dma_addr_t addr) \ |
152 | { \ |
153 | uint##_bits##_t val; \ |
154 | dma_memory_read(as, addr, &val, (_bits) / 8); \ |
155 | return _end##_bits##_to_cpu(val); \ |
156 | } \ |
157 | static inline void st##_sname##_##_end##_dma(AddressSpace *as, \ |
158 | dma_addr_t addr, \ |
159 | uint##_bits##_t val) \ |
160 | { \ |
161 | val = cpu_to_##_end##_bits(val); \ |
162 | dma_memory_write(as, addr, &val, (_bits) / 8); \ |
163 | } |
164 | |
165 | static inline uint8_t ldub_dma(AddressSpace *as, dma_addr_t addr) |
166 | { |
167 | uint8_t val; |
168 | |
169 | dma_memory_read(as, addr, &val, 1); |
170 | return val; |
171 | } |
172 | |
173 | static inline void stb_dma(AddressSpace *as, dma_addr_t addr, uint8_t val) |
174 | { |
175 | dma_memory_write(as, addr, &val, 1); |
176 | } |
177 | |
178 | DEFINE_LDST_DMA(uw, w, 16, le); |
179 | DEFINE_LDST_DMA(l, l, 32, le); |
180 | DEFINE_LDST_DMA(q, q, 64, le); |
181 | DEFINE_LDST_DMA(uw, w, 16, be); |
182 | DEFINE_LDST_DMA(l, l, 32, be); |
183 | DEFINE_LDST_DMA(q, q, 64, be); |
184 | |
185 | #undef DEFINE_LDST_DMA |
186 | |
187 | struct ScatterGatherEntry { |
188 | dma_addr_t base; |
189 | dma_addr_t len; |
190 | }; |
191 | |
192 | void qemu_sglist_init(QEMUSGList *qsg, DeviceState *dev, int alloc_hint, |
193 | AddressSpace *as); |
194 | void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len); |
195 | void qemu_sglist_destroy(QEMUSGList *qsg); |
196 | #endif |
197 | |
198 | typedef BlockAIOCB *DMAIOFunc(int64_t offset, QEMUIOVector *iov, |
199 | BlockCompletionFunc *cb, void *cb_opaque, |
200 | void *opaque); |
201 | |
202 | BlockAIOCB *dma_blk_io(AioContext *ctx, |
203 | QEMUSGList *sg, uint64_t offset, uint32_t align, |
204 | DMAIOFunc *io_func, void *io_func_opaque, |
205 | BlockCompletionFunc *cb, void *opaque, DMADirection dir); |
206 | BlockAIOCB *dma_blk_read(BlockBackend *blk, |
207 | QEMUSGList *sg, uint64_t offset, uint32_t align, |
208 | BlockCompletionFunc *cb, void *opaque); |
209 | BlockAIOCB *dma_blk_write(BlockBackend *blk, |
210 | QEMUSGList *sg, uint64_t offset, uint32_t align, |
211 | BlockCompletionFunc *cb, void *opaque); |
212 | uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg); |
213 | uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg); |
214 | |
215 | void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie, |
216 | QEMUSGList *sg, enum BlockAcctType type); |
217 | |
218 | #endif |
219 | |