dsp: remove global msm_audio_ion_private_data

Change-Id: I2903b19295695c91d62fa5bbb8a9c9c884dfaf98
This commit is contained in:
pavanisr
2020-11-04 14:55:07 +05:30
committed by Gerrit - the friendly Code Review server
parent 3f099a7afc
commit e8e79f3322
4 changed files with 136 additions and 884 deletions

View File

@@ -41,15 +41,13 @@
struct msm_audio_ion_private { struct msm_audio_ion_private {
bool smmu_enabled; bool smmu_enabled;
struct device *cb_dev; struct device *cb_dev;
struct device *cb_cma_dev;
u8 device_status; u8 device_status;
struct list_head alloc_list; struct list_head alloc_list;
struct mutex list_mutex; struct mutex list_mutex;
u64 smmu_sid_bits; u64 smmu_sid_bits;
u32 smmu_version; u32 smmu_version;
bool is_non_hypervisor; bool is_non_hypervisor;
/*list to store fd, phy. addr and handle data */ char *driver_name;
struct list_head fd_list;
/*char dev related data */ /*char dev related data */
dev_t ion_major; dev_t ion_major;
struct class *ion_class; struct class *ion_class;
@@ -66,12 +64,20 @@ struct msm_audio_alloc_data {
struct list_head list; struct list_head list;
}; };
static struct msm_audio_ion_private msm_audio_ion_data = {0,}; struct msm_audio_ion_fd_list_private {
struct mutex list_mutex;
/*list to store fd, phy. addr and handle data */
struct list_head fd_list;
};
static struct msm_audio_ion_fd_list_private msm_audio_ion_fd_list = {0,};
static bool msm_audio_ion_fd_list_init = false;
struct msm_audio_fd_data { struct msm_audio_fd_data {
int fd; int fd;
void *handle; void *handle;
dma_addr_t paddr; dma_addr_t paddr;
struct device *dev;
struct list_head list; struct list_head list;
}; };
@@ -90,7 +96,8 @@ static void msm_audio_ion_add_allocation(
mutex_unlock(&(msm_audio_ion_data->list_mutex)); mutex_unlock(&(msm_audio_ion_data->list_mutex));
} }
static void *msm_audio_ion_map_kernel(struct dma_buf *dma_buf) static void *msm_audio_ion_map_kernel(struct dma_buf *dma_buf,
struct msm_audio_ion_private *ion_data)
{ {
int rc = 0; int rc = 0;
void *addr = NULL; void *addr = NULL;
@@ -113,15 +120,15 @@ static void *msm_audio_ion_map_kernel(struct dma_buf *dma_buf)
* TBD: remove the below section once new API * TBD: remove the below section once new API
* for mapping kernel virtual address is available. * for mapping kernel virtual address is available.
*/ */
mutex_lock(&(msm_audio_ion_data.list_mutex)); mutex_lock(&(ion_data->list_mutex));
list_for_each_entry(alloc_data, &(msm_audio_ion_data.alloc_list), list_for_each_entry(alloc_data, &(ion_data->alloc_list),
list) { list) {
if (alloc_data->dma_buf == dma_buf) { if (alloc_data->dma_buf == dma_buf) {
alloc_data->vaddr = addr; alloc_data->vaddr = addr;
break; break;
} }
} }
mutex_unlock(&(msm_audio_ion_data.list_mutex)); mutex_unlock(&(ion_data->list_mutex));
exit: exit:
return addr; return addr;
@@ -129,19 +136,14 @@ exit:
static int msm_audio_dma_buf_map(struct dma_buf *dma_buf, static int msm_audio_dma_buf_map(struct dma_buf *dma_buf,
dma_addr_t *addr, size_t *len, bool is_iova, dma_addr_t *addr, size_t *len, bool is_iova,
bool cma_mem) struct msm_audio_ion_private *ion_data)
{ {
struct msm_audio_alloc_data *alloc_data = NULL; struct msm_audio_alloc_data *alloc_data = NULL;
struct device *cb_dev;
unsigned long ionflag = 0; unsigned long ionflag = 0;
int rc = 0; int rc = 0;
void *vaddr = NULL; void *vaddr = NULL;
struct device *cb_dev = ion_data->cb_dev;
if (cma_mem)
cb_dev = msm_audio_ion_data.cb_cma_dev;
else
cb_dev = msm_audio_ion_data.cb_dev;
/* Data required per buffer mapping */ /* Data required per buffer mapping */
alloc_data = kzalloc(sizeof(*alloc_data), GFP_KERNEL); alloc_data = kzalloc(sizeof(*alloc_data), GFP_KERNEL);
@@ -193,7 +195,7 @@ static int msm_audio_dma_buf_map(struct dma_buf *dma_buf,
/* physical address from mapping */ /* physical address from mapping */
if (!is_iova) { if (!is_iova) {
*addr = sg_phys(alloc_data->table->sgl); *addr = sg_phys(alloc_data->table->sgl);
vaddr = msm_audio_ion_map_kernel((void *)dma_buf); vaddr = msm_audio_ion_map_kernel((void *)dma_buf, ion_data);
if (IS_ERR_OR_NULL(vaddr)) { if (IS_ERR_OR_NULL(vaddr)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", pr_err("%s: ION memory mapping for AUDIO failed\n",
__func__); __func__);
@@ -205,8 +207,7 @@ static int msm_audio_dma_buf_map(struct dma_buf *dma_buf,
*addr = MSM_AUDIO_ION_PHYS_ADDR(alloc_data); *addr = MSM_AUDIO_ION_PHYS_ADDR(alloc_data);
} }
msm_audio_ion_add_allocation(&msm_audio_ion_data, msm_audio_ion_add_allocation(ion_data, alloc_data);
alloc_data);
return rc; return rc;
detach_dma_buf: detach_dma_buf:
@@ -219,26 +220,22 @@ free_alloc_data:
return rc; return rc;
} }
static int msm_audio_dma_buf_unmap(struct dma_buf *dma_buf, bool cma_mem) static int msm_audio_dma_buf_unmap(struct dma_buf *dma_buf, struct msm_audio_ion_private *ion_data)
{ {
int rc = 0; int rc = 0;
struct msm_audio_alloc_data *alloc_data = NULL; struct msm_audio_alloc_data *alloc_data = NULL;
struct list_head *ptr, *next; struct list_head *ptr, *next;
struct device *cb_dev;
bool found = false; bool found = false;
struct device *cb_dev = ion_data->cb_dev;
if (cma_mem)
cb_dev = msm_audio_ion_data.cb_cma_dev;
else
cb_dev = msm_audio_ion_data.cb_dev;
/* /*
* Though list_for_each_safe is delete safe, lock * Though list_for_each_safe is delete safe, lock
* should be explicitly acquired to avoid race condition * should be explicitly acquired to avoid race condition
* on adding elements to the list. * on adding elements to the list.
*/ */
mutex_lock(&(msm_audio_ion_data.list_mutex)); mutex_lock(&(ion_data->list_mutex));
list_for_each_safe(ptr, next, list_for_each_safe(ptr, next,
&(msm_audio_ion_data.alloc_list)) { &(ion_data->alloc_list)) {
alloc_data = list_entry(ptr, struct msm_audio_alloc_data, alloc_data = list_entry(ptr, struct msm_audio_alloc_data,
list); list);
@@ -260,7 +257,7 @@ static int msm_audio_dma_buf_unmap(struct dma_buf *dma_buf, bool cma_mem)
break; break;
} }
} }
mutex_unlock(&(msm_audio_ion_data.list_mutex)); mutex_unlock(&(ion_data->list_mutex));
if (!found) { if (!found) {
dev_err(cb_dev, dev_err(cb_dev,
@@ -273,19 +270,20 @@ static int msm_audio_dma_buf_unmap(struct dma_buf *dma_buf, bool cma_mem)
} }
static int msm_audio_ion_get_phys(struct dma_buf *dma_buf, static int msm_audio_ion_get_phys(struct dma_buf *dma_buf,
dma_addr_t *addr, size_t *len, bool is_iova) dma_addr_t *addr, size_t *len, bool is_iova,
struct msm_audio_ion_private *ion_data)
{ {
int rc = 0; int rc = 0;
rc = msm_audio_dma_buf_map(dma_buf, addr, len, is_iova, false); rc = msm_audio_dma_buf_map(dma_buf, addr, len, is_iova, ion_data);
if (rc) { if (rc) {
pr_err("%s: failed to map DMA buf, err = %d\n", pr_err("%s: failed to map DMA buf, err = %d\n",
__func__, rc); __func__, rc);
goto err; goto err;
} }
if (msm_audio_ion_data.smmu_enabled && is_iova) { if (ion_data->smmu_enabled && is_iova) {
/* Append the SMMU SID information to the IOVA address */ /* Append the SMMU SID information to the IOVA address */
*addr |= msm_audio_ion_data.smmu_sid_bits; *addr |= ion_data->smmu_sid_bits;
} }
pr_debug("phys=%pK, len=%zd, rc=%d\n", &(*addr), *len, rc); pr_debug("phys=%pK, len=%zd, rc=%d\n", &(*addr), *len, rc);
@@ -293,26 +291,26 @@ err:
return rc; return rc;
} }
static int msm_audio_ion_unmap_kernel(struct dma_buf *dma_buf) static int msm_audio_ion_unmap_kernel(struct dma_buf *dma_buf, struct msm_audio_ion_private *ion_data)
{ {
int rc = 0; int rc = 0;
void *vaddr = NULL; void *vaddr = NULL;
struct msm_audio_alloc_data *alloc_data = NULL; struct msm_audio_alloc_data *alloc_data = NULL;
struct device *cb_dev = msm_audio_ion_data.cb_dev; struct device *cb_dev = ion_data->cb_dev;
/* /*
* TBD: remove the below section once new API * TBD: remove the below section once new API
* for unmapping kernel virtual address is available. * for unmapping kernel virtual address is available.
*/ */
mutex_lock(&(msm_audio_ion_data.list_mutex)); mutex_lock(&(ion_data->list_mutex));
list_for_each_entry(alloc_data, &(msm_audio_ion_data.alloc_list), list_for_each_entry(alloc_data, &(ion_data->alloc_list),
list) { list) {
if (alloc_data->dma_buf == dma_buf) { if (alloc_data->dma_buf == dma_buf) {
vaddr = alloc_data->vaddr; vaddr = alloc_data->vaddr;
break; break;
} }
} }
mutex_unlock(&(msm_audio_ion_data.list_mutex)); mutex_unlock(&(ion_data->list_mutex));
if (!vaddr) { if (!vaddr) {
dev_err(cb_dev, dev_err(cb_dev,
@@ -336,7 +334,7 @@ err:
} }
static int msm_audio_ion_map_buf(struct dma_buf *dma_buf, dma_addr_t *paddr, static int msm_audio_ion_map_buf(struct dma_buf *dma_buf, dma_addr_t *paddr,
size_t *plen, void **vaddr) size_t *plen, void **vaddr, struct msm_audio_ion_private *ion_data)
{ {
int rc = 0; int rc = 0;
bool is_iova = true; bool is_iova = true;
@@ -346,7 +344,7 @@ static int msm_audio_ion_map_buf(struct dma_buf *dma_buf, dma_addr_t *paddr,
return -EINVAL; return -EINVAL;
} }
rc = msm_audio_ion_get_phys(dma_buf, paddr, plen, is_iova); rc = msm_audio_ion_get_phys(dma_buf, paddr, plen, is_iova, ion_data);
if (rc) { if (rc) {
pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n", pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
__func__, rc); __func__, rc);
@@ -354,11 +352,11 @@ static int msm_audio_ion_map_buf(struct dma_buf *dma_buf, dma_addr_t *paddr,
goto err; goto err;
} }
*vaddr = msm_audio_ion_map_kernel(dma_buf); *vaddr = msm_audio_ion_map_kernel(dma_buf, ion_data);
if (IS_ERR_OR_NULL(*vaddr)) { if (IS_ERR_OR_NULL(*vaddr)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__); pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
rc = -ENOMEM; rc = -ENOMEM;
msm_audio_dma_buf_unmap(dma_buf, false); msm_audio_dma_buf_unmap(dma_buf, ion_data);
goto err; goto err;
} }
@@ -366,49 +364,12 @@ err:
return rc; return rc;
} }
/**
* msm_audio_ion_dma_map -
* Memory maps for a given DMA buffer
*
* @phys_addr: Physical address of DMA buffer to be mapped
* @iova_base: IOVA address of memory mapped DMA buffer
* @size: buffer size
* @dir: DMA direction
* Returns 0 on success or error on failure
*/
int msm_audio_ion_dma_map(dma_addr_t *phys_addr, dma_addr_t *iova_base,
u32 size, enum dma_data_direction dir)
{
dma_addr_t iova;
struct device *cb_dev = msm_audio_ion_data.cb_dev;
if (!phys_addr || !iova_base || !size)
return -EINVAL;
iova = dma_map_resource(cb_dev, *phys_addr, size,
dir, 0);
if (dma_mapping_error(cb_dev, iova)) {
pr_err("%s: dma_mapping_error\n", __func__);
return -EIO;
}
pr_debug("%s: dma_mapping_success iova:0x%lx\n", __func__,
(unsigned long)iova);
if (msm_audio_ion_data.smmu_enabled)
/* Append the SMMU SID information to the IOVA address */
iova |= msm_audio_ion_data.smmu_sid_bits;
*iova_base = iova;
return 0;
}
EXPORT_SYMBOL(msm_audio_ion_dma_map);
void msm_audio_fd_list_debug(void) void msm_audio_fd_list_debug(void)
{ {
struct msm_audio_fd_data *msm_audio_fd_data = NULL; struct msm_audio_fd_data *msm_audio_fd_data = NULL;
list_for_each_entry(msm_audio_fd_data, list_for_each_entry(msm_audio_fd_data,
&msm_audio_ion_data.fd_list, list) { &msm_audio_ion_fd_list.fd_list, list) {
pr_debug("%s fd %d handle %pK phy. addr %pK\n", __func__, pr_debug("%s fd %d handle %pK phy. addr %pK\n", __func__,
msm_audio_fd_data->fd, msm_audio_fd_data->handle, msm_audio_fd_data->fd, msm_audio_fd_data->handle,
(void *)msm_audio_fd_data->paddr); (void *)msm_audio_fd_data->paddr);
@@ -419,18 +380,18 @@ void msm_audio_update_fd_list(struct msm_audio_fd_data *msm_audio_fd_data)
{ {
struct msm_audio_fd_data *msm_audio_fd_data1 = NULL; struct msm_audio_fd_data *msm_audio_fd_data1 = NULL;
mutex_lock(&(msm_audio_ion_data.list_mutex)); mutex_lock(&(msm_audio_ion_fd_list.list_mutex));
list_for_each_entry(msm_audio_fd_data1, list_for_each_entry(msm_audio_fd_data1,
&msm_audio_ion_data.fd_list, list) { &msm_audio_ion_fd_list.fd_list, list) {
if (msm_audio_fd_data1->fd == msm_audio_fd_data->fd) { if (msm_audio_fd_data1->fd == msm_audio_fd_data->fd) {
pr_err("%s fd already present, not updating the list", pr_err("%s fd already present, not updating the list",
__func__); __func__);
mutex_unlock(&(msm_audio_ion_data.list_mutex)); mutex_unlock(&(msm_audio_ion_fd_list.list_mutex));
return; return;
} }
} }
list_add_tail(&msm_audio_fd_data->list, &msm_audio_ion_data.fd_list); list_add_tail(&msm_audio_fd_data->list, &msm_audio_ion_fd_list.fd_list);
mutex_unlock(&(msm_audio_ion_data.list_mutex)); mutex_unlock(&(msm_audio_ion_fd_list.list_mutex));
} }
void msm_audio_delete_fd_entry(void *handle) void msm_audio_delete_fd_entry(void *handle)
@@ -438,9 +399,9 @@ void msm_audio_delete_fd_entry(void *handle)
struct msm_audio_fd_data *msm_audio_fd_data = NULL; struct msm_audio_fd_data *msm_audio_fd_data = NULL;
struct list_head *ptr, *next; struct list_head *ptr, *next;
mutex_lock(&(msm_audio_ion_data.list_mutex)); mutex_lock(&(msm_audio_ion_fd_list.list_mutex));
list_for_each_safe(ptr, next, list_for_each_safe(ptr, next,
&msm_audio_ion_data.fd_list) { &msm_audio_ion_fd_list.fd_list) {
msm_audio_fd_data = list_entry(ptr, struct msm_audio_fd_data, msm_audio_fd_data = list_entry(ptr, struct msm_audio_fd_data,
list); list);
if (msm_audio_fd_data->handle == handle) { if (msm_audio_fd_data->handle == handle) {
@@ -451,7 +412,7 @@ void msm_audio_delete_fd_entry(void *handle)
break; break;
} }
} }
mutex_unlock(&(msm_audio_ion_data.list_mutex)); mutex_unlock(&(msm_audio_ion_fd_list.list_mutex));
} }
int msm_audio_get_phy_addr(int fd, dma_addr_t *paddr) int msm_audio_get_phy_addr(int fd, dma_addr_t *paddr)
@@ -464,19 +425,19 @@ int msm_audio_get_phy_addr(int fd, dma_addr_t *paddr)
return status; return status;
} }
pr_debug("%s, fd %d\n", __func__, fd); pr_debug("%s, fd %d\n", __func__, fd);
mutex_lock(&(msm_audio_ion_data.list_mutex)); mutex_lock(&(msm_audio_ion_fd_list.list_mutex));
list_for_each_entry(msm_audio_fd_data, list_for_each_entry(msm_audio_fd_data,
&msm_audio_ion_data.fd_list, list) { &msm_audio_ion_fd_list.fd_list, list) {
if (msm_audio_fd_data->fd == fd) { if (msm_audio_fd_data->fd == fd) {
*paddr = msm_audio_fd_data->paddr; *paddr = msm_audio_fd_data->paddr;
status = 0; status = 0;
pr_debug("%s Found fd %d paddr %pK\n", pr_debug("%s Found fd %d paddr %pK\n",
__func__, fd, paddr); __func__, fd, paddr);
mutex_unlock(&(msm_audio_ion_data.list_mutex)); mutex_unlock(&(msm_audio_ion_fd_list.list_mutex));
return status; return status;
} }
} }
mutex_unlock(&(msm_audio_ion_data.list_mutex)); mutex_unlock(&(msm_audio_ion_fd_list.list_mutex));
return status; return status;
} }
EXPORT_SYMBOL(msm_audio_get_phy_addr); EXPORT_SYMBOL(msm_audio_get_phy_addr);
@@ -486,16 +447,16 @@ void msm_audio_get_handle(int fd, void **handle)
struct msm_audio_fd_data *msm_audio_fd_data = NULL; struct msm_audio_fd_data *msm_audio_fd_data = NULL;
pr_debug("%s fd %d\n", __func__, fd); pr_debug("%s fd %d\n", __func__, fd);
mutex_lock(&(msm_audio_ion_data.list_mutex)); mutex_lock(&(msm_audio_ion_fd_list.list_mutex));
list_for_each_entry(msm_audio_fd_data, list_for_each_entry(msm_audio_fd_data,
&msm_audio_ion_data.fd_list, list) { &msm_audio_ion_fd_list.fd_list, list) {
if (msm_audio_fd_data->fd == fd) { if (msm_audio_fd_data->fd == fd) {
*handle = (struct dma_buf *)msm_audio_fd_data->handle; *handle = (struct dma_buf *)msm_audio_fd_data->handle;
pr_debug("%s handle %pK\n", __func__, *handle); pr_debug("%s handle %pK\n", __func__, *handle);
break; break;
} }
} }
mutex_unlock(&(msm_audio_ion_data.list_mutex)); mutex_unlock(&(msm_audio_ion_fd_list.list_mutex));
} }
/** /**
@@ -512,13 +473,14 @@ void msm_audio_get_handle(int fd, void **handle)
* *
* Returns 0 on success or error on failure * Returns 0 on success or error on failure
*/ */
int msm_audio_ion_import(struct dma_buf **dma_buf, int fd, static int msm_audio_ion_import(struct dma_buf **dma_buf, int fd,
unsigned long *ionflag, size_t bufsz, unsigned long *ionflag, size_t bufsz,
dma_addr_t *paddr, size_t *plen, void **vaddr) dma_addr_t *paddr, size_t *plen, void **vaddr,
struct msm_audio_ion_private *ion_data)
{ {
int rc = 0; int rc = 0;
if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) { if (!(ion_data->device_status & MSM_AUDIO_ION_PROBED)) {
pr_debug("%s: probe is not done, deferred\n", __func__); pr_debug("%s: probe is not done, deferred\n", __func__);
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
@@ -545,15 +507,13 @@ int msm_audio_ion_import(struct dma_buf **dma_buf, int fd,
goto err_ion_flag; goto err_ion_flag;
} }
} }
rc = msm_audio_ion_map_buf(*dma_buf, paddr, plen, vaddr, ion_data);
rc = msm_audio_ion_map_buf(*dma_buf, paddr, plen, vaddr);
if (rc) { if (rc) {
pr_err("%s: failed to map ION buf, rc = %d\n", __func__, rc); pr_err("%s: failed to map ION buf, rc = %d\n", __func__, rc);
goto err; goto err;
} }
pr_debug("%s: mapped address = %pK, size=%zd\n", __func__, pr_debug("%s: mapped address = %pK, size=%zd\n", __func__,
*vaddr, bufsz); *vaddr, bufsz);
return 0; return 0;
err_ion_flag: err_ion_flag:
@@ -572,7 +532,7 @@ EXPORT_SYMBOL(msm_audio_ion_import);
* *
* Returns 0 on success or error on failure * Returns 0 on success or error on failure
*/ */
int msm_audio_ion_free(struct dma_buf *dma_buf) static int msm_audio_ion_free(struct dma_buf *dma_buf, struct msm_audio_ion_private *ion_data)
{ {
int ret = 0; int ret = 0;
@@ -581,11 +541,11 @@ int msm_audio_ion_free(struct dma_buf *dma_buf)
return -EINVAL; return -EINVAL;
} }
ret = msm_audio_ion_unmap_kernel(dma_buf); ret = msm_audio_ion_unmap_kernel(dma_buf, ion_data);
if (ret) if (ret)
return ret; return ret;
msm_audio_dma_buf_unmap(dma_buf, false); msm_audio_dma_buf_unmap(dma_buf, ion_data);
return 0; return 0;
} }
@@ -602,15 +562,17 @@ void msm_audio_ion_crash_handler(void)
struct msm_audio_fd_data *msm_audio_fd_data = NULL; struct msm_audio_fd_data *msm_audio_fd_data = NULL;
struct list_head *ptr, *next; struct list_head *ptr, *next;
void *handle = NULL; void *handle = NULL;
struct msm_audio_ion_private *ion_data = NULL;
pr_debug("Inside %s\n", __func__); pr_debug("Inside %s\n", __func__);
list_for_each_entry(msm_audio_fd_data, list_for_each_entry(msm_audio_fd_data,
&msm_audio_ion_data.fd_list, list) { &msm_audio_ion_fd_list.fd_list, list) {
handle = msm_audio_fd_data->handle; handle = msm_audio_fd_data->handle;
msm_audio_ion_free(handle); ion_data = dev_get_drvdata(msm_audio_fd_data->dev);
msm_audio_ion_free(handle, ion_data);
} }
list_for_each_safe(ptr, next, list_for_each_safe(ptr, next,
&msm_audio_ion_data.fd_list) { &msm_audio_ion_fd_list.fd_list) {
msm_audio_fd_data = list_entry(ptr, struct msm_audio_fd_data, msm_audio_fd_data = list_entry(ptr, struct msm_audio_fd_data,
list); list);
list_del(&(msm_audio_fd_data->list)); list_del(&(msm_audio_fd_data->list));
@@ -653,19 +615,17 @@ static long msm_audio_ion_ioctl(struct file *file, unsigned int ioctl_num,
void *vaddr; void *vaddr;
int ret = 0; int ret = 0;
struct msm_audio_fd_data *msm_audio_fd_data = NULL; struct msm_audio_fd_data *msm_audio_fd_data = NULL;
struct msm_audio_ion_private *ion_data =
container_of(file->f_inode->i_cdev, struct msm_audio_ion_private, cdev);
pr_debug("%s ioctl num %u\n", __func__, ioctl_num); pr_debug("%s ioctl num %u\n", __func__, ioctl_num);
switch (ioctl_num) { switch (ioctl_num) {
case IOCTL_MAP_PHYS_ADDR: case IOCTL_MAP_PHYS_ADDR:
msm_audio_fd_data = kzalloc((sizeof(struct msm_audio_fd_data)), msm_audio_fd_data = kzalloc((sizeof(struct msm_audio_fd_data)),
GFP_KERNEL); GFP_KERNEL);
if (!msm_audio_fd_data) { if (!msm_audio_fd_data)
ret = -ENOMEM; return -ENOMEM;
pr_err("%s : Out of memory ret %d\n", __func__, ret);
return ret;
}
ret = msm_audio_ion_import((struct dma_buf **)&mem_handle, (int)ioctl_param, ret = msm_audio_ion_import((struct dma_buf **)&mem_handle, (int)ioctl_param,
NULL, 0, &paddr, &pa_len, &vaddr); NULL, 0, &paddr, &pa_len, &vaddr, ion_data);
if (ret < 0) { if (ret < 0) {
pr_err("%s Memory map Failed %d\n", __func__, ret); pr_err("%s Memory map Failed %d\n", __func__, ret);
kfree(msm_audio_fd_data); kfree(msm_audio_fd_data);
@@ -674,11 +634,12 @@ static long msm_audio_ion_ioctl(struct file *file, unsigned int ioctl_num,
msm_audio_fd_data->fd = (int)ioctl_param; msm_audio_fd_data->fd = (int)ioctl_param;
msm_audio_fd_data->handle = mem_handle; msm_audio_fd_data->handle = mem_handle;
msm_audio_fd_data->paddr = paddr; msm_audio_fd_data->paddr = paddr;
msm_audio_fd_data->dev = ion_data->cb_dev;
msm_audio_update_fd_list(msm_audio_fd_data); msm_audio_update_fd_list(msm_audio_fd_data);
break; break;
case IOCTL_UNMAP_PHYS_ADDR: case IOCTL_UNMAP_PHYS_ADDR:
msm_audio_get_handle((int)ioctl_param, &mem_handle); msm_audio_get_handle((int)ioctl_param, &mem_handle);
ret = msm_audio_ion_free(mem_handle); ret = msm_audio_ion_free(mem_handle, ion_data);
if (ret < 0) { if (ret < 0) {
pr_err("%s Ion free failed %d\n", __func__, ret); pr_err("%s Ion free failed %d\n", __func__, ret);
return ret; return ret;
@@ -694,14 +655,6 @@ static long msm_audio_ion_ioctl(struct file *file, unsigned int ioctl_num,
return ret; return ret;
} }
static int msm_audio_smmu_init(struct device *dev)
{
INIT_LIST_HEAD(&msm_audio_ion_data.alloc_list);
mutex_init(&(msm_audio_ion_data.list_mutex));
return 0;
}
static const struct of_device_id msm_audio_ion_dt_match[] = { static const struct of_device_id msm_audio_ion_dt_match[] = {
{ .compatible = "qcom,msm-audio-ion" }, { .compatible = "qcom,msm-audio-ion" },
{ .compatible = "qcom,msm-audio-ion-cma"}, { .compatible = "qcom,msm-audio-ion-cma"},
@@ -721,7 +674,7 @@ static int msm_audio_ion_reg_chrdev(struct msm_audio_ion_private *ion_data)
int ret = 0; int ret = 0;
ret = alloc_chrdev_region(&ion_data->ion_major, 0, ret = alloc_chrdev_region(&ion_data->ion_major, 0,
MINOR_NUMBER_COUNT, MSM_AUDIO_ION_DRIVER_NAME); MINOR_NUMBER_COUNT, ion_data->driver_name);
if (ret < 0) { if (ret < 0) {
pr_err("%s alloc_chr_dev_region failed ret : %d\n", pr_err("%s alloc_chr_dev_region failed ret : %d\n",
__func__, ret); __func__, ret);
@@ -729,7 +682,7 @@ static int msm_audio_ion_reg_chrdev(struct msm_audio_ion_private *ion_data)
} }
pr_debug("%s major number %d", __func__, MAJOR(ion_data->ion_major)); pr_debug("%s major number %d", __func__, MAJOR(ion_data->ion_major));
ion_data->ion_class = class_create(THIS_MODULE, ion_data->ion_class = class_create(THIS_MODULE,
MSM_AUDIO_ION_DRIVER_NAME); ion_data->driver_name);
if (IS_ERR(ion_data->ion_class)) { if (IS_ERR(ion_data->ion_class)) {
ret = PTR_ERR(ion_data->ion_class); ret = PTR_ERR(ion_data->ion_class);
pr_err("%s class create failed. ret : %d", __func__, ret); pr_err("%s class create failed. ret : %d", __func__, ret);
@@ -737,7 +690,7 @@ static int msm_audio_ion_reg_chrdev(struct msm_audio_ion_private *ion_data)
} }
ion_data->chardev = device_create(ion_data->ion_class, NULL, ion_data->chardev = device_create(ion_data->ion_class, NULL,
ion_data->ion_major, NULL, ion_data->ion_major, NULL,
MSM_AUDIO_ION_DRIVER_NAME); ion_data->driver_name);
if (IS_ERR(ion_data->chardev)) { if (IS_ERR(ion_data->chardev)) {
ret = PTR_ERR(ion_data->chardev); ret = PTR_ERR(ion_data->chardev);
pr_err("%s device create failed ret : %d\n", __func__, ret); pr_err("%s device create failed ret : %d\n", __func__, ret);
@@ -781,6 +734,8 @@ static int msm_audio_ion_probe(struct platform_device *pdev)
bool is_non_hypervisor_en; bool is_non_hypervisor_en;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct of_phandle_args iommuspec; struct of_phandle_args iommuspec;
struct msm_audio_ion_private *msm_audio_ion_data = NULL;
#ifndef CONFIG_SPF_CORE #ifndef CONFIG_SPF_CORE
enum apr_subsys_state q6_state; enum apr_subsys_state q6_state;
#endif #endif
@@ -790,26 +745,25 @@ static int msm_audio_ion_probe(struct platform_device *pdev)
dev_err(dev, dev_err(dev,
"%s: device tree is not found\n", "%s: device tree is not found\n",
__func__); __func__);
msm_audio_ion_data.smmu_enabled = 0;
return 0; return 0;
} }
msm_audio_ion_data = devm_kzalloc(&pdev->dev, (sizeof(struct msm_audio_ion_private)),
GFP_KERNEL);
if (!msm_audio_ion_data)
return -ENOMEM;
is_non_hypervisor_en = of_property_read_bool(dev->of_node, is_non_hypervisor_en = of_property_read_bool(dev->of_node,
msm_audio_ion_non_hyp); msm_audio_ion_non_hyp);
msm_audio_ion_data.is_non_hypervisor = is_non_hypervisor_en; msm_audio_ion_data->is_non_hypervisor = is_non_hypervisor_en;
if (of_device_is_compatible(dev->of_node, "qcom,msm-audio-ion-cma")) {
msm_audio_ion_data.cb_cma_dev = dev;
return 0;
}
smmu_enabled = of_property_read_bool(dev->of_node, smmu_enabled = of_property_read_bool(dev->of_node,
msm_audio_ion_dt); msm_audio_ion_dt);
msm_audio_ion_data.smmu_enabled = smmu_enabled; msm_audio_ion_data->smmu_enabled = smmu_enabled;
if (!smmu_enabled) { if (!smmu_enabled)
dev_dbg(dev, "%s: SMMU is Disabled\n", __func__); dev_dbg(dev, "%s: SMMU is Disabled\n", __func__);
goto exit;
}
#ifndef CONFIG_SPF_CORE #ifndef CONFIG_SPF_CORE
q6_state = apr_get_q6_state(); q6_state = apr_get_q6_state();
if (q6_state == APR_SUBSYS_DOWN) { if (q6_state == APR_SUBSYS_DOWN) {
@@ -820,10 +774,11 @@ static int msm_audio_ion_probe(struct platform_device *pdev)
} }
#endif #endif
dev_dbg(dev, "%s: adsp is ready\n", __func__); dev_dbg(dev, "%s: adsp is ready\n", __func__);
if (smmu_enabled) {
msm_audio_ion_data->driver_name = "msm_audio_ion";
rc = of_property_read_u32(dev->of_node, rc = of_property_read_u32(dev->of_node,
msm_audio_ion_smmu, msm_audio_ion_smmu,
&msm_audio_ion_data.smmu_version); &(msm_audio_ion_data->smmu_version));
if (rc) { if (rc) {
dev_err(dev, dev_err(dev,
"%s: qcom,smmu_version missing in DT node\n", "%s: qcom,smmu_version missing in DT node\n",
@@ -831,8 +786,7 @@ static int msm_audio_ion_probe(struct platform_device *pdev)
return rc; return rc;
} }
dev_dbg(dev, "%s: SMMU is Enabled. SMMU version is (%d)", dev_dbg(dev, "%s: SMMU is Enabled. SMMU version is (%d)",
__func__, msm_audio_ion_data.smmu_version); __func__, msm_audio_ion_data->smmu_version);
/* Get SMMU SID information from Devicetree */ /* Get SMMU SID information from Devicetree */
rc = of_property_read_u64(dev->of_node, rc = of_property_read_u64(dev->of_node,
msm_audio_ion_smmu_sid_mask, msm_audio_ion_smmu_sid_mask,
@@ -852,28 +806,23 @@ static int msm_audio_ion_probe(struct platform_device *pdev)
else else
smmu_sid = (iommuspec.args[0] & smmu_sid_mask); smmu_sid = (iommuspec.args[0] & smmu_sid_mask);
msm_audio_ion_data.smmu_sid_bits = msm_audio_ion_data->smmu_sid_bits =
smmu_sid << MSM_AUDIO_SMMU_SID_OFFSET; smmu_sid << MSM_AUDIO_SMMU_SID_OFFSET;
if (msm_audio_ion_data.smmu_version == 0x2) {
rc = msm_audio_smmu_init(dev);
} else {
dev_err(dev, "%s: smmu version invalid %d\n",
__func__, msm_audio_ion_data.smmu_version);
rc = -EINVAL;
} }
if (rc)
dev_err(dev, "%s: smmu init failed, err = %d\n",
__func__, rc);
exit:
if (!rc) if (!rc)
msm_audio_ion_data.device_status |= MSM_AUDIO_ION_PROBED; msm_audio_ion_data->device_status |= MSM_AUDIO_ION_PROBED;
msm_audio_ion_data.cb_dev = dev; msm_audio_ion_data->cb_dev = dev;
dev_set_drvdata(dev, msm_audio_ion_data);
INIT_LIST_HEAD(&msm_audio_ion_data.fd_list); if (!msm_audio_ion_fd_list_init) {
rc = msm_audio_ion_reg_chrdev(&msm_audio_ion_data); INIT_LIST_HEAD(&msm_audio_ion_fd_list.fd_list);
mutex_init(&(msm_audio_ion_fd_list.list_mutex));
msm_audio_ion_fd_list_init = true;
}
INIT_LIST_HEAD(&msm_audio_ion_data->alloc_list);
mutex_init(&(msm_audio_ion_data->list_mutex));
rc = msm_audio_ion_reg_chrdev(msm_audio_ion_data);
if (rc) { if (rc) {
pr_err("%s register char dev failed, rc : %d", __func__, rc); pr_err("%s register char dev failed, rc : %d", __func__, rc);
return rc; return rc;
@@ -883,13 +832,10 @@ exit:
static int msm_audio_ion_remove(struct platform_device *pdev) static int msm_audio_ion_remove(struct platform_device *pdev)
{ {
struct device *audio_cb_dev; struct msm_audio_ion_private *ion_data = dev_get_drvdata(&pdev->dev);
ion_data->smmu_enabled = 0;
audio_cb_dev = msm_audio_ion_data.cb_dev; ion_data->device_status = 0;
msm_audio_ion_unreg_chrdev(ion_data);
msm_audio_ion_data.smmu_enabled = 0;
msm_audio_ion_data.device_status = 0;
msm_audio_ion_unreg_chrdev(&msm_audio_ion_data);
return 0; return 0;
} }

View File

@@ -1,668 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mhi.h>
#include <linux/mutex.h>
#include "voice_mhi.h"
#include <dsp/msm_audio_ion.h>
#include <dsp/spf-core.h>
#include <dsp/audio_prm.h>
#include <ipc/gpr-lite.h>
#define VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG 0x080011E7
#define VOICE_MHI_STATE_SET(a, b) ((a) |= (1UL<<(b)))
#define VOICE_MHI_STATE_RESET(a, b) ((a) &= ~(1UL<<(b)))
#define VOICE_MHI_STATE_CHECK(a, b) (1UL & (a >> b))
#define CMD_STATUS_SUCCESS 0
#define CMD_STATUS_FAIL 1
#define TIMEOUT_MS 500
#define PORT_NUM 0x01
#define PORT_MASK 0x03
#define CONVERT_PORT_APR(x, y) (x << 8 | y)
#define VCPM_MODULE_INSTANCE_ID 0x00000004
#define APM_CMD_SET_CFG 0x01001006
enum voice_states {
VOICE_MHI_INIT = 0,
VOICE_MHI_PROBED = VOICE_MHI_INIT,
VOICE_MHI_ADSP_UP,
VOICE_MHI_SDX_UP,
VOICE_MHI_INCALL
};
struct voice_mhi_addr {
dma_addr_t base;
uint32_t size;
};
struct voice_mhi_dev_info {
struct platform_device *pdev;
struct voice_mhi_addr phys_addr;
struct voice_mhi_addr iova_pcie;
struct voice_mhi_addr iova_adsp;
};
struct voice_mhi {
struct voice_mhi_dev_info dev_info;
struct mhi_device *mhi_dev;
uint32_t vote_count;
struct mutex mutex;
enum voice_states voice_mhi_state;
bool vote_enable;
bool pcie_enabled;
struct gpr_device *gdev;
struct work_struct voice_mhi_work_pcie;
struct work_struct voice_mhi_work_adsp;
wait_queue_head_t voice_mhi_wait;
u32 mvm_state;
u32 async_err;
};
typedef struct vcpm_param_id_mailbox_memory_config_t
{
uint32_t mailbox_mem_address_adsp_lsw;
/**< Lower 32 bits of IO virtual address(understandable to ADSP) of Mailbox Memory carved out from APQ DDR
specifically for mailbox packet exchange between ADSP and MDM. */
uint32_t mailbox_mem_address_adsp_msw;
/**< Upper 32 bits of IO virtual address(understandable to ADSP) of Mailbox Memory carved out from APQ DDR
specifically for mailbox packet exchange between ADSP and MDM. */
uint32_t mailbox_mem_address_pcie_lsw;
/**< Lower 32 bits of IO virtual address(understandable to PCIe) of Mailbox Memory carved out from APQ DDR
specifically for mailbox packet exchange between ADSP and MDM. */
uint32_t mailbox_mem_address_pcie_msw;
/**< Upper 32 bits of IO virtual address(understandable to PCIe) of Mailbox Memory carved out from APQ DDR
specifically for mailbox packet exchange between ADSP and MDM. */
uint32_t mem_size;
/**< Size(in bytes) of the Mailbox Memory carved out from APQ DDR.
*/
}vcpm_param_id_mailbox_memory_config_t;
typedef struct vcpm_cmd_set_cfg_t {
apm_cmd_header_t payload_header;
apm_module_param_data_t module_payload;
vcpm_param_id_mailbox_memory_config_t mb_memory_config;
}vcpm_cmd_set_cfg_t;
static struct voice_mhi voice_mhi_lcl;
static int voice_mhi_pcie_up_callback(struct mhi_device *,
const struct mhi_device_id *);
static void voice_mhi_pcie_down_callback(struct mhi_device *);
static void voice_mhi_pcie_status_callback(struct mhi_device *, enum MHI_CB);
static int32_t voice_mhi_gpr_callback(struct gpr_device *adev, void *data);
//static int voice_mhi_notifier_service_cb(struct notifier_block *nb,
// unsigned long opcode, void *ptr);
// static struct notifier_block voice_mhi_service_nb = {
// .notifier_call = voice_mhi_notifier_service_cb,
// .priority = -INT_MAX,
// };
static const struct mhi_device_id voice_mhi_match_table[] = {
{ .chan = "AUDIO_VOICE_0", .driver_data = 0 },
{},
};
static struct mhi_driver voice_mhi_driver = {
.id_table = voice_mhi_match_table,
.probe = voice_mhi_pcie_up_callback,
.remove = voice_mhi_pcie_down_callback,
.status_cb = voice_mhi_pcie_status_callback,
.driver = {
.name = "voice_mhi_audio",
.owner = THIS_MODULE,
},
};
// static int voice_mhi_notifier_service_cb(struct notifier_block *nb,
// unsigned long opcode, void *ptr)
// {
// pr_err("%s: opcode 0x%lx\n", __func__, opcode);
// switch (opcode) {
// case AUDIO_NOTIFIER_SERVICE_DOWN:
// if (voice_mhi_lcl.apr_mvm_handle) {
// apr_reset(voice_mhi_lcl.apr_mvm_handle);
// voice_mhi_lcl.apr_mvm_handle = NULL;
// VOICE_MHI_STATE_RESET(voice_mhi_lcl.voice_mhi_state,
// VOICE_MHI_ADSP_UP);
// }
// break;
// case AUDIO_NOTIFIER_SERVICE_UP:
// if (!VOICE_MHI_STATE_CHECK(voice_mhi_lcl.voice_mhi_state,
// VOICE_MHI_ADSP_UP)) {
// VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state,
// VOICE_MHI_ADSP_UP);
// schedule_work(&voice_mhi_lcl.voice_mhi_work_adsp);
// }
// break;
// default:
// break;
// }
// return NOTIFY_OK;
// }
static int32_t voice_mhi_gpr_callback(struct gpr_device *adev, void *data)
{
struct gpr_hdr *hdr = (struct gpr_hdr *)data;
uint32_t *payload = GPR_PKT_GET_PAYLOAD(uint32_t, data);
//bool resp_recieved = false;
if (data == NULL) {
pr_err("%s: data is NULL\n", __func__);
return -EINVAL;
}
switch (hdr->opcode) {
case GPR_IBASIC_RSP_RESULT:
pr_err("%s: GPR_IBASIC_RSP_RESULT received",__func__);
voice_mhi_lcl.mvm_state = CMD_STATUS_SUCCESS;
voice_mhi_lcl.async_err = payload[1];
wake_up(&voice_mhi_lcl.voice_mhi_wait);
break;
case VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG:
pr_err("%s: cmd VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG\n",
__func__);
voice_mhi_lcl.mvm_state = CMD_STATUS_SUCCESS;
voice_mhi_lcl.async_err = payload[1];
wake_up(&voice_mhi_lcl.voice_mhi_wait);
break;
default:
pr_err("%s: Invalid opcode %d\n", __func__,
hdr->opcode);
break;
}
return 0;
}
/**
* voice_mhi_start -
* Start vote for MHI/PCIe clock
*
* Returns 0 on success or error on failure
*/
int voice_mhi_start(void)
{
int ret = 0;
mutex_lock(&voice_mhi_lcl.mutex);
if (voice_mhi_lcl.pcie_enabled) {
if (!voice_mhi_lcl.mhi_dev) {
pr_err("%s: NULL device found\n", __func__);
ret = -EINVAL;
goto done;
}
if (voice_mhi_lcl.vote_count == 0) {
ret = mhi_device_get_sync(voice_mhi_lcl.mhi_dev,
MHI_VOTE_DEVICE);
if (ret) {
pr_err("%s: mhi_device_get_sync failed\n",
__func__);
ret = -EINVAL;
goto done;
}
pr_err("%s: mhi_device_get_sync success\n", __func__);
} else {
/* For DSDA, no additional voting is needed */
pr_err("%s: mhi is already voted\n", __func__);
}
voice_mhi_lcl.vote_count++;
} else {
/* PCIe not supported - return success*/
goto done;
}
done:
mutex_unlock(&voice_mhi_lcl.mutex);
return ret;
}
EXPORT_SYMBOL(voice_mhi_start);
/**
* voice_mhi_end -
* End vote for MHI/PCIe clock
*
* Returns 0 on success or error on failure
*/
int voice_mhi_end(void)
{
mutex_lock(&voice_mhi_lcl.mutex);
if (voice_mhi_lcl.pcie_enabled) {
if (!voice_mhi_lcl.mhi_dev || voice_mhi_lcl.vote_count == 0) {
pr_err("%s: NULL device found\n", __func__);
mutex_unlock(&voice_mhi_lcl.mutex);
return -EINVAL;
}
if (voice_mhi_lcl.vote_count == 1)
mhi_device_put(voice_mhi_lcl.mhi_dev, MHI_VOTE_DEVICE);
voice_mhi_lcl.vote_count--;
}
mutex_unlock(&voice_mhi_lcl.mutex);
return 0;
}
EXPORT_SYMBOL(voice_mhi_end);
static int voice_mhi_set_mailbox_memory_config(void)
{
struct gpr_pkt *pkt;
int ret = 0;
struct gpr_device *gdev;
vcpm_cmd_set_cfg_t vcpm_set_cfg;
uint32_t size;
//return 0;
size = GPR_HDR_SIZE + sizeof (vcpm_cmd_set_cfg_t);
pkt = kzalloc(size, GFP_KERNEL);
if (!pkt) {
pr_err("%s: memory allocation failed\n", __func__);
return -ENOMEM;
}
if (!voice_mhi_lcl.gdev) {
pr_err("%s: GPR handle is NULL\n", __func__);
return -EINVAL;
}
memset(pkt, 0, sizeof(struct gpr_pkt));
memset(&vcpm_set_cfg, 0, sizeof(vcpm_cmd_set_cfg_t));
pkt->hdr.header = GPR_SET_FIELD(GPR_PKT_VERSION, GPR_PKT_VER) |
GPR_SET_FIELD(GPR_PKT_HEADER_SIZE, GPR_PKT_HEADER_WORD_SIZE_V) |
GPR_SET_FIELD(GPR_PKT_PACKET_SIZE, size);
pkt->hdr.opcode = APM_CMD_SET_CFG;
pkt->hdr.dst_port = VCPM_MODULE_INSTANCE_ID;
pkt->hdr.src_port = GPR_SVC_VPM;
pkt->hdr.dst_domain_id = GPR_IDS_DOMAIN_ID_ADSP_V;
pkt->hdr.src_domain_id = GPR_IDS_DOMAIN_ID_APPS_V;
mutex_lock(&voice_mhi_lcl.mutex);
gdev = voice_mhi_lcl.gdev;
/*
* Handle can be NULL as it is not tied to any session
*/
vcpm_set_cfg.payload_header.payload_address_lsw = 0;
vcpm_set_cfg.payload_header.payload_address_msw = 0;
vcpm_set_cfg.payload_header.mem_map_handle = 0;
vcpm_set_cfg.payload_header.payload_size = sizeof(vcpm_cmd_set_cfg_t) - sizeof(apm_cmd_header_t);
vcpm_set_cfg.module_payload.module_instance_id = VCPM_MODULE_INSTANCE_ID;
vcpm_set_cfg.module_payload.error_code = 0;
vcpm_set_cfg.module_payload.param_id = VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG;
vcpm_set_cfg.module_payload.param_size =
sizeof(vcpm_cmd_set_cfg_t) - sizeof(apm_cmd_header_t) - sizeof(apm_module_param_data_t);
vcpm_set_cfg.mb_memory_config.mailbox_mem_address_pcie_lsw =
(uint32_t) voice_mhi_lcl.dev_info.iova_pcie.base;
vcpm_set_cfg.mb_memory_config.mailbox_mem_address_pcie_msw =
(uint64_t) voice_mhi_lcl.dev_info.iova_pcie.base >> 32;
vcpm_set_cfg.mb_memory_config.mailbox_mem_address_adsp_lsw =
(uint32_t) voice_mhi_lcl.dev_info.iova_adsp.base;
vcpm_set_cfg.mb_memory_config.mailbox_mem_address_adsp_msw =
(uint64_t) voice_mhi_lcl.dev_info.iova_adsp.base >> 32;
vcpm_set_cfg.mb_memory_config.mem_size = voice_mhi_lcl.dev_info.iova_adsp.size;
voice_mhi_lcl.mvm_state = CMD_STATUS_FAIL;
voice_mhi_lcl.async_err = 0;
memcpy(&pkt->payload, &vcpm_set_cfg, sizeof(vcpm_cmd_set_cfg_t));
ret = gpr_send_pkt(gdev, pkt);
if (ret < 0) {
pr_err("%s: Set mailbox memory config failed ret = %d\n",
__func__, ret);
goto unlock;
}
ret = wait_event_timeout(voice_mhi_lcl.voice_mhi_wait,
(voice_mhi_lcl.mvm_state ==
CMD_STATUS_SUCCESS),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -ETIME;
goto unlock;
}
if (voice_mhi_lcl.async_err > 0) {
pr_err("%s: DSP returned error[%d]\n",
__func__, voice_mhi_lcl.async_err);
ret = voice_mhi_lcl.async_err;
goto unlock;
}
ret = 0;
unlock:
mutex_unlock(&voice_mhi_lcl.mutex);
return ret;
}
static void voice_mhi_map_pcie_and_send(struct work_struct *work)
{
dma_addr_t iova, phys_addr;
uint32_t mem_size;
struct device *md;
mutex_lock(&voice_mhi_lcl.mutex);
if (voice_mhi_lcl.mhi_dev) {
md = &voice_mhi_lcl.mhi_dev->dev;
} else {
pr_err("%s: MHI device handle is NULL\n", __func__);
goto err;
}
phys_addr = voice_mhi_lcl.dev_info.phys_addr.base;
mem_size = voice_mhi_lcl.dev_info.iova_pcie.size;
if (md) {
iova = dma_map_resource(md->parent, phys_addr, mem_size,
DMA_BIDIRECTIONAL, 0);
if (dma_mapping_error(md->parent, iova)) {
pr_err("%s: dma_mapping_error\n", __func__);
goto err;
}
pr_err("%s: dma_mapping_success iova:0x%lx\n",
__func__, (unsigned long)iova);
voice_mhi_lcl.dev_info.iova_pcie.base = iova;
mutex_unlock(&voice_mhi_lcl.mutex);
if (spf_core_is_apm_ready()) {
voice_mhi_set_mailbox_memory_config();
voice_mhi_start();
}
return;
}
err:
mutex_unlock(&voice_mhi_lcl.mutex);
return;
}
static void voice_mhi_gpr_send(struct work_struct *work)
{
// ret = voice_mhi_apr_register();
// if (ret) {
// pr_err("%s: APR registration failed %d\n", __func__, ret);
// return;
// }
pr_err("%s: GPR is up \n", __func__);
mutex_lock(&voice_mhi_lcl.mutex);
if (VOICE_MHI_STATE_CHECK(voice_mhi_lcl.voice_mhi_state,
VOICE_MHI_SDX_UP)) {
mutex_unlock(&voice_mhi_lcl.mutex);
if (spf_core_is_apm_ready()) {
voice_mhi_set_mailbox_memory_config();
voice_mhi_start();
return;
} else {
pr_err("%s: Gecko core not ready \n", __func__);
}
} else {
mutex_unlock(&voice_mhi_lcl.mutex);
schedule_work(&voice_mhi_lcl.voice_mhi_work_adsp);
}
}
static int voice_mhi_pcie_up_callback(struct mhi_device *voice_mhi_dev,
const struct mhi_device_id *id)
{
if ((!voice_mhi_dev) || (id != &voice_mhi_match_table[0])) {
pr_err("%s: Invalid device or table received\n", __func__);
return -EINVAL;
}
pr_err("%s: MHI PCIe UP callback\n", __func__);
mutex_lock(&voice_mhi_lcl.mutex);
voice_mhi_lcl.mhi_dev = voice_mhi_dev;
VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state, VOICE_MHI_SDX_UP);
mutex_unlock(&voice_mhi_lcl.mutex);
schedule_work(&voice_mhi_lcl.voice_mhi_work_pcie);
return 0;
}
static void voice_mhi_pcie_down_callback(struct mhi_device *voice_mhi_dev)
{
dma_addr_t iova;
struct device *md = NULL;
mutex_lock(&voice_mhi_lcl.mutex);
if (voice_mhi_lcl.mhi_dev)
md = &voice_mhi_lcl.mhi_dev->dev;
VOICE_MHI_STATE_RESET(voice_mhi_lcl.voice_mhi_state, VOICE_MHI_SDX_UP);
iova = voice_mhi_lcl.dev_info.iova_pcie.base;
if (md)
dma_unmap_resource(md->parent, iova, PAGE_SIZE,
DMA_BIDIRECTIONAL, 0);
voice_mhi_lcl.mhi_dev = NULL;
voice_mhi_lcl.vote_count = 0;
mutex_unlock(&voice_mhi_lcl.mutex);
}
static void voice_mhi_pcie_status_callback(struct mhi_device *voice_mhi_dev,
enum MHI_CB mhi_cb)
{
}
static int voice_mhi_gpr_probe(struct gpr_device *gdev)
{
int ret = 0;
pr_err("%s Enter ", __func__);
mutex_lock(&voice_mhi_lcl.mutex);
voice_mhi_lcl.gdev = gdev;
VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state,
VOICE_MHI_ADSP_UP);
mutex_unlock(&voice_mhi_lcl.mutex);
//schedule_work(&voice_mhi_lcl.voice_mhi_work_adsp);
pr_err("%s Exit ", __func__);
return ret;
}
static int voice_mhi_gpr_exit(struct gpr_device *gdev)
{
voice_mhi_end();
mutex_lock(&voice_mhi_lcl.mutex);
voice_mhi_lcl.gdev = NULL;
VOICE_MHI_STATE_RESET(voice_mhi_lcl.voice_mhi_state,
VOICE_MHI_ADSP_UP);
mutex_unlock(&voice_mhi_lcl.mutex);
return 0;
}
static const struct of_device_id voice_mhi_gpr_device_id[] = {
{ .compatible = "qcom,voice_mhi_gpr" },
{},
};
MODULE_DEVICE_TABLE(of, voice_mhi_gpr_device_id);
static struct gpr_driver voice_mhi_gpr_driver = {
.probe = voice_mhi_gpr_probe,
.remove = voice_mhi_gpr_exit,
.callback = voice_mhi_gpr_callback,
.driver = {
.name = "qcom-voice_mhi_gpr",
.of_match_table = of_match_ptr(voice_mhi_gpr_device_id),
},
};
// static int voice_mhi_apr_register(void)
// {
// int ret = 0;
// mutex_lock(&voice_mhi_lcl.mutex);
// voice_mhi_lcl.apr_mvm_handle = apr_register("ADSP", "MVM",
// (apr_fn)voice_mhi_apr_callback,
// CONVERT_PORT_APR(PORT_NUM,
// PORT_MASK),
// &voice_mhi_lcl);
// if (voice_mhi_lcl.apr_mvm_handle == NULL) {
// pr_err("%s: error in APR register\n", __func__);
// ret = -ENODEV;
// }
// mutex_unlock(&voice_mhi_lcl.mutex);
// return ret;
// }
static int voice_mhi_probe(struct platform_device *pdev)
{
int ret = 0;
struct device_node *node;
uint32_t mem_size = 0;
void *ptr;
dma_addr_t phys_addr, iova;
const __be32 *cell;
pr_err("%s: Enter\n", __func__);
memset(&voice_mhi_lcl, 0, sizeof(voice_mhi_lcl));
mutex_init(&voice_mhi_lcl.mutex);
/* Add remaining init here */
voice_mhi_lcl.pcie_enabled = false;
voice_mhi_lcl.voice_mhi_state = VOICE_MHI_INIT;
voice_mhi_lcl.vote_count = 0;
voice_mhi_lcl.gdev = NULL;
INIT_WORK(&voice_mhi_lcl.voice_mhi_work_pcie,
voice_mhi_map_pcie_and_send);
INIT_WORK(&voice_mhi_lcl.voice_mhi_work_adsp,
voice_mhi_gpr_send);
init_waitqueue_head(&voice_mhi_lcl.voice_mhi_wait);
node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
if (node) {
cell = of_get_property(node, "size", NULL);
if (cell)
mem_size = of_read_number(cell, 2);
else {
pr_err("%s: cell not found\n", __func__);
ret = -EINVAL;
goto done;
}
} else {
pr_err("%s: Node read failed\n", __func__);
ret = -EINVAL;
goto done;
}
pr_err("%s: mem_size = %d\n", __func__, mem_size);
if (mem_size) {
ptr = dma_alloc_attrs(&pdev->dev, mem_size, &phys_addr,
GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
if (IS_ERR_OR_NULL(ptr)) {
pr_err("%s: Memory alloc failed\n", __func__);
ret = -ENOMEM;
goto done;
} else {
pr_err("%s: Memory alloc success phys_addr:0x%lx\n",
__func__, (unsigned long)phys_addr);
}
ret = msm_audio_ion_dma_map(&phys_addr, &iova, mem_size,
DMA_BIDIRECTIONAL);
if (ret) {
pr_err("%s: dma mapping failed %d\n", __func__, ret);
goto err_free;
}
pr_err("%s: dma_mapping_success iova:0x%lx\n",
__func__, (unsigned long)iova);
voice_mhi_lcl.dev_info.iova_adsp.size = mem_size;
voice_mhi_lcl.dev_info.iova_pcie.size = mem_size;
voice_mhi_lcl.dev_info.pdev = pdev;
voice_mhi_lcl.dev_info.phys_addr.base = phys_addr;
voice_mhi_lcl.dev_info.iova_adsp.base = iova;
ret = gpr_driver_register(&voice_mhi_gpr_driver);
if (ret) {
pr_err("%s: gpr driver register failed = %d\n",
__func__, ret);
ret = -EINVAL;
goto err_free;
}
pr_err("%s: gpr register success",__func__);
ret = mhi_driver_register(&voice_mhi_driver);
if (ret) {
pr_err("%s: mhi register failed %d\n", __func__, ret);
goto err_free;
}
mutex_lock(&voice_mhi_lcl.mutex);
voice_mhi_lcl.pcie_enabled = true;
VOICE_MHI_STATE_SET(voice_mhi_lcl.voice_mhi_state,
VOICE_MHI_PROBED);
mutex_unlock(&voice_mhi_lcl.mutex);
} else {
pr_err("%s: Memory size can't be zero\n", __func__);
ret = -ENOMEM;
goto done;
}
done:
return ret;
err_free:
dma_free_attrs(&pdev->dev, mem_size, ptr, phys_addr,
DMA_ATTR_NO_KERNEL_MAPPING);
return ret;
}
static int voice_mhi_remove(struct platform_device *pdev)
{
if (voice_mhi_lcl.gdev)
voice_mhi_lcl.gdev = NULL;
mhi_driver_unregister(&voice_mhi_driver);
gpr_driver_unregister(&voice_mhi_gpr_driver);
memset(&voice_mhi_lcl, 0, sizeof(voice_mhi_lcl));
mutex_destroy(&voice_mhi_lcl.mutex);
return 0;
}
static const struct of_device_id voice_mhi_of_match[] = {
{ .compatible = "qcom,voice-mhi-audio", },
{},
};
static struct platform_driver voice_mhi_platform_driver = {
.probe = voice_mhi_probe,
.remove = voice_mhi_remove,
.driver = {
.name = "voice_mhi_audio",
.owner = THIS_MODULE,
.of_match_table = voice_mhi_of_match,
.suppress_bind_attrs = true,
}
};
module_platform_driver(voice_mhi_platform_driver);
MODULE_DESCRIPTION("Voice MHI module");
MODULE_LICENSE("GPL v2");

View File

@@ -1,24 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef __VOICE_MHI_H__
#define __VOICE_MHI_H__
#ifdef CONFIG_VOICE_MHI
int voice_mhi_start(void);
int voice_mhi_end(void);
#else
static inline int voice_mhi_start(void)
{
return 0;
}
static inline int voice_mhi_end(void)
{
return 0;
}
#endif
#endif

View File

@@ -27,8 +27,6 @@ struct audio_buffer {
uint32_t actual_size; /* actual number of bytes read by DSP */ uint32_t actual_size; /* actual number of bytes read by DSP */
struct dma_buf *dma_buf; struct dma_buf *dma_buf;
}; };
int msm_audio_ion_dma_map(dma_addr_t *phys_addr, dma_addr_t *iova_base,
u32 size, enum dma_data_direction dir);
int msm_audio_get_phy_addr(int fd, dma_addr_t *paddr); int msm_audio_get_phy_addr(int fd, dma_addr_t *paddr);
void msm_audio_ion_crash_handler(void); void msm_audio_ion_crash_handler(void);
#endif /* _LINUX_MSM_AUDIO_ION_H */ #endif /* _LINUX_MSM_AUDIO_ION_H */