lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 27 Aug 2012 11:19:28 +0530
From:	Arun Murthy <arun.murthy@...ricsson.com>
To:	<linux-kernel@...r.kernel.org>, <netdev@...r.kernel.org>,
	<linux-doc@...r.kernel.org>, <gregkh@...uxfoundation.org>,
	<alan@...rguk.ukuu.org.uk>
Cc:	<arun.murthy@...ricsson.com>
Subject: [PATCHv3 3/4] modem_shm: u8500-shm: U8500 Shared Memory Driver

The communication between APE and CMT in u8500 is by means of a shared DDR.
Since its a shared memory, this driver implements shrm protocol.

Signed-off-by: Arun Murthy <arun.murthy@...ricsson.com>
---
 drivers/modem_shm/Kconfig                   |    2 +
 drivers/modem_shm/Makefile                  |    1 +
 drivers/modem_shm/u8500_shm/Kconfig         |   43 +
 drivers/modem_shm/u8500_shm/Makefile        |    7 +
 drivers/modem_shm/u8500_shm/shrm.h          |   23 +
 drivers/modem_shm/u8500_shm/shrm_char.c     |  816 ++++++++++++++
 drivers/modem_shm/u8500_shm/shrm_config.h   |  114 ++
 drivers/modem_shm/u8500_shm/shrm_driver.c   |  733 ++++++++++++
 drivers/modem_shm/u8500_shm/shrm_driver.h   |  226 ++++
 drivers/modem_shm/u8500_shm/shrm_fifo.c     |  838 ++++++++++++++
 drivers/modem_shm/u8500_shm/shrm_ioctl.h    |   43 +
 drivers/modem_shm/u8500_shm/shrm_net.c      |  313 ++++++
 drivers/modem_shm/u8500_shm/shrm_net.h      |   46 +
 drivers/modem_shm/u8500_shm/shrm_private.h  |  184 +++
 drivers/modem_shm/u8500_shm/shrm_protocol.c | 1591 +++++++++++++++++++++++++++
 15 files changed, 4980 insertions(+), 0 deletions(-)
 create mode 100644 drivers/modem_shm/u8500_shm/Kconfig
 create mode 100644 drivers/modem_shm/u8500_shm/Makefile
 create mode 100644 drivers/modem_shm/u8500_shm/shrm.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_char.c
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_config.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_driver.c
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_driver.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_fifo.c
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_ioctl.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_net.c
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_net.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_private.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_protocol.c

diff --git a/drivers/modem_shm/Kconfig b/drivers/modem_shm/Kconfig
index f59d3dc..dc74597 100644
--- a/drivers/modem_shm/Kconfig
+++ b/drivers/modem_shm/Kconfig
@@ -18,3 +18,5 @@ config MODEM_U8500
 	 Application processor.
 
 	 If unsure, say N.
+
+source "drivers/modem_shm/u8500_shm/Kconfig"
diff --git a/drivers/modem_shm/Makefile b/drivers/modem_shm/Makefile
index a9aac0f..eeef578 100644
--- a/drivers/modem_shm/Makefile
+++ b/drivers/modem_shm/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_MODEM_SHM)		:= modem_access.o
 obj-$(CONFIG_MODEM_U8500)	+= modem_u8500.o
