/* sound/soc/samsung/abox/abox_mmap_fd.c * * ALSA SoC Audio Layer - Samsung Abox mmap_fd driver * * Copyright (c) 2018 Samsung Electronics Co. Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* #define DEBUG */ #include #include #include #include #include #include "../../../../drivers/iommu/exynos-iommu.h" #include "../../../../drivers/staging/android/uapi/ion.h" #include "abox.h" int abox_mmap_fd(struct abox_platform_data *data, struct snd_pcm_mmap_fd *mmap_fd) { struct device *dev = &data->pdev->dev; int id = data->id; struct abox_ion_buf *buf = &data->ion_buf; struct dma_buf *temp_buf; int ret = 0; dev_dbg(dev, "%s id(%d)\n", __func__, id); if (buf->fd >= 0) { mmap_fd->dir = SNDRV_PCM_STREAM_PLAYBACK; mmap_fd->size = buf->size; mmap_fd->actual_size = buf->size; mmap_fd->fd = buf->fd; } else { mmap_fd->fd = dma_buf_fd(buf->dma_buf, O_CLOEXEC); if (mmap_fd->fd >= 0) { mmap_fd->dir = SNDRV_PCM_STREAM_PLAYBACK; mmap_fd->size = buf->size; mmap_fd->actual_size = buf->size; } else { ret = -EFAULT; dev_err(dev, "%s dma_buf_fd is failed\n", __func__); dma_buf_put(buf->dma_buf); goto error_get_fd; } buf->fd = mmap_fd->fd; dev_dbg(dev, "%s fd(%d)\n", __func__, buf->fd); temp_buf = dma_buf_get(buf->fd); data->mmap_fd_state = true; dev_dbg(dev, "%s-(%p)(%p)\n", __func__, buf->dma_buf, temp_buf); } dev_info(dev, "%s id(%d) fd(%d)\n", __func__, id, buf->fd); error_get_fd: return ret; } int abox_ion_alloc(struct abox_platform_data *data, struct abox_ion_buf *buf, unsigned long iova, size_t size, size_t align) { struct device *dev = &data->pdev->dev; struct device *dev_abox = &data->abox_data->pdev->dev; /* const char *heapname = "crypto_heap"; */ const char *heapname = "ion_system_heap"; int ret = 0; if (!buf) return -ENOMEM; size = PAGE_ALIGN(size); buf->dma_buf = ion_alloc_dmabuf(heapname, size, ION_FLAG_SYNC_FORCE); if (IS_ERR(buf->dma_buf)) { ret = -ENOMEM; goto error_alloc; } buf->attachment = dma_buf_attach(buf->dma_buf, dev_abox); if (IS_ERR(buf->attachment)) { ret = -ENOMEM; goto error_attach; } buf->sgt = dma_buf_map_attachment( buf->attachment, DMA_BIDIRECTIONAL); if (IS_ERR(buf->sgt)) { ret = -ENOMEM; goto error_map_dmabuf; } if (!buf->kva) buf->kva = dma_buf_vmap(buf->dma_buf); if (IS_ERR_OR_NULL(buf->kva)) { ret = -ENOMEM; goto error_dma_buf_vmap; } buf->size = size; buf->iova = iova; buf->direction = DMA_BIDIRECTIONAL; ret = abox_iommu_map_sg(&data->abox_data->pdev->dev, buf->iova, buf->sgt->sgl, buf->sgt->nents, DMA_BIDIRECTIONAL, buf->size, buf->kva); if (ret < 0) { dev_err(dev, "Failed to iommu_map(%#lx): %d\n", buf->iova, ret); goto error_iommu_map_sg; } return ret; error_iommu_map_sg: dma_buf_vunmap(buf->dma_buf, buf->kva); error_dma_buf_vmap: dma_buf_unmap_attachment(buf->attachment, buf->sgt, DMA_BIDIRECTIONAL); error_map_dmabuf: dma_buf_detach(buf->dma_buf, buf->attachment); error_attach: dma_buf_put(buf->dma_buf); error_alloc: dev_err(dev, "%s: Error occured while allocating\n", __func__); return ret; } int abox_ion_free(struct abox_platform_data *data) { struct device *dev = &data->pdev->dev; int ret = 0; ret = abox_iommu_unmap(&data->abox_data->pdev->dev, data->ion_buf.iova); if (ret < 0) dev_err(dev, "Failed to iommu_unmap: %d\n", ret); if (data->ion_buf.kva) { dma_buf_vunmap(data->ion_buf.dma_buf, data->ion_buf.kva); if (data->mmap_fd_state == true) dma_buf_put(data->ion_buf.dma_buf); } dma_buf_unmap_attachment(data->ion_buf.attachment, data->ion_buf.sgt, DMA_BIDIRECTIONAL); dma_buf_detach(data->ion_buf.dma_buf, data->ion_buf.attachment); dma_buf_put(data->ion_buf.dma_buf); return ret; }