Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1992b451 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ADSPRPC: Support for RPC to multiple DSP processors"

parents 0298082a 7d1e7b42
Loading
Loading
Loading
Loading
+190 −133
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
#define RPC_HASH_BITS	5
#define RPC_HASH_SZ	(1 << RPC_HASH_BITS)
#define BALIGN		32
#define NUM_CHANNELS    2

#define LOCK_MMAP(kernel)\
		do {\
@@ -127,6 +128,7 @@ static inline int buf_get_pages(void *addr, int sz, int nr_pages, int access,
struct smq_invoke_ctx {
	struct completion work;
	int retval;
	int cid;
	atomic_t free;
};

@@ -143,20 +145,24 @@ struct fastrpc_smmu {
	bool enabled;
};

struct fastrpc_apps {
struct fastrpc_channel_context {
	smd_channel_t *chan;
	struct smq_context_list clst;
	struct device *dev;
	struct completion work;
	struct fastrpc_smmu smmu;
	struct kref kref;
};

struct fastrpc_apps {
	struct fastrpc_channel_context channel[NUM_CHANNELS];
	struct smq_context_list clst;
	struct ion_client *iclient;
	struct cdev cdev;
	struct class *class;
	struct device *dev;
	struct fastrpc_smmu smmu;
	struct mutex smd_mutex;
	dev_t dev_no;
	spinlock_t wrlock;
	spinlock_t hlock;
	struct kref kref;
	struct hlist_head htbl[RPC_HASH_SZ];
};

@@ -181,6 +187,7 @@ struct file_data {
	spinlock_t hlock;
	struct hlist_head hlst;
	uint32_t mode;
	int cid;
};

struct fastrpc_device {
@@ -189,16 +196,36 @@ struct fastrpc_device {
	struct fastrpc_buf buf;
};

struct fastrpc_channel_info {
	char *name;
	char *node;
	char *group;
	int channel;
};

static struct fastrpc_apps gfa;

static void free_mem(struct fastrpc_buf *buf)
static const struct fastrpc_channel_info gcinfo[NUM_CHANNELS] = {
	{
		.name = "adsprpc-smd",
		.node = "qcom,msm-audio-ion",
		.group = "lpass_audio",
		.channel = SMD_APPS_QDSP,
	},
	{
		.name = "mdsprpc-smd",
		.channel = SMD_APPS_MODEM,
	},
};

static void free_mem(struct fastrpc_buf *buf, int cid)
{
	struct fastrpc_apps *me = &gfa;

	if (!IS_ERR_OR_NULL(buf->handle)) {
		if (me->smmu.enabled && buf->phys) {
		if (me->channel[cid].smmu.enabled && buf->phys) {
			ion_unmap_iommu(me->iclient, buf->handle,
					me->smmu.domain_id, 0);
					me->channel[cid].smmu.domain_id, 0);
			buf->phys = 0;
		}
		if (!IS_ERR_OR_NULL(buf->virt)) {
@@ -223,7 +250,7 @@ static void free_map(struct fastrpc_mmap *map)
	map->handle = 0;
}

static int alloc_mem(struct fastrpc_buf *buf)
static int alloc_mem(struct fastrpc_buf *buf, int cid)
{
	struct fastrpc_apps *me = &gfa;
	struct ion_client *clnt = gfa.iclient;
@@ -234,7 +261,7 @@ static int alloc_mem(struct fastrpc_buf *buf)
	buf->handle = 0;
	buf->virt = 0;
	buf->phys = 0;
	heap = me->smmu.enabled ? ION_HEAP(ION_IOMMU_HEAP_ID) :
	heap = me->channel[cid].smmu.enabled ? ION_HEAP(ION_IOMMU_HEAP_ID) :
		ION_HEAP(ION_ADSP_HEAP_ID) | ION_HEAP(ION_AUDIO_HEAP_ID);
	buf->handle = ion_alloc(clnt, buf->size, SZ_4K, heap, ION_FLAG_CACHED);
	VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
@@ -244,11 +271,11 @@ static int alloc_mem(struct fastrpc_buf *buf)
	VERIFY(err, 0 == IS_ERR_OR_NULL(buf->virt));
	if (err)
		goto bail;
	if (me->smmu.enabled) {
	if (me->channel[cid].smmu.enabled) {
		len = buf->size;
		VERIFY(err, 0 == ion_map_iommu(clnt, buf->handle,
					me->smmu.domain_id, 0, SZ_4K, 0,
					&buf->phys, &len, 0, 0));
					me->channel[cid].smmu.domain_id, 0,
					SZ_4K, 0, &buf->phys, &len, 0, 0));
		if (err)
			goto bail;
	} else {
@@ -259,7 +286,7 @@ static int alloc_mem(struct fastrpc_buf *buf)
	}
 bail:
	if (err && !IS_ERR_OR_NULL(buf->handle))
		free_mem(buf);
		free_mem(buf, cid);
	return err;
}

@@ -281,7 +308,7 @@ static void context_list_dtor(struct smq_context_list *me)
}

static void context_list_alloc_ctx(struct smq_context_list *me,
					struct smq_invoke_ctx **po)
				struct smq_invoke_ctx **po, int cid)
{
	int i = me->last;
	struct smq_invoke_ctx *ctx;
@@ -296,6 +323,7 @@ static void context_list_alloc_ctx(struct smq_context_list *me,
	}
	me->last = i;
	ctx->retval = -1;
	ctx->cid = cid;
	init_completion(&ctx->work);
	*po = ctx;
}
@@ -312,20 +340,21 @@ static void context_notify_user(struct smq_invoke_ctx *me, int retval)
	complete(&me->work);
}

static void context_notify_all_users(struct smq_context_list *me)
static void context_notify_all_users(struct smq_context_list *me, int cid)
{
	int i;

	if (!me->ls)
		return;
	for (i = 0; i < me->size; ++i) {
		if (atomic_read(&me->ls[i].free) != 0)
		if ((atomic_read(&me->ls[i].free) != 0) &&
			(me->ls[i].cid == cid))
			complete(&me->ls[i].work);
	}
}

static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
			struct fastrpc_buf *ibuf, struct fastrpc_buf *obuf)
		struct fastrpc_buf *ibuf, struct fastrpc_buf *obuf, int cid)
{
	struct smq_phy_page *pgstart, *pages;
	struct smq_invoke_buf *list;
@@ -343,7 +372,7 @@ static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
	if (rlen < 0) {
		rlen = ((uint32_t)pages - (uint32_t)obuf->virt) - obuf->size;
		obuf->size += buf_page_size(rlen);
		VERIFY(err, 0 == alloc_mem(obuf));
		VERIFY(err, 0 == alloc_mem(obuf, cid));
		if (err)
			goto bail;
		goto retry;
@@ -380,9 +409,9 @@ static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
			pages = pages + 1;
		} else {
			if (obuf->handle != ibuf->handle)
				free_mem(obuf);
				free_mem(obuf, cid);
			obuf->size += buf_page_size(sizeof(*pages));
			VERIFY(err, 0 == alloc_mem(obuf));
			VERIFY(err, 0 == alloc_mem(obuf, cid));
			if (err)
				goto bail;
			goto retry;
@@ -392,7 +421,7 @@ static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
	obuf->used = obuf->size - rlen;
 bail:
	if (err && (obuf->handle != ibuf->handle))
		free_mem(obuf);
		free_mem(obuf, cid);
	UNLOCK_MMAP(kernel);
	return err;
}
@@ -400,7 +429,7 @@ static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
			remote_arg_t *rpra, remote_arg_t *upra,
			struct fastrpc_buf *ibuf, struct fastrpc_buf **abufs,
			int *nbufs, int *fds)
			int *nbufs, int *fds, int cid)
{
	struct fastrpc_apps *me = &gfa;
	struct smq_invoke_buf *list;
@@ -429,15 +458,16 @@ static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
		if (list[i].num) {
			rpra[i].buf.pv = pra[i].buf.pv;
			continue;
		} else if (me->smmu.enabled && fds && (fds[i] >= 0)) {
		} else if (me->channel[cid].smmu.enabled &&
					fds && (fds[i] >= 0)) {
			len = buf_page_size(pra[i].buf.len);
			handles[i] = ion_import_dma_buf(me->iclient, fds[i]);
			VERIFY(err, 0 == IS_ERR_OR_NULL(handles[i]));
			if (err)
				goto bail;
			VERIFY(err, 0 == ion_map_iommu(me->iclient, handles[i],
						me->smmu.domain_id, 0, SZ_4K, 0,
						&iova, &len, 0, 0));
					me->channel[cid].smmu.domain_id,
					0, SZ_4K, 0, &iova, &len, 0, 0));
			if (err)
				goto bail;
			rpra[i].buf.pv = pra[i].buf.pv;
