summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorKarthikeyan Ramasubramanian <kramasub@codeaurora.org>2015-12-17 17:26:20 -0700
committerJeevan Shriram <jshriram@codeaurora.org>2016-04-07 16:00:45 -0700
commit4aec450882c1563e57459fbc62a560dc205cb7c5 (patch)
tree6d324d148ec318f8fd3ec61604ed265aed3fddb4 /drivers
parent0b9105a22471bb9a4f4b03560ed39e477573a745 (diff)
soc: qcom: glink_smd_xprt: Fix handling subsystem restart
If the local client of the G-Link channel comes up and waits for the remote client, then it's states are set accordingly. But if the remote subsystem is restarted as soon as it boots up, then it's states are not adjusted accordingly. This causes the G-Link channel states to lose synchronization once the remote client comes up successfully after the reset. Adjust the states of the local client if it is waiting for the remote client and the remote subsystem is reset as soon as it boots up. CRs-Fixed: 952834 Change-Id: I5fe327ea61eb2d16591861b1246fdca2ecce2b1c Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/soc/qcom/glink_smd_xprt.c36
1 files changed, 27 insertions, 9 deletions
diff --git a/drivers/soc/qcom/glink_smd_xprt.c b/drivers/soc/qcom/glink_smd_xprt.c
index c4ac66f81af4..c3fb34773db0 100644
--- a/drivers/soc/qcom/glink_smd_xprt.c
+++ b/drivers/soc/qcom/glink_smd_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -113,6 +113,7 @@ struct edge_info {
* @name: The name of this channel.
* @lcid: The local channel id the core uses for this channel.
* @rcid: The true remote channel id for this channel.
+ * @ch_probe_lock: Lock to protect channel probe status.
* @wait_for_probe: This channel is waiting for a probe from SMD.
* @had_probed: This channel probed in the past and may skip probe.
* @edge: Handle to the edge_info this channel is associated with.
@@ -138,6 +139,7 @@ struct channel {
char name[GLINK_NAME_SIZE];
uint32_t lcid;
uint32_t rcid;
+ struct mutex ch_probe_lock;
bool wait_for_probe;
bool had_probed;
struct edge_info *edge;
@@ -321,6 +323,7 @@ static void process_ctl_event(struct work_struct *work)
}
strlcpy(ch->name, name, GLINK_NAME_SIZE);
ch->edge = einfo;
+ mutex_init(&ch->ch_probe_lock);
INIT_LIST_HEAD(&ch->intents);
INIT_LIST_HEAD(&ch->used_intents);
spin_lock_init(&ch->intents_lock);
@@ -879,10 +882,11 @@ static void smd_data_ch_close(struct channel *ch)
__func__, ch->lcid);
ch->is_closing = true;
- ch->wait_for_probe = false;
ch->tx_resume_needed = false;
flush_workqueue(ch->wq);
+ mutex_lock(&ch->ch_probe_lock);
+ ch->wait_for_probe = false;
if (ch->smd_ch) {
smd_close(ch->smd_ch);
ch->smd_ch = NULL;
@@ -893,6 +897,7 @@ static void smd_data_ch_close(struct channel *ch)
ch->lcid);
mutex_unlock(&ch->edge->rx_cmd_lock);
}
+ mutex_unlock(&ch->ch_probe_lock);
ch->local_legacy = false;
@@ -965,13 +970,17 @@ static int channel_probe(struct platform_device *pdev)
if (!found)
return -EPROBE_DEFER;
- if (!ch->wait_for_probe)
+ mutex_lock(&ch->ch_probe_lock);
+ if (!ch->wait_for_probe) {
+ mutex_unlock(&ch->ch_probe_lock);
return -EPROBE_DEFER;
+ }
ch->wait_for_probe = false;
ch->had_probed = true;
data_ch_probe_body(ch);
+ mutex_unlock(&ch->ch_probe_lock);
return 0;
}
@@ -1012,6 +1021,7 @@ static int add_platform_driver(struct channel *ch)
static bool first = true;
mutex_lock(&pdrv_list_mutex);
+ mutex_lock(&ch->ch_probe_lock);
ch->wait_for_probe = true;
list_for_each_entry(pdrv, &pdrv_list, node) {
if (!strcmp(ch->name, pdrv->pdrv.driver.name)) {
@@ -1021,10 +1031,13 @@ static int add_platform_driver(struct channel *ch)
}
if (!found) {
+ mutex_unlock(&ch->ch_probe_lock);
pdrv = kzalloc(sizeof(*pdrv), GFP_KERNEL);
if (!pdrv) {
ret = -ENOMEM;
+ mutex_lock(&ch->ch_probe_lock);
ch->wait_for_probe = false;
+ mutex_unlock(&ch->ch_probe_lock);
goto out;
}
pdrv->pdrv.driver.name = ch->name;
@@ -1035,12 +1048,14 @@ static int add_platform_driver(struct channel *ch)
if (ret) {
list_del(&pdrv->node);
kfree(pdrv);
+ mutex_lock(&ch->ch_probe_lock);
ch->wait_for_probe = false;
+ mutex_unlock(&ch->ch_probe_lock);
}
} else {
if (ch->had_probed)
data_ch_probe_body(ch);
-
+ mutex_unlock(&ch->ch_probe_lock);
/*
* channel_probe might have seen the device we want, but
* returned EPROBE_DEFER so we need to kick the deferred list
@@ -1170,6 +1185,7 @@ static int tx_cmd_ch_open(struct glink_transport_if *if_ptr, uint32_t lcid,
}
strlcpy(ch->name, name, GLINK_NAME_SIZE);
ch->edge = einfo;
+ mutex_init(&ch->ch_probe_lock);
INIT_LIST_HEAD(&ch->intents);
INIT_LIST_HEAD(&ch->used_intents);
spin_lock_init(&ch->intents_lock);
@@ -1445,14 +1461,16 @@ static int ssr(struct glink_transport_if *if_ptr)
spin_lock_irqsave(&einfo->channels_lock, flags);
list_for_each_entry(ch, &einfo->channels, node) {
- if (!ch->smd_ch)
- continue;
spin_unlock_irqrestore(&einfo->channels_lock, flags);
ch->is_closing = true;
- ch->wait_for_probe = false;
flush_workqueue(ch->wq);
- smd_close(ch->smd_ch);
- ch->smd_ch = NULL;
+ mutex_lock(&ch->ch_probe_lock);
+ ch->wait_for_probe = false;
+ if (ch->smd_ch) {
+ smd_close(ch->smd_ch);
+ ch->smd_ch = NULL;
+ }
+ mutex_unlock(&ch->ch_probe_lock);
ch->local_legacy = false;
ch->remote_legacy = false;
ch->rcid = 0;