+obj-$(CONFIG_U8500_SHRM)	+= u8500_shm/
diff --git a/drivers/modem_shm/u8500_shm/Kconfig b/drivers/modem_shm/u8500_shm/Kconfig
new file mode 100644
index 0000000..465c8bb
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/Kconfig
@@ -0,0 +1,43 @@
+#
+# SHM HW kernel configuration
+#
+config U8500_SHRM
+	bool "U8500 SHRM hardware driver"
+	depends on ARCH_U8500 && PHONET && MODEM_U8500
+	default Y
+	---help---
+	  If you say Y here, you will enable the STN8500 SHM hardware driver.
+
+	  If unsure, say N.
+choice
+	prompt "Modem Image Version"
+	depends on U8500_SHRM
+	default SHRM_V1_UPDATES_VERSION
+
+	config SHRM_V1_UPDATES_VERSION
+	depends on U8500_SHRM
+	bool "SHRM V1 UPDATES"
+	help
+	 Modem Images with V1 Updates
+
+endchoice
+
+config U8500_SHRM_LOOP_BACK
+	bool "U8500 SHRM loopback"
+	depends on U8500_SHRM
+	default n
+	---help---
+	  If you say Y here, you will enable the shm loopback
+
+	  If unsure, say N.
+
+config U8500_SHRM_MODEM_SILENT_RESET
+	bool "U8500 SHRM Modem Silent Reset"
+	depends on U8500_SHRM
+	default n
+	---help---
+	  If you say Y here, you will enable the modem silent reset feature
+
+	  If unsure, say N.
+
+
diff --git a/drivers/modem_shm/u8500_shm/Makefile b/drivers/modem_shm/u8500_shm/Makefile
new file mode 100644
index 0000000..aefd315
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for U8500 SHRM drivers
+#
+
+u8500_shrm-objs := 	shrm_driver.o shrm_fifo.o shrm_protocol.o shrm_net.o shrm_char.o
+
+obj-$(CONFIG_U8500_SHRM)	+= u8500_shrm.o
diff --git a/drivers/modem_shm/u8500_shm/shrm.h b/drivers/modem_shm/u8500_shm/shrm.h
new file mode 100644
index 0000000..5b41cec
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHM_DRIVER_IF_H__
+#define __SHM_DRIVER_IF_H__
+
+#include <linux/device.h>
+
+/* forward declaration */
+struct shrm_dev;
+
+typedef void (*rx_cb)(void *data, unsigned int length);
+typedef void (*received_msg_handler)(unsigned char l2_header,
+			void *msg_ptr, unsigned int length,
+			struct shrm_dev *shrm);
+
+#endif
diff --git a/drivers/modem_shm/u8500_shm/shrm_char.c b/drivers/modem_shm/u8500_shm/shrm_char.c
new file mode 100644
index 0000000..c8671ca
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_char.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_config.h"
+#include "shrm_ioctl.h"
+#include "shrm.h"
+
+#define NAME "IPC_ISA"
+/* L2 header for rtc_calibration device is 0xC8 and hence 0xC8 + 1 = 201 */
+#define MAX_L2_HEADERS 201
+
+#define SIZE_OF_FIFO (512*1024)
+
+static u8 message_fifo[ISA_DEVICES][SIZE_OF_FIFO];
+
+static u8 wr_rpc_msg[10*1024];
+static u8 wr_sec_msg[10*1024];
+static u8 wr_audio_msg[10*1024];
+static u8 wr_rtc_cal_msg[100];
+
+struct map_device {
+	u8 l2_header;
+	u8 idx;
+	char *name;
+};
+
+static struct map_device map_dev[] = {
+	{ISI_MESSAGING, 0, "isi"},
+	{RPC_MESSAGING, 1, "rpc"},
+	{AUDIO_MESSAGING, 2, "modemaudio"},
+	{SECURITY_MESSAGING, 3, "sec"},
+	{COMMON_LOOPBACK_MESSAGING, 4, "common_loopback"},
+	{AUDIO_LOOPBACK_MESSAGING, 5, "audio_loopback"},
+	{CIQ_MESSAGING, 6, "ciq"},
+	{RTC_CAL_MESSAGING, 7, "rtc_calibration"},
+};
+
+/* major number at load time */
+static int major;
+/* global fops mutex */
+static DEFINE_MUTEX(isa_lock);
+
+/**
+ * shrm_get_cdev_index() - return the index mapped to l2 header
+ * @l2_header:	L2 header
+ *
+ * struct map_device maps the index(count) with the device L2 header.
+ * This function returns the index for the provided L2 header in case
+ * of success else -ve value.
+ */
+int shrm_get_cdev_index(u8 l2_header)
+{
+	u8 cnt;
+	for (cnt = 0; cnt < ISA_DEVICES; cnt++) {
+		if (map_dev[cnt].l2_header == l2_header)
+			return map_dev[cnt].idx;
+	}
+	return -EINVAL;
+}
+
+/**
+ * shrm_get_cdev_l2header() - return l2_header mapped to the index
+ * @idx:	index
+ *
+ * struct map_device maps the index(count) with the device L2 header.
+ * This function returns the L2 header for the given index in case
+ * of success else -ve value.
+ */
+int shrm_get_cdev_l2header(u8 idx)
+{
+	u8 cnt;
+	for (cnt = 0; cnt < ISA_DEVICES; cnt++) {
+		if (map_dev[cnt].idx == idx)
+			return map_dev[cnt].l2_header;
+	}
+	return -EINVAL;
+}
+
+void shrm_char_reset_queues(struct shrm_dev *shrm)
+{
+	struct isadev_context *isadev;
+	struct isa_driver_context *isa_context;
+	struct queue_element *cur_msg = NULL;
+	struct list_head *cur_msg_ptr = NULL;
+	struct list_head *msg_ptr;
+	struct message_queue *q;
+	int no_dev;
+
+	dev_info(shrm->dev, "%s: Resetting char device queues\n", __func__);
+	isa_context = shrm->isa_context;
+	for (no_dev = 0 ; no_dev < ISA_DEVICES ; no_dev++) {
+		isadev = &isa_context->isadev[no_dev];
+		q = &isadev->dl_queue;
+
+		spin_lock_bh(&q->update_lock);
+		/* empty out the msg queue */
+		list_for_each_safe(cur_msg_ptr, msg_ptr, &q->msg_list) {
+			cur_msg = list_entry(cur_msg_ptr,
+					struct queue_element, entry);
+			list_del(cur_msg_ptr);
+			kfree(cur_msg);
+		}
+
+		/* reset the msg queue pointers */
+		q->size = SIZE_OF_FIFO;
+		q->readptr = 0;
+		q->writeptr = 0;
+		q->no = 0;
+
+		/* wake up the blocking read/select */
+		atomic_set(&q->q_rp, 1);
+		wake_up_interruptible(&q->wq_readable);
+
+		spin_unlock_bh(&q->update_lock);
+	}
+}
+
+/**
+ * create_queue() - To create FIFO for Tx and Rx message buffering.
+ * @q:		message queue.
+ * @devicetype:	device type 0-isi,1-rpc,2-audio,3-security,
+ * 4-common_loopback, 5-audio_loopback.
+ * @shrm:	pointer to the shrm device information structure
+ *
+ * This function creates a FIFO buffer of n_bytes size using
+ * dma_alloc_coherent(). It also initializes all queue handling
+ * locks, queue management pointers. It also initializes message list
+ * which occupies this queue.
+ */
+static int create_queue(struct message_queue *q, u32 devicetype,
+						struct shrm_dev *shrm)
+{
+	q->fifo_base = (u8 *)&message_fifo[devicetype];
+	q->size = SIZE_OF_FIFO;
+	q->readptr = 0;
+	q->writeptr = 0;
+	q->no = 0;
+	q->shrm = shrm;
+	spin_lock_init(&q->update_lock);
+	INIT_LIST_HEAD(&q->msg_list);
+	init_waitqueue_head(&q->wq_readable);
+	atomic_set(&q->q_rp, 0);
+
+	return 0;
+}
+
+static void delete_queue(struct message_queue *q)
+{
+	q->size = 0;
+	q->readptr = 0;
+	q->writeptr = 0;
+}
+
+/**
+ * add_msg_to_queue() - Add a message inside queue
+ * @q:		message queue
+ * @size:	size in bytes
+ *
+ * This function tries to allocate n_bytes of size in FIFO q.
+ * It returns negative number when no memory can be allocated
+ * currently.
+ */
+int add_msg_to_queue(struct message_queue *q, u32 size)
+{
+	struct queue_element *new_msg = NULL;
+	struct shrm_dev *shrm = q->shrm;
+
+	dev_dbg(shrm->dev, "%s IN q->writeptr=%d\n", __func__, q->writeptr);
+	new_msg = kmalloc(sizeof(struct queue_element), GFP_ATOMIC);
+	if (new_msg == NULL) {
+		dev_err(shrm->dev, "unable to allocate memory\n");
+		return -ENOMEM;
+	}
+	new_msg->offset = q->writeptr;
+	new_msg->size = size;
+	new_msg->no = q->no++;
+
+	/* check for overflow condition */
+	if (q->readptr <= q->writeptr) {
+		if (((q->writeptr-q->readptr) + size) >= q->size) {
+			dev_err(shrm->dev, "Buffer overflow !!\n");
+			BUG_ON(((q->writeptr-q->readptr) + size) >= q->size);
+		}
+	} else {
+		if ((q->writeptr + size) >= q->readptr) {
+			dev_err(shrm->dev, "Buffer overflow !!\n");
+			BUG_ON((q->writeptr + size) >= q->readptr);
+		}
+	}
+	q->writeptr = (q->writeptr + size) % q->size;
+	if (list_empty(&q->msg_list)) {
+		list_add_tail(&new_msg->entry, &q->msg_list);
+		/* There can be 2 blocking calls read  and another select */
+		atomic_set(&q->q_rp, 1);
+		wake_up_interruptible(&q->wq_readable);
+	} else
+		list_add_tail(&new_msg->entry, &q->msg_list);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return 0;
+}
+
+/**
+ * remove_msg_from_queue() - To remove a message from the msg queue.
+ * @q:	message queue
+ *
+ * This function delets a message from the message list associated with message
+ * queue q and also updates read ptr.
+ * If the message list is empty, then, event is set to block the select and
+ * read calls of the paricular queue.
+ *
+ * The message list is FIFO style and message is always added to tail and
+ * removed from head.
+ */
+int remove_msg_from_queue(struct message_queue *q)
+{
+	struct queue_element *old_msg = NULL;
+	struct shrm_dev *shrm = q->shrm;
+	struct list_head *msg_ptr = NULL;
+	struct list_head *old_msg_ptr = NULL;
+
+	dev_dbg(shrm->dev, "%s IN q->readptr %d\n", __func__, q->readptr);
+
+	list_for_each_safe(old_msg_ptr, msg_ptr, &q->msg_list) {
+		old_msg = list_entry(old_msg_ptr, struct queue_element, entry);
+		if (old_msg == NULL) {
+			dev_err(shrm->dev, "no message found\n");
+			return -EFAULT;
+		}
+		list_del(old_msg_ptr);
+		q->readptr = (q->readptr + old_msg->size)%q->size;
+		kfree(old_msg);
+		break;
+	}
+	if (list_empty(&q->msg_list)) {
+		dev_dbg(shrm->dev, "List is empty setting RP= 0\n");
+		atomic_set(&q->q_rp, 0);
+	}
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return 0;
+}
+
+/**
+ * get_size_of_new_msg() - retrieve new message from message list
+ * @q:	message queue
+ *
+ * This function will retrieve most recent message from the corresponding
+ * queue list. New message is always retrieved from head side.
+ * It returns new message no, offset if FIFO and size.
+ */
+int get_size_of_new_msg(struct message_queue *q)
+{
+	struct queue_element *new_msg = NULL;
+	struct list_head *msg_list;
+	struct shrm_dev *shrm = q->shrm;
+	int size = 0;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	spin_lock_bh(&q->update_lock);
+	list_for_each(msg_list, &q->msg_list) {
+		new_msg = list_entry(msg_list, struct queue_element, entry);
+		if (new_msg == NULL) {
+			spin_unlock_bh(&q->update_lock);
+			dev_err(shrm->dev, "no message found\n");
+			return -EFAULT;
+		}
+		size = new_msg->size;
+		break;
+	}
+	spin_unlock_bh(&q->update_lock);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return size;
+}
+
+/**
+ * isa_select() - shrm char interface driver select interface
+ * @filp:	file descriptor pointer
+ * @wait:	poll_table_struct pointer
+ *
+ * This function is used to perform non-blocking read operations. It allows
+ * a process to determine whether it can read from one or more open files
+ * without blocking. These calls can also block a process until any of a
+ * given set of file descriptors becomes available for reading.
+ * If a file is ready to read, POLLIN | POLLRDNORM bitmask is returned.
+ * The driver method is called whenever the user-space program performs a select
+ * system call involving a file descriptor associated with the driver.
+ */
+static u32 isa_select(struct file *filp,
+				struct poll_table_struct *wait)
+{
+	struct isadev_context *isadev = filp->private_data;
+	struct shrm_dev *shrm = isadev->dl_queue.shrm;
+	struct message_queue *q;
+	u32 mask = 0;
+	u32 m = iminor(filp->f_path.dentry->d_inode);
+	u8 idx = shrm_get_cdev_index(m);
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (shrm->msr_flag)
+		return -ENODEV;
+
+	if (isadev->device_id != idx)
+			return -1;
+
+	q = &isadev->dl_queue;
+	poll_wait(filp, &q->wq_readable, wait);
+	if (atomic_read(&q->q_rp) == 1)
+		mask = POLLIN | POLLRDNORM;
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return mask;
+}
+
+/**
+ * isa_read() - Read from device
+ * @filp:	file descriptor
+ * @buf:	user buffer pointer
+ * @len:	size of requested data transfer
+ * @ppos:	not used
+ *
+ * It reads a oldest message from queue and copies it into user buffer and
+ * returns its size.
+ * If there is no message present in queue, then it blocks until new data is
+ * available.
+ */
+ssize_t isa_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
+{
+	u32 size = 0;
+	int ret;
+	char *psrc;
+	struct isadev_context *isadev = (struct isadev_context *)
+							filp->private_data;
+	struct shrm_dev *shrm = isadev->dl_queue.shrm;
+	struct message_queue *q;
+	u32 msgsize;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	q = &isadev->dl_queue;
+
+	if (shrm->msr_flag) {
+		atomic_set(&q->q_rp, 0);
+		return -ENODEV;
+	}
+
+	spin_lock_bh(&q->update_lock);
+	if (list_empty(&q->msg_list)) {
+		spin_unlock_bh(&q->update_lock);
+		dev_dbg(shrm->dev, "Waiting for Data\n");
+		if (wait_event_interruptible(q->wq_readable,
+				atomic_read(&q->q_rp) == 1))
+			return -ERESTARTSYS;
+	} else
+		spin_unlock_bh(&q->update_lock);
+
+	if (shrm->msr_flag) {
+		atomic_set(&q->q_rp, 0);
+		return -ENODEV;
+	}
+
+	msgsize = get_size_of_new_msg(q);
+
+	if (len < msgsize)
+		return -EINVAL;
+
+	if ((q->readptr + msgsize) >= q->size) {
+		dev_dbg(shrm->dev, "Inside Loop Back\n");
+		psrc = (char *)buf;
+		size = (q->size-q->readptr);
+		/* Copy First Part of msg */
+		if (copy_to_user(psrc,
+				(u8 *)(q->fifo_base + q->readptr),
+				size)) {
+			dev_err(shrm->dev, "copy_to_user failed\n");
+			return -EFAULT;
+		}
+		psrc += size;
+		/* Copy Second Part of msg at the top of fifo */
+		if (copy_to_user(psrc,
+				(u8 *)(q->fifo_base),
+				(msgsize-size))) {
+			dev_err(shrm->dev, "copy_to_user failed\n");
+			return -EFAULT;
+		}
+	} else {
+		if (copy_to_user(buf,
+				(u8 *)(q->fifo_base + q->readptr),
+				msgsize)) {
+			dev_err(shrm->dev, "copy_to_user failed\n");
+			return -EFAULT;
+		}
+	}
+	spin_lock_bh(&q->update_lock);
+	ret = remove_msg_from_queue(q);
+	if (ret < 0) {
+		dev_err(shrm->dev,
+				"Remove msg from message queue failed\n");
+		msgsize = ret;
+	}
+	spin_unlock_bh(&q->update_lock);
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return msgsize;
+}
+
+/**
+ * isa_write() - Write to shrm char device
+ * @filp:	file descriptor
+ * @buf:	user buffer pointer
+ * @len:	size of requested data transfer
+ * @ppos:	not used
+ *
+ * It checks if there is space available in queue, and copies the message
+ * inside queue. If there is no space, it blocks until space becomes available.
+ * It also schedules transfer thread to transmit the newly added message.
+ */
+ssize_t isa_write(struct file *filp, const char __user *buf,
+				 size_t len, loff_t *ppos)
+{
+	struct isadev_context *isadev = filp->private_data;
+	struct shrm_dev *shrm = isadev->dl_queue.shrm;
+	struct message_queue *q;
+	void *addr = 0;
+	int err, l2_header;
+	int ret = 0;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	q = &isadev->dl_queue;
+	l2_header = shrm_get_cdev_l2header(isadev->device_id);
+	if (l2_header < 0) {
+		dev_err(shrm->dev, "failed to get L2 header\n");
+		return l2_header;
+	}
+
+	switch (l2_header) {
+	case RPC_MESSAGING:
+		dev_dbg(shrm->dev, "RPC\n");
+		addr = (void *)wr_rpc_msg;
+		break;
+	case AUDIO_MESSAGING:
+		dev_dbg(shrm->dev, "Audio\n");
+		addr = (void *)wr_audio_msg;
+		break;
+	case SECURITY_MESSAGING:
+		dev_dbg(shrm->dev, "Security\n");
+		addr = (void *)wr_sec_msg;
+		break;
+	case COMMON_LOOPBACK_MESSAGING:
+		dev_dbg(shrm->dev, "Common loopback\n");
+		addr = isadev->addr;
+		break;
+	case AUDIO_LOOPBACK_MESSAGING:
+		dev_dbg(shrm->dev, "Audio loopback\n");
+		addr = isadev->addr;
+		break;
+	case CIQ_MESSAGING:
+		dev_dbg(shrm->dev, "CIQ\n");
+		addr = isadev->addr;
+		break;
+	case RTC_CAL_MESSAGING:
+		dev_dbg(shrm->dev, "isa_write(): RTC Calibration\n");
+		addr = (void *)wr_rtc_cal_msg;
+		break;
+	default:
+		dev_dbg(shrm->dev, "Wrong device\n");
+		return -EFAULT;
+	}
+
+	if (copy_from_user(addr, buf, len)) {
+		dev_err(shrm->dev, "copy_from_user failed\n");
+		return -EFAULT;
+	}
+	/* Write msg to Fifo */
+	if ((l2_header == AUDIO_MESSAGING) ||
+			(l2_header == AUDIO_LOOPBACK_MESSAGING)) {
+		mutex_lock(&shrm->isa_context->tx_audio_mutex);
+		err = shrm_write_msg(shrm, l2_header, addr, len);
+		if (!err)
+			ret = len;
+		else
+			ret = err;
+		mutex_unlock(&shrm->isa_context->tx_audio_mutex);
+	} else {
+		spin_lock_bh(&shrm->isa_context->common_tx);
+		err = shrm_write_msg(shrm, l2_header, addr, len);
+		if (!err)
+			ret = len;
+		else
+			ret = err;
+		spin_unlock_bh(&shrm->isa_context->common_tx);
+	}
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return ret;
+}
+
+/**
+ * isa_close() - Close device file
+ * @inode:	structure is used by the kernel internally to represent files
+ * @filp:	device file descriptor
+ *
+ * This function deletes structues associated with this file, deletes
+ * queues, flushes and destroys workqueus and closes this file.
+ * It also unregisters itself from l2mux driver.
+ */
+static int isa_close(struct inode *inode, struct file *filp)
+{
+	struct isadev_context *isadev = filp->private_data;
+	struct shrm_dev *shrm = isadev->dl_queue.shrm;
+	struct isa_driver_context *isa_context = shrm->isa_context;
+	u8 m;
+	int idx;
+
+	mutex_lock(&isa_lock);
+	m = iminor(filp->f_path.dentry->d_inode);
+	idx = shrm_get_cdev_index(m);
+	if (idx < 0) {
+		dev_err(shrm->dev, "failed to get index\n");
+		mutex_unlock(&isa_lock);
+		return idx;
+	}
+	dev_dbg(shrm->dev, "isa_close %d", m);
+
+	if (atomic_dec_and_test(&isa_context->is_open[idx])) {
+		atomic_inc(&isa_context->is_open[idx]);
+		dev_err(shrm->dev, "Device not opened yet\n");
+		mutex_unlock(&isa_lock);
+		return -ENODEV;
+	}
+	atomic_set(&isa_context->is_open[idx], 1);
+
+	switch (m) {
+	case RPC_MESSAGING:
+		dev_info(shrm->dev, "Close RPC_MESSAGING Device\n");
+		break;
+	case AUDIO_MESSAGING:
+		dev_info(shrm->dev, "Close AUDIO_MESSAGING Device\n");
+		break;
+	case SECURITY_MESSAGING:
+		dev_info(shrm->dev, "CLose SECURITY_MESSAGING Device\n");
+		break;
+	case COMMON_LOOPBACK_MESSAGING:
+		dev_info(shrm->dev, "Close COMMON_LOOPBACK_MESSAGING Device\n");
+		break;
+	case AUDIO_LOOPBACK_MESSAGING:
+		dev_info(shrm->dev, "Close AUDIO_LOOPBACK_MESSAGING Device\n");
+		break;
+	case CIQ_MESSAGING:
+		dev_info(shrm->dev, "Close CIQ_MESSAGING Device\n");
+		break;
+	case RTC_CAL_MESSAGING:
+		dev_info(shrm->dev, "Close RTC_CAL_MESSAGING Device\n");
+		break;
+	default:
+		dev_info(shrm->dev, "No such device present\n");
+		mutex_unlock(&isa_lock);
+		return -ENODEV;
+	};
+	kfree(isadev->addr);
+	mutex_unlock(&isa_lock);
+	return 0;
+}
+/**
+ * isa_open() -  Open device file
+ * @inode:	structure is used by the kernel internally to represent files
+ * @filp:	device file descriptor
+ *
+ * This function performs initialization tasks needed to open SHRM channel.
+ * Following tasks are performed.
+ * -return if device is already opened
+ * -create uplink FIFO
+ * -create downlink FIFO
+ * -init delayed workqueue thread
+ * -register to l2mux driver
+ */
+static int isa_open(struct inode *inode, struct file *filp)
+{
+	int err = 0;
+	u8 m;
+	int idx;
+	struct isadev_context *isadev;
+	struct isa_driver_context *isa_context = container_of(
+						inode->i_cdev,
+						struct isa_driver_context,
+						cdev);
+	struct shrm_dev *shrm = isa_context->isadev->dl_queue.shrm;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (get_boot_state() != BOOT_DONE) {
+		dev_err(shrm->dev, "Boot is not done\n");
+		return -EBUSY;
+	}
+	mutex_lock(&isa_lock);
+	m = iminor(inode);
+
+	if ((m != RPC_MESSAGING) &&
+				(m != AUDIO_LOOPBACK_MESSAGING) &&
+				(m != COMMON_LOOPBACK_MESSAGING) &&
+				(m != AUDIO_MESSAGING) &&
+				(m != SECURITY_MESSAGING) &&
+				(m != CIQ_MESSAGING) &&
+				(m != RTC_CAL_MESSAGING)) {
+		dev_err(shrm->dev, "No such device present\n");
+		mutex_unlock(&isa_lock);
+		return -ENODEV;
+	}
+	idx = shrm_get_cdev_index(m);
+	if (idx < 0) {
+		dev_err(shrm->dev, "failed to get index\n");
+		mutex_unlock(&isa_lock);
+		return idx;
+	}
+	if (!atomic_dec_and_test(&isa_context->is_open[idx])) {
+		atomic_inc(&isa_context->is_open[idx]);
+		dev_err(shrm->dev, "Device already opened\n");
+		mutex_unlock(&isa_lock);
+		return -EBUSY;
+	}
+	isadev = &isa_context->isadev[idx];
+	filp->private_data = isadev;
+
+	switch (m) {
+	case RPC_MESSAGING:
+		isadev->addr = NULL;
+		dev_info(shrm->dev, "Open RPC_MESSAGING Device\n");
+		break;
+	case AUDIO_MESSAGING:
+		isadev->addr = NULL;
+		dev_info(shrm->dev, "Open AUDIO_MESSAGING Device\n");
+		break;
+	case SECURITY_MESSAGING:
+		isadev->addr = NULL;
+		dev_info(shrm->dev, "Open SECURITY_MESSAGING Device\n");
+		break;
+	case COMMON_LOOPBACK_MESSAGING:
+		isadev->addr = kzalloc(10 * 1024, GFP_KERNEL);
+		if (!isadev->addr) {
+			mutex_unlock(&isa_lock);
+			return -ENOMEM;
+		}
+		dev_info(shrm->dev, "Open COMMON_LOOPBACK_MESSAGING Device\n");
+		break;
+	case AUDIO_LOOPBACK_MESSAGING:
+		isadev->addr = kzalloc(10 * 1024, GFP_KERNEL);
+		if (!isadev->addr) {
+			mutex_unlock(&isa_lock);
+			return -ENOMEM;
+		}
+		dev_info(shrm->dev, "Open AUDIO_LOOPBACK_MESSAGING Device\n");
+		break;
+	case CIQ_MESSAGING:
+		isadev->addr = kzalloc(10 * 1024, GFP_KERNEL);
+		if (!isadev->addr) {
+			mutex_unlock(&isa_lock);
+			return -ENOMEM;
+		}
+		dev_info(shrm->dev, "Open CIQ_MESSAGING Device\n");
+		break;
+	case RTC_CAL_MESSAGING:
+		isadev->addr = NULL;
+		dev_info(shrm->dev, "Open RTC_CAL_MESSAGING Device\n");
+		break;
+	};
+
+	mutex_unlock(&isa_lock);
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return err;
+}
+
+static struct file_operations isa_fops = {
+	.owner = THIS_MODULE,
+	.open = isa_open,
+	.release = isa_close,
+	.read = isa_read,
+	.write = isa_write,
+	.poll = isa_select,
+};
+
+/**
+ * isa_init() - module insertion function
+ * @shrm:	pointer to the shrm device information structure
+ *
+ * This function registers module as a character driver using
+ * register_chrdev_region() or alloc_chrdev_region. It adds this
+ * driver to system using cdev_add() call. Major number is dynamically
+ * allocated using alloc_chrdev_region() by default or left to user to specify
+ * it during load time. For this variable major is used as module_param
+ * Nodes to be created using
+ * mknod /dev/isi c $major 0
+ * mknod /dev/rpc c $major 1
+ * mknod /dev/audio c $major 2
+ * mknod /dev/sec c $major 3
+ */
+int isa_init(struct shrm_dev *shrm)
+{
+	dev_t	dev_id;
+	int	retval, no_dev;
+	struct isadev_context *isadev;
+	struct isa_driver_context *isa_context;
+
+	isa_context = kzalloc(sizeof(struct isa_driver_context),
+								GFP_KERNEL);
+	if (isa_context == NULL) {
+		dev_err(shrm->dev, "Failed to alloc memory\n");
+		return -ENOMEM;
+	}
+	shrm->isa_context = isa_context;
+	/*
+	 * L2 header of loopback device is 192(0xc0). As per the shrm
+	 * protocol the minor id of the deivce is mapped to the
+	 * L2 header.
+	 */
+	retval = alloc_chrdev_region(&dev_id, 0, MAX_L2_HEADERS, NAME);
+	major = MAJOR(dev_id);
+	dev_dbg(shrm->dev, " major %d\n", major);
+
+	cdev_init(&isa_context->cdev, &isa_fops);
+	isa_context->cdev.owner = THIS_MODULE;
+	retval = cdev_add(&isa_context->cdev, dev_id, MAX_L2_HEADERS);
+	if (retval) {
+		dev_err(shrm->dev, "Failed to add char device\n");
+		return retval;
+	}
+	/* create class and device */
+	isa_context->shrm_class = class_create(THIS_MODULE, NAME);
+	if (IS_ERR(isa_context->shrm_class)) {
+		dev_err(shrm->dev, "Error creating shrm class\n");
+		cdev_del(&isa_context->cdev);
+		retval = PTR_ERR(isa_context->shrm_class);
+		kfree(isa_context);
+		return retval;
+	}
+
+	for (no_dev = 0; no_dev < ISA_DEVICES; no_dev++) {
+		atomic_set(&isa_context->is_open[no_dev], 1);
+		device_create(isa_context->shrm_class, NULL,
+				MKDEV(MAJOR(dev_id),
+				map_dev[no_dev].l2_header), NULL,
+				map_dev[no_dev].name);
+	}
+
+	isa_context->isadev = kzalloc(sizeof
+				(struct isadev_context)*ISA_DEVICES,
+				GFP_KERNEL);
+	if (isa_context->isadev == NULL) {
+		dev_err(shrm->dev, "Failed to alloc memory\n");
+		goto alloc_fail;
+	}
+	for (no_dev = 0 ; no_dev < ISA_DEVICES ; no_dev++) {
+		isadev = &isa_context->isadev[no_dev];
+		isadev->device_id = no_dev;
+		retval = create_queue(&isadev->dl_queue,
+					isadev->device_id, shrm);
+
+		if (retval < 0) {
+			dev_err(shrm->dev, "create dl_queue failed\n");
+			delete_queue(&isadev->dl_queue);
+			kfree(isadev);
+			return retval;
+		}
+	}
+	mutex_init(&isa_context->tx_audio_mutex);
+	spin_lock_init(&isa_context->common_tx);
+	dev_dbg(shrm->dev, " SHRM Char Driver added\n");
+	return retval;
+alloc_fail:
+	class_destroy(isa_context->shrm_class);
+	cdev_del(&isa_context->cdev);
+	unregister_chrdev_region(dev_id, ISA_DEVICES);
+	kfree(isa_context);
+	return -ENOMEM;
+}
+
+void isa_exit(struct shrm_dev *shrm)
+{
+	int no_dev;
+	struct isadev_context *isadev;
+	struct isa_driver_context *isa_context = shrm->isa_context;
+	dev_t dev_id = MKDEV(major, 0);
+
+	for (no_dev = 0 ; no_dev < ISA_DEVICES ; no_dev++) {
+		device_destroy(isa_context->shrm_class,
+				MKDEV(MAJOR(dev_id),
+				map_dev[no_dev].l2_header));
+		isadev = &isa_context->isadev[no_dev];
+		delete_queue(&isadev->dl_queue);
+		kfree(isadev);
+	}
+	class_destroy(isa_context->shrm_class);
+	cdev_del(&isa_context->cdev);
+	unregister_chrdev_region(dev_id, ISA_DEVICES);
+	kfree(isa_context);
+	dev_dbg(shrm->dev, " SHRM Char Driver removed\n");
+}
diff --git a/drivers/modem_shm/u8500_shm/shrm_config.h b/drivers/modem_shm/u8500_shm/shrm_config.h
new file mode 100644
index 0000000..293f706
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_config.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_CONFIG_H
+#define __SHRM_CONFIG_H
+
+
+/*
+Note: modem need to define IPC as a non-cacheable area.
+In Cortex R4 MPU requires that base address of NC area is aligned on a
+region-sized boundary.On modem side, only 1 NC area can be defined, hence
+the whole IPC area must be defined as NC (at least).
+
+*/
+
+/* cache line size = 32bytes*/
+#define SHRM_CACHE_LINE 32
+#define SHRM_PTR_SIZE 4
+
+/* FIFO 0 address configuration */
+/* ---------------------------- */
+/* 128KB */
+#define SHRM_FIFO_0_SIZE (128*1024)
+
+
+/* == APE addresses == */
+#ifdef CONFIG_SHRM_V1_UPDATES_VERSION
+#define SHRM_IPC_BASE_AMCU 0x06F80000
+#define SHRM_IPC_END_AMCU 0x06FFFFFF
+#else
+#define SHRM_IPC_BASE_AMCU 0x06000000
+#define SHRM_IPC_END_AMCU 0x0607FFFF
+#endif
+
+/* offset pointers */
+#define SHRM_ACFIFO_0_WRITE_AMCU SHRM_IPC_BASE_AMCU
+#define SHRM_ACFIFO_0_READ_AMCU (SHRM_ACFIFO_0_WRITE_AMCU + SHRM_PTR_SIZE)
+#define SHRM_CAFIFO_0_WRITE_AMCU (SHRM_ACFIFO_0_WRITE_AMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_0_READ_AMCU (SHRM_CAFIFO_0_WRITE_AMCU + SHRM_PTR_SIZE)
+#define SHRM_CA_MOD_RESET_STATUS_AMCU (SHRM_IPC_END_AMCU - 4)
+/* FIFO start */
+#define SHRM_ACFIFO_0_START_AMCU (SHRM_CAFIFO_0_WRITE_AMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_0_START_AMCU (SHRM_ACFIFO_0_START_AMCU + SHRM_FIFO_0_SIZE)
+
+
+/* == CMT addresses ==*/
+#define SHRM_IPC_BASE_CMCU (SHRM_IPC_BASE_AMCU+0x08000000)
+/* offset pointers */
+#define SHRM_ACFIFO_0_WRITE_CMCU SHRM_IPC_BASE_CMCU
+#define SHRM_ACFIFO_0_READ_CMCU (SHRM_ACFIFO_0_WRITE_CMCU + SHRM_PTR_SIZE)
+#define SHRM_CAFIFO_0_WRITE_CMCU (SHRM_ACFIFO_0_WRITE_CMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_0_READ_CMCU (SHRM_CAFIFO_0_WRITE_CMCU + SHRM_PTR_SIZE)
+/* FIFO*/
+#define SHRM_ACFIFO_0_START_CMCU (SHRM_CAFIFO_0_WRITE_CMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_0_START_CMCU (SHRM_ACFIFO_0_START_CMCU + SHRM_FIFO_0_SIZE)
+
+
+/* ADSP addresses*/
+#define SHRM_ACFIFO_0_START_ADSP 0x0
+#define SHRM_CAFIFO_0_START_ADSP 0x0
+#define SHRM_ACFIFO_0_WRITE_ADSP 0x0
+#define SHRM_ACFIFO_0_READ_ADSP 0x0
+#define SHRM_CAFIFO_0_WRITE_ADSP 0x0
+#define SHRM_CAFIFO_0_READ_ADSP 0x0
+
+/* FIFO 1 address configuration */
+/* ---------------------------- */
+
+
+/* FIFO 1 - 4K  */
+#define SHRM_FIFO_1_SIZE (4*1024)
+
+
+/* == APE addresses == */
+#define SHRM_ACFIFO_1_WRITE_AMCU (SHRM_CAFIFO_0_START_AMCU + SHRM_FIFO_0_SIZE)
+#define SHRM_ACFIFO_1_READ_AMCU (SHRM_ACFIFO_1_WRITE_AMCU + SHRM_PTR_SIZE)
+#define SHRM_CAFIFO_1_WRITE_AMCU (SHRM_ACFIFO_1_WRITE_AMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_1_READ_AMCU (SHRM_CAFIFO_1_WRITE_AMCU + SHRM_PTR_SIZE)
+/* FIFO*/
+#define SHRM_ACFIFO_1_START_AMCU (SHRM_CAFIFO_1_WRITE_AMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_1_START_AMCU (SHRM_ACFIFO_1_START_AMCU + SHRM_FIFO_1_SIZE)
+
+
+/* == CMT addresses ==*/
+#define SHRM_ACFIFO_1_WRITE_CMCU (SHRM_CAFIFO_0_START_CMCU + SHRM_FIFO_0_SIZE)
+#define SHRM_ACFIFO_1_READ_CMCU (SHRM_ACFIFO_1_WRITE_CMCU + SHRM_PTR_SIZE)
+#define SHRM_CAFIFO_1_WRITE_CMCU (SHRM_ACFIFO_1_WRITE_CMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_1_READ_CMCU (SHRM_CAFIFO_1_WRITE_CMCU + SHRM_PTR_SIZE)
+/* FIFO1 start */
+#define SHRM_ACFIFO_1_START_CMCU (SHRM_CAFIFO_1_WRITE_CMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_1_START_CMCU (SHRM_ACFIFO_1_START_CMCU + SHRM_FIFO_1_SIZE)
+
+
+/* ADSP addresses*/
+#define SHRM_ACFIFO_1_START_ADSP 0x0
+#define SHRM_CAFIFO_1_START_ADSP 0x0
+#define SHRM_ACFIFO_1_WRITE_ADSP 0x0
+#define SHRM_ACFIFO_1_READ_ADSP 0x0
+#define SHRM_CAFIFO_1_WRITE_ADSP 0x0
+#define SHRM_CAFIFO_1_READ_ADSP 0x0
+
+
+#define U8500_SHRM_FIFO_APE_COMMON_BASE  (SHRM_ACFIFO_0_START_AMCU)
+#define U8500_SHRM_FIFO_CMT_COMMON_BASE  (SHRM_CAFIFO_0_START_AMCU)
+#define U8500_SHRM_FIFO_APE_AUDIO_BASE   (SHRM_ACFIFO_1_START_AMCU)
+#define U8500_SHRM_FIFO_CMT_AUDIO_BASE   (SHRM_CAFIFO_1_START_AMCU)
+
+#endif /* __SHRM_CONFIG_H */
diff --git a/drivers/modem_shm/u8500_shm/shrm_driver.c b/drivers/modem_shm/u8500_shm/shrm_driver.c
new file mode 100644
index 0000000..19119d6
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_driver.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/io.h>
+#include <linux/skbuff.h>
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtimer.h>
+static struct hrtimer timer;
+#endif
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/phonet.h>
+
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_config.h"
+#include "shrm_net.h"
+#include "shrm.h"
+#include "shrm_ioctl.h"
+
+/* debug functionality */
+#define ISA_DEBUG 0
+
+/* count for no of msg to be check befor suspend */
+#define CHK_SLP_MSG_CNT 3
+
+#define PHONET_TASKLET
+#define MAX_RCV_LEN	2048
+
+static void do_phonet_rcv_tasklet(unsigned long unused);
+struct tasklet_struct phonet_rcv_tasklet;
+
+/**
+ * audio_receive() - Receive audio channel completion callback
+ * @shrm:	pointer to shrm device information structure
+ * @data:	message pointer
+ * @n_bytes:	message size
+ * @l2_header:	L2 header/device ID 2->audio, 5->audio_loopback
+ *
+ * This fucntion is called from the audio receive handler. Copies the audio
+ * message from the FIFO to the AUDIO queue. The message is later copied from
+ * this queue to the user buffer through the char or net interface read
+ * operation.
+ */
+static int audio_receive(struct shrm_dev *shrm, void *data,
+					u32 n_bytes, u8 l2_header)
+{
+	u32 size = 0;
+	int ret = 0;
+	int idx;
+	u8 *psrc;
+	struct message_queue *q;
+	struct isadev_context *audiodev;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	idx = shrm_get_cdev_index(l2_header);
+	if (idx < 0) {
+		dev_err(shrm->dev, "failed to get index\n");
+		return idx;
+	}
+	audiodev = &shrm->isa_context->isadev[idx];
+	q = &audiodev->dl_queue;
+	spin_lock(&q->update_lock);
+	/* Memcopy RX data first */
+	if ((q->writeptr+n_bytes) >= q->size) {
+		psrc = (u8 *)data;
+		size = (q->size-q->writeptr);
+		/* Copy First Part of msg */
+		memcpy((q->fifo_base+q->writeptr), psrc, size);
+		psrc += size;
+		/* Copy Second Part of msg at the top of fifo */
+		memcpy(q->fifo_base, psrc, (n_bytes-size));
+	} else {
+		memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+	}
+	ret = add_msg_to_queue(q, n_bytes);
+	spin_unlock(&q->update_lock);
+	if (ret < 0)
+		dev_err(shrm->dev, "Adding a msg to message queue failed");
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return ret;
+}
+
+/**
+ * common_receive() - Receive common channel completion callback
+ * @shrm:	pointer to the shrm device information structure
+ * @data:	message pointer
+ * @n_bytes:	message size
+ * @l2_header:	L2 header / device ID
+ *
+ * This function is called from the receive handler to copy the respective
+ * ISI, RPC, SECURITY message to its respective queue. The message is then
+ * copied from queue to the user buffer on char net interface read operation.
+ */
+static int common_receive(struct shrm_dev *shrm, void *data,
+					u32 n_bytes, u8 l2_header)
+{
+	u32 size = 0;
+	int ret = 0;
+	int idx;
+	u8 *psrc;
+	struct message_queue *q;
+	struct isadev_context *isa_dev;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	idx = shrm_get_cdev_index(l2_header);
+	if (idx < 0) {
+		dev_err(shrm->dev, "failed to get index\n");
+		return idx;
+	}
+	isa_dev = &shrm->isa_context->isadev[idx];
+	q = &isa_dev->dl_queue;
+	spin_lock(&q->update_lock);
+	/* Memcopy RX data first */
+	if ((q->writeptr+n_bytes) >= q->size) {
+		dev_dbg(shrm->dev, "Inside Loop Back\n");
+		psrc = (u8 *)data;
+		size = (q->size-q->writeptr);
+		/* Copy First Part of msg */
+		memcpy((q->fifo_base+q->writeptr), psrc, size);
+		psrc += size;
+		/* Copy Second Part of msg at the top of fifo */
+		memcpy(q->fifo_base, psrc, (n_bytes-size));
+	} else {
+		memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+	}
+	ret = add_msg_to_queue(q, n_bytes);
+	spin_unlock(&q->update_lock);
+	if (ret < 0) {
+		dev_err(shrm->dev, "Adding a msg to message queue failed");
+		return ret;
+	}
+
+
+	if (l2_header == ISI_MESSAGING) {
+		if (shrm->netdev_flag_up) {
+			dev_dbg(shrm->dev,
+				"scheduling the phonet tasklet from %s!\n",
+				__func__);
+			tasklet_schedule(&phonet_rcv_tasklet);
+		}
+		dev_dbg(shrm->dev,
+				"Out of phonet tasklet %s!!!\n", __func__);
+	}
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return ret;
+}
+
+/**
+ * rx_common_l2msg_handler() - common channel receive handler
+ * @l2_header:		L2 header
+ * @msg:		pointer to the receive buffer
+ * @length:		length of the msg to read
+ * @shrm:		pointer to shrm device information structure
+ *
+ * This function is called to receive the message from CaMsgPendingNotification
+ * interrupt handler.
+ */
+static void rx_common_l2msg_handler(u8 l2_header,
+				 void *msg, u32 length,
+				 struct shrm_dev *shrm)
+{
+	int ret = 0;
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	ret = common_receive(shrm, msg, length, l2_header);
+	if (ret < 0)
+		dev_err(shrm->dev,
+			"common receive with l2 header %d failed\n", l2_header);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+/**
+ * rx_audio_l2msg_handler() - audio channel receive handler
+ * @l2_header:		L2 header
+ * @msg:		pointer to the receive buffer
+ * @length:		length of the msg to read
+ * @shrm:		pointer to shrm device information structure
+ *
+ * This function is called to receive the message from CaMsgPendingNotification
+ * interrupt handler.
+ */
+static void rx_audio_l2msg_handler(u8 l2_header,
+				void *msg, u32 length,
+				struct shrm_dev *shrm)
+{
+	int ret = 0;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	ret = audio_receive(shrm, msg, length, l2_header);
+	if (ret < 0)
+		dev_err(shrm->dev, "audio receive failed\n");
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static int __init shrm_initialise_irq(struct shrm_dev *shrm)
+{
+	int err = 0;
+
+	err  = shrm_protocol_init(shrm,
+			rx_common_l2msg_handler, rx_audio_l2msg_handler);
+	if (err < 0) {
+		dev_err(shrm->dev, "SHRM Protocol Init Failure\n");
+		return err;
+	}
+
+	err = request_irq(shrm->ca_wake_irq,
+			ca_wake_irq_handler, IRQF_TRIGGER_RISING,
+				 "ca_wake-up", shrm);
+	if (err < 0) {
+		dev_err(shrm->dev,
+				"Unable to allocate shrm tx interrupt line\n");
+		free_irq(shrm->ca_wake_irq, shrm);
+		return err;
+	}
+
+	err = request_irq(shrm->ac_read_notif_0_irq,
+		ac_read_notif_0_irq_handler, 0,
+		"ac_read_notif_0", shrm);
+
+	if (err < 0) {
+		dev_err(shrm->dev,
+				"error ac_read_notif_0_irq interrupt line\n");
+		goto irq_err1;
+	}
+
+	err = request_irq(shrm->ac_read_notif_1_irq,
+		ac_read_notif_1_irq_handler, 0,
+		"ac_read_notif_1", shrm);
+
+	if (err < 0) {
+		dev_err(shrm->dev,
+				"error ac_read_notif_1_irq interrupt line\n");
+		goto irq_err2;
+	}
+
+	err = request_irq(shrm->ca_msg_pending_notif_0_irq,
+		 ca_msg_pending_notif_0_irq_handler, 0,
+		"ca_msg_pending_notif_0", shrm);
+
+	if (err < 0) {
+		dev_err(shrm->dev,
+				"error ca_msg_pending_notif_0_irq line\n");
+		goto irq_err3;
+	}
+
+	err = request_irq(shrm->ca_msg_pending_notif_1_irq,
+		 ca_msg_pending_notif_1_irq_handler, 0,
+		"ca_msg_pending_notif_1", shrm);
+
+	if (err < 0) {
+		dev_err(shrm->dev,
+			"error ca_msg_pending_notif_1_irq interrupt line\n");
+		goto irq_err4;
+	}
+	return err;
+irq_err4:
+	free_irq(shrm->ca_msg_pending_notif_0_irq, shrm);
+irq_err3:
+	free_irq(shrm->ac_read_notif_1_irq, shrm);
+irq_err2:
+	free_irq(shrm->ac_read_notif_0_irq, shrm);
+irq_err1:
+	free_irq(shrm->ca_wake_irq, shrm);
+	return err;
+}
+
+static void free_shrm_irq(struct shrm_dev *shrm)
+{
+	free_irq(shrm->ca_wake_irq, shrm);
+	free_irq(shrm->ac_read_notif_0_irq, shrm);
+	free_irq(shrm->ac_read_notif_1_irq, shrm);
+	free_irq(shrm->ca_msg_pending_notif_0_irq, shrm);
+	free_irq(shrm->ca_msg_pending_notif_1_irq, shrm);
+}
+
+
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+static enum hrtimer_restart callback(struct hrtimer *timer)
+{
+	return HRTIMER_NORESTART;
+}
+#endif
+
+void do_phonet_rcv_tasklet(unsigned long unused)
+{
+	ssize_t ret;
+	struct shrm_dev *shrm = (struct shrm_dev *)unused;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	for (;;) {
+		ret = shrm_net_receive(shrm->ndev);
+		if (ret == 0) {
+			dev_dbg(shrm->dev, "len is zero, queue empty\n");
+			break;
+		}
+		if (ret < 0) {
+			dev_err(shrm->dev, "len < 0 !!! error!!!\n");
+			break;
+		}
+	}
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static int shrm_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	struct resource *res;
+	struct shrm_dev *shrm = NULL;
+
+	shrm = kzalloc(sizeof(struct shrm_dev), GFP_KERNEL);
+	if (shrm == NULL) {
+		dev_err(&pdev->dev,
+			"Could not allocate memory for struct shrm_dev\n");
+		return -ENOMEM;
+	}
+
+	shrm->dev = &pdev->dev;
+	shrm->modem = modem_get(shrm->dev, "u8500-shrm-modem");
+	if (shrm->modem == NULL) {
+		dev_err(shrm->dev, " Could not retrieve the modem.\n");
+		err = -ENODEV;
+		goto rollback_intr;
+	}
+
+	/* initialise the SHRM */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(shrm->dev,
+				"Unable to map Ca Wake up interrupt\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ca_wake_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+	if (!res) {
+		dev_err(shrm->dev,
+			"Unable to map APE_Read_notif_common IRQ base\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ac_read_notif_0_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+
+	if (!res) {
+		dev_err(shrm->dev,
+			"Unable to map APE_Read_notif_audio IRQ base\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ac_read_notif_1_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
+
+	if (!res) {
+		dev_err(shrm->dev,
+			"Unable to map Cmt_msg_pending_notif_common IRQbase\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ca_msg_pending_notif_0_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 4);
+
+	if (!res) {
+		dev_err(shrm->dev,
+			"Unable to map Cmt_msg_pending_notif_audio IRQ base\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ca_msg_pending_notif_1_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res) {
+		dev_err(shrm->dev,
+				"Could not get SHRM IO memory information\n");
+		err = -ENODEV;
+		goto rollback_intr;
+	}
+	shrm->intr_base = (void __iomem *)ioremap_nocache(res->start,
+					res->end - res->start + 1);
+	if (!(shrm->intr_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ape_common_fifo_base_phy =
+			(u32 *)U8500_SHRM_FIFO_APE_COMMON_BASE;
+	shrm->ape_common_fifo_base =
+		(void __iomem *)ioremap_nocache(
+					U8500_SHRM_FIFO_APE_COMMON_BASE,
+					SHRM_FIFO_0_SIZE);
+	shrm->ape_common_fifo_size = (SHRM_FIFO_0_SIZE)/4;
+
+	if (!(shrm->ape_common_fifo_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_ape_common_fifo_base;
+	}
+	shrm->cmt_common_fifo_base_phy =
+		(u32 *)U8500_SHRM_FIFO_CMT_COMMON_BASE;
+	shrm->cmt_common_fifo_base =
+		(void __iomem *)ioremap_nocache(
+			U8500_SHRM_FIFO_CMT_COMMON_BASE, SHRM_FIFO_0_SIZE);
+	shrm->cmt_common_fifo_size = (SHRM_FIFO_0_SIZE)/4;
+
+	if (!(shrm->cmt_common_fifo_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_cmt_common_fifo_base;
+	}
+	shrm->ape_audio_fifo_base_phy =
+			(u32 *)U8500_SHRM_FIFO_APE_AUDIO_BASE;
+	shrm->ape_audio_fifo_base =
+		(void __iomem *)ioremap_nocache(U8500_SHRM_FIFO_APE_AUDIO_BASE,
+							SHRM_FIFO_1_SIZE);
+	shrm->ape_audio_fifo_size = (SHRM_FIFO_1_SIZE)/4;
+
+	if (!(shrm->ape_audio_fifo_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_ape_audio_fifo_base;
+	}
+	shrm->cmt_audio_fifo_base_phy =
+			(u32 *)U8500_SHRM_FIFO_CMT_AUDIO_BASE;
+	shrm->cmt_audio_fifo_base =
+		(void __iomem *)ioremap_nocache(U8500_SHRM_FIFO_CMT_AUDIO_BASE,
+							SHRM_FIFO_1_SIZE);
+	shrm->cmt_audio_fifo_size = (SHRM_FIFO_1_SIZE)/4;
+
+	if (!(shrm->cmt_audio_fifo_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_cmt_audio_fifo_base;
+	}
+	shrm->ac_common_shared_wptr =
+		(void __iomem *)ioremap(SHRM_ACFIFO_0_WRITE_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ac_common_shared_wptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_ac_common_shared_wptr;
+	}
+	shrm->ac_common_shared_rptr =
+		(void __iomem *)ioremap(SHRM_ACFIFO_0_READ_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ac_common_shared_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_common_shared_wptr =
+		(void __iomem *)ioremap(SHRM_CAFIFO_0_WRITE_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ca_common_shared_wptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_common_shared_rptr =
+		(void __iomem *)ioremap(SHRM_CAFIFO_0_READ_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ca_common_shared_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ac_audio_shared_wptr =
+		(void __iomem *)ioremap(SHRM_ACFIFO_1_WRITE_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ac_audio_shared_wptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ac_audio_shared_rptr =
+		(void __iomem *)ioremap(SHRM_ACFIFO_1_READ_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ac_audio_shared_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_audio_shared_wptr =
+		(void __iomem *)ioremap(SHRM_CAFIFO_1_WRITE_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ca_audio_shared_wptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_audio_shared_rptr =
+		(void __iomem *)ioremap(SHRM_CAFIFO_1_READ_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ca_audio_shared_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_reset_status_rptr =
+		(void __iomem *)ioremap(SHRM_CA_MOD_RESET_STATUS_AMCU, SHRM_PTR_SIZE);
+	if (!(shrm->ca_reset_status_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+
+	if (isa_init(shrm) != 0) {
+		dev_err(shrm->dev, "Driver Initialization Error\n");
+		err = -EBUSY;
+	}
+	/* install handlers and tasklets */
+	if (shrm_initialise_irq(shrm)) {
+		dev_err(shrm->dev,
+				"shrm error in interrupt registration\n");
+		goto rollback_irq;
+	}
+#ifdef CONFIG_HIGH_RES_TIMERS
+	hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	timer.function = callback;
+	hrtimer_start(&timer, ktime_set(0, 2*NSEC_PER_MSEC), HRTIMER_MODE_REL);
+#endif
+	err = shrm_register_netdev(shrm);
+	if (err < 0)
+		goto rollback_irq;
+
+	tasklet_init(&phonet_rcv_tasklet, do_phonet_rcv_tasklet, 0);
+	phonet_rcv_tasklet.data = (unsigned long)shrm;
+
+	platform_set_drvdata(pdev, shrm);
+
+	return err;
+rollback_irq:
+	free_shrm_irq(shrm);
+rollback_map:
+	iounmap(shrm->ac_common_shared_wptr);
+	iounmap(shrm->ac_common_shared_rptr);
+	iounmap(shrm->ca_common_shared_wptr);
+	iounmap(shrm->ca_common_shared_rptr);
+	iounmap(shrm->ac_audio_shared_wptr);
+	iounmap(shrm->ac_audio_shared_rptr);
+	iounmap(shrm->ca_audio_shared_wptr);
+	iounmap(shrm->ca_audio_shared_rptr);
+rollback_ac_common_shared_wptr:
+	iounmap(shrm->cmt_audio_fifo_base);
+rollback_cmt_audio_fifo_base:
+	iounmap(shrm->ape_audio_fifo_base);
+rollback_ape_audio_fifo_base:
+	iounmap(shrm->cmt_common_fifo_base);
+rollback_cmt_common_fifo_base:
+	iounmap(shrm->ape_common_fifo_base);
+rollback_ape_common_fifo_base:
+	iounmap(shrm->intr_base);
+rollback_intr:
+	kfree(shrm);
+	return err;
+}
+
+static int __exit shrm_remove(struct platform_device *pdev)
+{
+	struct shrm_dev *shrm = platform_get_drvdata(pdev);
+
+	free_shrm_irq(shrm);
+	iounmap(shrm->intr_base);
+	iounmap(shrm->ape_common_fifo_base);
+	iounmap(shrm->cmt_common_fifo_base);
+	iounmap(shrm->ape_audio_fifo_base);
+	iounmap(shrm->cmt_audio_fifo_base);
+	iounmap(shrm->ac_common_shared_wptr);
+	iounmap(shrm->ac_common_shared_rptr);
+	iounmap(shrm->ca_common_shared_wptr);
+	iounmap(shrm->ca_common_shared_rptr);
+	iounmap(shrm->ac_audio_shared_wptr);
+	iounmap(shrm->ac_audio_shared_rptr);
+	iounmap(shrm->ca_audio_shared_wptr);
+	iounmap(shrm->ca_audio_shared_rptr);
+	shrm_unregister_netdev(shrm);
+	isa_exit(shrm);
+	kfree(shrm);
+
+	return 0;
+}
+
+static int u8500_shrm_chk_unread_msg(struct shrm_dev *shrm)
+{
+	struct message_queue *q;
+	struct isadev_context *isa_dev;
+	int idx;
+	u8 cnt;
+
+	struct sleep_msg_list {
+		u8 l2_header;
+		char *name;
+	};
+
+	/* list of messages or l2 header to be check before going susped */
+	struct sleep_msg_list slp_msg[] = {
+		{RPC_MESSAGING, "RPC"},
+		{SECURITY_MESSAGING, "Security"},
+		{ISI_MESSAGING, "ISI"},
+	};
+
+	for (cnt = 0; cnt < CHK_SLP_MSG_CNT; cnt++) {
+		idx = shrm_get_cdev_index(slp_msg[cnt].l2_header);
+		isa_dev = &shrm->isa_context->isadev[idx];
+		q = &isa_dev->dl_queue;
+		if (!list_empty(&q->msg_list)) {
+
+			if (atomic_dec_and_test(&shrm->isa_context->is_open[idx])) {
+				atomic_inc(&shrm->isa_context->is_open[idx]);
+				dev_info(shrm->dev, "%s device not opened yet, flush queue\n",
+					slp_msg[cnt].name);
+				shrm_char_reset_queues(shrm);
+			} else {
+				atomic_inc(&shrm->isa_context->is_open[idx]);
+				dev_info(shrm->dev, "Some %s msg unread = %d\n",
+					slp_msg[cnt].name, get_size_of_new_msg(q));
+				return -EBUSY;
+			}
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * u8500_shrm_suspend() - This routine puts the SHRM in to sustend state.
+ * @dev:	pointer to device structure.
+ *
+ * This routine checks the current ongoing communication with Modem by
+ * examining the ca_wake state and prevents suspend if modem communication
+ * is on-going.
+ * If ca_wake = 1 (high), modem comm. is on-going; don't suspend
+ * If ca_wake = 0 (low), no comm. with modem on-going.Allow suspend
+ */
+int u8500_shrm_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct shrm_dev *shrm = platform_get_drvdata(pdev);
+	int err;
+
+	dev_dbg(&pdev->dev, "%s called...\n", __func__);
+	dev_dbg(&pdev->dev, "ca_wake_req_state = %x\n",
+						get_ca_wake_req_state());
+
+	/*
+	* Is there are any messages unread in the RPC or Security queue,
+	* dont suspend as these are real time and modem expects response
+	* within 1sec else will end up in a crash. If userspace doesn't
+	* open the device, then will flush the queue and allow device go to suspend
+	*/
+
+	if (u8500_shrm_chk_unread_msg(shrm))
+		return -EBUSY;
+
+	/* if ca_wake_req is high, prevent system suspend */
+	if (!get_ca_wake_req_state()) {
+		err = shrm_suspend_netdev(shrm->ndev);
+		return err;
+	} else
+		return -EBUSY;
+}
+
+/**
+ * u8500_shrm_resume() - This routine resumes the SHRM from suspend state.
+ * @dev:	pointer to device structure
+ *
+ * This routine restore back the current state of the SHRM
+ */
+int u8500_shrm_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct shrm_dev *shrm = platform_get_drvdata(pdev);
+	int err;
+
+	dev_dbg(&pdev->dev, "%s called...\n", __func__);
+	err = shrm_resume_netdev(shrm->ndev);
+
+	return err;
+}
+
+static const struct dev_pm_ops shrm_dev_pm_ops = {
+	.suspend_noirq = u8500_shrm_suspend,
+	.resume_noirq = u8500_shrm_resume,
+};
+#endif
+
+static struct platform_driver shrm_driver = {
+	.remove = __exit_p(shrm_remove),
+	.driver = {
+		.name = "u8500_shrm",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &shrm_dev_pm_ops,
+#endif
+	},
+};
+
+static int __init shrm_driver_init(void)
+{
+	return platform_driver_probe(&shrm_driver, shrm_probe);
+}
+
+static void __exit shrm_driver_exit(void)
+{
+	platform_driver_unregister(&shrm_driver);
+}
+
+module_init(shrm_driver_init);
+module_exit(shrm_driver_exit);
+
+MODULE_AUTHOR("Arun Murthy, Kumar Sanghvi");
+MODULE_DESCRIPTION("Shared Memory Modem Driver Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/modem_shm/u8500_shm/shrm_driver.h b/drivers/modem_shm/u8500_shm/shrm_driver.h
new file mode 100644
index 0000000..f703ee5
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_driver.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_DRIVER_H__
+#define __SHRM_DRIVER_H__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/cdev.h>
+#include <linux/kthread.h>
+#include <linux/modem_shm/modem_client.h>
+
+#include "shrm.h"
+
+#define ISA_DEVICES 8
+
+#define BOOT_INIT  (0)
+#define BOOT_INFO_SYNC  (1)
+#define BOOT_DONE  (2)
+#define BOOT_UNKNOWN (3)
+
+/**
+ * struct shrm_dev - shrm device information
+ * @ca_wake_irq:		CMT wake interrupt number
+ * @ac_read_notif_0_irq:	ape-cmt common channel read notify interrupt
+ * @ac_read_notif_1_irq:	ape-cmt audio channel read notify interrupt
+ * @ca_msg_pending_notif_0_irq:	cmt-ape common channel msg pending interrupt
+ * @ca_msg_pending_notif_1_irq:	cmt-ape audio channel msg pending interrupt
+ * @intr_base:			interrupt base register address
+ * @ape_common_fifo_base:	ape side common channel fifo base addr
+ * @ape_audio_fifo_base:	ape side audio channel fifo base addr
+ * @cmt_common_fifo_base:	cmt side common channel fifo base addr
+ * @cmt_audio_fifo_base:	cmt side audio channel fifo base addr
+ * @ape_common_fifo_base_phy:	physical addr of ape common fifo
+ * @ape_audio_fifo_base_phy:	physical addr of ape audio fifo
+ * @cmt_common_fifo_base_phy:	physical addr of cmt common fifo
+ * @cmt_audio_fifo_base_phy:	physical addr of cmt audio fifo
+ * @ape_common_fifo_size:	ape side common channel fifo size
+ * @ape_audio_fifo_size:	ape side audio channel fifo size
+ * @cmt_common_fifo_size:	cmt side common channel fifo size
+ * @cmt_audio_fifo_size:	cmt side audio channel fifo size
+ * @netdev_flag_up:		flag to indicate up/down of netwok device
+ * @msr_flag:			flag to check on-going MSR sequence
+ * @ac_common_shared_wptr:	ape-cmt common channel write pointer
+ * @ac_common_shared_rptr:	ape-cmt common channel read pointer
+ * @ca_common_shared_wptr:	cmt-ape common channel write pointer
+ * @ca_common_shared_rptr:	cmt-ape common channel read pointer
+ * @ac_audio_shared_wptr:	ape-cmt audio channel write pointer
+ * @ac_audio_shared_rptr:	ape-cmt audio channel read pointer
+ * @ca_audio_shared_wptr:	cmt-ape audio channel write pointer
+ * @ca_audio_shared_rptr:	cmt-ape audio channel read pointer
+ * @ca_reset_status_rptr:	cmt-ape modem reset status pointer
+ * @dev:			pointer to the driver device
+ * @ndev:			pointer to the network device structure
+ * @modem:			poiner to struct modem
+ * @isa_context:		pointer to t_isa_driver_sontext dtructure
+ * @shrm_common_ch_wr_kw:	kthread worker for writing to common channel
+ * @shrm_common_ch_wr_kw_task:	task for writing to common channel
+ * @shrm_audio_ch_wr_kw:		kthread worker for writing to audio channel
+ * @shrm_audio_ch_wr_kw_task:	task for writing to audio channel
+ * @shrm_ac_wake_kw:		kthread worker for receiving ape-cmt wake requests
+ * @shrm_ac_wake_kw_task:	task for receiving ape-cmt wake requests
+ * @shrm_ca_wake_kw:		kthread worker for receiving cmt-ape wake requests
+ * @shrm_ca_wake_kw_task:	task for receiving cmt-ape wake requests
+ * @shrm_ac_sleep_kw:		kthread worker for recieving ape-cmt sleep requests
+ * @shrm_ac_sleep_kw_task:	task for recieving ape-cmt sleep requests
+ * @shrm_mod_stuck_kw:		kthread worker to reset the modem
+ * @shrm_mod_stuck_kw_task:	task for sending modem reset request
+ * @send_ac_msg_pend_notify_0:	work for handling pending message on common
+ * channel
+ * @send_ac_msg_pend_notify_1:	work for handling pending message on audio
+ * channel
+ * @shrm_ac_wake_req:		work to send ape-cmt wake request
+ * @shrm_ca_wake_req:		work to send cmt-ape wake request
+ * @shrm_ca_sleep_req:		work to send cmt-ape sleep request
+ * @shrm_ac_sleep_req:		work to send ape-cmt sleep request
+ * @shrm_mod_reset_req:		work to send a reset request to modem
+ * @shrm_print_dbg_info:		work function to print all prcmu/abb registers
+ */
+struct shrm_dev {
+	u8 ca_wake_irq;
+	u8 ac_read_notif_0_irq;
+	u8 ac_read_notif_1_irq;
+	u8 ca_msg_pending_notif_0_irq;
+	u8 ca_msg_pending_notif_1_irq;
+	void __iomem *intr_base;
+	void __iomem *ape_common_fifo_base;
+	void __iomem *ape_audio_fifo_base;
+	void __iomem *cmt_common_fifo_base;
+	void __iomem *cmt_audio_fifo_base;
+
+	u32 *ape_common_fifo_base_phy;
+	u32 *ape_audio_fifo_base_phy;
+	u32 *cmt_common_fifo_base_phy;
+	u32 *cmt_audio_fifo_base_phy;
+
+	int ape_common_fifo_size;
+	int ape_audio_fifo_size;
+	int cmt_common_fifo_size;
+	int cmt_audio_fifo_size;
+	int netdev_flag_up;
+	int msr_flag;
+
+	void __iomem *ac_common_shared_wptr;
+	void __iomem *ac_common_shared_rptr;
+	void __iomem *ca_common_shared_wptr;
+	void __iomem *ca_common_shared_rptr;
+
+	void __iomem *ac_audio_shared_wptr;
+	void __iomem *ac_audio_shared_rptr;
+	void __iomem *ca_audio_shared_wptr;
+	void __iomem *ca_audio_shared_rptr;
+
+	void __iomem *ca_reset_status_rptr;
+
+	struct device *dev;
+	struct net_device *ndev;
+	struct modem *modem;
+	struct isa_driver_context *isa_context;
+	struct kthread_worker shrm_common_ch_wr_kw;
+	struct task_struct *shrm_common_ch_wr_kw_task;
+	struct kthread_worker shrm_audio_ch_wr_kw;
+	struct task_struct *shrm_audio_ch_wr_kw_task;
+	struct kthread_worker shrm_ac_wake_kw;
+	struct task_struct *shrm_ac_wake_kw_task;
+	struct kthread_worker shrm_ca_wake_kw;
+	struct task_struct *shrm_ca_wake_kw_task;
+	struct kthread_worker shrm_ac_sleep_kw;
+	struct task_struct *shrm_ac_sleep_kw_task;
+	struct kthread_worker shrm_mod_stuck_kw;
+	struct task_struct *shrm_mod_stuck_kw_task;
+	struct kthread_work send_ac_msg_pend_notify_0;
+	struct kthread_work send_ac_msg_pend_notify_1;
+	struct kthread_work shrm_ac_wake_req;
+	struct kthread_work shrm_ca_wake_req;
+	struct kthread_work shrm_ca_sleep_req;
+	struct kthread_work shrm_ac_sleep_req;
+	struct kthread_work shrm_mod_reset_req;
+	struct kthread_work shrm_print_dbg_info;
+};
+
+/**
+ * struct queue_element - information to add an element to queue
+ * @entry:	list entry
+ * @offset:	message offset
+ * @size:	message size
+ * @no:		total number of messages
+ */
+struct queue_element {
+	struct list_head entry;
+	u32 offset;
+	u32 size;
+	u32 no;
+};
+
+/**
+ * struct message_queue - ISI, RPC, AUDIO, SECURITY message queue information
+ * @fifo_base:		pointer to the respective fifo base
+ * @size:		size of the data to be read
+ * @readptr:		fifo read pointer
+ * @writeptr:		fifo write pointer
+ * @no:			total number of messages
+ * @update_lock:	spinlock for protecting the queue read operation
+ * @q_rp:		queue write pointer
+ * @wq_readable:	wait queue head
+ * @msg_list:		message list
+ * @shrm:		pointer to shrm device information structure
+ */
+struct message_queue {
+      u8 *fifo_base;
+      u32 size;
+      u32 readptr;
+      u32 writeptr;
+      u32 no;
+      spinlock_t update_lock;
+      atomic_t q_rp;
+      wait_queue_head_t wq_readable;
+      struct list_head msg_list;
+      struct shrm_dev *shrm;
+};
+
+/**
+ * struct isadev_context - shrm char interface context
+ * @dl_queue:	structre to store the queue related info
+ * @device_id:	message id(ISI, RPC, AUDIO, SECURITY)
+ * @addr:	device addresses.
+ */
+struct isadev_context {
+	struct message_queue dl_queue;
+	u8 device_id;
+	void *addr;
+};
+
+/**
+ * struct isa_driver_context - shrm char interface device information
+ * @is_open:		flag to check the usage of queue
+ * @isadev:		pointer to struct t_isadev_context
+ * @common_tx:		spinlock for protecting common channel
+ * @tx_audio_mutex:	mutex for protecting audio channel
+ * @cdev:		character device structre
+ * @shrm_class:		pointer to the class structure
+ */
+struct isa_driver_context {
+	atomic_t is_open[ISA_DEVICES];
+	struct isadev_context *isadev;
+	spinlock_t common_tx;
+	struct mutex tx_audio_mutex;
+	struct cdev cdev;
+	struct class *shrm_class;
+};
+
+#endif
diff --git a/drivers/modem_shm/u8500_shm/shrm_fifo.c b/drivers/modem_shm/u8500_shm/shrm_fifo.c
new file mode 100644
index 0000000..f6dc069
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_fifo.c
@@ -0,0 +1,838 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/mfd/dbx500-prcmu.h>
+
+#include "shrm.h"
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_net.h"
+
+#define L1_BOOT_INFO_REQ	1
+#define L1_BOOT_INFO_RESP	2
+#define L1_NORMAL_MSG		3
+#define L1_HEADER_MASK		28
+#define L1_MAPID_MASK		0xF0000000
+#define CONFIG_OFFSET		8
+#define COUNTER_OFFSET		20
+#define L2_HEADER_SIZE		4
+#define L2_HEADER_OFFSET	24
+#define MASK_0_15_BIT		0xFF
+#define MASK_16_31_BIT		0xFF00
+#define MASK_16_27_BIT		0xFFF0000
+#define MASK_0_39_BIT		0xFFFFF
+#define MASK_40_55_BIT		0xFF00000
+#define MASK_8_16_BIT           0x0000FF00
+#define MSG_LEN_OFFSET          16
+#define SHRM_VER                2
+#define ca_ist_inactivity_timer 25 /*25ms */
+#define ca_csc_inactivity_timer 25 /*25ms */
+
+static u8 msg_audio_counter;
+static u8 msg_common_counter;
+
+static struct fifo_write_params ape_shrm_fifo_0;
+static struct fifo_write_params ape_shrm_fifo_1;
+static struct fifo_read_params cmt_shrm_fifo_0;
+static struct fifo_read_params cmt_shrm_fifo_1;
+
+
+static u8 cmt_read_notif_0_send;
+static u8 cmt_read_notif_1_send;
+
+void shrm_fifo_init(struct shrm_dev *shrm)
+{
+	ape_shrm_fifo_0.writer_local_wptr	= 0;
+	ape_shrm_fifo_0.writer_local_rptr	= 0;
+	*((u32 *)shrm->ac_common_shared_wptr) = 0;
+	*((u32 *)shrm->ac_common_shared_rptr) = 0;
+	ape_shrm_fifo_0.shared_wptr		= 0;
+	ape_shrm_fifo_0.shared_rptr		= 0;
+	ape_shrm_fifo_0.availablesize = shrm->ape_common_fifo_size;
+	ape_shrm_fifo_0.end_addr_fifo    = shrm->ape_common_fifo_size;
+	ape_shrm_fifo_0.fifo_virtual_addr = shrm->ape_common_fifo_base;
+	spin_lock_init(&ape_shrm_fifo_0.fifo_update_lock);
+
+
+	cmt_shrm_fifo_0.reader_local_rptr	= 0;
+	cmt_shrm_fifo_0.reader_local_wptr	= 0;
+	cmt_shrm_fifo_0.shared_wptr	=
+			*((u32 *)shrm->ca_common_shared_wptr);
+	cmt_shrm_fifo_0.shared_rptr	=
+			*((u32 *)shrm->ca_common_shared_rptr);
+	cmt_shrm_fifo_0.availablesize	= shrm->cmt_common_fifo_size;
+	cmt_shrm_fifo_0.end_addr_fifo	= shrm->cmt_common_fifo_size;
+	cmt_shrm_fifo_0.fifo_virtual_addr = shrm->cmt_common_fifo_base;
+
+	ape_shrm_fifo_1.writer_local_wptr	= 0;
+	ape_shrm_fifo_1.writer_local_rptr	= 0;
+	ape_shrm_fifo_1.shared_wptr		= 0;
+	ape_shrm_fifo_1.shared_rptr		= 0;
+	*((u32 *)shrm->ac_audio_shared_wptr) = 0;
+	*((u32 *)shrm->ac_audio_shared_rptr) = 0;
+	ape_shrm_fifo_1.availablesize = shrm->ape_audio_fifo_size;
+	ape_shrm_fifo_1.end_addr_fifo    = shrm->ape_audio_fifo_size;
+	ape_shrm_fifo_1.fifo_virtual_addr = shrm->ape_audio_fifo_base;
+	spin_lock_init(&ape_shrm_fifo_1.fifo_update_lock);
+
+	cmt_shrm_fifo_1.reader_local_rptr	= 0;
+	cmt_shrm_fifo_1.reader_local_wptr	= 0;
+	cmt_shrm_fifo_1.shared_wptr		=
+			*((u32 *)shrm->ca_audio_shared_wptr);
+	cmt_shrm_fifo_1.shared_rptr		=
+			*((u32 *)shrm->ca_audio_shared_rptr);
+	cmt_shrm_fifo_1.availablesize	= shrm->cmt_audio_fifo_size;
+	cmt_shrm_fifo_1.end_addr_fifo	= shrm->cmt_audio_fifo_size;
+	cmt_shrm_fifo_1.fifo_virtual_addr = shrm->cmt_audio_fifo_base;
+	msg_audio_counter = 0;
+	msg_common_counter = 0;
+}
+
+u8 read_boot_info_req(struct shrm_dev *shrm,
+				u32 *config,
+				u32 *version)
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_0;
+	u32 *msg;
+	u32 header = 0;
+	u8 msgtype;
+
+	/* Read L1 header read content of reader_local_rptr */
+	msg = (u32 *)
+		(fifo->reader_local_rptr + fifo->fifo_virtual_addr);
+	header = *msg;
+	msgtype = (header & L1_MAPID_MASK) >> L1_MSG_MAPID_OFFSET;
+	if (msgtype != L1_BOOT_INFO_REQ) {
+		dev_err(shrm->dev, "Read_Boot_Info_Req Fatal ERROR\n");
+		dev_err(shrm->dev, "Received msgtype is %d\n", msgtype);
+		dev_info(shrm->dev, "Initiating a modem reset\n");
+		queue_kthread_work(&shrm->shrm_ac_wake_kw,
+				&shrm->shrm_mod_reset_req);
+		return 0;
+	}
+	*config = (header >> CONFIG_OFFSET) & MASK_0_15_BIT;
+	*version = header & MASK_0_15_BIT;
+	fifo->reader_local_rptr += 1;
+
+	return 1;
+}
+
+void write_boot_info_resp(struct shrm_dev *shrm, u32 config,
+							u32 version)
+{
+	struct fifo_write_params *fifo = &ape_shrm_fifo_0;
+	u32 *msg;
+	u8 msg_length;
+	version = SHRM_VER;
+
+	spin_lock_bh(&fifo->fifo_update_lock);
+	/* Read L1 header read content of reader_local_rptr */
+	msg = (u32 *)
+		(fifo->writer_local_wptr+fifo->fifo_virtual_addr);
+	if (version < 1)	{
+		*msg = ((L1_BOOT_INFO_RESP << L1_MSG_MAPID_OFFSET) |
+				((config << CONFIG_OFFSET) & MASK_16_31_BIT)
+				| (version & MASK_0_15_BIT));
+		msg_length = 1;
+	} else {
+		*msg = ((L1_BOOT_INFO_RESP << L1_MSG_MAPID_OFFSET) |
+			((0x8 << MSG_LEN_OFFSET) & MASK_16_27_BIT) |
+			((config << CONFIG_OFFSET) & MASK_8_16_BIT)|
+			version);
+		msg++;
+		*msg = ca_ist_inactivity_timer;
+		msg++;
+		*msg = ca_csc_inactivity_timer;
+		msg_length = L1_NORMAL_MSG;
+	}
+	fifo->writer_local_wptr += msg_length;
+	fifo->availablesize -= msg_length;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+/**
+ * shrm_write_msg_to_fifo() - write message to FIFO
+ * @shrm:	pointer to shrm device information structure
+ * @channel:	audio or common channel
+ * @l2header:	L2 header or device ID
+ * @addr:	pointer to write buffer address
+ * @length:	length of mst to write
+ *
+ * Function Which Writes the data into Fifo in IPC zone
+ * It is called from shrm_write_msg. This function will copy the msg
+ * from the kernel buffer to FIFO. There are 4 kernel buffers from where
+ * the data is to copied to FIFO one for each of the messages ISI, RPC,
+ * AUDIO and SECURITY. ISI, RPC and SECURITY messages are pushed to FIFO
+ * in commmon channel and AUDIO message is pushed onto audio channel FIFO.
+ */
+int shrm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
+				u8 l2header, void *addr, u32 length)
+{
+	struct fifo_write_params *fifo = NULL;
+	u32 l1_header = 0, l2_header = 0;
+	u32 requiredsize;
+	u32 size = 0;
+	u32 *msg;
+	u8 *src;
+
+	if (channel == COMMON_CHANNEL)
+		fifo = &ape_shrm_fifo_0;
+	else if (channel == AUDIO_CHANNEL)
+		fifo = &ape_shrm_fifo_1;
+	else {
+		dev_err(shrm->dev, "invalid channel\n");
+		return -EINVAL;
+	}
+
+	/* L2 size in 32b */
+	requiredsize = ((length + 3) / 4);
+	/* Add size of L1 & L2 header */
+	requiredsize += 2;
+
+	/* if availablesize = or < requiredsize then error */
+	if (fifo->availablesize <= requiredsize) {
+		/* Fatal ERROR - should never happens */
+		dev_dbg(shrm->dev, "wr_wptr= %x\n",
+					fifo->writer_local_wptr);
+		dev_dbg(shrm->dev, "wr_rptr= %x\n",
+					fifo->writer_local_rptr);
+		dev_dbg(shrm->dev, "shared_wptr= %x\n",
+						fifo->shared_wptr);
+		dev_dbg(shrm->dev, "shared_rptr= %x\n",
+						fifo->shared_rptr);
+		dev_dbg(shrm->dev, "availsize= %x\n",
+						fifo->availablesize);
+		dev_dbg(shrm->dev, "end__fifo= %x\n",
+				fifo->end_addr_fifo);
+		dev_warn(shrm->dev, "Modem is busy, please wait."
+				" c_cnt = %d; a_cnt = %d\n", msg_common_counter,
+				msg_audio_counter);
+		if (channel == COMMON_CHANNEL) {
+			dev_warn(shrm->dev,
+					"Modem is lagging behind in reading."
+					"Stopping n/w dev queue\n");
+			shrm_stop_netdev(shrm->ndev);
+		}
+
+		return -EAGAIN;
+	}
+
+	if (channel == COMMON_CHANNEL) {
+		/* build L1 header */
+		l1_header = ((L1_NORMAL_MSG << L1_MSG_MAPID_OFFSET) |
+				(((msg_common_counter++) << COUNTER_OFFSET)
+				 & MASK_40_55_BIT) |
+				((length + L2_HEADER_SIZE) & MASK_0_39_BIT));
+	} else if (channel == AUDIO_CHANNEL) {
+		/* build L1 header */
+		l1_header = ((L1_NORMAL_MSG << L1_MSG_MAPID_OFFSET) |
+				(((msg_audio_counter++) << COUNTER_OFFSET)
+				 & MASK_40_55_BIT) |
+				((length + L2_HEADER_SIZE) & MASK_0_39_BIT));
+	}
+
+	/*
+	 * Need to take care race condition for fifo->availablesize
+	 * & fifo->writer_local_rptr with Ac_Read_notification interrupt.
+	 * One option could be use stack variable for LocalRptr and recompute
+	 * fifo->availablesize,based on flag enabled in the
+	 * Ac_read_notification
+	 */
+	l2_header = ((l2header << L2_HEADER_OFFSET) |
+					((length) & MASK_0_39_BIT));
+	spin_lock_bh(&fifo->fifo_update_lock);
+	/* Check Local Rptr is less than or equal to Local WPtr */
+	if (fifo->writer_local_rptr <= fifo->writer_local_wptr) {
+		msg = (u32 *)
+			(fifo->fifo_virtual_addr+fifo->writer_local_wptr);
+
+		/* check enough place bewteen writer_local_wptr & end of FIFO */
+		if ((fifo->end_addr_fifo-fifo->writer_local_wptr) >=
+							requiredsize) {
+			/* Add L1 header and L2 header */
+			*msg = l1_header;
+			msg++;
+			*msg = l2_header;
+			msg++;
+
+			/* copy the l2 message in 1 memcpy */
+			memcpy((void *)msg, addr, length);
+			/* UpdateWptr */
+			fifo->writer_local_wptr += requiredsize;
+			fifo->availablesize -= requiredsize;
+			fifo->writer_local_wptr %= fifo->end_addr_fifo;
+		} else {
+			/*
+			 * message is split between and of FIFO and beg of FIFO
+			 * copy first part from writer_local_wptr to end of FIFO
+			 */
+			size = fifo->end_addr_fifo-fifo->writer_local_wptr;
+
+			if (size == 1) {
+				/* Add L1 header */
+				*msg = l1_header;
+				msg++;
+				/* UpdateWptr */
+				fifo->writer_local_wptr = 0;
+				fifo->availablesize -= size;
+				/*
+				 * copy second part from beg of FIFO
+				 * with remaining part of msg
+				 */
+				msg =	(u32 *)
+						fifo->fifo_virtual_addr;
+				*msg = l2_header;
+				msg++;
+
+				/* copy the l3 message in 1 memcpy */
+				memcpy((void *)msg, addr, length);
+				/* UpdateWptr */
+				fifo->writer_local_wptr +=
+							requiredsize-size;
+				fifo->availablesize -=
+							(requiredsize-size);
+			} else if (size == 2) {
+				/* Add L1 header and L2 header */
+				*msg = l1_header;
+				msg++;
+				*msg = l2_header;
+				msg++;
+
+				/* UpdateWptr */
+				fifo->writer_local_wptr = 0;
+				fifo->availablesize -= size;
+
+				/*
+				 * copy second part from beg of FIFO
+				 * with remaining part of msg
+				 */
+				msg =	(u32 *)
+						fifo->fifo_virtual_addr;
+				/* copy the l3 message in 1 memcpy */
+				memcpy((void *)msg, addr, length);
+
+				/* UpdateWptr */
+				fifo->writer_local_wptr +=
+							requiredsize-size;
+				fifo->availablesize -=
+							(requiredsize-size);
+			} else {
+				/* Add L1 header and L2 header */
+				*msg = l1_header;
+				msg++;
+				*msg = l2_header;
+				msg++;
+
+				/* copy the l2 message in 1 memcpy */
+				memcpy((void *)msg, addr, (size-2)*4);
+
+
+				/* UpdateWptr */
+				fifo->writer_local_wptr = 0;
+				fifo->availablesize -= size;
+
+				/*
+				 * copy second part from beg of FIFO
+				 * with remaining part of msg
+				 */
+				msg = (u32 *)fifo->fifo_virtual_addr;
+				src = (u8 *)addr+((size - 2) * 4);
+				memcpy((void *)msg, src,
+						(length-((size - 2) * 4)));
+
+				/* UpdateWptr */
+				fifo->writer_local_wptr +=
+							requiredsize-size;
+				fifo->availablesize -=
+							(requiredsize-size);
+			}
+
+		}
+	} else {
+		/* writer_local_rptr > writer_local_wptr */
+		msg = (u32 *)
+			(fifo->fifo_virtual_addr+fifo->writer_local_wptr);
+		/* Add L1 header and L2 header */
+		*msg = l1_header;
+		msg++;
+		*msg = l2_header;
+		msg++;
+		/*
+		 * copy message possbile between writer_local_wptr up
+		 * to writer_local_rptr copy the l3 message in 1 memcpy
+		 */
+		memcpy((void *)msg, addr, length);
+
+		/* UpdateWptr */
+		fifo->writer_local_wptr += requiredsize;
+		fifo->availablesize -= requiredsize;
+
+	}
+	spin_unlock_bh(&fifo->fifo_update_lock);
+	return length;
+}
+
+/**
+ * read_one_l2msg_common() - read message from common channel
+ * @shrm:	pointer to shrm device information structure
+ * @l2_msg:	pointer to the read L2 message buffer
+ * @len:	message length
+ *
+ * This function read one message from the FIFO  and returns l2 header type
+ */
+u8 read_one_l2msg_common(struct shrm_dev *shrm,
+			u8 *l2_msg, u32 *len)
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_0;
+
+	u32 *msg;
+	u32 l1_header = 0;
+	u32 l2_header = 0;
+	u32 length;
+	u8 msgtype;
+	u32 msg_size;
+	u32 size = 0;
+
+	/* Read L1 header read content of reader_local_rptr */
+	msg = (u32 *)
+		(fifo->reader_local_rptr+fifo->fifo_virtual_addr);
+	l1_header = *msg++;
+	msgtype = (l1_header & 0xF0000000) >> L1_HEADER_MASK;
+
+	if (msgtype != L1_NORMAL_MSG) {
+		/* Fatal ERROR - should never happens */
+		dev_info(shrm->dev, "wr_wptr= %x\n",
+						fifo->reader_local_wptr);
+		dev_info(shrm->dev, "wr_rptr= %x\n",
+						fifo->reader_local_rptr);
+		dev_info(shrm->dev, "shared_wptr= %x\n",
+						fifo->shared_wptr);
+		dev_info(shrm->dev, "shared_rptr= %x\n",
+						fifo->shared_rptr);
+		dev_info(shrm->dev, "availsize= %x\n",
+						fifo->availablesize);
+		dev_info(shrm->dev, "end_fifo= %x\n",
+						fifo->end_addr_fifo);
+		/* Fatal ERROR - should never happens */
+		dev_crit(shrm->dev, "Fatal ERROR - should never happen\n");
+		dev_info(shrm->dev, "Initiating a modem reset\n");
+		queue_kthread_work(&shrm->shrm_ac_wake_kw,
+				&shrm->shrm_mod_reset_req);
+	 }
+	if (fifo->reader_local_rptr == (fifo->end_addr_fifo-1)) {
+		l2_header = (*((u32 *)fifo->fifo_virtual_addr));
+		length = l2_header & MASK_0_39_BIT;
+	} else {
+		/* Read L2 header,Msg size & content of reader_local_rptr */
+		l2_header = *msg;
+		length = l2_header & MASK_0_39_BIT;
+	}
+
+	*len = length;
+	msg_size = ((length + 3) / 4);
+	msg_size += 2;
+
+	if (fifo->reader_local_rptr + msg_size <=
+						fifo->end_addr_fifo) {
+		/* Skip L2 header */
+		msg++;
+
+		/* read msg between reader_local_rptr and end of FIFO */
+		memcpy((void *)l2_msg, (void *)msg, length);
+		/* UpdateLocalRptr */
+		fifo->reader_local_rptr += msg_size;
+		fifo->reader_local_rptr %= fifo->end_addr_fifo;
+	} else {
+		/*
+		 * msg split between end of FIFO and beg copy first
+		 * part of msg read msg between reader_local_rptr
+		 * and end of FIFO
+		 */
+		size = fifo->end_addr_fifo-fifo->reader_local_rptr;
+		if (size == 1) {
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			/* Skip L2 header */
+			msg++;
+			memcpy((void *)l2_msg, (void *)(msg), length);
+		} else if (size == 2) {
+			/* Skip L2 header */
+			msg++;
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			memcpy((void *)l2_msg,
+						(void *)(msg), length);
+		} else {
+			/* Skip L2 header */
+			msg++;
+			memcpy((void *)l2_msg, (void *)msg, ((size - 2) * 4));
+			/* copy second part of msg */
+			l2_msg += ((size - 2) * 4);
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			memcpy((void *)l2_msg, (void *)(msg),
+						(length-((size - 2) * 4)));
+		}
+		fifo->reader_local_rptr =
+			(fifo->reader_local_rptr+msg_size) %
+				fifo->end_addr_fifo;
+	}
+	return (l2_header>>L2_HEADER_OFFSET) & MASK_0_15_BIT;
+ }
+
+u8 read_remaining_messages_common()
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_0;
+	/*
+	 * There won't be any Race condition reader_local_rptr &
+	 * fifo->reader_local_wptr with CaMsgpending Notification Interrupt
+	 */
+	return ((fifo->reader_local_rptr != fifo->reader_local_wptr) ? 1 : 0);
+}
+
+u8 read_one_l2msg_audio(struct shrm_dev *shrm,
+				u8 *l2_msg, u32 *len)
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_1;
+
+	u32 *msg;
+	u32 l1_header = 0;
+	u32 l2_header = 0;
+	u32 length;
+	u8 msgtype;
+	u32 msg_size;
+	u32 size = 0;
+
+	/* Read L1 header read content of reader_local_rptr */
+	 msg = (u32 *)
+			(fifo->reader_local_rptr+fifo->fifo_virtual_addr);
+	 l1_header = *msg++;
+	 msgtype = (l1_header & 0xF0000000) >> L1_HEADER_MASK;
+
+	if (msgtype != L1_NORMAL_MSG) {
+		/* Fatal ERROR - should never happens */
+		dev_info(shrm->dev, "wr_local_wptr= %x\n",
+						fifo->reader_local_wptr);
+		dev_info(shrm->dev, "wr_local_rptr= %x\n",
+						fifo->reader_local_rptr);
+		dev_info(shrm->dev, "shared_wptr= %x\n",
+						fifo->shared_wptr);
+		dev_info(shrm->dev, "shared_rptr= %x\n",
+						fifo->shared_rptr);
+		dev_info(shrm->dev, "availsize=%x\n",
+						fifo->availablesize);
+		dev_info(shrm->dev, "end_fifo= %x\n",
+						fifo->end_addr_fifo);
+		dev_info(shrm->dev, "Received msgtype is %d\n", msgtype);
+		/* Fatal ERROR - should never happens */
+		dev_crit(shrm->dev, "Fatal ERROR - should never happen\n");
+		dev_info(shrm->dev, "Initiating a modem reset\n");
+		queue_kthread_work(&shrm->shrm_ac_wake_kw,
+				&shrm->shrm_mod_reset_req);
+	 }
+	if (fifo->reader_local_rptr == (fifo->end_addr_fifo-1)) {
+		l2_header = (*((u32 *)fifo->fifo_virtual_addr));
+		length = l2_header & MASK_0_39_BIT;
+	} else {
+		/* Read L2 header,Msg size & content of reader_local_rptr */
+		l2_header = *msg;
+		length = l2_header & MASK_0_39_BIT;
+	}
+
+	*len = length;
+	msg_size = ((length + 3) / 4);
+	msg_size += 2;
+
+	if (fifo->reader_local_rptr + msg_size <=
+						fifo->end_addr_fifo) {
+		/* Skip L2 header */
+		msg++;
+		/* read msg between reader_local_rptr and end of FIFO */
+		memcpy((void *)l2_msg, (void *)msg, length);
+		/* UpdateLocalRptr */
+		fifo->reader_local_rptr += msg_size;
+		fifo->reader_local_rptr %= fifo->end_addr_fifo;
+	} else {
+
+		/*
+		 * msg split between end of FIFO and beg
+		 * copy first part of msg
+		 * read msg between reader_local_rptr and end of FIFO
+		 */
+		size = fifo->end_addr_fifo-fifo->reader_local_rptr;
+		if (size == 1) {
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			/* Skip L2 header */
+			msg++;
+			memcpy((void *)l2_msg, (void *)(msg), length);
+		} else if (size == 2) {
+			/* Skip L2 header */
+			msg++;
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			memcpy((void *)l2_msg, (void *)(msg), length);
+		} else {
+			/* Skip L2 header */
+			msg++;
+			memcpy((void *)l2_msg, (void *)msg, ((size - 2) * 4));
+			/* copy second part of msg */
+			l2_msg += ((size - 2) * 4);
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			memcpy((void *)l2_msg, (void *)(msg),
+						(length-((size - 2) * 4)));
+		}
+		fifo->reader_local_rptr =
+			(fifo->reader_local_rptr+msg_size) %
+			fifo->end_addr_fifo;
+
+	}
+	return (l2_header>>L2_HEADER_OFFSET) & MASK_0_15_BIT;
+ }
+
+u8 read_remaining_messages_audio()
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_1;
+
+	return ((fifo->reader_local_rptr != fifo->reader_local_wptr) ?
+									1 : 0);
+}
+
+u8 is_the_only_one_unread_message(struct shrm_dev *shrm,
+						u8 channel, u32 length)
+{
+	struct fifo_write_params *fifo = NULL;
+	u32 messagesize = 0;
+	u8 is_only_one_unread_msg = 0;
+
+	if (channel == COMMON_CHANNEL)
+		fifo = &ape_shrm_fifo_0;
+	else /* channel = AUDIO_CHANNEL */
+		fifo = &ape_shrm_fifo_1;
+
+	/* L3 size in 32b */
+	messagesize = ((length + 3) / 4);
+	/* Add size of L1 & L2 header */
+	messagesize += 2;
+	/*
+	 * possibility of race condition with Ac Read notification interrupt.
+	 * need to check ?
+	 */
+	if (fifo->writer_local_wptr > fifo->writer_local_rptr)
+		is_only_one_unread_msg =
+			((fifo->writer_local_rptr + messagesize) ==
+			fifo->writer_local_wptr) ? 1 : 0;
+	else
+		/* Msg split between end of fifo and starting of Fifo */
+		is_only_one_unread_msg =
+			(((fifo->writer_local_rptr + messagesize) %
+			fifo->end_addr_fifo) == fifo->writer_local_wptr) ?
+									1 : 0;
+
+	return is_only_one_unread_msg;
+}
+
+void update_ca_common_local_wptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update CA common reader local write pointer with the
+	 * shared write pointer
+	 */
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_0;
+
+	fifo->shared_wptr =
+		(*((u32 *)shrm->ca_common_shared_wptr));
+	fifo->reader_local_wptr = fifo->shared_wptr;
+}
+
+void update_ca_audio_local_wptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update CA audio reader local write pointer with the
+	 * shared write pointer
+	 */
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_1;
+
+	fifo->shared_wptr =
+		(*((u32 *)shrm->ca_audio_shared_wptr));
+	fifo->reader_local_wptr = fifo->shared_wptr;
+}
+
+void update_ac_common_local_rptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update AC common writer local read pointer with the
+	 * shared read pointer
+	 */
+	struct fifo_write_params *fifo;
+	u32 free_space = 0;
+
+	fifo = &ape_shrm_fifo_0;
+
+	spin_lock_bh(&fifo->fifo_update_lock);
+	fifo->shared_rptr =
+		(*((u32 *)shrm->ac_common_shared_rptr));
+
+	if (fifo->shared_rptr >= fifo->writer_local_rptr)
+		free_space =
+			(fifo->shared_rptr-fifo->writer_local_rptr);
+	else {
+		free_space =
+			(fifo->end_addr_fifo-fifo->writer_local_rptr);
+		free_space += fifo->shared_rptr;
+	}
+
+	/* Chance of race condition of below variables with write_msg */
+	fifo->availablesize += free_space;
+	fifo->writer_local_rptr = fifo->shared_rptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void update_ac_audio_local_rptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update AC audio writer local read pointer with the
+	 * shared read pointer
+	 */
+	struct fifo_write_params *fifo;
+	u32 free_space = 0;
+
+	fifo = &ape_shrm_fifo_1;
+	spin_lock_bh(&fifo->fifo_update_lock);
+	fifo->shared_rptr =
+		(*((u32 *)shrm->ac_audio_shared_rptr));
+
+	if (fifo->shared_rptr >= fifo->writer_local_rptr)
+		free_space =
+			(fifo->shared_rptr-fifo->writer_local_rptr);
+	else {
+		free_space =
+			(fifo->end_addr_fifo-fifo->writer_local_rptr);
+		free_space += fifo->shared_rptr;
+	}
+
+	/* Chance of race condition of below variables with write_msg */
+	fifo->availablesize += free_space;
+	fifo->writer_local_rptr = fifo->shared_rptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void update_ac_common_shared_wptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update AC common shared write pointer with the
+	 * local write pointer
+	 */
+	struct fifo_write_params *fifo;
+
+	fifo = &ape_shrm_fifo_0;
+	spin_lock_bh(&fifo->fifo_update_lock);
+	/* Update shared pointer fifo offset of the IPC zone */
+	(*((u32 *)shrm->ac_common_shared_wptr)) =
+						fifo->writer_local_wptr;
+
+	fifo->shared_wptr = fifo->writer_local_wptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void update_ac_audio_shared_wptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update AC audio shared write pointer with the
+	 * local write pointer
+	 */
+	struct fifo_write_params *fifo;
+
+	fifo = &ape_shrm_fifo_1;
+	spin_lock_bh(&fifo->fifo_update_lock);
+	/* Update shared pointer fifo offset of the IPC zone */
+	(*((u32 *)shrm->ac_audio_shared_wptr)) =
+						fifo->writer_local_wptr;
+	fifo->shared_wptr = fifo->writer_local_wptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void update_ca_common_shared_rptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update CA common shared read pointer with the
+	 * local read pointer
+	 */
+	struct fifo_read_params *fifo;
+
+	fifo = &cmt_shrm_fifo_0;
+
+	/* Update shared pointer fifo offset of the IPC zone */
+	(*((u32 *)shrm->ca_common_shared_rptr)) =
+						fifo->reader_local_rptr;
+	fifo->shared_rptr = fifo->reader_local_rptr;
+}
+
+void update_ca_audio_shared_rptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update CA audio shared read pointer with the
+	 * local read pointer
+	 */
+	struct fifo_read_params *fifo;
+
+	fifo = &cmt_shrm_fifo_1;
+
+	/* Update shared pointer fifo offset of the IPC zone */
+	(*((u32 *)shrm->ca_audio_shared_rptr)) =
+						fifo->reader_local_rptr;
+	fifo->shared_rptr = fifo->reader_local_rptr;
+}
+
+void get_reader_pointers(u8 channel_type, u32 *reader_local_rptr,
+				u32 *reader_local_wptr, u32 *shared_rptr)
+{
+	struct fifo_read_params *fifo = NULL;
+
+	if (channel_type == COMMON_CHANNEL)
+		fifo = &cmt_shrm_fifo_0;
+	else /* channel_type = AUDIO_CHANNEL */
+		fifo = &cmt_shrm_fifo_1;
+
+	*reader_local_rptr = fifo->reader_local_rptr;
+	*reader_local_wptr = fifo->reader_local_wptr;
+	*shared_rptr = fifo->shared_rptr;
+}
+
+void get_writer_pointers(u8 channel_type, u32 *writer_local_rptr,
+			 u32 *writer_local_wptr, u32 *shared_wptr)
+{
+	struct fifo_write_params *fifo = NULL;
+
+	if (channel_type == COMMON_CHANNEL)
+		fifo = &ape_shrm_fifo_0;
+	else /* channel_type = AUDIO_CHANNEL */
+		fifo = &ape_shrm_fifo_1;
+
+	spin_lock_bh(&fifo->fifo_update_lock);
+	*writer_local_rptr = fifo->writer_local_rptr;
+	*writer_local_wptr = fifo->writer_local_wptr;
+	*shared_wptr = fifo->shared_wptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void set_ca_msg_0_read_notif_send(u8 val)
+{
+	cmt_read_notif_0_send = val;
+}
+
+u8 get_ca_msg_0_read_notif_send(void)
+{
+	return cmt_read_notif_0_send;
+}
+
+void set_ca_msg_1_read_notif_send(u8 val)
+{
+	cmt_read_notif_1_send = val;
+}
+
+u8 get_ca_msg_1_read_notif_send(void)
+{
+	return cmt_read_notif_1_send;
+}
diff --git a/drivers/modem_shm/u8500_shm/shrm_ioctl.h b/drivers/modem_shm/u8500_shm/shrm_ioctl.h
new file mode 100644
index 0000000..039839e
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_ioctl.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __MODEM_IPC_INCLUDED
+#define __MODEM_IPC_INCLUDED
+
+#define DLP_IOCTL_MAGIC_NUMBER 'M'
+#define COMMON_BUFFER_SIZE (1024*1024)
+
+/**
+DLP Message Structure for Userland
+*/
+struct t_dlp_message{
+	unsigned int offset;
+	unsigned int size;
+};
+
+/**
+mmap constants.
+*/
+enum t_dlp_mmap_params {
+	MMAP_DLQUEUE,
+	MMAP_ULQUEUE
+};
+
+/**
+DLP IOCTLs for Userland
+*/
+#define DLP_IOC_ALLOCATE_BUFFER \
+	_IOWR(DLP_IOCTL_MAGIC_NUMBER, 0, struct t_dlp_message *)
+#define DLP_IOC_DEALLOCATE_BUFFER \
+	_IOWR(DLP_IOCTL_MAGIC_NUMBER, 1, struct t_dlp_message *)
+#define DLP_IOC_GET_MESSAGE \
+	_IOWR(DLP_IOCTL_MAGIC_NUMBER, 2, struct t_dlp_message *)
+#define DLP_IOC_PUT_MESSAGE \
+	_IOWR(DLP_IOCTL_MAGIC_NUMBER, 3, struct t_dlp_message *)
+
+#endif /*__MODEM_IPC_INCLUDED*/
diff --git a/drivers/modem_shm/u8500_shm/shrm_net.c b/drivers/modem_shm/u8500_shm/shrm_net.c
new file mode 100644
index 0000000..28dbcd3
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_net.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/phonet.h>
+#include <linux/if_phonet.h>
+#include <linux/if_arp.h>
+#include <net/sock.h>
+#include <net/phonet/phonet.h>
+#include <net/phonet/pep.h>
+
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_config.h"
+#include "shrm_net.h"
+#include "shrm.h"
+
+
+/**
+ * shrm_net_receive() - receive data and copy to user space buffer
+ * @dev:	pointer to the network device structure
+ *
+ * Copy data from ISI queue to the user space buffer.
+ */
+int shrm_net_receive(struct net_device *dev)
+{
+	struct sk_buff *skb;
+	struct isadev_context *isadev;
+	struct message_queue *q;
+	u32 msgsize;
+	u32 size = 0;
+	struct shrm_net_iface_priv *net_iface_priv =
+		(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	isadev = &shrm->isa_context->isadev[ISI_MESSAGING];
+	q = &isadev->dl_queue;
+
+	spin_lock_bh(&q->update_lock);
+	if (list_empty(&q->msg_list)) {
+		spin_unlock_bh(&q->update_lock);
+		dev_dbg(shrm->dev, "Empty Shrm queue\n");
+		return 0;
+	}
+	spin_unlock_bh(&q->update_lock);
+
+	msgsize = get_size_of_new_msg(q);
+	if (msgsize <= 0)
+		return msgsize;
+
+	/*
+	 * The packet has been retrieved from the transmission
+	 * medium. Build an skb around it, so upper layers can handle it
+	 */
+	skb = dev_alloc_skb(msgsize);
+	if (!skb) {
+		if (printk_ratelimit())
+			dev_notice(shrm->dev,
+			"isa rx: low on mem - packet dropped\n");
+		dev->stats.rx_dropped++;
+		goto out;
+	}
+
+	if ((q->readptr+msgsize) >= q->size) {
+		size = (q->size-q->readptr);
+		/*Copy First Part of msg*/
+		skb_copy_to_linear_data(skb,
+				(u8 *)(q->fifo_base + q->readptr), size);
+		skb_put(skb, size);
+
+		/*Copy Second Part of msg at the top of fifo*/
+		skb_copy_to_linear_data_offset(skb, size,
+				(u8 *)(q->fifo_base), (msgsize - size));
+		skb_put(skb, msgsize-size);
+
+	} else {
+		skb_copy_to_linear_data(skb,
+				(u8 *)(q->fifo_base+q->readptr), msgsize);
+		skb_put(skb, msgsize);
+	}
+
+	spin_lock_bh(&q->update_lock);
+	remove_msg_from_queue(q);
+	spin_unlock_bh(&q->update_lock);
+
+	skb_reset_mac_header(skb);
+	__skb_pull(skb, dev->hard_header_len);
+	/*Write metadata, and then pass to the receive level*/
+	skb->dev = dev;/*kmalloc(sizeof(struct net_device), GFP_ATOMIC);*/
+	skb->protocol = htons(ETH_P_PHONET);
+	skb->priority = 0;
+	skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
+	if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += msgsize;
+	} else
+		dev->stats.rx_dropped++;
+
+	return msgsize;
+out:
+	return -ENOMEM;
+}
+
+static int netdev_isa_open(struct net_device *dev)
+{
+	struct shrm_net_iface_priv *net_iface_priv =
+			(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	shrm->netdev_flag_up = 1;
+	if (!netif_carrier_ok(dev))
+		netif_carrier_on(dev);
+	netif_wake_queue(dev);
+	return 0;
+}
+
+static int netdev_isa_close(struct net_device *dev)
+{
+	struct shrm_net_iface_priv *net_iface_priv =
+			(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	shrm->netdev_flag_up = 0;
+	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+	return 0;
+}
+
+static int netdev_isa_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct if_phonet_req *req = (struct if_phonet_req *)ifr;
+
+	switch (cmd) {
+	case SIOCPNGAUTOCONF:
+		req->ifr_phonet_autoconf.device = PN_DEV_HOST;
+		return 0;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static struct net_device_stats *netdev_isa_stats(struct net_device *dev)
+{
+	return &dev->stats;
+}
+
+/**
+ * netdev_isa_write() - write through the net interface
+ * @skb:	pointer to the socket buffer
+ * @dev:	pointer to the network device structure
+ *
+ * Copies data(ISI message) from the user buffer to the kernel buffer and
+ * schedule transfer thread to transmit the message to the modem via FIFO.
+ */
+static netdev_tx_t netdev_isa_write(struct sk_buff *skb, struct net_device *dev)
+{
+	int err;
+	int retval = 0;
+	struct shrm_net_iface_priv *net_iface_priv =
+			(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	/*
+	 * FIXME:
+	 * U8500 modem requires that Pipe created/enabled Indication should
+	 * be sent from the port corresponding to GPRS socket.
+	 * Also, the U8500 modem does not implement Pipe controller
+	 * which takes care of port manipulations for GPRS traffic.
+	 *
+	 * Now, APE has GPRS socket and the socket for sending
+	 * Indication msgs bound to different ports.
+	 * Phonet stack does not allow an indication msg to be sent
+	 * from GPRS socket, since Phonet stack assumes the presence
+	 * of Pipe controller in modem.
+	 *
+	 * So, due to lack of Pipe controller implementation in the
+	 * U8500 modem, carry out the port manipulation related to
+	 * GPRS traffic here.
+	 * Ideally, it should be done either by Pipe controller in
+	 * modem OR some implementation of Pipe controller on APE side
+	 */
+	if (skb->data[RESOURCE_ID_INDEX] == PN_PIPE) {
+		if ((skb->data[MSG_ID_INDEX] == PNS_PIPE_CREATED_IND) ||
+			(skb->data[MSG_ID_INDEX] == PNS_PIPE_ENABLED_IND) ||
+			(skb->data[MSG_ID_INDEX] == PNS_PIPE_DISABLED_IND))
+			skb->data[SRC_OBJ_INDEX] = skb->data[PIPE_HDL_INDEX];
+	}
+
+	spin_lock_bh(&shrm->isa_context->common_tx);
+	err = shrm_write_msg(shrm, ISI_MESSAGING, skb->data,
+			skb->len);
+	if (!err) {
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += skb->len;
+		retval = NETDEV_TX_OK;
+		dev_kfree_skb(skb);
+	} else {
+		dev->stats.tx_dropped++;
+		retval = NETDEV_TX_BUSY;
+	}
+	spin_unlock_bh(&shrm->isa_context->common_tx);
+
+	return retval;
+}
+
+static const struct net_device_ops shrm_netdev_ops = {
+	.ndo_open = netdev_isa_open,
+	.ndo_stop = netdev_isa_close,
+	.ndo_do_ioctl = netdev_isa_ioctl,
+	.ndo_start_xmit = netdev_isa_write,
+	.ndo_get_stats = netdev_isa_stats,
+};
+
+static void shrm_net_init(struct net_device *dev)
+{
+	struct shrm_net_iface_priv *net_iface_priv;
+
+	dev->netdev_ops = &shrm_netdev_ops;
+	dev->header_ops = &phonet_header_ops;
+	dev->type = ARPHRD_PHONET;
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+	dev->mtu = PHONET_MAX_MTU;
+	dev->hard_header_len = SHRM_HLEN;
+	dev->addr_len = PHONET_ALEN;
+	dev->tx_queue_len = PN_TX_QUEUE_LEN;
+	dev->destructor = free_netdev;
+	dev->dev_addr[0] = PN_LINK_ADDR;
+	net_iface_priv = netdev_priv(dev);
+	memset(net_iface_priv, 0 , sizeof(struct shrm_net_iface_priv));
+}
+
+int shrm_register_netdev(struct shrm_dev *shrm)
+{
+	struct net_device *nw_device;
+	struct shrm_net_iface_priv *net_iface_priv;
+	char *devname = "shrm%d";
+	int err;
+
+	/* allocate the net device */
+	nw_device = shrm->ndev = alloc_netdev(
+			sizeof(struct shrm_net_iface_priv),
+			devname, shrm_net_init);
+	if (nw_device == NULL) {
+		dev_err(shrm->dev, "Failed to allocate SHRM Netdev\n");
+		return -ENOMEM;
+	}
+	err = register_netdev(shrm->ndev);
+	if (err) {
+		dev_err(shrm->dev, "Err %i in reg shrm-netdev\n", err);
+		free_netdev(shrm->ndev);
+		return -ENODEV;
+	}
+	dev_info(shrm->dev, "Registered shrm netdev\n");
+
+	net_iface_priv = (struct shrm_net_iface_priv *)netdev_priv(nw_device);
+	net_iface_priv->shrm_device = shrm;
+	net_iface_priv->iface_num = 0;
+
+	return err;
+}
+
+int shrm_stop_netdev(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+
+int shrm_restart_netdev(struct net_device *dev)
+{
+	if (netif_queue_stopped(dev))
+		netif_wake_queue(dev);
+	return 0;
+}
+
+int shrm_start_netdev(struct net_device *dev)
+{
+	struct shrm_net_iface_priv *net_iface_priv =
+			(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	if (!netif_carrier_ok(dev))
+		netif_carrier_on(dev);
+	netif_start_queue(dev);
+	shrm->netdev_flag_up = 1;
+	return 0;
+}
+
+int shrm_suspend_netdev(struct net_device *dev)
+{
+	if (netif_running(dev))
+		netif_stop_queue(dev);
+	netif_device_detach(dev);
+	return 0;
+}
+
+int shrm_resume_netdev(struct net_device *dev)
+{
+	netif_device_attach(dev);
+	if (netif_running(dev))
+		netif_wake_queue(dev);
+	return 0;
+}
+
+void shrm_unregister_netdev(struct shrm_dev *shrm)
+{
+	unregister_netdev(shrm->ndev);
+}
diff --git a/drivers/modem_shm/u8500_shm/shrm_net.h b/drivers/modem_shm/u8500_shm/shrm_net.h
new file mode 100644
index 0000000..19eb768
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_net.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_NET_H
+#define __SHRM_NET_H
+
+#define SHRM_HLEN 1
+#define PHONET_ALEN 1
+
+#define PN_PIPE		0xD9
+#define PN_DEV_HOST	0x00
+#define PN_LINK_ADDR	0x26
+#define PN_TX_QUEUE_LEN	3
+
+#define RESOURCE_ID_INDEX	3
+#define SRC_OBJ_INDEX		7
+#define MSG_ID_INDEX		9
+#define PIPE_HDL_INDEX		10
+#define NETLINK_SHRM            20
+
+/**
+ * struct shrm_net_iface_priv - shrm net interface device information
+ * @shrm_device:	pointer to the shrm device information structure
+ * @iface_num:		flag used to indicate the up/down of netdev
+ */
+struct shrm_net_iface_priv {
+	struct shrm_dev *shrm_device;
+	unsigned int iface_num;
+};
+
+int shrm_register_netdev(struct shrm_dev *shrm_dev_data);
+int shrm_net_receive(struct net_device *dev);
+int shrm_suspend_netdev(struct net_device *dev);
+int shrm_resume_netdev(struct net_device *dev);
+int shrm_stop_netdev(struct net_device *dev);
+int shrm_restart_netdev(struct net_device *dev);
+int shrm_start_netdev(struct net_device *dev);
+void shrm_unregister_netdev(struct shrm_dev *shrm_dev_data);
+
+#endif /* __SHRM_NET_H */
diff --git a/drivers/modem_shm/u8500_shm/shrm_private.h b/drivers/modem_shm/u8500_shm/shrm_private.h
new file mode 100644
index 0000000..b605d68
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_private.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_PRIVATE_INCLUDED
+#define __SHRM_PRIVATE_INCLUDED
+
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include "shrm.h"
+
+#define GOP_OUTPUT_REGISTER_BASE (0x0)
+#define GOP_SET_REGISTER_BASE    (0x4)
+#define GOP_CLEAR_REGISTER_BASE  (0x8)
+#define GOP_TOGGLE_REGISTER_BASE (0xc)
+
+
+#define GOP_AUDIO_AC_READ_NOTIFICATION_BIT (0)
+#define GOP_AUDIO_CA_MSG_PENDING_NOTIFICATION_BIT (1)
+#define GOP_COMMON_AC_READ_NOTIFICATION_BIT (2)
+#define GOP_COMMON_CA_MSG_PENDING_NOTIFICATION_BIT (3)
+#define GOP_CA_WAKE_REQ_BIT (7)
+#define GOP_AUDIO_CA_READ_NOTIFICATION_BIT (23)
+#define GOP_AUDIO_AC_MSG_PENDING_NOTIFICATION_BIT (24)
+#define GOP_COMMON_CA_READ_NOTIFICATION_BIT (25)
+#define GOP_COMMON_AC_MSG_PENDING_NOTIFICATION_BIT (26)
+#define GOP_CA_WAKE_ACK_BIT (27)
+
+#define L2_MSG_MAPID_OFFSET (24)
+#define L1_MSG_MAPID_OFFSET (28)
+
+#define SHRM_SLEEP_STATE (0)
+#define SHRM_PTR_FREE (1)
+#define SHRM_PTR_BUSY (2)
+#define SHRM_IDLE (3)
+
+#define ISI_MESSAGING (0)
+#define RPC_MESSAGING (1)
+#define AUDIO_MESSAGING (2)
+#define SECURITY_MESSAGING (3)
+#define COMMON_LOOPBACK_MESSAGING (0xC0)
+#define AUDIO_LOOPBACK_MESSAGING (0x80)
+#define CIQ_MESSAGING (0xC3)
+#define RTC_CAL_MESSAGING (0xC8)
+
+#define COMMON_CHANNEL		0
+#define AUDIO_CHANNEL		1
+
+typedef void (*MSG_PENDING_NOTIF)(const u32 Wptr);
+
+/**
+ * struct fifo_write_params - parameters used for FIFO write operation.
+ * @writer_local_rptr:	pointer to local read buffer
+ * @writer_local_wptr:	pointer to local write buffer
+ * @shared_wptr:	write pointer shared by cmt and ape
+ * @shared_rptr:	read pointer shared by cmt and ape
+ * @availablesize:	available memory in fifo
+ * @end_addr_fifo:	fifo end addr
+ * @fifo_virtual_addr:	fifo virtual addr
+ * @fifo_update_lock:	spin lock to update fifo.
+ *
+ * On writting a message to FIFO the same has to be read by the modem before
+ * writing the next message to the FIFO. In oder to over come this a local
+ * write and read pointer is used for internal purpose.
+ */
+struct fifo_write_params {
+	u32 writer_local_rptr;
+	u32 writer_local_wptr;
+	u32 shared_wptr;
+	u32 shared_rptr;
+	u32 availablesize;
+	u32 end_addr_fifo;
+	u32 *fifo_virtual_addr;
+	spinlock_t fifo_update_lock;
+} ;
+
+/**
+ * struct fifo_read_params - parameters used for FIFO read operation
+ * @reader_local_rptr:	pointer to local read buffer
+ * @reader_local_wptr:	pointer to local write buffer
+ * @shared_wptr:	write pointer shared by cmt and ape
+ * @shared_rptr:	read pointer shared by cmt and ape
+ * @availablesize:	available memory in fifo
+ * @end_addr_fifo:	fifo end add
+ * @fifo_virtual_addr:	fifo virtual addr
+ */
+struct fifo_read_params{
+	u32 reader_local_rptr;
+	u32 reader_local_wptr;
+	u32 shared_wptr;
+	u32 shared_rptr;
+	u32 availablesize;
+	u32 end_addr_fifo;
+	u32 *fifo_virtual_addr;
+
+} ;
+
+int shrm_protocol_init(struct shrm_dev *shrm,
+			received_msg_handler common_rx_handler,
+			received_msg_handler audio_rx_handler);
+void shrm_protocol_deinit(struct shrm_dev *shrm);
+void shrm_fifo_init(struct shrm_dev *shrm);
+int shrm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
+				u8 l2header, void *addr, u32 length);
+int shrm_write_msg(struct shrm_dev *shrm,
+			u8 l2_header, void *addr, u32 length);
+
+u8 is_the_only_one_unread_message(struct shrm_dev *shrm,
+						u8 channel, u32 length);
+u8 read_remaining_messages_common(void);
+u8 read_remaining_messages_audio(void);
+u8 read_one_l2msg_audio(struct shrm_dev *shrm,
+			u8 *p_l2_msg, u32 *p_len);
+u8 read_one_l2msg_common(struct shrm_dev *shrm,
+				u8 *p_l2_msg, u32 *p_len);
+void receive_messages_common(struct shrm_dev *shrm);
+void receive_messages_audio(struct shrm_dev *shrm);
+
+void update_ac_common_local_rptr(struct shrm_dev *shrm);
+void update_ac_audio_local_rptr(struct shrm_dev *shrm);
+void update_ca_common_local_wptr(struct shrm_dev *shrm);
+void update_ca_audio_local_wptr(struct shrm_dev *shrm);
+void update_ac_common_shared_wptr(struct shrm_dev *shrm);
+void update_ac_audio_shared_wptr(struct shrm_dev *shrm);
+void update_ca_common_shared_rptr(struct shrm_dev *shrm);
+void update_ca_audio_shared_rptr(struct shrm_dev *shrm);
+
+
+void get_writer_pointers(u8 msg_type, u32 *WriterLocalRptr, \
+			u32 *WriterLocalWptr, u32 *SharedWptr);
+void get_reader_pointers(u8 msg_type, u32 *ReaderLocalRptr, \
+			u32 *ReaderLocalWptr, u32 *SharedRptr);
+u8 read_boot_info_req(struct shrm_dev *shrm,
+				u32 *pConfig,
+				u32 *pVersion);
+void write_boot_info_resp(struct shrm_dev *shrm, u32 Config,
+							u32 Version);
+
+void send_ac_msg_pending_notification_0(struct shrm_dev *shrm);
+void send_ac_msg_pending_notification_1(struct shrm_dev *shrm);
+void ca_msg_read_notification_0(struct shrm_dev *shrm);
+void ca_msg_read_notification_1(struct shrm_dev *shrm);
+
+void set_ca_msg_0_read_notif_send(u8 val);
+u8 get_ca_msg_0_read_notif_send(void);
+void set_ca_msg_1_read_notif_send(u8 val);
+u8 get_ca_msg_1_read_notif_send(void);
+
+irqreturn_t ca_wake_irq_handler(int irq, void *ctrlr);
+irqreturn_t ac_read_notif_0_irq_handler(int irq, void *ctrlr);
+irqreturn_t ac_read_notif_1_irq_handler(int irq, void *ctrlr);
+irqreturn_t ca_msg_pending_notif_0_irq_handler(int irq, void *ctrlr);
+irqreturn_t ca_msg_pending_notif_1_irq_handler(int irq, void *ctrlr);
+
+void shrm_ca_msgpending_0_tasklet(unsigned long);
+void shrm_ca_msgpending_1_tasklet(unsigned long);
+void shrm_ac_read_notif_0_tasklet(unsigned long);
+void shrm_ac_read_notif_1_tasklet(unsigned long);
+void shrm_ca_wake_req_tasklet(unsigned long);
+
+u8 get_boot_state(void);
+
+int get_ca_wake_req_state(void);
+
+/* shrm character interface */
+int isa_init(struct shrm_dev *shrm);
+void isa_exit(struct shrm_dev *shrm);
+int add_msg_to_queue(struct message_queue *q, u32 size);
+ssize_t isa_read(struct file *filp, char __user *buf, size_t len,
+							loff_t *ppos);
+int get_size_of_new_msg(struct message_queue *q);
+int remove_msg_from_queue(struct message_queue *q);
+void shrm_char_reset_queues(struct shrm_dev *shrm);
+int shrm_get_cdev_index(u8 l2_header);
+int shrm_get_cdev_l2header(u8 idx);
+
+#endif
diff --git a/drivers/modem_shm/u8500_shm/shrm_protocol.c b/drivers/modem_shm/u8500_shm/shrm_protocol.c
new file mode 100644
index 0000000..907926a
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_protocol.c
@@ -0,0 +1,1591 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@...ricsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/netlink.h>
+#include <linux/kthread.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/abx500.h>
+#include <linux/modem_shm/modem_client.h>
+
+#include "shrm.h"
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_net.h"
+
+#define L2_HEADER_ISI		0x0
+#define L2_HEADER_RPC		0x1
+#define L2_HEADER_AUDIO		0x2
+#define L2_HEADER_SECURITY	0x3
+#define L2_HEADER_COMMON_SIMPLE_LOOPBACK	0xC0
+#define L2_HEADER_COMMON_ADVANCED_LOOPBACK	0xC1
+#define L2_HEADER_AUDIO_SIMPLE_LOOPBACK		0x80
+#define L2_HEADER_AUDIO_ADVANCED_LOOPBACK	0x81
+#define L2_HEADER_CIQ		0xC3
+#define L2_HEADER_RTC_CALIBRATION		0xC8
+#define MAX_PAYLOAD 1024
+#define MOD_STUCK_TIMEOUT	6
+#define FIFO_FULL_TIMEOUT	1
+#define PRCM_MOD_AWAKE_STATUS_PRCM_MOD_COREPD_AWAKE	BIT(0)
+#define PRCM_MOD_AWAKE_STATUS_PRCM_MOD_AAPD_AWAKE	BIT(1)
+#define PRCM_MOD_AWAKE_STATUS_PRCM_MOD_VMODEM_OFF_ISO	BIT(2)
+#define PRCM_MOD_PURESET	BIT(0)
+#define PRCM_MOD_SW_RESET	BIT(1)
+
+#define PRCM_HOSTACCESS_REQ	0x334
+#define PRCM_MOD_AWAKE_STATUS	0x4A0
+#define PRCM_MOD_RESETN_VAL	0x204
+
+static u8 boot_state = BOOT_INIT;
+static u8 recieve_common_msg[8*1024];
+static u8 recieve_audio_msg[8*1024];
+static received_msg_handler rx_common_handler;
+static received_msg_handler rx_audio_handler;
+static struct hrtimer timer;
+static struct hrtimer mod_stuck_timer_0;
+static struct hrtimer mod_stuck_timer_1;
+static struct hrtimer fifo_full_timer;
+struct sock *shrm_nl_sk;
+
+static char shrm_common_tx_state = SHRM_SLEEP_STATE;
+static char shrm_common_rx_state = SHRM_SLEEP_STATE;
+static char shrm_audio_tx_state = SHRM_SLEEP_STATE;
+static char shrm_audio_rx_state = SHRM_SLEEP_STATE;
+
+static atomic_t ac_sleep_disable_count = ATOMIC_INIT(0);
+static atomic_t ac_msg_pend_1 = ATOMIC_INIT(0);
+static atomic_t mod_stuck = ATOMIC_INIT(0);
+static atomic_t fifo_full = ATOMIC_INIT(0);
+static struct shrm_dev *shm_dev;
+
+/* Spin lock and tasklet declaration */
+DECLARE_TASKLET(shrm_ca_0_tasklet, shrm_ca_msgpending_0_tasklet, 0);
+DECLARE_TASKLET(shrm_ca_1_tasklet, shrm_ca_msgpending_1_tasklet, 0);
+DECLARE_TASKLET(shrm_ac_read_0_tasklet, shrm_ac_read_notif_0_tasklet, 0);
+DECLARE_TASKLET(shrm_ac_read_1_tasklet, shrm_ac_read_notif_1_tasklet, 0);
+
+static DEFINE_MUTEX(ac_state_mutex);
+
+static DEFINE_SPINLOCK(ca_common_lock);
+static DEFINE_SPINLOCK(ca_audio_lock);
+static DEFINE_SPINLOCK(ca_wake_req_lock);
+static DEFINE_SPINLOCK(boot_lock);
+static DEFINE_SPINLOCK(mod_stuck_lock);
+static DEFINE_SPINLOCK(start_timer_lock);
+
+enum shrm_nl {
+	SHRM_NL_MOD_RESET = 1,
+	SHRM_NL_MOD_QUERY_STATE,
+	SHRM_NL_USER_MOD_RESET,
+	SHRM_NL_STATUS_MOD_ONLINE,
+	SHRM_NL_STATUS_MOD_OFFLINE,
+};
+
+static int check_modem_in_reset(void);
+
+void shrm_print_dbg_info_work(struct kthread_work *work)
+{
+#if SHRM_DEBUG
+	abx500_dump_all_banks();
+	prcmu_debug_dump_regs();
+	prcmu_debug_dump_data_mem();
+#endif
+}
+
+void shrm_mod_reset_req_work(struct kthread_work *work)
+{
+	unsigned long flags;
+
+	/* update the boot_state */
+	spin_lock_irqsave(&boot_lock, flags);
+	if (boot_state != BOOT_DONE) {
+		dev_info(shm_dev->dev, "Modem in reset state\n");
+		spin_unlock_irqrestore(&boot_lock, flags);
+		return;
+	}
+	boot_state = BOOT_UNKNOWN;
+	wmb();
+	spin_unlock_irqrestore(&boot_lock, flags);
+	dev_err(shm_dev->dev, "APE makes modem reset\n");
+	prcmu_modem_reset();
+}
+
+static void shrm_ac_sleep_req_work(struct kthread_work *work)
+{
+	mutex_lock(&ac_state_mutex);
+	if (atomic_read(&ac_sleep_disable_count) == 0)
+		modem_release(shm_dev->modem);
+	mutex_unlock(&ac_state_mutex);
+}
+
+static void shrm_ac_wake_req_work(struct kthread_work *work)
+{
+	mutex_lock(&ac_state_mutex);
+	if (modem_request(shm_dev->modem) < 0) {
+		dev_err(shm_dev->dev,
+				"prcmu_ac_wake_req failed, initiating MSR\n");
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_print_dbg_info);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+	}
+
+	mutex_unlock(&ac_state_mutex);
+}
+
+static u32 get_host_accessport_val(void)
+{
+	u32 prcm_hostaccess;
+	u32 status;
+	u32 reset_stats;
+
+	status = (prcmu_read(PRCM_MOD_AWAKE_STATUS) & 0x03);
+	reset_stats = (prcmu_read(PRCM_MOD_RESETN_VAL) & 0x03);
+	prcm_hostaccess = prcmu_read(PRCM_HOSTACCESS_REQ);
+	wmb();
+	prcm_hostaccess = ((prcm_hostaccess & 0x01) &&
+		(status == (PRCM_MOD_AWAKE_STATUS_PRCM_MOD_AAPD_AWAKE |
+			    PRCM_MOD_AWAKE_STATUS_PRCM_MOD_COREPD_AWAKE)) &&
+		(reset_stats == (PRCM_MOD_SW_RESET | PRCM_MOD_PURESET)));
+
+	return prcm_hostaccess;
+}
+
+static enum hrtimer_restart shrm_fifo_full_timeout(struct hrtimer *timer)
+{
+	queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+	queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_print_dbg_info);
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart shrm_mod_stuck_timeout(struct hrtimer *timer)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mod_stuck_lock, flags);
+	/* Check MSR is already in progress */
+	if (shm_dev->msr_flag || boot_state == BOOT_UNKNOWN ||
+			atomic_read(&mod_stuck) || atomic_read(&fifo_full)) {
+		spin_unlock_irqrestore(&mod_stuck_lock, flags);
+		return HRTIMER_NORESTART;
+	}
+	atomic_set(&mod_stuck, 1);
+	spin_unlock_irqrestore(&mod_stuck_lock, flags);
+	dev_err(shm_dev->dev, "No response from modem, timeout %dsec\n",
+			MOD_STUCK_TIMEOUT);
+	dev_err(shm_dev->dev, "APE initiating MSR\n");
+	queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+	queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_print_dbg_info);
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart callback(struct hrtimer *timer)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ca_wake_req_lock, flags);
+	if (((shrm_common_rx_state == SHRM_IDLE) ||
+				(shrm_common_rx_state == SHRM_SLEEP_STATE))
+			&& ((shrm_common_tx_state == SHRM_IDLE) ||
+				(shrm_common_tx_state == SHRM_SLEEP_STATE))
+			&& ((shrm_audio_rx_state == SHRM_IDLE)  ||
+				(shrm_audio_rx_state == SHRM_SLEEP_STATE))
+			&& ((shrm_audio_tx_state == SHRM_IDLE)  ||
+				(shrm_audio_tx_state == SHRM_SLEEP_STATE))) {
+
+		shrm_common_rx_state = SHRM_SLEEP_STATE;
+		shrm_audio_rx_state = SHRM_SLEEP_STATE;
+		shrm_common_tx_state = SHRM_SLEEP_STATE;
+		shrm_audio_tx_state = SHRM_SLEEP_STATE;
+
+		queue_kthread_work(&shm_dev->shrm_ac_sleep_kw,
+				&shm_dev->shrm_ac_sleep_req);
+
+	}
+	spin_unlock_irqrestore(&ca_wake_req_lock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+int nl_send_multicast_message(int msg, gfp_t gfp_mask)
+{
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh = NULL;
+	int err;
+
+	/* prepare netlink message */
+	skb = alloc_skb(NLMSG_SPACE(MAX_PAYLOAD), gfp_mask);
+	if (!skb) {
+		dev_err(shm_dev->dev, "%s:alloc_skb failed\n", __func__);
+		err = -ENOMEM;
+		goto out;
+	}
+
+	nlh = (struct nlmsghdr *)skb->data;
+	nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
+	dev_dbg(shm_dev->dev, "nlh->nlmsg_len = %d\n", nlh->nlmsg_len);
+
+	nlh->nlmsg_pid = 0;  /* from kernel */
+	nlh->nlmsg_flags = 0;
+	*(int *)NLMSG_DATA(nlh) = msg;
+	skb_put(skb, MAX_PAYLOAD);
+	/* sender is in group 1<<0 */
+	NETLINK_CB(skb).pid = 0;  /* from kernel */
+	/* to mcast group 1<<0 */
+	NETLINK_CB(skb).dst_group = 1;
+
+	/*multicast the message to all listening processes*/
+	err = netlink_broadcast(shrm_nl_sk, skb, 0, 1, gfp_mask);
+	dev_dbg(shm_dev->dev, "ret val from nl-multicast = %d\n", err);
+
+out:
+	return err;
+}
+
+static void nl_send_unicast_message(int dst_pid)
+{
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh = NULL;
+	int err;
+	int bt_state;
+	unsigned long flags;
+
+	dev_dbg(shm_dev->dev, "Sending unicast message\n");
+
+	/* prepare the NL message for unicast */
+	skb = alloc_skb(NLMSG_SPACE(MAX_PAYLOAD), GFP_KERNEL);
+	if (!skb) {
+		dev_err(shm_dev->dev, "%s:alloc_skb failed\n", __func__);
+		return;
+	}
+
+	nlh = (struct nlmsghdr *)skb->data;
+	nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
+	dev_dbg(shm_dev->dev, "nlh->nlmsg_len = %d\n", nlh->nlmsg_len);
+
+	nlh->nlmsg_pid = 0;  /* from kernel */
+	nlh->nlmsg_flags = 0;
+
+	spin_lock_irqsave(&boot_lock, flags);
+	bt_state = boot_state;
+	spin_unlock_irqrestore(&boot_lock, flags);
+
+	if (bt_state == BOOT_DONE)
+		*(int *)NLMSG_DATA(nlh) = SHRM_NL_STATUS_MOD_ONLINE;
+	else
+		*(int *)NLMSG_DATA(nlh) = SHRM_NL_STATUS_MOD_OFFLINE;
+
+	skb_put(skb, MAX_PAYLOAD);
+	/* sender is in group 1<<0 */
+	NETLINK_CB(skb).pid = 0;  /* from kernel */
+	NETLINK_CB(skb).dst_group = 0;
+
+	/*unicast the message to the querying processes*/
+	err = netlink_unicast(shrm_nl_sk, skb, dst_pid, MSG_DONTWAIT);
+	dev_dbg(shm_dev->dev, "ret val from nl-unicast = %d\n", err);
+}
+
+
+static int check_modem_in_reset(void)
+{
+	u8 bt_state;
+	unsigned long flags;
+
+	spin_lock_irqsave(&boot_lock, flags);
+	bt_state = boot_state;
+	spin_unlock_irqrestore(&boot_lock, flags);
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+	if (bt_state != BOOT_UNKNOWN &&
+			(!readl(shm_dev->ca_reset_status_rptr)))
+		return 0;
+	else
+		return -ENODEV;
+#else
+	/*
+	 * this check won't be applicable and won't work correctly
+	 * if modem-silent-feature is not enabled
+	 * so, simply return 0
+	 */
+	return 0;
+#endif
+}
+
+void shrm_ca_msgpending_0_tasklet(unsigned long tasklet_data)
+{
+	struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+	u32 reader_local_rptr;
+	u32 reader_local_wptr;
+	u32 shared_rptr;
+	u32 config = 0, version = 0;
+	unsigned long flags;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	/* Interprocess locking */
+	spin_lock(&ca_common_lock);
+
+	/* Update_reader_local_wptr with shared_wptr */
+	update_ca_common_local_wptr(shrm);
+	get_reader_pointers(COMMON_CHANNEL, &reader_local_rptr,
+				&reader_local_wptr, &shared_rptr);
+
+	set_ca_msg_0_read_notif_send(0);
+
+	if (boot_state == BOOT_DONE) {
+		shrm_common_rx_state = SHRM_PTR_FREE;
+
+		if (reader_local_rptr != shared_rptr)
+			ca_msg_read_notification_0(shrm);
+		if (reader_local_rptr != reader_local_wptr)
+			receive_messages_common(shrm);
+		get_reader_pointers(COMMON_CHANNEL, &reader_local_rptr,
+				&reader_local_wptr, &shared_rptr);
+		if (reader_local_rptr == reader_local_wptr)
+			shrm_common_rx_state = SHRM_IDLE;
+	} else {
+		/* BOOT phase.only a BOOT_RESP should be in FIFO */
+		if (boot_state != BOOT_INFO_SYNC) {
+			if (!read_boot_info_req(shrm, &config, &version)) {
+				dev_err(shrm->dev,
+						"Unable to read boot state\n");
+				return;
+			}
+			/* SendReadNotification */
+			ca_msg_read_notification_0(shrm);
+			/*
+			 * Check the version number before
+			 * sending Boot info response
+			 */
+
+			/* send MsgPending notification */
+			write_boot_info_resp(shrm, config, version);
+			spin_lock_irqsave(&boot_lock, flags);
+			boot_state = BOOT_INFO_SYNC;
+			spin_unlock_irqrestore(&boot_lock, flags);
+			dev_info(shrm->dev, "BOOT_INFO_SYNC\n");
+			queue_kthread_work(&shrm->shrm_common_ch_wr_kw,
+					&shrm->send_ac_msg_pend_notify_0);
+		} else {
+			ca_msg_read_notification_0(shrm);
+			dev_info(shrm->dev,
+				"BOOT_INFO_SYNC\n");
+		}
+	}
+	/* Interprocess locking */
+	spin_unlock(&ca_common_lock);
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_ca_msgpending_1_tasklet(unsigned long tasklet_data)
+{
+	struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+	u32 reader_local_rptr;
+	u32 reader_local_wptr;
+	u32 shared_rptr;
+
+	/*
+	 * This function is called when CaMsgPendingNotification Trigerred
+	 * by CMU. It means that CMU has wrote a message into Ca Audio FIFO
+	 */
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+				__func__);
+		return;
+	}
+
+	/* Interprocess locking */
+	spin_lock(&ca_audio_lock);
+
+	/* Update_reader_local_wptr(with shared_wptr) */
+	update_ca_audio_local_wptr(shrm);
+	get_reader_pointers(AUDIO_CHANNEL, &reader_local_rptr,
+					&reader_local_wptr, &shared_rptr);
+
+	set_ca_msg_1_read_notif_send(0);
+
+	if (boot_state != BOOT_DONE) {
+		dev_err(shrm->dev, "Boot Error\n");
+		return;
+	}
+	shrm_audio_rx_state = SHRM_PTR_FREE;
+	/* Check we already read the message */
+	if (reader_local_rptr != shared_rptr)
+		ca_msg_read_notification_1(shrm);
+	if (reader_local_rptr != reader_local_wptr)
+		receive_messages_audio(shrm);
+
+	get_reader_pointers(AUDIO_CHANNEL, &reader_local_rptr,
+			&reader_local_wptr, &shared_rptr);
+	if (reader_local_rptr == reader_local_wptr)
+		shrm_audio_rx_state = SHRM_IDLE;
+
+	 /* Interprocess locking */
+	spin_unlock(&ca_audio_lock);
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_ac_read_notif_0_tasklet(unsigned long tasklet_data)
+{
+	struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+	u32 writer_local_rptr;
+	u32 writer_local_wptr;
+	u32 shared_wptr;
+	unsigned long flags;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	/* Update writer_local_rptrwith shared_rptr */
+	update_ac_common_local_rptr(shrm);
+	get_writer_pointers(COMMON_CHANNEL, &writer_local_rptr,
+				&writer_local_wptr, &shared_wptr);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+				__func__);
+		return;
+	}
+
+	if (boot_state == BOOT_INFO_SYNC) {
+		/* BOOT_RESP sent by APE has been received by CMT */
+		spin_lock_irqsave(&boot_lock, flags);
+		boot_state = BOOT_DONE;
+		spin_unlock_irqrestore(&boot_lock, flags);
+		dev_info(shrm->dev, "IPC_ISA BOOT_DONE\n");
+
+		if (shrm->msr_flag) {
+			shrm_start_netdev(shrm->ndev);
+			shrm->msr_flag = 0;
+
+			/* multicast that modem is online */
+			nl_send_multicast_message(SHRM_NL_STATUS_MOD_ONLINE,
+					GFP_ATOMIC);
+		}
+
+	} else if (boot_state == BOOT_DONE) {
+		if (writer_local_rptr != writer_local_wptr) {
+			shrm_common_tx_state = SHRM_PTR_FREE;
+			queue_kthread_work(&shrm->shrm_common_ch_wr_kw,
+					&shrm->send_ac_msg_pend_notify_0);
+		} else {
+			shrm_common_tx_state = SHRM_IDLE;
+			shrm_restart_netdev(shrm->ndev);
+		}
+	} else {
+		dev_err(shrm->dev, "Invalid boot state\n");
+	}
+	/* start timer here */
+	hrtimer_start(&timer, ktime_set(0, 25*NSEC_PER_MSEC),
+			HRTIMER_MODE_REL);
+	atomic_dec(&ac_sleep_disable_count);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_ac_read_notif_1_tasklet(unsigned long tasklet_data)
+{
+	struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+	u32 writer_local_rptr;
+	u32 writer_local_wptr;
+	u32 shared_wptr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+				__func__);
+		return;
+	}
+
+	/* Update writer_local_rptr(with shared_rptr) */
+	update_ac_audio_local_rptr(shrm);
+	get_writer_pointers(AUDIO_CHANNEL, &writer_local_rptr,
+				&writer_local_wptr, &shared_wptr);
+	if (boot_state != BOOT_DONE) {
+		dev_err(shrm->dev, "Error Case in boot state\n");
+		return;
+	}
+	if (writer_local_rptr != writer_local_wptr) {
+		shrm_audio_tx_state = SHRM_PTR_FREE;
+		queue_kthread_work(&shrm->shrm_audio_ch_wr_kw,
+				&shrm->send_ac_msg_pend_notify_1);
+	} else {
+		shrm_audio_tx_state = SHRM_IDLE;
+	}
+	/* start timer here */
+	hrtimer_start(&timer, ktime_set(0, 25*NSEC_PER_MSEC),
+			HRTIMER_MODE_REL);
+	atomic_dec(&ac_sleep_disable_count);
+	atomic_dec(&ac_msg_pend_1);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_ca_sleep_req_work(struct kthread_work *work)
+{
+	u8 bt_state;
+	unsigned long flags;
+
+	dev_dbg(shm_dev->dev, "%s:IRQ_PRCMU_CA_SLEEP\n", __func__);
+
+	spin_lock_irqsave(&boot_lock, flags);
+	bt_state = boot_state;
+	spin_unlock_irqrestore(&boot_lock, flags);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if ((bt_state != BOOT_DONE) &&
+			(!readl(shm_dev->ca_reset_status_rptr))) {
+		dev_err(shm_dev->dev, "%s:Modem state reset or unknown\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return;
+	}
+	shrm_common_rx_state = SHRM_IDLE;
+	shrm_audio_rx_state =  SHRM_IDLE;
+
+	if (!get_host_accessport_val()) {
+		dev_err(shm_dev->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return;
+	}
+	writel((1<<GOP_CA_WAKE_ACK_BIT),
+		shm_dev->intr_base + GOP_SET_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	hrtimer_start(&timer, ktime_set(0, 10*NSEC_PER_MSEC),
+			HRTIMER_MODE_REL);
+	atomic_dec(&ac_sleep_disable_count);
+}
+
+void shrm_ca_wake_req_work(struct kthread_work *work)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = container_of(work,
+			struct shrm_dev, shrm_ca_wake_req);
+
+	/* initialize the FIFO Variables */
+	if (boot_state == BOOT_INIT) {
+		shrm_fifo_init(shrm);
+	}
+	mutex_lock(&ac_state_mutex);
+	if (modem_request(shrm->modem) < 0) {
+		dev_err(shrm->dev,
+				"prcmu_ac_wake_req failed, initiating MSR\n");
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shrm->shrm_print_dbg_info);
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shrm->shrm_mod_reset_req);
+	}
+	mutex_unlock(&ac_state_mutex);
+
+	local_irq_save(flags);
+	preempt_disable();
+	/* send ca_wake_ack_interrupt to CMU */
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+			__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+	}
+
+	/* send ca_wake_ack_interrupt to CMU */
+	writel((1<<GOP_CA_WAKE_ACK_BIT),
+			shm_dev->intr_base + GOP_SET_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+}
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+static int shrm_modem_reset_sequence(void)
+{
+	int err;
+	unsigned long flags;
+
+	hrtimer_cancel(&timer);
+	hrtimer_cancel(&mod_stuck_timer_0);
+	hrtimer_cancel(&mod_stuck_timer_1);
+	hrtimer_cancel(&fifo_full_timer);
+	atomic_set(&mod_stuck, 0);
+	atomic_set(&fifo_full, 0);
+	tasklet_disable_nosync(&shrm_ac_read_0_tasklet);
+	tasklet_disable_nosync(&shrm_ac_read_1_tasklet);
+	tasklet_disable_nosync(&shrm_ca_0_tasklet);
+	tasklet_disable_nosync(&shrm_ca_1_tasklet);
+
+	/*
+	 * keep the count to 0 so that we can bring down the line
+	 * for normal ac-wake and ac-sleep logic
+	 */
+	atomic_set(&ac_sleep_disable_count, 0);
+	atomic_set(&ac_msg_pend_1, 0);
+
+	/* workaround for MSR */
+	queue_kthread_work(&shm_dev->shrm_ac_wake_kw,
+			&shm_dev->shrm_ac_wake_req);
+
+	/* reset char device queues */
+	shrm_char_reset_queues(shm_dev);
+
+	/* reset protocol states */
+	shrm_common_tx_state = SHRM_SLEEP_STATE;
+	shrm_common_rx_state = SHRM_SLEEP_STATE;
+	shrm_audio_tx_state = SHRM_SLEEP_STATE;
+	shrm_audio_rx_state = SHRM_SLEEP_STATE;
+
+	/* set the msr flag */
+	shm_dev->msr_flag = 1;
+
+	/* multicast that modem is going to reset */
+	err = nl_send_multicast_message(SHRM_NL_MOD_RESET, GFP_ATOMIC);
+
+	/* reset the boot state */
+	spin_lock_irqsave(&boot_lock, flags);
+	boot_state = BOOT_INIT;
+	spin_unlock_irqrestore(&boot_lock, flags);
+
+	tasklet_enable(&shrm_ac_read_0_tasklet);
+	tasklet_enable(&shrm_ac_read_1_tasklet);
+	tasklet_enable(&shrm_ca_0_tasklet);
+	tasklet_enable(&shrm_ca_1_tasklet);
+	/* re-enable irqs */
+	enable_irq(shm_dev->ac_read_notif_0_irq);
+	enable_irq(shm_dev->ac_read_notif_1_irq);
+	enable_irq(shm_dev->ca_msg_pending_notif_0_irq);
+	enable_irq(shm_dev->ca_msg_pending_notif_1_irq);
+	enable_irq(IRQ_PRCMU_CA_WAKE);
+	enable_irq(IRQ_PRCMU_CA_SLEEP);
+
+	return err;
+}
+#endif
+
+static void shrm_modem_reset_callback(unsigned long irq)
+{
+	dev_err(shm_dev->dev, "Received mod_reset_req interrupt\n");
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+	{
+		int err;
+		dev_warn(shm_dev->dev, "Initiating Modem silent reset\n");
+
+		err = shrm_modem_reset_sequence();
+		if (err)
+			dev_err(shm_dev->dev,
+				"Failed multicast of modem reset\n");
+	}
+#else
+	dev_info(shm_dev->dev, "Modem in reset loop, doing System reset\n");
+
+	/* Call the PRCMU reset API */
+	prcmu_system_reset(SW_RESET_NO_ARGUMENT);
+#endif
+}
+
+DECLARE_TASKLET(shrm_sw_reset_callback, shrm_modem_reset_callback,
+		IRQ_PRCMU_MODEM_SW_RESET_REQ);
+
+static irqreturn_t shrm_prcmu_irq_handler(int irq, void *data)
+{
+	struct shrm_dev *shrm = data;
+	unsigned long flags;
+
+	switch (irq) {
+	case IRQ_PRCMU_CA_WAKE:
+		if (shrm->msr_flag)
+			atomic_set(&ac_sleep_disable_count, 0);
+		atomic_inc(&ac_sleep_disable_count);
+		queue_kthread_work(&shrm->shrm_ca_wake_kw, &shrm->shrm_ca_wake_req);
+		break;
+	case IRQ_PRCMU_CA_SLEEP:
+		queue_kthread_work(&shrm->shrm_ca_wake_kw, &shrm->shrm_ca_sleep_req);
+		break;
+	case IRQ_PRCMU_MODEM_SW_RESET_REQ:
+		/* update the boot_state */
+		spin_lock_irqsave(&boot_lock, flags);
+		boot_state = BOOT_UNKNOWN;
+
+		/*
+		 * put a barrier over here to make sure boot_state is updated
+		 * else, it is seen that some of already executing modem
+		 * irqs or tasklets fail the protocol checks and will ultimately
+		 * try to acces the modem causing system to hang.
+		 * This is particularly seen with user-space initiated modem reset
+		 */
+		wmb();
+		spin_unlock_irqrestore(&boot_lock, flags);
+
+		disable_irq_nosync(shrm->ac_read_notif_0_irq);
+		disable_irq_nosync(shrm->ac_read_notif_1_irq);
+		disable_irq_nosync(shrm->ca_msg_pending_notif_0_irq);
+		disable_irq_nosync(shrm->ca_msg_pending_notif_1_irq);
+		disable_irq_nosync(IRQ_PRCMU_CA_WAKE);
+		disable_irq_nosync(IRQ_PRCMU_CA_SLEEP);
+
+		/* stop network queue */
+		shrm_stop_netdev(shm_dev->ndev);
+
+		tasklet_schedule(&shrm_sw_reset_callback);
+		break;
+	default:
+		dev_err(shrm->dev, "%s: => IRQ %d\n", __func__, irq);
+		return IRQ_NONE;
+	}
+	return IRQ_HANDLED;
+}
+
+static void send_ac_msg_pend_notify_0_work(struct kthread_work *work)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = container_of(work, struct shrm_dev,
+			send_ac_msg_pend_notify_0);
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	update_ac_common_shared_wptr(shrm);
+
+	mutex_lock(&ac_state_mutex);
+	atomic_inc(&ac_sleep_disable_count);
+	if (modem_request(shrm->modem) < 0) {
+		dev_err(shrm->dev,
+				"prcmu_ac_wake_req failed, initiating MSR\n");
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shrm->shrm_print_dbg_info);
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shrm->shrm_mod_reset_req);
+	}
+	mutex_unlock(&ac_state_mutex);
+
+	spin_lock_irqsave(&start_timer_lock, flags);
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		spin_unlock_irqrestore(&start_timer_lock, flags);
+		return;
+	}
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		spin_unlock_irqrestore(&start_timer_lock, flags);
+		return;
+	}
+
+	/* Trigger AcMsgPendingNotification to CMU */
+	writel((1<<GOP_COMMON_AC_MSG_PENDING_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_SET_REGISTER_BASE);
+
+	/* timer to detect modem stuck or hang */
+	hrtimer_start(&mod_stuck_timer_0, ktime_set(MOD_STUCK_TIMEOUT, 0),
+			HRTIMER_MODE_REL);
+	spin_unlock_irqrestore(&start_timer_lock, flags);
+	if (shrm_common_tx_state == SHRM_PTR_FREE)
+		shrm_common_tx_state = SHRM_PTR_BUSY;
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static void send_ac_msg_pend_notify_1_work(struct kthread_work *work)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = container_of(work, struct shrm_dev,
+			send_ac_msg_pend_notify_1);
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	/* Update shared_wptr with writer_local_wptr) */
+	update_ac_audio_shared_wptr(shrm);
+
+	mutex_lock(&ac_state_mutex);
+	if (!atomic_read(&ac_msg_pend_1)) {
+		atomic_inc(&ac_sleep_disable_count);
+		atomic_inc(&ac_msg_pend_1);
+	}
+	if (modem_request(shrm->modem) < 0) {
+		dev_err(shrm->dev,
+				"prcmu_ac_wake_req failed, initiating MSR\n");
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shm_dev->shrm_print_dbg_info);
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+	}
+	mutex_unlock(&ac_state_mutex);
+
+	spin_lock_irqsave(&start_timer_lock, flags);
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		spin_unlock_irqrestore(&start_timer_lock, flags);
+		return;
+	}
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		spin_unlock_irqrestore(&start_timer_lock, flags);
+		return;
+	}
+
+	/* Trigger AcMsgPendingNotification to CMU */
+	writel((1<<GOP_AUDIO_AC_MSG_PENDING_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_SET_REGISTER_BASE);
+
+	/* timer to detect modem stuck or hang */
+	hrtimer_start(&mod_stuck_timer_1, ktime_set(MOD_STUCK_TIMEOUT, 0),
+			HRTIMER_MODE_REL);
+	spin_unlock_irqrestore(&start_timer_lock, flags);
+	if (shrm_audio_tx_state == SHRM_PTR_FREE)
+		shrm_audio_tx_state = SHRM_PTR_BUSY;
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_nl_receive(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh = NULL;
+	int msg;
+
+	dev_dbg(shm_dev->dev, "Received NL msg from user-space\n");
+
+	nlh = (struct nlmsghdr *)skb->data;
+	msg = *((int *)(NLMSG_DATA(nlh)));
+	switch (msg) {
+	case SHRM_NL_MOD_QUERY_STATE:
+		dev_dbg(shm_dev->dev, "mod-query-state from user-space\n");
+		nl_send_unicast_message(nlh->nlmsg_pid);
+		break;
+
+	case SHRM_NL_USER_MOD_RESET:
+		dev_info(shm_dev->dev, "user-space inited mod-reset-req\n");
+		dev_info(shm_dev->dev, "PCRMU resets modem\n");
+		if (atomic_read(&mod_stuck) || atomic_read(&fifo_full)) {
+			dev_info(shm_dev->dev,
+					"Modem reset already in progress\n");
+			break;
+		}
+		atomic_set(&mod_stuck, 1);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+		break;
+
+	default:
+		dev_err(shm_dev->dev, "Invalid NL msg from user-space\n");
+		break;
+	};
+}
+
+int shrm_protocol_init(struct shrm_dev *shrm,
+			received_msg_handler common_rx_handler,
+			received_msg_handler audio_rx_handler)
+{
+	int err;
+	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+	struct netlink_kernel_cfg nl_cfg;
+#endif
+
+	shm_dev = shrm;
+	boot_state = BOOT_INIT;
+	dev_info(shrm->dev, "IPC_ISA BOOT_INIT\n");
+	rx_common_handler = common_rx_handler;
+	rx_audio_handler = audio_rx_handler;
+	atomic_set(&ac_sleep_disable_count, 0);
+
+	hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	timer.function = callback;
+	hrtimer_init(&mod_stuck_timer_0, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	mod_stuck_timer_0.function = shrm_mod_stuck_timeout;
+	hrtimer_init(&mod_stuck_timer_1, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	mod_stuck_timer_1.function = shrm_mod_stuck_timeout;
+	hrtimer_init(&fifo_full_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	fifo_full_timer.function = shrm_fifo_full_timeout;
+
+	init_kthread_worker(&shrm->shrm_common_ch_wr_kw);
+	shrm->shrm_common_ch_wr_kw_task = kthread_run(kthread_worker_fn,
+						     &shrm->shrm_common_ch_wr_kw,
+						     "shrm_common_channel_irq");
+	if (IS_ERR(shrm->shrm_common_ch_wr_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		return -ENOMEM;
+	}
+
+	init_kthread_worker(&shrm->shrm_audio_ch_wr_kw);
+	shrm->shrm_audio_ch_wr_kw_task = kthread_run(kthread_worker_fn,
+						    &shrm->shrm_audio_ch_wr_kw,
+						    "shrm_audio_channel_irq");
+	if (IS_ERR(shrm->shrm_audio_ch_wr_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw1;
+	}
+	/* must use the FIFO scheduler as it is realtime sensitive */
+	sched_setscheduler(shrm->shrm_audio_ch_wr_kw_task, SCHED_FIFO, &param);
+
+	init_kthread_worker(&shrm->shrm_ac_wake_kw);
+	shrm->shrm_ac_wake_kw_task = kthread_run(kthread_worker_fn,
+						&shrm->shrm_ac_wake_kw,
+						"shrm_ac_wake_req");
+	if (IS_ERR(shrm->shrm_ac_wake_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw2;
+	}
+	/* must use the FIFO scheduler as it is realtime sensitive */
+	sched_setscheduler(shrm->shrm_ac_wake_kw_task, SCHED_FIFO, &param);
+
+	init_kthread_worker(&shrm->shrm_ca_wake_kw);
+	shrm->shrm_ca_wake_kw_task = kthread_run(kthread_worker_fn,
+						&shrm->shrm_ca_wake_kw,
+						"shrm_ca_wake_req");
+	if (IS_ERR(shrm->shrm_ca_wake_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw3;
+	}
+	/* must use the FIFO scheduler as it is realtime sensitive */
+	sched_setscheduler(shrm->shrm_ca_wake_kw_task, SCHED_FIFO, &param);
+
+	init_kthread_worker(&shrm->shrm_ac_sleep_kw);
+	shrm->shrm_ac_sleep_kw_task = kthread_run(kthread_worker_fn,
+						 &shrm->shrm_ac_sleep_kw,
+						 "shrm_ac_sleep_req");
+	if (IS_ERR(shrm->shrm_ac_sleep_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw4;
+	}
+	init_kthread_worker(&shrm->shrm_mod_stuck_kw);
+	shrm->shrm_mod_stuck_kw_task = kthread_run(kthread_worker_fn,
+						     &shrm->shrm_mod_stuck_kw,
+						     "shrm_mod_reset_req");
+	if (IS_ERR(shrm->shrm_mod_stuck_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw5;
+	}
+
+	init_kthread_work(&shrm->send_ac_msg_pend_notify_0,
+			  send_ac_msg_pend_notify_0_work);
+	init_kthread_work(&shrm->send_ac_msg_pend_notify_1,
+			  send_ac_msg_pend_notify_1_work);
+	init_kthread_work(&shrm->shrm_ca_wake_req, shrm_ca_wake_req_work);
+	init_kthread_work(&shrm->shrm_ca_sleep_req, shrm_ca_sleep_req_work);
+	init_kthread_work(&shrm->shrm_ac_sleep_req, shrm_ac_sleep_req_work);
+	init_kthread_work(&shrm->shrm_ac_wake_req, shrm_ac_wake_req_work);
+	init_kthread_work(&shrm->shrm_mod_reset_req, shrm_mod_reset_req_work);
+	init_kthread_work(&shrm->shrm_print_dbg_info, shrm_print_dbg_info_work);
+
+	/* set tasklet data */
+	shrm_ca_0_tasklet.data = (unsigned long)shrm;
+	shrm_ca_1_tasklet.data = (unsigned long)shrm;
+
+	err = request_irq(IRQ_PRCMU_CA_SLEEP, shrm_prcmu_irq_handler,
+			IRQF_NO_SUSPEND, "ca-sleep", shrm);
+	if (err < 0) {
+		dev_err(shm_dev->dev, "Failed alloc IRQ_PRCMU_CA_SLEEP.\n");
+		goto free_kw6;
+	}
+
+	err = request_irq(IRQ_PRCMU_CA_WAKE, shrm_prcmu_irq_handler,
+		IRQF_NO_SUSPEND, "ca-wake", shrm);
+	if (err < 0) {
+		dev_err(shm_dev->dev, "Failed alloc IRQ_PRCMU_CA_WAKE.\n");
+		goto drop2;
+	}
+
+	err = request_irq(IRQ_PRCMU_MODEM_SW_RESET_REQ, shrm_prcmu_irq_handler,
+			IRQF_NO_SUSPEND, "modem-sw-reset-req", shrm);
+	if (err < 0) {
+		dev_err(shm_dev->dev,
+				"Failed alloc IRQ_PRCMU_MODEM_SW_RESET_REQ.\n");
+		goto drop1;
+	}
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+	nl_cfg.input = shrm_nl_receive;
+	nl_cfg.cb_mutex = NULL;
+	/* init netlink socket for user-space communication */
+	shrm_nl_sk = netlink_kernel_create(NULL, NETLINK_SHRM, THIS_MODULE, &nl_cfg);
+
+	if (!shrm_nl_sk) {
+		dev_err(shm_dev->dev, "netlink socket creation failed\n");
+		goto drop;
+	}
+#endif
+	return 0;
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+drop:
+	free_irq(IRQ_PRCMU_MODEM_SW_RESET_REQ, NULL);
+#endif
+drop1:
+	free_irq(IRQ_PRCMU_CA_WAKE, NULL);
+drop2:
+	free_irq(IRQ_PRCMU_CA_SLEEP, NULL);
+free_kw6:
+	kthread_stop(shrm->shrm_mod_stuck_kw_task);
+free_kw5:
+	kthread_stop(shrm->shrm_ac_sleep_kw_task);
+free_kw4:
+	kthread_stop(shrm->shrm_ca_wake_kw_task);
+free_kw3:
+	kthread_stop(shrm->shrm_ac_wake_kw_task);
+free_kw2:
+	kthread_stop(shrm->shrm_audio_ch_wr_kw_task);
+free_kw1:
+	kthread_stop(shrm->shrm_common_ch_wr_kw_task);
+	return err;
+}
+
+void shrm_protocol_deinit(struct shrm_dev *shrm)
+{
+	free_irq(IRQ_PRCMU_CA_SLEEP, NULL);
+	free_irq(IRQ_PRCMU_CA_WAKE, NULL);
+	free_irq(IRQ_PRCMU_MODEM_SW_RESET_REQ, NULL);
+	flush_kthread_worker(&shrm->shrm_common_ch_wr_kw);
+	flush_kthread_worker(&shrm->shrm_audio_ch_wr_kw);
+	flush_kthread_worker(&shrm->shrm_ac_wake_kw);
+	flush_kthread_worker(&shrm->shrm_ca_wake_kw);
+	flush_kthread_worker(&shrm->shrm_ac_sleep_kw);
+	flush_kthread_worker(&shrm->shrm_mod_stuck_kw);
+	kthread_stop(shrm->shrm_common_ch_wr_kw_task);
+	kthread_stop(shrm->shrm_audio_ch_wr_kw_task);
+	kthread_stop(shrm->shrm_ac_wake_kw_task);
+	kthread_stop(shrm->shrm_ca_wake_kw_task);
+	kthread_stop(shrm->shrm_ac_sleep_kw_task);
+	kthread_stop(shrm->shrm_mod_stuck_kw_task);
+	modem_put(shrm->modem);
+}
+
+int get_ca_wake_req_state(void)
+{
+	return ((atomic_read(&ac_sleep_disable_count) > 0) ||
+			modem_get_usage(shm_dev->modem));
+}
+
+irqreturn_t ca_wake_irq_handler(int irq, void *ctrlr)
+{
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	/* initialize the FIFO Variables */
+	if (boot_state == BOOT_INIT)
+		shrm_fifo_init(shrm);
+
+	dev_dbg(shrm->dev, "Inside ca_wake_irq_handler\n");
+
+	/* Clear the interrupt */
+	writel((1 << GOP_CA_WAKE_REQ_BIT),
+				shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
+
+	/* send ca_wake_ack_interrupt to CMU */
+	writel((1 << GOP_CA_WAKE_ACK_BIT),
+		shrm->intr_base + GOP_SET_REGISTER_BASE);
+
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+}
+
+
+irqreturn_t ac_read_notif_0_irq_handler(int irq, void *ctrlr)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	/* Cancel the modem stuck timer */
+	spin_lock_irqsave(&start_timer_lock, flags);
+	hrtimer_cancel(&mod_stuck_timer_0);
+	spin_unlock_irqrestore(&start_timer_lock, flags);
+	if (atomic_read(&fifo_full)) {
+		atomic_set(&fifo_full, 0);
+		hrtimer_cancel(&fifo_full_timer);
+	}
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return IRQ_NONE;
+	}
+
+	shrm_ac_read_0_tasklet.data = (unsigned long)shrm;
+	tasklet_schedule(&shrm_ac_read_0_tasklet);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+	/* Clear the interrupt */
+	writel((1 << GOP_COMMON_AC_READ_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ac_read_notif_1_irq_handler(int irq, void *ctrlr)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN+\n", __func__);
+	/* Cancel the modem stuck timer */
+	spin_lock_irqsave(&start_timer_lock, flags);
+	hrtimer_cancel(&mod_stuck_timer_1);
+	spin_unlock_irqrestore(&start_timer_lock, flags);
+	if (atomic_read(&fifo_full)) {
+		atomic_set(&fifo_full, 0);
+		hrtimer_cancel(&fifo_full_timer);
+	}
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return IRQ_NONE;
+	}
+
+	shrm_ac_read_1_tasklet.data = (unsigned long)shrm;
+	tasklet_schedule(&shrm_ac_read_1_tasklet);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+	/* Clear the interrupt */
+	writel((1 << GOP_AUDIO_AC_READ_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ca_msg_pending_notif_0_irq_handler(int irq, void *ctrlr)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return IRQ_NONE;
+	}
+
+	tasklet_schedule(&shrm_ca_0_tasklet);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+	/* Clear the interrupt */
+	writel((1 << GOP_COMMON_CA_MSG_PENDING_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ca_msg_pending_notif_1_irq_handler(int irq, void *ctrlr)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return IRQ_NONE;
+	}
+
+	tasklet_schedule(&shrm_ca_1_tasklet);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+				&shrm->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+	/* Clear the interrupt */
+	writel((1<<GOP_AUDIO_CA_MSG_PENDING_NOTIFICATION_BIT),
+			shrm->intr_base+GOP_CLEAR_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+
+}
+
+/**
+ * shrm_write_msg() - write message to shared memory
+ * @shrm:	pointer to the shrm device information structure
+ * @l2_header:	L2 header
+ * @addr:	pointer to the message
+ * @length:	length of the message to be written
+ *
+ * This function is called from net or char interface driver write operation.
+ * Prior to calling this function the message is copied from the user space
+ * buffer to the kernel buffer. This function based on the l2 header routes
+ * the message to the respective channel and FIFO. Then makes a call to the
+ * fifo write function where the message is written to the physical device.
+ */
+int shrm_write_msg(struct shrm_dev *shrm, u8 l2_header,
+					void *addr, u32 length)
+{
+	u8 channel = 0;
+	int ret, i;
+	u8 *temp;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (boot_state != BOOT_DONE) {
+		dev_err(shrm->dev,
+			"error:after boot done  call this fn, L2Header = %d\n",
+			l2_header);
+		dev_err(shrm->dev, "packet not sent, modem in reset");
+		temp = (u8 *)addr;
+		for (i = 0; i < length; i++)
+			dev_dbg(shrm->dev, "data[%d]=%02x\t", i, temp[i]);
+		dev_dbg(shrm->dev, "\n");
+		/*
+		 * If error is returned then phonet tends to resend the msg
+		 * this will lead to the msg bouncing to and fro between
+		 * phonet and shrm, hence dont return error.
+		*/
+		ret = 0;
+		goto out;
+	}
+
+	if ((l2_header == L2_HEADER_ISI) ||
+			(l2_header == L2_HEADER_RPC) ||
+			(l2_header == L2_HEADER_SECURITY) ||
+			(l2_header == L2_HEADER_COMMON_SIMPLE_LOOPBACK) ||
+			(l2_header == L2_HEADER_COMMON_ADVANCED_LOOPBACK) ||
+			(l2_header == L2_HEADER_CIQ) ||
+			(l2_header == L2_HEADER_RTC_CALIBRATION)) {
+		channel = 0;
+		if (shrm_common_tx_state == SHRM_SLEEP_STATE)
+			shrm_common_tx_state = SHRM_PTR_FREE;
+		else if (shrm_common_tx_state == SHRM_IDLE)
+			shrm_common_tx_state = SHRM_PTR_FREE;
+
+	} else if ((l2_header == L2_HEADER_AUDIO) ||
+			(l2_header == L2_HEADER_AUDIO_SIMPLE_LOOPBACK) ||
+			(l2_header == L2_HEADER_AUDIO_ADVANCED_LOOPBACK)) {
+		if (shrm_audio_tx_state == SHRM_SLEEP_STATE)
+			shrm_audio_tx_state = SHRM_PTR_FREE;
+		else if (shrm_audio_tx_state == SHRM_IDLE)
+			shrm_audio_tx_state = SHRM_PTR_FREE;
+
+		channel = 1;
+	} else {
+		ret = -ENODEV;
+		goto out;
+	}
+	ret = shrm_write_msg_to_fifo(shrm, channel, l2_header, addr, length);
+	if (ret < 0) {
+		dev_err(shrm->dev, "write message to fifo failed\n");
+		if (ret == -EAGAIN) {
+			if (!atomic_read(&fifo_full)) {
+				/* Start a timer so as to handle this gently */
+				atomic_set(&fifo_full, 1);
+				hrtimer_start(&fifo_full_timer, ktime_set(
+						FIFO_FULL_TIMEOUT, 0),
+						HRTIMER_MODE_REL);
+			}
+		}
+		return ret;
+	}
+	/*
+	 * notify only if new msg copied is the only unread one
+	 * otherwise it means that reading process is ongoing
+	 */
+	if (is_the_only_one_unread_message(shrm, channel, length)) {
+
+		/* Send Message Pending Noitication to CMT */
+		if (channel == 0)
+			queue_kthread_work(&shrm->shrm_common_ch_wr_kw,
+					&shrm->send_ac_msg_pend_notify_0);
+		else
+			queue_kthread_work(&shrm->shrm_audio_ch_wr_kw,
+					&shrm->send_ac_msg_pend_notify_1);
+
+	}
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return 0;
+
+out:
+	return ret;
+}
+
+void ca_msg_read_notification_0(struct shrm_dev *shrm)
+{
+	unsigned long flags;
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (get_ca_msg_0_read_notif_send() == 0) {
+		update_ca_common_shared_rptr(shrm);
+
+		local_irq_save(flags);
+		preempt_disable();
+		if (check_modem_in_reset()) {
+			dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+					__func__);
+			preempt_enable();
+			local_irq_restore(flags);
+			return;
+		}
+
+		if (!get_host_accessport_val()) {
+			dev_err(shrm->dev, "%s: host_accessport is low\n",
+					__func__);
+			queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+			preempt_enable();
+			local_irq_restore(flags);
+			return;
+		}
+		/* Trigger CaMsgReadNotification to CMU */
+		writel((1 << GOP_COMMON_CA_READ_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_SET_REGISTER_BASE);
+		preempt_enable();
+		local_irq_restore(flags);
+		set_ca_msg_0_read_notif_send(1);
+		shrm_common_rx_state = SHRM_PTR_BUSY;
+	}
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void ca_msg_read_notification_1(struct shrm_dev *shrm)
+{
+	unsigned long flags;
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (get_ca_msg_1_read_notif_send() == 0) {
+		update_ca_audio_shared_rptr(shrm);
+
+		local_irq_save(flags);
+		preempt_disable();
+		if (check_modem_in_reset()) {
+			dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+					__func__);
+			preempt_enable();
+			local_irq_restore(flags);
+			return;
+		}
+
+		if (!get_host_accessport_val()) {
+			dev_err(shrm->dev, "%s: host_accessport is low\n",
+					__func__);
+			queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+			preempt_enable();
+			local_irq_restore(flags);
+			return;
+		}
+		/* Trigger CaMsgReadNotification to CMU */
+		writel((1<<GOP_AUDIO_CA_READ_NOTIFICATION_BIT),
+			shrm->intr_base+GOP_SET_REGISTER_BASE);
+		preempt_enable();
+		local_irq_restore(flags);
+		set_ca_msg_1_read_notif_send(1);
+		shrm_audio_rx_state = SHRM_PTR_BUSY;
+	}
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+/**
+ * receive_messages_common - receive common channnel msg from
+ * CMT(Cellular Mobile Terminal)
+ * @shrm:	pointer to shrm device information structure
+ *
+ * The messages sent from CMT to APE are written to the respective FIFO
+ * and an interrupt is triggered by the CMT. This ca message pending
+ * interrupt calls this function. This function sends a read notification
+ * acknowledgement to the CMT and calls the common channel receive handler
+ * where the messsage is copied to the respective(ISI, RPC, SECURIT) queue
+ * based on the message l2 header.
+ */
+void receive_messages_common(struct shrm_dev *shrm)
+{
+	u8 l2_header;
+	u32 len;
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return;
+	}
+
+	l2_header = read_one_l2msg_common(shrm, recieve_common_msg, &len);
+	/* Send Recieve_Call_back to Upper Layer */
+	if (!rx_common_handler) {
+		dev_err(shrm->dev, "common_rx_handler is Null\n");
+		BUG();
+	}
+	(*rx_common_handler)(l2_header, &recieve_common_msg, len,
+					shrm);
+	/* SendReadNotification */
+	ca_msg_read_notification_0(shrm);
+
+	while (read_remaining_messages_common()) {
+		if (check_modem_in_reset()) {
+			dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+					__func__);
+			return;
+		}
+
+		l2_header = read_one_l2msg_common(shrm, recieve_common_msg,
+								&len);
+		/* Send Recieve_Call_back to Upper Layer */
+		(*rx_common_handler)(l2_header,
+					&recieve_common_msg, len,
+					shrm);
+	}
+}
+
+/**
+ * receive_messages_audio() - receive audio message from CMT
+ * @shrm:	pointer to shrm device information structure
+ *
+ * The messages sent from CMT to APE are written to the respective FIFO
+ * and an interrupt is triggered by the CMT. This ca message pending
+ * interrupt calls this function. This function sends a read notification
+ * acknowledgement to the CMT and calls the common channel receive handler
+ * where the messsage is copied to the audio queue.
+ */
+void receive_messages_audio(struct shrm_dev *shrm)
+{
+	u8 l2_header;
+	u32 len;
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return;
+	}
+
+	l2_header = read_one_l2msg_audio(shrm, recieve_audio_msg, &len);
+	/* Send Recieve_Call_back to Upper Layer */
+
+	if (!rx_audio_handler) {
+		dev_crit(shrm->dev, "audio_rx_handler is Null\n");
+		BUG();
+	}
+	(*rx_audio_handler)(l2_header, &recieve_audio_msg,
+					len, shrm);
+
+	/* SendReadNotification */
+	ca_msg_read_notification_1(shrm);
+	while (read_remaining_messages_audio())	{
+		if (check_modem_in_reset()) {
+			dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+					__func__);
+			return;
+		}
+
+		l2_header = read_one_l2msg_audio(shrm,
+						recieve_audio_msg, &len);
+		/* Send Recieve_Call_back to Upper Layer */
+		(*rx_audio_handler)(l2_header,
+					&recieve_audio_msg, len,
+					shrm);
+	}
+}
+
+u8 get_boot_state()
+{
+	return boot_state;
+}
-- 
1.7.4.3

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists