diff options
author | Karthikeyan Ramasubramanian <kramasub@codeaurora.org> | 2015-12-17 17:26:20 -0700 |
---|---|---|
committer | Jeevan Shriram <jshriram@codeaurora.org> | 2016-04-07 16:00:45 -0700 |
commit | 4aec450882c1563e57459fbc62a560dc205cb7c5 (patch) | |
tree | 6d324d148ec318f8fd3ec61604ed265aed3fddb4 /drivers | |
parent | 0b9105a22471bb9a4f4b03560ed39e477573a745 (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.c | 36 |
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; |