@@ -457,7 +487,7 @@ static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
			pbuf = obufs + bufs;
			pbuf->size = buf_num_pages(0, pra[i].buf.len) *
								PAGE_SIZE;
			VERIFY(err, 0 == alloc_mem(pbuf));
			VERIFY(err, 0 == alloc_mem(pbuf, cid));
			if (err)
				goto bail;
			bufs++;
@@ -604,7 +634,7 @@ static int fastrpc_invoke_send(struct fastrpc_apps *me,
	msg.invoke.page.addr = buf->phys;
	msg.invoke.page.size = buf_page_size(buf->used);
	spin_lock(&me->wrlock);
	len = smd_write(me->chan, &msg, sizeof(msg));
	len = smd_write(me->channel[ctx->cid].chan, &msg, sizeof(msg));
	spin_unlock(&me->wrlock);
	VERIFY(err, len == sizeof(msg));
	return err;
@@ -613,23 +643,29 @@ static int fastrpc_invoke_send(struct fastrpc_apps *me,
static void fastrpc_deinit(void)
{
	struct fastrpc_apps *me = &gfa;
	int i;

	smd_close(me->chan);
	for (i = 0; i < NUM_CHANNELS; i++) {
		if (me->channel[i].chan) {
			(void)smd_close(me->channel[i].chan);
			me->channel[i].chan = 0;
		}
	}
	context_list_dtor(&me->clst);
	ion_client_destroy(me->iclient);
	me->iclient = 0;
	me->chan = 0;
}

static void fastrpc_read_handler(void)
static void fastrpc_read_handler(int cid)
{
	struct fastrpc_apps *me = &gfa;
	struct smq_invoke_rsp rsp;
	int err = 0;

	do {
		VERIFY(err, sizeof(rsp) ==
				 smd_read_from_cb(me->chan, &rsp, sizeof(rsp)));
		VERIFY(err, sizeof(rsp) == smd_read_from_cb(
							me->channel[cid].chan,
							&rsp, sizeof(rsp)));
		if (err)
			goto bail;
		context_notify_user(rsp.ctx, rsp.retval);
@@ -640,33 +676,32 @@ static void fastrpc_read_handler(void)

static void smd_event_handler(void *priv, unsigned event)
{
	struct fastrpc_apps *me = (struct fastrpc_apps *)priv;
	struct fastrpc_apps *me = &gfa;
	int cid = (int)priv;

	switch (event) {
	case SMD_EVENT_OPEN:
		complete(&(me->work));
		complete(&me->channel[cid].work);
		break;
	case SMD_EVENT_CLOSE:
		context_notify_all_users(&me->clst);
		context_notify_all_users(&me->clst, cid);
		break;
	case SMD_EVENT_DATA:
		fastrpc_read_handler();
		fastrpc_read_handler(cid);
		break;
	}
}

static int fastrpc_init(void)
{
	int err = 0;
	int i, err = 0;
	struct fastrpc_apps *me = &gfa;
	struct device_node *node;
	struct fastrpc_smmu *smmu;
	bool enabled = 0;

	if (me->chan == 0) {
		int i;
	spin_lock_init(&me->hlock);
	spin_lock_init(&me->wrlock);
		init_completion(&me->work);
	mutex_init(&me->smd_mutex);
	for (i = 0; i < RPC_HASH_SZ; ++i)
		INIT_HLIST_HEAD(&me->htbl[i]);
@@ -678,24 +713,25 @@ static int fastrpc_init(void)
	VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
	if (err)
		goto ion_bail;
		node = of_find_compatible_node(NULL, NULL,
						"qcom,msm-audio-ion");
	for (i = 0; i < NUM_CHANNELS; i++) {
		init_completion(&me->channel[i].work);
		if (!gcinfo[i].node)
			continue;
		smmu = &me->channel[i].smmu;
		node = of_find_compatible_node(NULL, NULL, gcinfo[i].node);
		if (node)
			enabled = of_property_read_bool(node,
						"qcom,smmu-enabled");
		if (enabled)
			me->smmu.group = iommu_group_find("lpass_audio");
		if (me->smmu.group)
			me->smmu.domain = iommu_group_get_iommudata(
							me->smmu.group);
		if (!IS_ERR_OR_NULL(me->smmu.domain)) {
			me->smmu.domain_id = msm_find_domain_no(
							me->smmu.domain);
			if (me->smmu.domain_id >= 0)
				me->smmu.enabled = enabled;
			smmu->group = iommu_group_find(gcinfo[i].group);
		if (smmu->group)
			smmu->domain = iommu_group_get_iommudata(smmu->group);
		if (!IS_ERR_OR_NULL(smmu->domain)) {
			smmu->domain_id = msm_find_domain_no(smmu->domain);
			if (smmu->domain_id >= 0)
				smmu->enabled = enabled;
		}
	}

	return 0;

ion_bail:
@@ -704,16 +740,16 @@ context_list_bail:
	return err;
}

static void free_dev(struct fastrpc_device *dev)
static void free_dev(struct fastrpc_device *dev, int cid)
{
	if (dev) {
		free_mem(&dev->buf);
		free_mem(&dev->buf, cid);
		kfree(dev);
		module_put(THIS_MODULE);
	}
}

static int alloc_dev(struct fastrpc_device **dev)
static int alloc_dev(struct fastrpc_device **dev, int cid)
{
	int err = 0;
	struct fastrpc_device *fd = 0;
@@ -728,7 +764,7 @@ static int alloc_dev(struct fastrpc_device **dev)
	INIT_HLIST_NODE(&fd->hn);

	fd->buf.size = PAGE_SIZE;
	VERIFY(err, 0 == alloc_mem(&fd->buf));
	VERIFY(err, 0 == alloc_mem(&fd->buf, cid));
	if (err)
		goto bail;
	fd->tgid = current->tgid;
@@ -736,11 +772,12 @@ static int alloc_dev(struct fastrpc_device **dev)
	*dev = fd;
 bail:
	if (err)
		free_dev(fd);
		free_dev(fd, cid);
	return err;
}

static int get_dev(struct fastrpc_apps *me, struct fastrpc_device **rdev)
static int get_dev(struct fastrpc_apps *me, int cid,
			struct fastrpc_device **rdev)
{
	struct hlist_head *head;
	struct fastrpc_device *dev = 0, *devfree = 0;
@@ -764,8 +801,8 @@ static int get_dev(struct fastrpc_apps *me, struct fastrpc_device **rdev)
	*rdev = devfree;
 bail:
	if (err) {
		free_dev(devfree);
		err = alloc_dev(rdev);
		free_dev(devfree, cid);
		err = alloc_dev(rdev, cid);
	}
	return err;
}
@@ -782,11 +819,11 @@ static void add_dev(struct fastrpc_apps *me, struct fastrpc_device *dev)
	return;
}

static int fastrpc_release_current_dsp_process(void);
static int fastrpc_release_current_dsp_process(int cid);

static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode,
			uint32_t kernel, struct fastrpc_ioctl_invoke *invoke,
			remote_arg_t *pra, int *fds)
			remote_arg_t *pra, int *fds, int cid)
{
	remote_arg_t *rpra = 0;
	struct fastrpc_device *dev = 0;
@@ -799,28 +836,29 @@ static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode,

	sc = invoke->sc;
	obuf.handle = 0;
	if (me->smmu.enabled) {
		VERIFY(err, 0 == iommu_attach_group(me->smmu.domain,
							me->smmu.group));
	if (me->channel[cid].smmu.enabled) {
		VERIFY(err, 0 == iommu_attach_group(
						me->channel[cid].smmu.domain,
						me->channel[cid].smmu.group));
		if (err)
			return err;
	}
	if (REMOTE_SCALARS_LENGTH(sc)) {
		VERIFY(err, 0 == get_dev(me, &dev));
		VERIFY(err, 0 == get_dev(me, cid, &dev));
		if (err)
			goto bail;
		VERIFY(err, 0 == get_page_list(kernel, sc, pra, &dev->buf,
						&obuf));
						&obuf, cid));
		if (err)
			goto bail;
		rpra = (remote_arg_t *)obuf.virt;
		VERIFY(err, 0 == get_args(kernel, sc, pra, rpra, invoke->pra,
					&obuf, &abufs, &nbufs, fds));
					&obuf, &abufs, &nbufs, fds, cid));
		if (err)
			goto bail;
	}

	context_list_alloc_ctx(&me->clst, &ctx);
	context_list_alloc_ctx(&me->clst, &ctx, cid);
	inv_args_pre(sc, rpra);
	if (FASTRPC_MODE_SERIAL == mode)
		inv_args(sc, rpra, obuf.used);
@@ -847,32 +885,34 @@ static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode,
	}
	context_free(ctx);

	if (me->smmu.enabled) {
	if (me->channel[cid].smmu.enabled) {
		bufs = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc);
		if (fds) {
			handles = (struct ion_handle **)(fds + bufs);
			for (i = 0; i < bufs; i++)
				if (!IS_ERR_OR_NULL(handles[i])) {
					ion_unmap_iommu(me->iclient, handles[i],
							me->smmu.domain_id, 0);
						me->channel[cid].smmu.domain_id,
						0);
					ion_free(me->iclient, handles[i]);
				}
		}
		iommu_detach_group(me->smmu.domain, me->smmu.group);
		iommu_detach_group(me->channel[cid].smmu.domain,
					me->channel[cid].smmu.group);
	}
	for (i = 0, b = abufs; i < nbufs; ++i, ++b)
		free_mem(b);
		free_mem(b, cid);

	kfree(abufs);
	if (dev) {
		add_dev(me, dev);
		if (obuf.handle != dev->buf.handle)
			free_mem(&obuf);
			free_mem(&obuf, cid);
	}
	return err;
}

static int fastrpc_create_current_dsp_process(void)
static int fastrpc_create_current_dsp_process(int cid)
{
	int err = 0;
	struct fastrpc_ioctl_invoke ioctl;
@@ -887,11 +927,11 @@ static int fastrpc_create_current_dsp_process(void)
	ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
	ioctl.pra = ra;
	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
		FASTRPC_MODE_PARALLEL, 1, &ioctl, ra, 0)));
		FASTRPC_MODE_PARALLEL, 1, &ioctl, ra, 0, cid)));
	return err;
}

static int fastrpc_release_current_dsp_process(void)
static int fastrpc_release_current_dsp_process(int cid)
{
	int err = 0;
	struct fastrpc_apps *me = &gfa;
@@ -906,14 +946,14 @@ static int fastrpc_release_current_dsp_process(void)
	ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
	ioctl.pra = ra;
	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
		FASTRPC_MODE_PARALLEL, 1, &ioctl, ra, 0)));
		FASTRPC_MODE_PARALLEL, 1, &ioctl, ra, 0, cid)));
	return err;
}

static int fastrpc_mmap_on_dsp(struct fastrpc_apps *me,
					 struct fastrpc_ioctl_mmap *mmap,
					 struct smq_phy_page *pages,
					 int num)
					 int cid, int num)
{
	struct fastrpc_ioctl_invoke ioctl;
	remote_arg_t ra[3];
@@ -945,7 +985,7 @@ static int fastrpc_mmap_on_dsp(struct fastrpc_apps *me,
	ioctl.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
	ioctl.pra = ra;
	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
		FASTRPC_MODE_PARALLEL, 1, &ioctl, ra, 0)));
		FASTRPC_MODE_PARALLEL, 1, &ioctl, ra, 0, cid)));
	mmap->vaddrout = routargs.vaddrout;
	if (err)
		goto bail;
