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(&region->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(&region->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(&region->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, &region);
+	ret = audpcm_ion_lookup_vaddr(audio, addr, len, &region);
 	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(&region->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);