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

Commit 8df20053 authored by Arun Kumar Neelakantam's avatar Arun Kumar Neelakantam Committed by Gerrit - the friendly Code Review server
Browse files

msm: bam_dmux: Fix race condition during SSR



BAM DMUX drivers set the global flags to identify the SSR during
SUBSYS_BEFORE_SHUTDOWN notification, but the flags change is not reflected
in some code paths like msm_bam_dmux_write().

Add the SSR flag check and SRCU locking to complete all pending bam dmux
writes before returning the control in SSR call back function for
SUBSYS_BEFORE_SHUTDOWN notification.

CRs-Fixed: 584805
Change-Id: I26647b485977943f272c44f7450ed6c4a4aa62f3
Signed-off-by: default avatarArun Kumar Neelakantam <aneela@codeaurora.org>
parent 012fce15
Loading
Loading
Loading
Loading
+23 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/kfifo.h>
#include <linux/of.h>
#include <linux/ipc_logging.h>
#include <linux/srcu.h>
#include <mach/sps.h>
#include <mach/bam_dmux.h>
#include <mach/msm_smsm.h>
@@ -222,6 +223,8 @@ static struct delayed_work queue_rx_work;
static struct workqueue_struct *bam_mux_rx_workqueue;
static struct workqueue_struct *bam_mux_tx_workqueue;

static struct srcu_struct bam_dmux_srcu;

/* A2 power collaspe */
#define UL_TIMEOUT_DELAY 1000	/* in ms */
#define ENABLE_DISCONNECT_ACK	0x1
@@ -739,6 +742,7 @@ int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
	struct sk_buff *new_skb = NULL;
	dma_addr_t dma_address;
	struct tx_pkt_info *pkt;
	int rcu_id;

	if (id >= BAM_DMUX_NUM_CHANNELS)
		return -EINVAL;
@@ -747,11 +751,19 @@ int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
	if (!bam_mux_initialized)
		return -ENODEV;

	rcu_id = srcu_read_lock(&bam_dmux_srcu);
	if (in_global_reset) {
		BAM_DMUX_LOG("%s: In SSR... ch_id[%d]\n", __func__, id);
		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
		return -EFAULT;
	}

	DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
	spin_lock_irqsave(&bam_ch[id].lock, flags);
	if (!bam_ch_is_open(id)) {
		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
		pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
		return -ENODEV;
	}

@@ -759,6 +771,7 @@ int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
	    (bam_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
		pr_err("%s: watermark exceeded: %d\n", __func__, id);
		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
		return -EAGAIN;
	}
	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
@@ -767,8 +780,10 @@ int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
	if (!bam_is_connected) {
		read_unlock(&ul_wakeup_lock);
		ul_wakeup();
		if (unlikely(in_global_reset == 1))
		if (unlikely(in_global_reset == 1)) {
			srcu_read_unlock(&bam_dmux_srcu, rcu_id);
			return -EFAULT;
		}
		read_lock(&ul_wakeup_lock);
		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
	}
@@ -846,6 +861,7 @@ int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
	}
	ul_packet_written = 1;
	read_unlock(&ul_wakeup_lock);
	srcu_read_unlock(&bam_dmux_srcu, rcu_id);
	return rc;

write_fail3:
@@ -856,6 +872,7 @@ write_fail2:
		dev_kfree_skb_any(new_skb);
write_fail:
	read_unlock(&ul_wakeup_lock);
	srcu_read_unlock(&bam_dmux_srcu, rcu_id);
	return -ENOMEM;
}

@@ -1956,9 +1973,12 @@ static int restart_notifier_cb(struct notifier_block *this,
	 * because a watchdog crash from a bus stall would likely occur.
	 */
	if (code == SUBSYS_BEFORE_SHUTDOWN) {
		BAM_DMUX_LOG("%s: begin\n", __func__);
		in_global_reset = 1;
		in_ssr = 1;
		BAM_DMUX_LOG("%s: begin\n", __func__);
		/* wait till all bam_dmux writes completes */
		synchronize_srcu(&bam_dmux_srcu);
		BAM_DMUX_LOG("%s: ssr signaling complete\n", __func__);
		flush_workqueue(bam_mux_rx_workqueue);
	}
	if (code != SUBSYS_AFTER_SHUTDOWN)
@@ -2478,6 +2498,7 @@ static int bam_dmux_probe(struct platform_device *pdev)
	INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
	INIT_DELAYED_WORK(&queue_rx_work, queue_rx_work_func);
	wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
	init_srcu_struct(&bam_dmux_srcu);

	rc = bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
			SMSM_A2_POWER_CONTROL,