diff options
| author | Mahesh Sivasubramanian <msivasub@codeaurora.org> | 2015-12-07 11:19:22 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:16:10 -0700 |
| commit | b780053bf349562b91d4e3f47859eb004d66850d (patch) | |
| tree | ef95a8700ef6d439aac85b12a4235e74310a4ea9 /drivers/soc | |
| parent | e64f8b1ef4dace28107536874029de65b52c1e58 (diff) | |
soc: qcom: rpm-smd: Account for NOACK messages during system sleep
When a system is entering RPM assisted sleep, the NOACK messages are not
accounted in preventing such sleep modes as no driver is waiting on it. In
such scenarios, some active messages could still be in the Apps RX buffer
which reduces the number of outstanding sleep messages.
Fix by accounting for NOACK messages while flushing sleep set requests and
ensuring that they are read before sending any Sleep set requests.
Change-Id: I804cd923b88809b9d638756d934403914b5feff5
Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
Diffstat (limited to 'drivers/soc')
| -rw-r--r-- | drivers/soc/qcom/rpm-smd.c | 49 |
1 files changed, 39 insertions, 10 deletions
diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c index 4beb86a37191..193dfee8d1ea 100644 --- a/drivers/soc/qcom/rpm-smd.c +++ b/drivers/soc/qcom/rpm-smd.c @@ -93,6 +93,7 @@ static ATOMIC_NOTIFIER_HEAD(msm_rpm_sleep_notifier); static bool standalone; static int probe_status = -EPROBE_DEFER; static int msm_rpm_read_smd_data(char *buf); +static void msm_rpm_process_ack(uint32_t msg_id, int errno); int msm_rpm_register_notifier(struct notifier_block *nb) { @@ -354,6 +355,7 @@ struct msm_rpm_wait_data { bool ack_recd; int errno; struct completion ack; + bool delete_on_ack; }; DEFINE_SPINLOCK(msm_rpm_list_lock); @@ -524,6 +526,7 @@ static int msm_rpm_read_sleep_ack(void) { int ret; char buf[MAX_ERR_BUFFER_SIZE] = {0}; + uint32_t msg_id; if (glink_enabled) ret = msm_rpm_glink_rx_poll(glink_data->glink_handle); @@ -531,16 +534,33 @@ static int msm_rpm_read_sleep_ack(void) ret = msm_rpm_read_smd_data(buf); if (!ret) ret = smd_is_pkt_avail(msm_rpm_data.ch_info); + /* Mimic Glink behavior to ensure that the data is read + * and the msg is removed from the wait list. We should + * have gotten here only when there are no drivers waiting + * on ACKs. msm_rpm_get_entry_from_msg_id() return non-NULL + * only then. So BUG_ON to ensure that we didn't accidentally + * get here. + */ + msg_id = msm_rpm_get_msg_id_from_ack(buf); + msm_rpm_process_ack(msg_id, 0); } return ret; } +static void msm_rpm_flush_noack_messages(void) +{ + while (!list_empty(&msm_rpm_wait_list)) + msm_rpm_read_sleep_ack(); +} + static int msm_rpm_flush_requests(bool print) { struct rb_node *t; int ret; int count = 0; + msm_rpm_flush_noack_messages(); + for (t = rb_first(&tr_root); t; t = rb_next(t)) { struct slp_buf *s = rb_entry(t, struct slp_buf, node); @@ -578,7 +598,7 @@ static int msm_rpm_flush_requests(bool print) if (count >= MAX_WAIT_ON_ACK) { int ret = msm_rpm_read_sleep_ack(); - if (ret >= 0) + if (ret > 0) count--; else return ret; @@ -797,14 +817,18 @@ static void msm_rpm_notify(void *data, unsigned event) bool msm_rpm_waiting_for_ack(void) { - bool ret; + bool ret = false; unsigned long flags; + struct msm_rpm_wait_data *elem = NULL; spin_lock_irqsave(&msm_rpm_list_lock, flags); - ret = list_empty(&msm_rpm_wait_list); + elem = list_first_entry_or_null(&msm_rpm_wait_list, + struct msm_rpm_wait_data, list); + if (elem) + ret = !elem->delete_on_ack; spin_unlock_irqrestore(&msm_rpm_list_lock, flags); - return !ret; + return ret; } static struct msm_rpm_wait_data *msm_rpm_get_entry_from_msg_id(uint32_t msg_id) @@ -843,7 +867,7 @@ static uint32_t msm_rpm_get_next_msg_id(void) return id; } -static int msm_rpm_add_wait_list(uint32_t msg_id) +static int msm_rpm_add_wait_list(uint32_t msg_id, bool delete_on_ack) { unsigned long flags; struct msm_rpm_wait_data *data = @@ -856,8 +880,12 @@ static int msm_rpm_add_wait_list(uint32_t msg_id) data->ack_recd = false; data->msg_id = msg_id; data->errno = INIT_ERROR; + data->delete_on_ack = delete_on_ack; spin_lock_irqsave(&msm_rpm_list_lock, flags); - list_add(&data->list, &msm_rpm_wait_list); + if (delete_on_ack) + list_add_tail(&data->list, &msm_rpm_wait_list); + else + list_add(&data->list, &msm_rpm_wait_list); spin_unlock_irqrestore(&msm_rpm_list_lock, flags); return 0; @@ -875,18 +903,20 @@ static void msm_rpm_free_list_entry(struct msm_rpm_wait_data *elem) static void msm_rpm_process_ack(uint32_t msg_id, int errno) { - struct list_head *ptr; + struct list_head *ptr, *next; struct msm_rpm_wait_data *elem = NULL; unsigned long flags; spin_lock_irqsave(&msm_rpm_list_lock, flags); - list_for_each(ptr, &msm_rpm_wait_list) { + list_for_each_safe(ptr, next, &msm_rpm_wait_list) { elem = list_entry(ptr, struct msm_rpm_wait_data, list); if (elem && (elem->msg_id == msg_id)) { elem->errno = errno; elem->ack_recd = true; complete(&elem->ack); + if (elem->delete_on_ack) + list_del(&elem->list); break; } elem = NULL; @@ -1247,8 +1277,7 @@ static int msm_rpm_send_data(struct msm_rpm_request *cdata, return ret; } - if (!noack) - msm_rpm_add_wait_list(cdata->msg_hdr.msg_id); + msm_rpm_add_wait_list(cdata->msg_hdr.msg_id, noack); ret = msm_rpm_send_buffer(&cdata->buf[0], msg_size, noirq); |
