1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright(c) 2016-2018 Intel Corporation. All rights reserved. |
4 | */ |
5 | #include <linux/dma-mapping.h> |
6 | #include <linux/mei.h> |
7 | |
8 | #include "mei_dev.h" |
9 | |
10 | /** |
11 | * mei_dmam_dscr_alloc() - allocate a managed coherent buffer |
12 | * for the dma descriptor |
13 | * @dev: mei_device |
14 | * @dscr: dma descriptor |
15 | * |
16 | * Return: |
17 | * * 0 - on success or zero allocation request |
18 | * * -EINVAL - if size is not power of 2 |
19 | * * -ENOMEM - of allocation has failed |
20 | */ |
21 | static int mei_dmam_dscr_alloc(struct mei_device *dev, |
22 | struct mei_dma_dscr *dscr) |
23 | { |
24 | if (!dscr->size) |
25 | return 0; |
26 | |
27 | if (WARN_ON(!is_power_of_2(dscr->size))) |
28 | return -EINVAL; |
29 | |
30 | if (dscr->vaddr) |
31 | return 0; |
32 | |
33 | dscr->vaddr = dmam_alloc_coherent(dev: dev->dev, size: dscr->size, dma_handle: &dscr->daddr, |
34 | GFP_KERNEL); |
35 | if (!dscr->vaddr) |
36 | return -ENOMEM; |
37 | |
38 | return 0; |
39 | } |
40 | |
41 | /** |
42 | * mei_dmam_dscr_free() - free a managed coherent buffer |
43 | * from the dma descriptor |
44 | * @dev: mei_device |
45 | * @dscr: dma descriptor |
46 | */ |
47 | static void mei_dmam_dscr_free(struct mei_device *dev, |
48 | struct mei_dma_dscr *dscr) |
49 | { |
50 | if (!dscr->vaddr) |
51 | return; |
52 | |
53 | dmam_free_coherent(dev: dev->dev, size: dscr->size, vaddr: dscr->vaddr, dma_handle: dscr->daddr); |
54 | dscr->vaddr = NULL; |
55 | } |
56 | |
57 | /** |
58 | * mei_dmam_ring_free() - free dma ring buffers |
59 | * @dev: mei device |
60 | */ |
61 | void mei_dmam_ring_free(struct mei_device *dev) |
62 | { |
63 | int i; |
64 | |
65 | for (i = 0; i < DMA_DSCR_NUM; i++) |
66 | mei_dmam_dscr_free(dev, dscr: &dev->dr_dscr[i]); |
67 | } |
68 | |
69 | /** |
70 | * mei_dmam_ring_alloc() - allocate dma ring buffers |
71 | * @dev: mei device |
72 | * |
73 | * Return: -ENOMEM on allocation failure 0 otherwise |
74 | */ |
75 | int mei_dmam_ring_alloc(struct mei_device *dev) |
76 | { |
77 | int i; |
78 | |
79 | for (i = 0; i < DMA_DSCR_NUM; i++) |
80 | if (mei_dmam_dscr_alloc(dev, dscr: &dev->dr_dscr[i])) |
81 | goto err; |
82 | |
83 | return 0; |
84 | |
85 | err: |
86 | mei_dmam_ring_free(dev); |
87 | return -ENOMEM; |
88 | } |
89 | |
90 | /** |
91 | * mei_dma_ring_is_allocated() - check if dma ring is allocated |
92 | * @dev: mei device |
93 | * |
94 | * Return: true if dma ring is allocated |
95 | */ |
96 | bool mei_dma_ring_is_allocated(struct mei_device *dev) |
97 | { |
98 | return !!dev->dr_dscr[DMA_DSCR_HOST].vaddr; |
99 | } |
100 | |
101 | static inline |
102 | struct hbm_dma_ring_ctrl *mei_dma_ring_ctrl(struct mei_device *dev) |
103 | { |
104 | return (struct hbm_dma_ring_ctrl *)dev->dr_dscr[DMA_DSCR_CTRL].vaddr; |
105 | } |
106 | |
107 | /** |
108 | * mei_dma_ring_reset() - reset the dma control block |
109 | * @dev: mei device |
110 | */ |
111 | void mei_dma_ring_reset(struct mei_device *dev) |
112 | { |
113 | struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); |
114 | |
115 | if (!ctrl) |
116 | return; |
117 | |
118 | memset(ctrl, 0, sizeof(*ctrl)); |
119 | } |
120 | |
121 | /** |
122 | * mei_dma_copy_from() - copy from dma ring into buffer |
123 | * @dev: mei device |
124 | * @buf: data buffer |
125 | * @offset: offset in slots. |
126 | * @n: number of slots to copy. |
127 | * |
128 | * Return: number of bytes copied |
129 | */ |
130 | static size_t mei_dma_copy_from(struct mei_device *dev, unsigned char *buf, |
131 | u32 offset, u32 n) |
132 | { |
133 | unsigned char *dbuf = dev->dr_dscr[DMA_DSCR_DEVICE].vaddr; |
134 | |
135 | size_t b_offset = offset << 2; |
136 | size_t b_n = n << 2; |
137 | |
138 | memcpy(buf, dbuf + b_offset, b_n); |
139 | |
140 | return b_n; |
141 | } |
142 | |
143 | /** |
144 | * mei_dma_copy_to() - copy to a buffer to the dma ring |
145 | * @dev: mei device |
146 | * @buf: data buffer |
147 | * @offset: offset in slots. |
148 | * @n: number of slots to copy. |
149 | * |
150 | * Return: number of bytes copied |
151 | */ |
152 | static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf, |
153 | u32 offset, u32 n) |
154 | { |
155 | unsigned char *hbuf = dev->dr_dscr[DMA_DSCR_HOST].vaddr; |
156 | |
157 | size_t b_offset = offset << 2; |
158 | size_t b_n = n << 2; |
159 | |
160 | memcpy(hbuf + b_offset, buf, b_n); |
161 | |
162 | return b_n; |
163 | } |
164 | |
165 | /** |
166 | * mei_dma_ring_read() - read data from the ring |
167 | * @dev: mei device |
168 | * @buf: buffer to read into: may be NULL in case of dropping the data. |
169 | * @len: length to read. |
170 | */ |
171 | void mei_dma_ring_read(struct mei_device *dev, unsigned char *buf, u32 len) |
172 | { |
173 | struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); |
174 | u32 dbuf_depth; |
175 | u32 rd_idx, rem, slots; |
176 | |
177 | if (WARN_ON(!ctrl)) |
178 | return; |
179 | |
180 | dev_dbg(dev->dev, "reading from dma %u bytes\n" , len); |
181 | |
182 | if (!len) |
183 | return; |
184 | |
185 | dbuf_depth = dev->dr_dscr[DMA_DSCR_DEVICE].size >> 2; |
186 | rd_idx = READ_ONCE(ctrl->dbuf_rd_idx) & (dbuf_depth - 1); |
187 | slots = mei_data2slots(length: len); |
188 | |
189 | /* if buf is NULL we drop the packet by advancing the pointer.*/ |
190 | if (!buf) |
191 | goto out; |
192 | |
193 | if (rd_idx + slots > dbuf_depth) { |
194 | buf += mei_dma_copy_from(dev, buf, offset: rd_idx, n: dbuf_depth - rd_idx); |
195 | rem = slots - (dbuf_depth - rd_idx); |
196 | rd_idx = 0; |
197 | } else { |
198 | rem = slots; |
199 | } |
200 | |
201 | mei_dma_copy_from(dev, buf, offset: rd_idx, n: rem); |
202 | out: |
203 | WRITE_ONCE(ctrl->dbuf_rd_idx, ctrl->dbuf_rd_idx + slots); |
204 | } |
205 | |
206 | static inline u32 mei_dma_ring_hbuf_depth(struct mei_device *dev) |
207 | { |
208 | return dev->dr_dscr[DMA_DSCR_HOST].size >> 2; |
209 | } |
210 | |
211 | /** |
212 | * mei_dma_ring_empty_slots() - calaculate number of empty slots in dma ring |
213 | * @dev: mei_device |
214 | * |
215 | * Return: number of empty slots |
216 | */ |
217 | u32 mei_dma_ring_empty_slots(struct mei_device *dev) |
218 | { |
219 | struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); |
220 | u32 wr_idx, rd_idx, hbuf_depth, empty; |
221 | |
222 | if (!mei_dma_ring_is_allocated(dev)) |
223 | return 0; |
224 | |
225 | if (WARN_ON(!ctrl)) |
226 | return 0; |
227 | |
228 | /* easier to work in slots */ |
229 | hbuf_depth = mei_dma_ring_hbuf_depth(dev); |
230 | rd_idx = READ_ONCE(ctrl->hbuf_rd_idx); |
231 | wr_idx = READ_ONCE(ctrl->hbuf_wr_idx); |
232 | |
233 | if (rd_idx > wr_idx) |
234 | empty = rd_idx - wr_idx; |
235 | else |
236 | empty = hbuf_depth - (wr_idx - rd_idx); |
237 | |
238 | return empty; |
239 | } |
240 | |
241 | /** |
242 | * mei_dma_ring_write - write data to dma ring host buffer |
243 | * |
244 | * @dev: mei_device |
245 | * @buf: data will be written |
246 | * @len: data length |
247 | */ |
248 | void mei_dma_ring_write(struct mei_device *dev, unsigned char *buf, u32 len) |
249 | { |
250 | struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); |
251 | u32 hbuf_depth; |
252 | u32 wr_idx, rem, slots; |
253 | |
254 | if (WARN_ON(!ctrl)) |
255 | return; |
256 | |
257 | dev_dbg(dev->dev, "writing to dma %u bytes\n" , len); |
258 | hbuf_depth = mei_dma_ring_hbuf_depth(dev); |
259 | wr_idx = READ_ONCE(ctrl->hbuf_wr_idx) & (hbuf_depth - 1); |
260 | slots = mei_data2slots(length: len); |
261 | |
262 | if (wr_idx + slots > hbuf_depth) { |
263 | buf += mei_dma_copy_to(dev, buf, offset: wr_idx, n: hbuf_depth - wr_idx); |
264 | rem = slots - (hbuf_depth - wr_idx); |
265 | wr_idx = 0; |
266 | } else { |
267 | rem = slots; |
268 | } |
269 | |
270 | mei_dma_copy_to(dev, buf, offset: wr_idx, n: rem); |
271 | |
272 | WRITE_ONCE(ctrl->hbuf_wr_idx, ctrl->hbuf_wr_idx + slots); |
273 | } |
274 | |