blob: 2bf02fcad7bbc8d9e6163fa4c42d42e6c17224ae [file] [log] [blame]
Meng Wang688a8672019-01-29 13:43:33 +08001// SPDX-License-Identifier: GPL-2.0-only
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302/*
Saurav Kumar5bdb6c32020-08-18 18:33:35 +05303 * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304 */
5
6#include <linux/init.h>
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/err.h>
10#include <linux/delay.h>
11#include <linux/slab.h>
12#include <linux/mutex.h>
13#include <linux/list.h>
14#include <linux/dma-mapping.h>
15#include <linux/dma-buf.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053016#include <linux/platform_device.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053017#include <linux/of_device.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053018#include <linux/export.h>
Banajit Goswami08bb7362017-11-03 22:48:23 -070019#include <linux/ion_kernel.h>
20#include <ipc/apr.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053021#include <dsp/msm_audio_ion.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053022
23#define MSM_AUDIO_ION_PROBED (1 << 0)
24
25#define MSM_AUDIO_ION_PHYS_ADDR(alloc_data) \
26 alloc_data->table->sgl->dma_address
27
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053028#define MSM_AUDIO_SMMU_SID_OFFSET 32
29
30struct msm_audio_ion_private {
Banajit Goswamif6077632018-03-11 22:41:27 -070031 bool smmu_enabled;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053032 struct device *cb_dev;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053033 u8 device_status;
34 struct list_head alloc_list;
35 struct mutex list_mutex;
36 u64 smmu_sid_bits;
37 u32 smmu_version;
38};
39
40struct msm_audio_alloc_data {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053041 size_t len;
Banajit Goswami08bb7362017-11-03 22:48:23 -070042 void *vaddr;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053043 struct dma_buf *dma_buf;
44 struct dma_buf_attachment *attach;
45 struct sg_table *table;
46 struct list_head list;
47};
48
49static struct msm_audio_ion_private msm_audio_ion_data = {0,};
50
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053051static void msm_audio_ion_add_allocation(
52 struct msm_audio_ion_private *msm_audio_ion_data,
53 struct msm_audio_alloc_data *alloc_data)
54{
55 /*
56 * Since these APIs can be invoked by multiple
57 * clients, there is need to make sure the list
58 * of allocations is always protected
59 */
60 mutex_lock(&(msm_audio_ion_data->list_mutex));
61 list_add_tail(&(alloc_data->list),
62 &(msm_audio_ion_data->alloc_list));
63 mutex_unlock(&(msm_audio_ion_data->list_mutex));
64}
65
Banajit Goswami08bb7362017-11-03 22:48:23 -070066static int msm_audio_dma_buf_map(struct dma_buf *dma_buf,
67 dma_addr_t *addr, size_t *len)
68{
69
Saurav Kumar5bdb6c32020-08-18 18:33:35 +053070 struct msm_audio_alloc_data *alloc_data = NULL;
Banajit Goswami08bb7362017-11-03 22:48:23 -070071 struct device *cb_dev;
Banajit Goswamif6077632018-03-11 22:41:27 -070072 unsigned long ionflag = 0;
Banajit Goswami08bb7362017-11-03 22:48:23 -070073 int rc = 0;
74
75 cb_dev = msm_audio_ion_data.cb_dev;
76
77 /* Data required per buffer mapping */
78 alloc_data = kzalloc(sizeof(*alloc_data), GFP_KERNEL);
79 if (!alloc_data)
80 return -ENOMEM;
81
82 alloc_data->dma_buf = dma_buf;
83 alloc_data->len = dma_buf->size;
84 *len = dma_buf->size;
85
86 /* Attach the dma_buf to context bank device */
87 alloc_data->attach = dma_buf_attach(alloc_data->dma_buf,
88 cb_dev);
89 if (IS_ERR(alloc_data->attach)) {
90 rc = PTR_ERR(alloc_data->attach);
91 dev_err(cb_dev,
92 "%s: Fail to attach dma_buf to CB, rc = %d\n",
93 __func__, rc);
Banajit Goswamif6077632018-03-11 22:41:27 -070094 goto free_alloc_data;
Banajit Goswami08bb7362017-11-03 22:48:23 -070095 }
96
Banajit Goswamif6077632018-03-11 22:41:27 -070097 /* For uncached buffers, avoid cache maintanance */
98 rc = dma_buf_get_flags(alloc_data->dma_buf, &ionflag);
99 if (rc) {
100 dev_err(cb_dev, "%s: dma_buf_get_flags failed: %d\n",
101 __func__, rc);
102 goto detach_dma_buf;
103 }
104
105 if (!(ionflag & ION_FLAG_CACHED))
106 alloc_data->attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC;
107
Banajit Goswami08bb7362017-11-03 22:48:23 -0700108 /*
109 * Get the scatter-gather list.
110 * There is no info as this is a write buffer or
111 * read buffer, hence the request is bi-directional
112 * to accommodate both read and write mappings.
113 */
114 alloc_data->table = dma_buf_map_attachment(alloc_data->attach,
115 DMA_BIDIRECTIONAL);
116 if (IS_ERR(alloc_data->table)) {
117 rc = PTR_ERR(alloc_data->table);
118 dev_err(cb_dev,
119 "%s: Fail to map attachment, rc = %d\n",
120 __func__, rc);
Banajit Goswamif6077632018-03-11 22:41:27 -0700121 goto detach_dma_buf;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700122 }
123
124 /* physical address from mapping */
125 *addr = MSM_AUDIO_ION_PHYS_ADDR(alloc_data);
126
127 msm_audio_ion_add_allocation(&msm_audio_ion_data,
128 alloc_data);
129 return rc;
130
Banajit Goswamif6077632018-03-11 22:41:27 -0700131detach_dma_buf:
Banajit Goswami08bb7362017-11-03 22:48:23 -0700132 dma_buf_detach(alloc_data->dma_buf,
133 alloc_data->attach);
Banajit Goswamif6077632018-03-11 22:41:27 -0700134free_alloc_data:
Banajit Goswami08bb7362017-11-03 22:48:23 -0700135 kfree(alloc_data);
Saurav Kumar5bdb6c32020-08-18 18:33:35 +0530136 alloc_data = NULL;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700137
138 return rc;
139}
140
141static int msm_audio_dma_buf_unmap(struct dma_buf *dma_buf)
142{
143 int rc = 0;
144 struct msm_audio_alloc_data *alloc_data = NULL;
145 struct list_head *ptr, *next;
146 struct device *cb_dev = msm_audio_ion_data.cb_dev;
147 bool found = false;
148
149 /*
150 * Though list_for_each_safe is delete safe, lock
151 * should be explicitly acquired to avoid race condition
152 * on adding elements to the list.
153 */
154 mutex_lock(&(msm_audio_ion_data.list_mutex));
155 list_for_each_safe(ptr, next,
156 &(msm_audio_ion_data.alloc_list)) {
157
158 alloc_data = list_entry(ptr, struct msm_audio_alloc_data,
159 list);
160
161 if (alloc_data->dma_buf == dma_buf) {
162 found = true;
163 dma_buf_unmap_attachment(alloc_data->attach,
164 alloc_data->table,
165 DMA_BIDIRECTIONAL);
166
167 dma_buf_detach(alloc_data->dma_buf,
168 alloc_data->attach);
169
170 dma_buf_put(alloc_data->dma_buf);
171
172 list_del(&(alloc_data->list));
173 kfree(alloc_data);
Saurav Kumar5bdb6c32020-08-18 18:33:35 +0530174 alloc_data = NULL;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700175 break;
176 }
177 }
178 mutex_unlock(&(msm_audio_ion_data.list_mutex));
179
180 if (!found) {
181 dev_err(cb_dev,
182 "%s: cannot find allocation, dma_buf %pK",
183 __func__, dma_buf);
184 rc = -EINVAL;
185 }
186
187 return rc;
188}
189
190static int msm_audio_ion_get_phys(struct dma_buf *dma_buf,
191 dma_addr_t *addr, size_t *len)
192{
193 int rc = 0;
194
195 rc = msm_audio_dma_buf_map(dma_buf, addr, len);
196 if (rc) {
197 pr_err("%s: failed to map DMA buf, err = %d\n",
198 __func__, rc);
199 goto err;
200 }
Banajit Goswamif6077632018-03-11 22:41:27 -0700201 if (msm_audio_ion_data.smmu_enabled) {
202 /* Append the SMMU SID information to the IOVA address */
203 *addr |= msm_audio_ion_data.smmu_sid_bits;
204 }
Banajit Goswami08bb7362017-11-03 22:48:23 -0700205
206 pr_debug("phys=%pK, len=%zd, rc=%d\n", &(*addr), *len, rc);
207err:
208 return rc;
209}
210
Aditya Bavanari542582c2018-06-26 18:41:06 +0530211int msm_audio_ion_get_smmu_info(struct device **cb_dev,
212 u64 *smmu_sid)
213{
214 if (!cb_dev || !smmu_sid) {
215 pr_err("%s: Invalid params\n",
216 __func__);
217 return -EINVAL;
218 }
219
220 if (!msm_audio_ion_data.cb_dev ||
221 !msm_audio_ion_data.smmu_sid_bits) {
222 pr_err("%s: Params not initialized\n",
223 __func__);
224 return -EINVAL;
225 }
226
227 *cb_dev = msm_audio_ion_data.cb_dev;
228 *smmu_sid = msm_audio_ion_data.smmu_sid_bits;
229
230 return 0;
231}
232
Banajit Goswami08bb7362017-11-03 22:48:23 -0700233static void *msm_audio_ion_map_kernel(struct dma_buf *dma_buf)
234{
Banajit Goswami08bb7362017-11-03 22:48:23 -0700235 int rc = 0;
236 void *addr = NULL;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700237 struct msm_audio_alloc_data *alloc_data = NULL;
238
239 rc = dma_buf_begin_cpu_access(dma_buf, DMA_BIDIRECTIONAL);
240 if (rc) {
241 pr_err("%s: kmap dma_buf_begin_cpu_access fail\n", __func__);
242 goto exit;
243 }
244
Banajit Goswami80b67f42018-03-03 01:44:55 -0800245 addr = dma_buf_vmap(dma_buf);
Banajit Goswami08bb7362017-11-03 22:48:23 -0700246 if (!addr) {
Banajit Goswami80b67f42018-03-03 01:44:55 -0800247 pr_err("%s: kernel mapping of dma_buf failed\n",
Banajit Goswami08bb7362017-11-03 22:48:23 -0700248 __func__);
249 goto exit;
250 }
Banajit Goswami08bb7362017-11-03 22:48:23 -0700251
252 /*
253 * TBD: remove the below section once new API
254 * for mapping kernel virtual address is available.
255 */
256 mutex_lock(&(msm_audio_ion_data.list_mutex));
257 list_for_each_entry(alloc_data, &(msm_audio_ion_data.alloc_list),
258 list) {
259 if (alloc_data->dma_buf == dma_buf) {
260 alloc_data->vaddr = addr;
261 break;
262 }
263 }
264 mutex_unlock(&(msm_audio_ion_data.list_mutex));
265
Banajit Goswami08bb7362017-11-03 22:48:23 -0700266exit:
267 return addr;
268}
269
Karthikeyan Mani9c69ccf2018-10-15 12:21:06 -0700270static int msm_audio_ion_unmap_kernel(struct dma_buf *dma_buf)
Banajit Goswami08bb7362017-11-03 22:48:23 -0700271{
Banajit Goswami80b67f42018-03-03 01:44:55 -0800272 int rc = 0;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700273 void *vaddr = NULL;
274 struct msm_audio_alloc_data *alloc_data = NULL;
275 struct device *cb_dev = msm_audio_ion_data.cb_dev;
276
277 /*
278 * TBD: remove the below section once new API
279 * for unmapping kernel virtual address is available.
280 */
281 mutex_lock(&(msm_audio_ion_data.list_mutex));
282 list_for_each_entry(alloc_data, &(msm_audio_ion_data.alloc_list),
283 list) {
284 if (alloc_data->dma_buf == dma_buf) {
285 vaddr = alloc_data->vaddr;
286 break;
287 }
288 }
289 mutex_unlock(&(msm_audio_ion_data.list_mutex));
290
291 if (!vaddr) {
292 dev_err(cb_dev,
293 "%s: cannot find allocation for dma_buf %pK",
294 __func__, dma_buf);
Karthikeyan Mani9c69ccf2018-10-15 12:21:06 -0700295 rc = -EINVAL;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700296 goto err;
297 }
298
Banajit Goswami80b67f42018-03-03 01:44:55 -0800299 dma_buf_vunmap(dma_buf, vaddr);
Banajit Goswami08bb7362017-11-03 22:48:23 -0700300
301 rc = dma_buf_end_cpu_access(dma_buf, DMA_BIDIRECTIONAL);
302 if (rc) {
303 dev_err(cb_dev, "%s: kmap dma_buf_end_cpu_access fail\n",
304 __func__);
305 goto err;
306 }
307
308err:
Karthikeyan Mani9c69ccf2018-10-15 12:21:06 -0700309 return rc;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700310}
311
312static int msm_audio_ion_map_buf(struct dma_buf *dma_buf, dma_addr_t *paddr,
Banajit Goswami293afe42018-03-16 23:29:29 -0700313 size_t *plen, void **vaddr)
Banajit Goswami08bb7362017-11-03 22:48:23 -0700314{
315 int rc = 0;
316
Saurav Kumar5bdb6c32020-08-18 18:33:35 +0530317 if (!dma_buf || !paddr || !vaddr || !plen) {
318 pr_err("%s: Invalid params\n", __func__);
319 return -EINVAL;
320 }
321
Banajit Goswami08bb7362017-11-03 22:48:23 -0700322 rc = msm_audio_ion_get_phys(dma_buf, paddr, plen);
323 if (rc) {
324 pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
325 __func__, rc);
Xiaojun Sangab07f122019-06-27 13:57:57 +0800326 dma_buf_put(dma_buf);
Banajit Goswami08bb7362017-11-03 22:48:23 -0700327 goto err;
328 }
329
Banajit Goswami293afe42018-03-16 23:29:29 -0700330 *vaddr = msm_audio_ion_map_kernel(dma_buf);
331 if (IS_ERR_OR_NULL(*vaddr)) {
Banajit Goswami08bb7362017-11-03 22:48:23 -0700332 pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
333 rc = -ENOMEM;
Xiaojun Sangab07f122019-06-27 13:57:57 +0800334 msm_audio_dma_buf_unmap(dma_buf);
Banajit Goswami08bb7362017-11-03 22:48:23 -0700335 goto err;
336 }
337
338err:
339 return rc;
340}
341
Banajit Goswamif6077632018-03-11 22:41:27 -0700342static u32 msm_audio_ion_get_smmu_sid_mode32(void)
343{
344 if (msm_audio_ion_data.smmu_enabled)
345 return upper_32_bits(msm_audio_ion_data.smmu_sid_bits);
346 else
347 return 0;
348}
349
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530350/**
351 * msm_audio_ion_alloc -
352 * Allocs ION memory for given client name
353 *
Banajit Goswami08bb7362017-11-03 22:48:23 -0700354 * @dma_buf: dma_buf for the ION memory
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530355 * @bufsz: buffer size
356 * @paddr: Physical address to be assigned with allocated region
Banajit Goswami08bb7362017-11-03 22:48:23 -0700357 * @plen: length of allocated region to be assigned
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530358 * vaddr: virtual address to be assigned
359 *
360 * Returns 0 on success or error on failure
361 */
Banajit Goswami08bb7362017-11-03 22:48:23 -0700362int msm_audio_ion_alloc(struct dma_buf **dma_buf, size_t bufsz,
363 dma_addr_t *paddr, size_t *plen, void **vaddr)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530364{
365 int rc = -EINVAL;
366 unsigned long err_ion_ptr = 0;
367
Banajit Goswamibfc919e2018-06-25 19:03:09 -0700368 if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530369 pr_debug("%s:probe is not done, deferred\n", __func__);
370 return -EPROBE_DEFER;
371 }
Banajit Goswami08bb7362017-11-03 22:48:23 -0700372 if (!dma_buf || !paddr || !vaddr || !bufsz || !plen) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530373 pr_err("%s: Invalid params\n", __func__);
374 return -EINVAL;
375 }
Banajit Goswami08bb7362017-11-03 22:48:23 -0700376
Banajit Goswamif6077632018-03-11 22:41:27 -0700377 if (msm_audio_ion_data.smmu_enabled == true) {
378 pr_debug("%s: system heap is used\n", __func__);
379 *dma_buf = ion_alloc(bufsz, ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
380 } else {
381 pr_debug("%s: audio heap is used\n", __func__);
382 *dma_buf = ion_alloc(bufsz, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
383 }
Banajit Goswami08bb7362017-11-03 22:48:23 -0700384 if (IS_ERR_OR_NULL((void *)(*dma_buf))) {
385 if (IS_ERR((void *)(*dma_buf)))
386 err_ion_ptr = PTR_ERR((int *)(*dma_buf));
Banajit Goswamif6077632018-03-11 22:41:27 -0700387 pr_err("%s: ION alloc fail err ptr=%ld, smmu_enabled=%d\n",
388 __func__, err_ion_ptr, msm_audio_ion_data.smmu_enabled);
Banajit Goswami08bb7362017-11-03 22:48:23 -0700389 rc = -ENOMEM;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530390 goto err;
391 }
392
Banajit Goswami293afe42018-03-16 23:29:29 -0700393 rc = msm_audio_ion_map_buf(*dma_buf, paddr, plen, vaddr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530394 if (rc) {
Banajit Goswami08bb7362017-11-03 22:48:23 -0700395 pr_err("%s: failed to map ION buf, rc = %d\n", __func__, rc);
Xiaojun Sangab07f122019-06-27 13:57:57 +0800396 goto err;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530397 }
398 pr_debug("%s: mapped address = %pK, size=%zd\n", __func__,
399 *vaddr, bufsz);
400
Banajit Goswami293afe42018-03-16 23:29:29 -0700401 memset(*vaddr, 0, bufsz);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530402
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530403err:
404 return rc;
405}
406EXPORT_SYMBOL(msm_audio_ion_alloc);
407
Banajit Goswami08bb7362017-11-03 22:48:23 -0700408/**
Vikram Panduranga24efd2a2018-12-12 14:25:06 -0800409 * msm_audio_ion_dma_map -
410 * Memory maps for a given DMA buffer
411 *
412 * @phys_addr: Physical address of DMA buffer to be mapped
413 * @iova_base: IOVA address of memory mapped DMA buffer
414 * @size: buffer size
415 * @dir: DMA direction
416 * Returns 0 on success or error on failure
417 */
418int msm_audio_ion_dma_map(dma_addr_t *phys_addr, dma_addr_t *iova_base,
419 u32 size, enum dma_data_direction dir)
420{
421 dma_addr_t iova;
422 struct device *cb_dev = msm_audio_ion_data.cb_dev;
423
424 if (!phys_addr || !iova_base || !size)
425 return -EINVAL;
426
427 iova = dma_map_resource(cb_dev, *phys_addr, size,
428 dir, 0);
429 if (dma_mapping_error(cb_dev, iova)) {
430 pr_err("%s: dma_mapping_error\n", __func__);
431 return -EIO;
432 }
433 pr_debug("%s: dma_mapping_success iova:0x%lx\n", __func__,
434 (unsigned long)iova);
435 if (msm_audio_ion_data.smmu_enabled)
436 /* Append the SMMU SID information to the IOVA address */
437 iova |= msm_audio_ion_data.smmu_sid_bits;
438
439 *iova_base = iova;
440
441 return 0;
442}
443EXPORT_SYMBOL(msm_audio_ion_dma_map);
444
445/**
Banajit Goswami08bb7362017-11-03 22:48:23 -0700446 * msm_audio_ion_import-
447 * Import ION buffer with given file descriptor
448 *
449 * @dma_buf: dma_buf for the ION memory
450 * @fd: file descriptor for the ION memory
451 * @ionflag: flags associated with ION buffer
452 * @bufsz: buffer size
453 * @paddr: Physical address to be assigned with allocated region
454 * @plen: length of allocated region to be assigned
455 * vaddr: virtual address to be assigned
456 *
457 * Returns 0 on success or error on failure
458 */
459int msm_audio_ion_import(struct dma_buf **dma_buf, int fd,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530460 unsigned long *ionflag, size_t bufsz,
Banajit Goswami08bb7362017-11-03 22:48:23 -0700461 dma_addr_t *paddr, size_t *plen, void **vaddr)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530462{
463 int rc = 0;
464
Banajit Goswamibfc919e2018-06-25 19:03:09 -0700465 if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
Banajit Goswamif6077632018-03-11 22:41:27 -0700466 pr_debug("%s: probe is not done, deferred\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530467 return -EPROBE_DEFER;
468 }
469
Banajit Goswami08bb7362017-11-03 22:48:23 -0700470 if (!dma_buf || !paddr || !vaddr || !plen) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530471 pr_err("%s: Invalid params\n", __func__);
Banajit Goswami0f1f3f62018-02-02 03:36:46 -0800472 return -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530473 }
474
Banajit Goswami08bb7362017-11-03 22:48:23 -0700475 /* bufsz should be 0 and fd shouldn't be 0 as of now */
476 *dma_buf = dma_buf_get(fd);
477 pr_debug("%s: dma_buf =%pK, fd=%d\n", __func__, *dma_buf, fd);
478 if (IS_ERR_OR_NULL((void *)(*dma_buf))) {
479 pr_err("%s: dma_buf_get failed\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530480 rc = -EINVAL;
481 goto err;
482 }
483
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530484 if (ionflag != NULL) {
Banajit Goswami0f1f3f62018-02-02 03:36:46 -0800485 rc = dma_buf_get_flags(*dma_buf, ionflag);
486 if (rc) {
487 pr_err("%s: could not get flags for the dma_buf\n",
488 __func__);
489 goto err_ion_flag;
490 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530491 }
492
Banajit Goswami293afe42018-03-16 23:29:29 -0700493 rc = msm_audio_ion_map_buf(*dma_buf, paddr, plen, vaddr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530494 if (rc) {
Banajit Goswami08bb7362017-11-03 22:48:23 -0700495 pr_err("%s: failed to map ION buf, rc = %d\n", __func__, rc);
Xiaojun Sangab07f122019-06-27 13:57:57 +0800496 goto err;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530497 }
498 pr_debug("%s: mapped address = %pK, size=%zd\n", __func__,
499 *vaddr, bufsz);
500
501 return 0;
502
Banajit Goswami08bb7362017-11-03 22:48:23 -0700503err_ion_flag:
504 dma_buf_put(*dma_buf);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530505err:
Banajit Goswami08bb7362017-11-03 22:48:23 -0700506 *dma_buf = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530507 return rc;
508}
Banajit Goswami08bb7362017-11-03 22:48:23 -0700509EXPORT_SYMBOL(msm_audio_ion_import);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530510
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530511/**
512 * msm_audio_ion_free -
513 * fress ION memory for given client and handle
514 *
Banajit Goswami08bb7362017-11-03 22:48:23 -0700515 * @dma_buf: dma_buf for the ION memory
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530516 *
517 * Returns 0 on success or error on failure
518 */
Banajit Goswami08bb7362017-11-03 22:48:23 -0700519int msm_audio_ion_free(struct dma_buf *dma_buf)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530520{
Karthikeyan Mani9c69ccf2018-10-15 12:21:06 -0700521 int ret = 0;
522
Banajit Goswami08bb7362017-11-03 22:48:23 -0700523 if (!dma_buf) {
524 pr_err("%s: dma_buf invalid\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530525 return -EINVAL;
526 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530527
Karthikeyan Mani9c69ccf2018-10-15 12:21:06 -0700528 ret = msm_audio_ion_unmap_kernel(dma_buf);
529 if (ret)
530 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530531
Banajit Goswami08bb7362017-11-03 22:48:23 -0700532 msm_audio_dma_buf_unmap(dma_buf);
533
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530534 return 0;
535}
536EXPORT_SYMBOL(msm_audio_ion_free);
537
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530538/**
539 * msm_audio_ion_mmap -
540 * Audio ION memory map
541 *
Banajit Goswami08bb7362017-11-03 22:48:23 -0700542 * @abuff: audio buf pointer
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530543 * @vma: virtual mem area
544 *
545 * Returns 0 on success or error on failure
546 */
Banajit Goswami08bb7362017-11-03 22:48:23 -0700547int msm_audio_ion_mmap(struct audio_buffer *abuff,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530548 struct vm_area_struct *vma)
549{
Banajit Goswami08bb7362017-11-03 22:48:23 -0700550 struct msm_audio_alloc_data *alloc_data = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530551 struct sg_table *table;
552 unsigned long addr = vma->vm_start;
553 unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
554 struct scatterlist *sg;
555 unsigned int i;
556 struct page *page;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700557 int ret = 0;
558 bool found = false;
559 struct device *cb_dev = msm_audio_ion_data.cb_dev;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530560
Banajit Goswami08bb7362017-11-03 22:48:23 -0700561 mutex_lock(&(msm_audio_ion_data.list_mutex));
562 list_for_each_entry(alloc_data, &(msm_audio_ion_data.alloc_list),
563 list) {
564 if (alloc_data->dma_buf == abuff->dma_buf) {
565 found = true;
566 table = alloc_data->table;
567 break;
568 }
569 }
570 mutex_unlock(&(msm_audio_ion_data.list_mutex));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530571
Banajit Goswami08bb7362017-11-03 22:48:23 -0700572 if (!found) {
573 dev_err(cb_dev,
574 "%s: cannot find allocation, dma_buf %pK",
575 __func__, abuff->dma_buf);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530576 return -EINVAL;
577 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530578 /* uncached */
579 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
580
581 /* We need to check if a page is associated with this sg list because:
582 * If the allocation came from a carveout we currently don't have
583 * pages associated with carved out memory. This might change in the
584 * future and we can remove this check and the else statement.
585 */
586 page = sg_page(table->sgl);
587 if (page) {
588 pr_debug("%s: page is NOT null\n", __func__);
589 for_each_sg(table->sgl, sg, table->nents, i) {
590 unsigned long remainder = vma->vm_end - addr;
591 unsigned long len = sg->length;
592
593 page = sg_page(sg);
594
595 if (offset >= len) {
596 offset -= len;
597 continue;
598 } else if (offset) {
599 page += offset / PAGE_SIZE;
600 len -= offset;
601 offset = 0;
602 }
603 len = min(len, remainder);
604 pr_debug("vma=%pK, addr=%x len=%ld vm_start=%x vm_end=%x vm_page_prot=%lu\n",
605 vma, (unsigned int)addr, len,
606 (unsigned int)vma->vm_start,
607 (unsigned int)vma->vm_end,
Xiaoyu Yea87e56d2017-10-25 22:59:48 -0700608 (unsigned long)pgprot_val(vma->vm_page_prot));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530609 remap_pfn_range(vma, addr, page_to_pfn(page), len,
610 vma->vm_page_prot);
611 addr += len;
612 if (addr >= vma->vm_end)
613 return 0;
614 }
615 } else {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530616 pr_debug("%s: page is NULL\n", __func__);
Banajit Goswami08bb7362017-11-03 22:48:23 -0700617 ret = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530618 }
Banajit Goswami08bb7362017-11-03 22:48:23 -0700619
620 return ret;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530621}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530622EXPORT_SYMBOL(msm_audio_ion_mmap);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530623
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530624/**
Banajit Goswami0f1f3f62018-02-02 03:36:46 -0800625 * msm_audio_ion_cache_operations-
626 * Cache operations on cached Audio ION buffers
627 *
628 * @abuff: audio buf pointer
629 * @cache_op: cache operation to be performed
630 *
631 * Returns 0 on success or error on failure
632 */
633int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op)
634{
635 unsigned long ionflag = 0;
636 int rc = 0;
637
638 if (!abuff) {
639 pr_err("%s: Invalid params: %pK\n", __func__, abuff);
640 return -EINVAL;
641 }
642 rc = dma_buf_get_flags(abuff->dma_buf, &ionflag);
643 if (rc) {
644 pr_err("%s: dma_buf_get_flags failed: %d\n", __func__, rc);
645 goto cache_op_failed;
646 }
647
648 /* Has to be CACHED */
649 if (ionflag & ION_FLAG_CACHED) {
650 /* MSM_AUDIO_ION_INV_CACHES or MSM_AUDIO_ION_CLEAN_CACHES */
651 switch (cache_op) {
652 case MSM_AUDIO_ION_INV_CACHES:
Banajit Goswami0f1f3f62018-02-02 03:36:46 -0800653 case MSM_AUDIO_ION_CLEAN_CACHES:
Banajit Goswamid188b952018-03-03 01:24:56 -0800654 dma_buf_begin_cpu_access(abuff->dma_buf,
655 DMA_BIDIRECTIONAL);
656 dma_buf_end_cpu_access(abuff->dma_buf,
657 DMA_BIDIRECTIONAL);
Banajit Goswami0f1f3f62018-02-02 03:36:46 -0800658 break;
659 default:
660 pr_err("%s: Invalid cache operation %d\n",
661 __func__, cache_op);
662 }
663 } else {
664 pr_err("%s: Cache ops called on uncached buffer: %pK\n",
665 __func__, abuff->dma_buf);
666 rc = -EINVAL;
667 }
668
669cache_op_failed:
670 return rc;
671}
672EXPORT_SYMBOL(msm_audio_ion_cache_operations);
673
674/**
Banajit Goswami08bb7362017-11-03 22:48:23 -0700675 * msm_audio_populate_upper_32_bits -
676 * retrieve upper 32bits of 64bit address
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530677 *
Banajit Goswami08bb7362017-11-03 22:48:23 -0700678 * @pa: 64bit physical address
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530679 *
680 */
Banajit Goswami08bb7362017-11-03 22:48:23 -0700681u32 msm_audio_populate_upper_32_bits(dma_addr_t pa)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530682{
Banajit Goswami08bb7362017-11-03 22:48:23 -0700683 if (sizeof(dma_addr_t) == sizeof(u32))
Banajit Goswamif6077632018-03-11 22:41:27 -0700684 return msm_audio_ion_get_smmu_sid_mode32();
Banajit Goswami08bb7362017-11-03 22:48:23 -0700685 else
686 return upper_32_bits(pa);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530687}
Banajit Goswami08bb7362017-11-03 22:48:23 -0700688EXPORT_SYMBOL(msm_audio_populate_upper_32_bits);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530689
690static int msm_audio_smmu_init(struct device *dev)
691{
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530692 INIT_LIST_HEAD(&msm_audio_ion_data.alloc_list);
693 mutex_init(&(msm_audio_ion_data.list_mutex));
694
695 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530696}
697
698static const struct of_device_id msm_audio_ion_dt_match[] = {
699 { .compatible = "qcom,msm-audio-ion" },
700 { }
701};
702MODULE_DEVICE_TABLE(of, msm_audio_ion_dt_match);
703
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530704static int msm_audio_ion_probe(struct platform_device *pdev)
705{
706 int rc = 0;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700707 u64 smmu_sid = 0;
708 u64 smmu_sid_mask = 0;
Banajit Goswamif6077632018-03-11 22:41:27 -0700709 const char *msm_audio_ion_dt = "qcom,smmu-enabled";
710 const char *msm_audio_ion_smmu = "qcom,smmu-version";
711 const char *msm_audio_ion_smmu_sid_mask = "qcom,smmu-sid-mask";
712 bool smmu_enabled;
713 enum apr_subsys_state q6_state;
714 struct device *dev = &pdev->dev;
Banajit Goswami08bb7362017-11-03 22:48:23 -0700715 struct of_phandle_args iommuspec;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530716
Banajit Goswamif6077632018-03-11 22:41:27 -0700717
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530718 if (dev->of_node == NULL) {
719 dev_err(dev,
720 "%s: device tree is not found\n",
721 __func__);
Banajit Goswamif6077632018-03-11 22:41:27 -0700722 msm_audio_ion_data.smmu_enabled = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530723 return 0;
724 }
725
Banajit Goswamif6077632018-03-11 22:41:27 -0700726 smmu_enabled = of_property_read_bool(dev->of_node,
727 msm_audio_ion_dt);
728 msm_audio_ion_data.smmu_enabled = smmu_enabled;
729
730 if (!smmu_enabled) {
731 dev_dbg(dev, "%s: SMMU is Disabled\n", __func__);
732 goto exit;
733 }
734
735 q6_state = apr_get_q6_state();
736 if (q6_state == APR_SUBSYS_DOWN) {
737 dev_dbg(dev,
738 "defering %s, adsp_state %d\n",
739 __func__, q6_state);
740 return -EPROBE_DEFER;
741 }
742 dev_dbg(dev, "%s: adsp is ready\n", __func__);
743
Banajit Goswami08bb7362017-11-03 22:48:23 -0700744 rc = of_property_read_u32(dev->of_node,
745 msm_audio_ion_smmu,
746 &msm_audio_ion_data.smmu_version);
747 if (rc) {
748 dev_err(dev,
749 "%s: qcom,smmu_version missing in DT node\n",
750 __func__);
751 return rc;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530752 }
Banajit Goswamif6077632018-03-11 22:41:27 -0700753 dev_dbg(dev, "%s: SMMU is Enabled. SMMU version is (%d)",
754 __func__, msm_audio_ion_data.smmu_version);
Banajit Goswami08bb7362017-11-03 22:48:23 -0700755
756 /* Get SMMU SID information from Devicetree */
757 rc = of_property_read_u64(dev->of_node,
758 msm_audio_ion_smmu_sid_mask,
759 &smmu_sid_mask);
760 if (rc) {
761 dev_err(dev,
762 "%s: qcom,smmu-sid-mask missing in DT node, using default\n",
763 __func__);
764 smmu_sid_mask = 0xFFFFFFFFFFFFFFFF;
765 }
Banajit Goswamif6077632018-03-11 22:41:27 -0700766
Banajit Goswami08bb7362017-11-03 22:48:23 -0700767 rc = of_parse_phandle_with_args(dev->of_node, "iommus",
768 "#iommu-cells", 0, &iommuspec);
769 if (rc)
770 dev_err(dev, "%s: could not get smmu SID, ret = %d\n",
771 __func__, rc);
772 else
773 smmu_sid = (iommuspec.args[0] & smmu_sid_mask);
774
775 msm_audio_ion_data.smmu_sid_bits =
776 smmu_sid << MSM_AUDIO_SMMU_SID_OFFSET;
777
778 if (msm_audio_ion_data.smmu_version == 0x2) {
779 rc = msm_audio_smmu_init(dev);
780 } else {
781 dev_err(dev, "%s: smmu version invalid %d\n",
782 __func__, msm_audio_ion_data.smmu_version);
783 rc = -EINVAL;
784 }
785 if (rc)
786 dev_err(dev, "%s: smmu init failed, err = %d\n",
787 __func__, rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530788
Banajit Goswamif6077632018-03-11 22:41:27 -0700789exit:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530790 if (!rc)
791 msm_audio_ion_data.device_status |= MSM_AUDIO_ION_PROBED;
792
Banajit Goswamice6e7802018-04-25 22:29:47 -0700793 msm_audio_ion_data.cb_dev = dev;
794
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530795 return rc;
796}
797
798static int msm_audio_ion_remove(struct platform_device *pdev)
799{
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530800 struct device *audio_cb_dev;
801
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530802 audio_cb_dev = msm_audio_ion_data.cb_dev;
803
Banajit Goswamif6077632018-03-11 22:41:27 -0700804 msm_audio_ion_data.smmu_enabled = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530805 msm_audio_ion_data.device_status = 0;
806 return 0;
807}
808
809static struct platform_driver msm_audio_ion_driver = {
810 .driver = {
811 .name = "msm-audio-ion",
812 .owner = THIS_MODULE,
813 .of_match_table = msm_audio_ion_dt_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +0800814 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530815 },
816 .probe = msm_audio_ion_probe,
817 .remove = msm_audio_ion_remove,
818};
819
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530820int __init msm_audio_ion_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530821{
822 return platform_driver_register(&msm_audio_ion_driver);
823}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530824
Asish Bhattacharya5faacb32017-12-04 17:23:15 +0530825void msm_audio_ion_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530826{
827 platform_driver_unregister(&msm_audio_ion_driver);
828}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530829
830MODULE_DESCRIPTION("MSM Audio ION module");
831MODULE_LICENSE("GPL v2");