summaryrefslogtreecommitdiff
path: root/drivers/misc/shrm/shrm_protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/shrm/shrm_protocol.c')
-rw-r--r--drivers/misc/shrm/shrm_protocol.c1191
1 files changed, 0 insertions, 1191 deletions
diff --git a/drivers/misc/shrm/shrm_protocol.c b/drivers/misc/shrm/shrm_protocol.c
deleted file mode 100644
index 686bebcb451..00000000000
--- a/drivers/misc/shrm/shrm_protocol.c
+++ /dev/null
@@ -1,1191 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Biju Das <biju.das@stericsson.com> for ST-Ericsson
- * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> for ST-Ericsson
- * Author: Arun Murthy <arun.murthy@stericsson.com> 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/workqueue.h>
-
-#include <mach/shrm.h>
-#include <mach/shrm_driver.h>
-#include <mach/shrm_private.h>
-#include <mach/shrm_net.h>
-#include <mach/prcmu.h>
-#include <mach/prcmu-regs.h>
-#include <mach/suspend.h>
-#include <mach/reboot_reasons.h>
-#include <linux/modem/modem_client.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 MAX_PAYLOAD 1024
-
-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;
-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 struct shrm_dev *shm_dev;
-
-/* Spin lock and tasklet declaration */
-DECLARE_TASKLET(shm_ca_0_tasklet, shm_ca_msgpending_0_tasklet, 0);
-DECLARE_TASKLET(shm_ca_1_tasklet, shm_ca_msgpending_1_tasklet, 0);
-DECLARE_TASKLET(shm_ac_read_0_tasklet, shm_ac_read_notif_0_tasklet, 0);
-DECLARE_TASKLET(shm_ac_read_1_tasklet, shm_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);
-
-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 void shm_ac_sleep_req_work(struct work_struct *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 shm_ac_wake_req_work(struct work_struct *work)
-{
- mutex_lock(&ac_state_mutex);
- modem_request(shm_dev->modem);
- mutex_unlock(&ac_state_mutex);
-}
-
-static u32 get_host_accessport_val(void)
-{
- u32 prcm_hostaccess;
-
- prcm_hostaccess = readl(PRCM_HOSTACCESS_REQ);
- wmb();
- prcm_hostaccess = prcm_hostaccess & 0x01;
-
- return prcm_hostaccess;
-}
-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_work(shm_dev->shm_ac_sleep_wq,
- &shm_dev->shm_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_info(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)
- 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 shm_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");
- BUG();
- }
- /* 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_work(shrm->shm_common_ch_wr_wq,
- &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 shm_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 shm_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_work(shrm->shm_common_ch_wr_wq,
- &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, 10*NSEC_PER_MSEC),
- HRTIMER_MODE_REL);
- atomic_dec(&ac_sleep_disable_count);
-
- dev_dbg(shrm->dev, "%s OUT\n", __func__);
-}
-
-void shm_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_work(shrm->shm_audio_ch_wr_wq,
- &shrm->send_ac_msg_pend_notify_1);
- } else {
- shrm_audio_tx_state = SHRM_IDLE;
- }
- /* start timer here */
- hrtimer_start(&timer, ktime_set(0, 10*NSEC_PER_MSEC),
- HRTIMER_MODE_REL);
- atomic_dec(&ac_sleep_disable_count);
-
- dev_dbg(shrm->dev, "%s OUT\n", __func__);
-}
-
-void shm_ca_sleep_req_work(struct work_struct *work)
-{
- dev_dbg(shm_dev->dev, "%s:IRQ_PRCMU_CA_SLEEP\n", __func__);
-
- shrm_common_rx_state = SHRM_IDLE;
- shrm_audio_rx_state = SHRM_IDLE;
-
- writel((1<<GOP_CA_WAKE_ACK_BIT),
- shm_dev->intr_base + GOP_SET_REGISTER_BASE);
-
- hrtimer_start(&timer, ktime_set(0, 10*NSEC_PER_MSEC),
- HRTIMER_MODE_REL);
-#ifdef CONFIG_UX500_SUSPEND
- suspend_unblock_sleep();
-#endif
- atomic_dec(&ac_sleep_disable_count);
-}
-
-void shm_ca_wake_req_work(struct work_struct *work)
-{
- struct shrm_dev *shrm = container_of(work,
- struct shrm_dev, shm_ca_wake_req);
-
- /* initialize the FIFO Variables */
- if (boot_state == BOOT_INIT)
- shm_fifo_init(shrm);
-
- mutex_lock(&ac_state_mutex);
- modem_request(shrm->modem);
- mutex_unlock(&ac_state_mutex);
-
- /* send ca_wake_ack_interrupt to CMU */
- if (!get_host_accessport_val())
- BUG();
- writel((1<<GOP_CA_WAKE_ACK_BIT),
- shm_dev->intr_base + GOP_SET_REGISTER_BASE);
-}
-#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
-static int shrm_modem_reset_sequence(void)
-{
- int err;
- unsigned long flags;
-
- /*
- * disable irqs
- * very much needed for user-space initiated
- * modem-reset
- */
- disable_irq_nosync(shm_dev->ac_read_notif_0_irq);
- disable_irq_nosync(shm_dev->ac_read_notif_1_irq);
- disable_irq_nosync(shm_dev->ca_msg_pending_notif_0_irq);
- disable_irq_nosync(shm_dev->ca_msg_pending_notif_1_irq);
- disable_irq_nosync(IRQ_PRCMU_CA_WAKE);
- disable_irq_nosync(IRQ_PRCMU_CA_SLEEP);
-
-
- /* 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);
-
- hrtimer_cancel(&timer);
-
- /*
- * 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);
-
- /* workaround for MSR */
- queue_work(shm_dev->shm_ac_wake_wq,
- &shm_dev->shm_ac_wake_req);
-
- /* stop network queue */
- shrm_stop_netdev(shm_dev->ndev);
-
- /* 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);
-
- /* 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_info(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;
-
- switch (irq) {
- case IRQ_PRCMU_CA_WAKE:
-#ifdef CONFIG_UX500_SUSPEND
- suspend_block_sleep();
-#endif
- if (shrm->msr_flag)
- atomic_set(&ac_sleep_disable_count, 0);
- atomic_inc(&ac_sleep_disable_count);
- queue_work(shrm->shm_ca_wake_wq, &shrm->shm_ca_wake_req);
- break;
- case IRQ_PRCMU_CA_SLEEP:
- queue_work(shrm->shm_ca_wake_wq, &shrm->shm_ca_sleep_req);
- break;
- case IRQ_PRCMU_MODEM_SW_RESET_REQ:
- 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 work_struct *work)
-{
- 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);
- modem_request(shrm->modem);
- mutex_unlock(&ac_state_mutex);
-
- if (!get_host_accessport_val())
- BUG();
-
- /* Trigger AcMsgPendingNotification to CMU */
- writel((1<<GOP_COMMON_AC_MSG_PENDING_NOTIFICATION_BIT),
- shrm->intr_base + GOP_SET_REGISTER_BASE);
-
- 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 work_struct *work)
-{
- 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);
- atomic_inc(&ac_sleep_disable_count);
- modem_request(shrm->modem);
- mutex_unlock(&ac_state_mutex);
-
- if (!get_host_accessport_val())
- BUG();
-
- /* Trigger AcMsgPendingNotification to CMU */
- writel((1<<GOP_AUDIO_AC_MSG_PENDING_NOTIFICATION_BIT),
- shrm->intr_base + GOP_SET_REGISTER_BASE);
-
- if (shrm_audio_tx_state == SHRM_PTR_FREE)
- shrm_audio_tx_state = SHRM_PTR_BUSY;
-
- dev_dbg(shrm->dev, "%s OUT\n", __func__);
-}
-
-void shm_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_info(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");
- prcmu_modem_reset();
- 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;
-
- 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;
-
- shrm->shm_common_ch_wr_wq = create_singlethread_workqueue
- ("shm_common_channel_irq");
- if (!shrm->shm_common_ch_wr_wq) {
- dev_err(shrm->dev, "failed to create work queue\n");
- return -ENOMEM;
- }
- shrm->shm_audio_ch_wr_wq = create_singlethread_workqueue
- ("shm_audio_channel_irq");
- if (!shrm->shm_audio_ch_wr_wq) {
- dev_err(shrm->dev, "failed to create work queue\n");
- err = -ENOMEM;
- goto free_wq1;
- }
- shrm->shm_ac_wake_wq = create_singlethread_workqueue("shm_ac_wake_req");
- if (!shrm->shm_ac_wake_wq) {
- dev_err(shrm->dev, "failed to create work queue\n");
- err = -ENOMEM;
- goto free_wq2;
- }
- shrm->shm_ca_wake_wq = create_singlethread_workqueue("shm_ca_wake_req");
- if (!shrm->shm_ac_wake_wq) {
- dev_err(shrm->dev, "failed to create work queue\n");
- err = -ENOMEM;
- goto free_wq3;
- }
- shrm->shm_ac_sleep_wq = create_singlethread_workqueue
- ("shm_ac_sleep_req");
- if (!shrm->shm_ac_sleep_wq) {
- dev_err(shrm->dev, "failed to create work queue\n");
- err = -ENOMEM;
- goto free_wq4;
- }
- INIT_WORK(&shrm->send_ac_msg_pend_notify_0,
- send_ac_msg_pend_notify_0_work);
- INIT_WORK(&shrm->send_ac_msg_pend_notify_1,
- send_ac_msg_pend_notify_1_work);
- INIT_WORK(&shrm->shm_ca_wake_req, shm_ca_wake_req_work);
- INIT_WORK(&shrm->shm_ca_sleep_req, shm_ca_sleep_req_work);
- INIT_WORK(&shrm->shm_ac_sleep_req, shm_ac_sleep_req_work);
- INIT_WORK(&shrm->shm_ac_wake_req, shm_ac_wake_req_work);
-
- /* set tasklet data */
- shm_ca_0_tasklet.data = (unsigned long)shrm;
- shm_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_wq5;
- }
-
- 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
- /* init netlink socket for user-space communication */
- shrm_nl_sk = netlink_kernel_create(NULL, NETLINK_SHRM, 1,
- shm_nl_receive, NULL, THIS_MODULE);
-
- 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_wq5:
- destroy_workqueue(shrm->shm_ac_sleep_wq);
-free_wq4:
- destroy_workqueue(shrm->shm_ca_wake_wq);
-free_wq3:
- destroy_workqueue(shrm->shm_ac_wake_wq);
-free_wq2:
- destroy_workqueue(shrm->shm_audio_ch_wr_wq);
-free_wq1:
- destroy_workqueue(shrm->shm_common_ch_wr_wq);
- 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_scheduled_work();
- destroy_workqueue(shrm->shm_common_ch_wr_wq);
- destroy_workqueue(shrm->shm_audio_ch_wr_wq);
- destroy_workqueue(shrm->shm_ac_wake_wq);
- destroy_workqueue(shrm->shm_ca_wake_wq);
- destroy_workqueue(shrm->shm_ac_sleep_wq);
- 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)
- shm_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)
-{
- 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_HANDLED;
- }
-
- shm_ac_read_0_tasklet.data = (unsigned long)shrm;
- tasklet_schedule(&shm_ac_read_0_tasklet);
-
- if (check_modem_in_reset()) {
- dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
- __func__);
- return IRQ_HANDLED;
- }
-
- /* Clear the interrupt */
- writel((1 << GOP_COMMON_AC_READ_NOTIFICATION_BIT),
- shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
-
- dev_dbg(shrm->dev, "%s OUT\n", __func__);
- return IRQ_HANDLED;
-}
-
-irqreturn_t ac_read_notif_1_irq_handler(int irq, void *ctrlr)
-{
- 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_HANDLED;
- }
-
- shm_ac_read_1_tasklet.data = (unsigned long)shrm;
- tasklet_schedule(&shm_ac_read_1_tasklet);
-
- if (check_modem_in_reset()) {
- dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
- __func__);
- return IRQ_HANDLED;
- }
-
- /* Clear the interrupt */
- writel((1 << GOP_AUDIO_AC_READ_NOTIFICATION_BIT),
- shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
-
- dev_dbg(shrm->dev, "%s OUT\n", __func__);
- return IRQ_HANDLED;
-}
-
-irqreturn_t ca_msg_pending_notif_0_irq_handler(int irq, void *ctrlr)
-{
- 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_HANDLED;
- }
-
- tasklet_schedule(&shm_ca_0_tasklet);
-
- if (check_modem_in_reset()) {
- dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
- __func__);
- return IRQ_HANDLED;
- }
-
- /* Clear the interrupt */
- writel((1 << GOP_COMMON_CA_MSG_PENDING_NOTIFICATION_BIT),
- shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
-
- dev_dbg(shrm->dev, "%s OUT\n", __func__);
- return IRQ_HANDLED;
-}
-
-irqreturn_t ca_msg_pending_notif_1_irq_handler(int irq, void *ctrlr)
-{
- 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_HANDLED;
- }
-
- tasklet_schedule(&shm_ca_1_tasklet);
-
- if (check_modem_in_reset()) {
- dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
- __func__);
- return IRQ_HANDLED;
- }
-
- /* Clear the interrupt */
- writel((1<<GOP_AUDIO_CA_MSG_PENDING_NOTIFICATION_BIT),
- shrm->intr_base+GOP_CLEAR_REGISTER_BASE);
-
- dev_dbg(shrm->dev, "%s OUT\n", __func__);
- return IRQ_HANDLED;
-
-}
-
-/**
- * shm_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 shm_write_msg(struct shrm_dev *shrm, u8 l2_header,
- void *addr, u32 length)
-{
- u8 channel = 0;
- int ret;
-
- dev_dbg(shrm->dev, "%s IN\n", __func__);
-
- if (boot_state != BOOT_DONE) {
- dev_err(shrm->dev,
- "error after boot done call this fn\n");
- ret = -ENODEV;
- 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)) {
- 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 = shm_write_msg_to_fifo(shrm, channel, l2_header, addr, length);
- if (ret < 0) {
- dev_err(shrm->dev, "write message to fifo failed\n");
- 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_work(shrm->shm_common_ch_wr_wq,
- &shrm->send_ac_msg_pend_notify_0);
- else
- queue_work(shrm->shm_audio_ch_wr_wq,
- &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)
-{
- dev_dbg(shrm->dev, "%s IN\n", __func__);
-
- if (get_ca_msg_0_read_notif_send() == 0) {
- update_ca_common_shared_rptr(shrm);
-
- if (check_modem_in_reset()) {
- dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
- __func__);
- return;
- }
-
- /* Trigger CaMsgReadNotification to CMU */
- writel((1 << GOP_COMMON_CA_READ_NOTIFICATION_BIT),
- shrm->intr_base + GOP_SET_REGISTER_BASE);
- 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)
-{
- dev_dbg(shrm->dev, "%s IN\n", __func__);
-
- if (get_ca_msg_1_read_notif_send() == 0) {
- update_ca_audio_shared_rptr(shrm);
-
- if (check_modem_in_reset()) {
- dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
- __func__);
- return;
- }
-
- /* Trigger CaMsgReadNotification to CMU */
- writel((1<<GOP_AUDIO_CA_READ_NOTIFICATION_BIT),
- shrm->intr_base+GOP_SET_REGISTER_BASE);
- 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;
-}