@@ -954,7 +994,7 @@ bail:
}

static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me,
				 struct fastrpc_ioctl_munmap *munmap)
				 struct fastrpc_ioctl_munmap *munmap, int cid)
{
	struct fastrpc_ioctl_invoke ioctl;
	remote_arg_t ra[1];
@@ -975,7 +1015,7 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me,
	ioctl.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
	ioctl.pra = ra;
	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
		FASTRPC_MODE_PARALLEL, 1, &ioctl, ra, 0)));
		FASTRPC_MODE_PARALLEL, 1, &ioctl, ra, 0, cid)));
	return err;
}

@@ -986,7 +1026,7 @@ static int fastrpc_internal_munmap(struct fastrpc_apps *me,
	int err = 0;
	struct fastrpc_mmap *map = 0, *mapfree = 0;
	struct hlist_node *n;
	VERIFY(err, 0 == (err = fastrpc_munmap_on_dsp(me, munmap)));
	VERIFY(err, 0 == (err = fastrpc_munmap_on_dsp(me, munmap, fdata->cid)));
	if (err)
		goto bail;
	spin_lock(&fdata->hlock);
@@ -1042,7 +1082,7 @@ static int fastrpc_internal_mmap(struct fastrpc_apps *me,
	if (err)
		goto bail;

	VERIFY(err, 0 == fastrpc_mmap_on_dsp(me, mmap, pages, num));
	VERIFY(err, 0 == fastrpc_mmap_on_dsp(me, mmap, pages, fdata->cid, num));
	if (err)
		goto bail;
	map->vaddrin = mmap->vaddrin;
@@ -1061,7 +1101,7 @@ static int fastrpc_internal_mmap(struct fastrpc_apps *me,
	return err;
}

static void cleanup_current_dev(void)
static void cleanup_current_dev(int cid)
{
	struct fastrpc_apps *me = &gfa;
	uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
@@ -1082,7 +1122,7 @@ static void cleanup_current_dev(void)
	}
	spin_unlock(&me->hlock);
	if (devfree) {
		free_dev(devfree);
		free_dev(devfree, cid);
		goto rnext;
	}
	return;
@@ -1091,21 +1131,26 @@ static void cleanup_current_dev(void)
static void fastrpc_channel_close(struct kref *kref)
{
	struct fastrpc_apps *me = &gfa;
	struct fastrpc_channel_context *ctx;
	int cid;

	smd_close(me->chan);
	me->chan = 0;
	ctx = container_of(kref, struct fastrpc_channel_context, kref);
	smd_close(ctx->chan);
	ctx->chan = 0;
	mutex_unlock(&me->smd_mutex);
	pr_info("'closed /dev/%s c %d 0'\n", DEVICE_NAME,
						MAJOR(me->dev_no));
	cid = ctx - &me->channel[0];
	pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name,
						MAJOR(me->dev_no), cid);
}

static int fastrpc_device_release(struct inode *inode, struct file *file)
{
	struct file_data *fdata = (struct file_data *)file->private_data;
	struct fastrpc_apps *me = &gfa;
	int cid = MINOR(inode->i_rdev);

	(void)fastrpc_release_current_dsp_process();
	cleanup_current_dev();
	(void)fastrpc_release_current_dsp_process(cid);
	cleanup_current_dev(cid);
	if (fdata) {
		struct fastrpc_mmap *map;
		struct hlist_node *n;
@@ -1116,7 +1161,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
			kfree(map);
		}
		kfree(fdata);
		kref_put_mutex(&me->kref, fastrpc_channel_close,
		kref_put_mutex(&me->channel[cid].kref, fastrpc_channel_close,
				&me->smd_mutex);
	}
	return 0;
@@ -1124,23 +1169,27 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)

static int fastrpc_device_open(struct inode *inode, struct file *filp)
{
	int cid = MINOR(inode->i_rdev);
	int err = 0;
	struct fastrpc_apps *me = &gfa;

	mutex_lock(&me->smd_mutex);
	if (kref_get_unless_zero(&me->kref) == 0) {
		VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
						SMD_APPS_QDSP, &me->chan,
						me, smd_event_handler));
	if (kref_get_unless_zero(&me->channel[cid].kref) == 0) {
		VERIFY(err, 0 == smd_named_open_on_edge(
					FASTRPC_SMD_GUID,
					gcinfo[cid].channel,
					&me->channel[cid].chan, (void *)cid,
					smd_event_handler));
		if (err)
			goto smd_bail;
		VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
		VERIFY(err, 0 != wait_for_completion_timeout(
							&me->channel[cid].work,
							RPC_TIMEOUT));
		if (err)
			goto completion_bail;
		kref_init(&me->kref);
		pr_info("'opened /dev/%s c %d 0'\n", DEVICE_NAME,
						MAJOR(me->dev_no));
		kref_init(&me->channel[cid].kref);
		pr_info("'opened /dev/%s c %d %d'\n", gcinfo[cid].name,
						MAJOR(me->dev_no), cid);
	}
	mutex_unlock(&me->smd_mutex);

@@ -1156,25 +1205,26 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)

		spin_lock_init(&fdata->hlock);
		INIT_HLIST_HEAD(&fdata->hlst);
		fdata->cid = cid;

		VERIFY(err, 0 == fastrpc_create_current_dsp_process());
		VERIFY(err, 0 == fastrpc_create_current_dsp_process(cid));
		if (err)
			goto bail;
		filp->private_data = fdata;
