msm: QDSP5: audio: Migrate to ION
PMEM is deprecated, switch to ION.
Change-Id: I3ebfd979f1c8060e72edeaa31afed31ca838706d
Signed-off-by: Sidipotu Ashok <sashok@codeaurora.org>
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 49c781f..880de09 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -38,7 +38,7 @@
#include <linux/delay.h>
#include <linux/earlysuspend.h>
#include <linux/list.h>
-#include <linux/android_pmem.h>
+#include <linux/ion.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
@@ -134,11 +134,10 @@
union msm_audio_event_payload payload;
};
-struct audpcm_pmem_region {
+struct audpcm_ion_region {
struct list_head list;
- struct file *file;
+ struct ion_handle *handle;
int fd;
- void *vaddr_ref;
void *vaddr;
unsigned long paddr;
unsigned long kvaddr;
@@ -222,8 +221,10 @@
struct mutex get_event_lock;
int event_abort;
- struct list_head pmem_region_queue;
+ struct list_head ion_region_queue;
struct audpcm_drv_operations drv_ops;
+ struct ion_client *client;
+ struct ion_handle *output_buff_handle;
};
static int auddec_dsp_config(struct audio *audio, int enable);
@@ -232,7 +233,7 @@
static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
static void audpcm_post_event(struct audio *audio, int type,
union msm_audio_event_payload payload);
-static unsigned long audpcm_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audpcm_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up);
static int rmt_put_resource(struct audio *audio)
@@ -762,7 +763,7 @@
if (drv_evt && drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
mutex_lock(&audio->lock);
- audpcm_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ audpcm_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
drv_evt->payload.aio_buf.buf_len, 0);
mutex_unlock(&audio->lock);
}
@@ -772,104 +773,118 @@
return rc;
}
-static int audpcm_pmem_check(struct audio *audio,
+static int audpcm_ion_check(struct audio *audio,
void *vaddr, unsigned long len)
{
- struct audpcm_pmem_region *region_elt;
- struct audpcm_pmem_region t = { .vaddr = vaddr, .len = len };
+ struct audpcm_ion_region *region_elt;
+ struct audpcm_ion_region t = {.vaddr = vaddr, .len = len };
- list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
- MM_ERR("region (vaddr %p len %ld)"
+ MM_ERR("[%p]:region (vaddr %p len %ld)"
" clashes with registered region"
" (vaddr %p paddr %p len %ld)\n",
- vaddr, len,
+ audio, vaddr, len,
region_elt->vaddr,
- (void *)region_elt->paddr,
- region_elt->len);
+ (void *)region_elt->paddr, region_elt->len);
return -EINVAL;
}
}
return 0;
}
-
-static int audpcm_pmem_add(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audpcm_ion_add(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- unsigned long paddr, kvaddr, len;
- struct file *file;
- struct audpcm_pmem_region *region;
- struct vm_area_struct *vma;
+ ion_phys_addr_t paddr;
+ size_t len;
+ unsigned long kvaddr;
+ struct audpcm_ion_region *region;
int rc = -EINVAL;
+ struct ion_handle *handle;
+ unsigned long ionflag;
- MM_DBG("\n"); /* Macro prints the file name and function */
+ MM_ERR("\n"); /* Macro prints the file name and function */
region = kmalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
- if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
- kfree(region);
- return -EINVAL;
+ if (!region) {
+ rc = -ENOMEM;
+ goto end;
}
-
- vma = find_vma_intersection(current->active_mm,
- (unsigned long) info->vaddr, (unsigned long) info->vaddr+1);
-
- if (vma && ((vma->vm_end - vma->vm_start) == len)) {
- rc = audpcm_pmem_check(audio, (void *) vma->vm_start, len);
- if (rc < 0) {
- put_pmem_file(file);
- kfree(region);
- return rc;
- }
- region->vaddr = (void *) vma->vm_start;
- region->vaddr_ref = info->vaddr;
- MM_DBG("Valid VMA region vma->vm_start = 0x%8x \
- vma->vm_end = 0x%8x\n", (int) vma->vm_start,
- (int) vma->vm_end);
- } else {
- MM_ERR("No valid VMA region found\n");
- put_pmem_file(file);
- kfree(region);
- return rc;
+ handle = ion_import_dma_buf(audio->client, info->fd);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: could not get handle of the given fd\n", __func__);
+ goto import_error;
}
+ rc = ion_handle_get_flags(audio->client, handle, &ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n", __func__);
+ goto flag_error;
+ }
+ kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag);
+ if (IS_ERR_OR_NULL((void *)kvaddr)) {
+ pr_err("%s: could not get virtual address\n", __func__);
+ goto map_error;
+ }
+ rc = ion_phys(audio->client, handle, &paddr, &len);
+ if (rc) {
+ pr_err("%s: could not get physical address\n", __func__);
+ goto ion_error;
+ }
+ rc = audpcm_ion_check(audio, info->vaddr, len);
+ if (rc < 0) {
+ MM_ERR("audpcm_ion_check failed\n");
+ goto ion_error;
+ }
+ region->handle = handle;
+ region->vaddr = info->vaddr;
region->fd = info->fd;
region->paddr = paddr;
region->kvaddr = kvaddr;
region->len = len;
- region->file = file;
region->ref_cnt = 0;
- MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
- region->vaddr, region->len);
- list_add_tail(®ion->list, &audio->pmem_region_queue);
+ MM_DBG("[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+ audio, region->paddr, region->vaddr,
+ region->len, region->kvaddr);
+ list_add_tail(®ion->list, &audio->ion_region_queue);
+
+ return rc;
+
+ion_error:
+ ion_unmap_kernel(audio->client, handle);
+map_error:
+flag_error:
+ ion_free(audio->client, handle);
+import_error:
+ kfree(region);
+end:
return rc;
}
-static int audpcm_pmem_remove(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audpcm_ion_remove(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- struct audpcm_pmem_region *region;
+ struct audpcm_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
- MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audpcm_ion_region, list);
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audpcm_pmem_region, list);
-
- if ((region->fd == info->fd) &&
- (region->vaddr_ref == info->vaddr)) {
+ if (region != NULL && (region->fd == info->fd) &&
+ (region->vaddr == info->vaddr)) {
if (region->ref_cnt) {
- MM_DBG("region %p in use ref_cnt %d\n",
- region, region->ref_cnt);
+ MM_DBG("%s[%p]:region %p in use ref_cnt %d\n",
+ __func__, audio, region,
+ region->ref_cnt);
break;
}
- MM_DBG("remove region fd %d vaddr %p \n", info->fd,
- info->vaddr);
+ MM_DBG("remove region fd %d vaddr %p\n",
+ info->fd, info->vaddr);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
rc = 0;
break;
@@ -879,24 +894,22 @@
return rc;
}
-static int audpcm_pmem_lookup_vaddr(struct audio *audio, void *addr,
- unsigned long len, struct audpcm_pmem_region **region)
+static int audpcm_ion_lookup_vaddr(struct audio *audio, void *addr,
+ unsigned long len, struct audpcm_ion_region **region)
{
- struct audpcm_pmem_region *region_elt;
-
+ struct audpcm_ion_region *region_elt;
int match_count = 0;
-
*region = NULL;
/* returns physical address or zero */
- list_for_each_entry(region_elt, &audio->pmem_region_queue,
- list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len) {
/* offset since we could pass vaddr inside a registerd
- * pmem buffer
+ * ion buffer
*/
+
match_count++;
if (!*region)
*region = region_elt;
@@ -904,31 +917,33 @@
}
if (match_count > 1) {
- MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
- list_for_each_entry(region_elt,
- &audio->pmem_region_queue, list) {
+ MM_ERR("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+ __func__, audio, addr, len);
+ list_for_each_entry(region_elt, &audio->ion_region_queue,
+ list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len)
- MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+ MM_ERR("\t%s[%p]:%p, %ld --> %p\n",
+ __func__, audio,
+ region_elt->vaddr,
region_elt->len,
(void *)region_elt->paddr);
}
}
-
return *region ? 0 : -1;
}
-
-static unsigned long audpcm_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audpcm_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up)
{
- struct audpcm_pmem_region *region;
+ struct audpcm_ion_region *region;
unsigned long paddr;
int ret;
- ret = audpcm_pmem_lookup_vaddr(audio, addr, len, ®ion);
+ ret = audpcm_ion_lookup_vaddr(audio, addr, len, ®ion);
if (ret) {
- MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+ MM_ERR("%s[%p]:lookup (%p, %ld) failed\n",
+ __func__, audio, addr, len);
return 0;
}
if (ref_up)
@@ -961,7 +976,7 @@
buf_node, dir, buf_node->buf.buf_addr,
buf_node->buf.buf_len, buf_node->buf.data_len);
- buf_node->paddr = audpcm_pmem_fixup(
+ buf_node->paddr = audpcm_ion_fixup(
audio, buf_node->buf.buf_addr,
buf_node->buf.buf_len, 1);
if (dir) {
@@ -1125,23 +1140,23 @@
rc = audpp_pause(audio->dec_id, (int) arg);
break;
- case AUDIO_REGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_REGISTER_PMEM\n");
+ case AUDIO_REGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_ERR("AUDIO_REGISTER_ION\n");
if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audpcm_pmem_add(audio, &info);
+ rc = audpcm_ion_add(audio, &info);
break;
}
- case AUDIO_DEREGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+ case AUDIO_DEREGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_ERR("AUDIO_DEREGISTER_ION\n");
if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audpcm_pmem_remove(audio, &info);
+ rc = audpcm_ion_remove(audio, &info);
break;
}
@@ -1340,15 +1355,16 @@
return rc;
}
-static void audpcm_reset_pmem_region(struct audio *audio)
+static void audpcm_reset_ion_region(struct audio *audio)
{
- struct audpcm_pmem_region *region;
+ struct audpcm_ion_region *region;
struct list_head *ptr, *next;
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audpcm_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audpcm_ion_region, list);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
}
@@ -1365,7 +1381,7 @@
if (audio->rmt_resource_released == 0)
rmt_put_resource(audio);
audio->drv_ops.out_flush(audio);
- audpcm_reset_pmem_region(audio);
+ audpcm_reset_ion_region(audio);
msm_adsp_put(audio->audplay);
audpp_adec_free(audio->dec_id);
@@ -1376,16 +1392,12 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audpcm_reset_event_queue(audio);
- MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
- if (audio->data) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- }
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
debugfs_remove(audio->dentry);
#endif
+ ion_client_destroy(audio->client);
kfree(audio);
return 0;
}
@@ -1506,7 +1518,13 @@
struct audio *audio = NULL;
int rc, i, dec_attrb, decid;
struct audpcm_event *e_node = NULL;
- unsigned pmem_sz = DMASZ_MAX;
+ unsigned mem_sz = DMASZ_MAX;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+ int len = 0;
+
#ifdef CONFIG_DEBUG_FS
/* 4 bytes represents decoder number, 1 byte for terminate string */
@@ -1543,44 +1561,57 @@
}
audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+ client = msm_ion_client_create(UINT_MAX, "Audio_PCM_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto client_create_error;
+ }
+ audio->client = client;
+
/* Non AIO interface */
if (!(file->f_flags & O_NONBLOCK)) {
- while (pmem_sz >= DMASZ_MIN) {
- MM_DBG("pmemsz = %d\n", pmem_sz);
- audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
- SZ_4K);
- if (audio->phys) {
- audio->map_v_write = ioremap(
- audio->phys, pmem_sz);
- if (IS_ERR(audio->map_v_write)) {
- MM_ERR("could not map write\
- buffers\n");
- rc = -ENOMEM;
- free_contiguous_memory_by_paddr(
- audio->phys);
- audpp_adec_free(audio->dec_id);
- MM_DBG("audio instance 0x%08x\
- freeing\n", (int)audio);
- kfree(audio);
- goto done;
- }
- audio->data = audio->map_v_write;
- MM_DBG("write buf: phy addr 0x%08x kernel addr\
- 0x%08x\n", audio->phys,\
- (int)audio->data);
- break;
- } else if (pmem_sz == DMASZ_MIN) {
- MM_ERR("could not allocate write buffers\n");
- rc = -ENOMEM;
- audpp_adec_free(audio->dec_id);
- MM_DBG("audio instance 0x%08x freeing\n",\
- (int)audio);
- kfree(audio);
- goto done;
- } else
- pmem_sz >>= 1;
+
+ MM_DBG("memsz = %d\n", mem_sz);
+
+ handle = ion_alloc(client, mem_sz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
}
- audio->out_dma_sz = pmem_sz;
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->out_dma_sz = mem_sz;
}
rc = audmgr_open(&audio->audmgr);
@@ -1631,7 +1662,7 @@
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->write_wait);
INIT_LIST_HEAD(&audio->out_queue);
- INIT_LIST_HEAD(&audio->pmem_region_queue);
+ INIT_LIST_HEAD(&audio->ion_region_queue);
INIT_LIST_HEAD(&audio->free_event_queue);
INIT_LIST_HEAD(&audio->event_queue);
init_waitqueue_head(&audio->wait);
@@ -1674,10 +1705,14 @@
done:
return rc;
err:
- if (audio->data) {
- iounmap(audio->map_v_write);
- free_contiguous_memory_by_paddr(audio->phys);
- }
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_flags_error:
+output_buff_get_phys_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
audpp_adec_free(audio->dec_id);
MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
kfree(audio);