bail:
		if (err) {
			cleanup_current_dev();
			cleanup_current_dev(cid);
			kfree(fdata);
			kref_put_mutex(&me->kref, fastrpc_channel_close,
					&me->smd_mutex);
			kref_put_mutex(&me->channel[cid].kref,
					fastrpc_channel_close, &me->smd_mutex);
		}
		module_put(THIS_MODULE);
	}
	return err;

completion_bail:
	smd_close(me->chan);
	me->chan = 0;
	smd_close(me->channel[cid].chan);
	me->channel[cid].chan = 0;
smd_bail:
	mutex_unlock(&me->smd_mutex);
	return err;
@@ -1227,7 +1277,7 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num,
			goto bail;
		}
		VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, fdata->mode,
							0, invoke, pra, fds)));
					0, invoke, pra, fds, fdata->cid)));
		if (err)
			goto bail;
		break;
@@ -1283,29 +1333,34 @@ static const struct file_operations fops = {
static int __init fastrpc_device_init(void)
{
	struct fastrpc_apps *me = &gfa;
	int err = 0;
	int i, err = 0;

	memset(me, 0, sizeof(*me));
	VERIFY(err, 0 == fastrpc_init());
	if (err)
		goto fastrpc_bail;
	VERIFY(err, 0 == alloc_chrdev_region(&me->dev_no, 0, 1, DEVICE_NAME));
	VERIFY(err, 0 == alloc_chrdev_region(&me->dev_no, 0, NUM_CHANNELS,
					DEVICE_NAME));
	if (err)
		goto alloc_chrdev_bail;
	cdev_init(&me->cdev, &fops);
	me->cdev.owner = THIS_MODULE;
	VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
	VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0),
				NUM_CHANNELS));
	if (err)
		goto cdev_init_bail;
	me->class = class_create(THIS_MODULE, "fastrpc");
	VERIFY(err, !IS_ERR(me->class));
	if (err)
		goto class_create_bail;
	me->dev = device_create(me->class, NULL, MKDEV(MAJOR(me->dev_no), 0),
				NULL, DEVICE_NAME);
	VERIFY(err, !IS_ERR(me->dev));
	for (i = 0; i < NUM_CHANNELS; i++) {
		me->channel[i].dev = device_create(me->class, NULL,
					MKDEV(MAJOR(me->dev_no), i),
					NULL, gcinfo[i].name);
		VERIFY(err, !IS_ERR(me->channel[i].dev));
		if (err)
			goto device_create_bail;
	}

	return 0;

@@ -1314,7 +1369,7 @@ device_create_bail:
class_create_bail:
	cdev_del(&me->cdev);
cdev_init_bail:
	unregister_chrdev_region(me->dev_no, 1);
	unregister_chrdev_region(me->dev_no, NUM_CHANNELS);
alloc_chrdev_bail:
	fastrpc_deinit();
fastrpc_bail:
@@ -1324,12 +1379,14 @@ fastrpc_bail:
static void __exit fastrpc_device_exit(void)
{
	struct fastrpc_apps *me = &gfa;
	int i;

	fastrpc_deinit();
	device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0));
	for (i = 0; i < NUM_CHANNELS; i++)
		device_destroy(me->class, MKDEV(MAJOR(me->dev_no), i));
	class_destroy(me->class);
	cdev_del(&me->cdev);
	unregister_chrdev_region(me->dev_no, 1);
	unregister_chrdev_region(me->dev_no, NUM_CHANNELS);
}

module_init(fastrpc_device_init);