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

Commit 645dc2b1 authored by Maya Erez's avatar Maya Erez Committed by Maya Erez
Browse files

wil6210: protect synchronous wmi commands handling



In case there are multiple WMI commands with the same reply_id,
the following scenario can occur:
- Driver sends the first command to the device
- The reply didn’t get on time and there is timeout
- Reply_id, reply_buf and reply_size are set to 0
- Driver sends second wmi command with the same reply_id as the first
- Driver sets wil->reply_id
- Reply for the first wmi command arrives and handled by wmi_recv_cmd
- As its ID fits the reply_id but the reply_buf is not set yet it is
handled as a reply with event handler, and WARN_ON is printed

This patch guarantee atomic setting of all the reply variables and
prevents the above scenario.

Change-Id: I7eac78d7beb90436d24468547aeb789f7c8ec878
Signed-off-by: default avatarMaya Erez <qca_merez@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
Git-commit: fe5c271e2878fb080f1b32fec5b4e3f7a6070152
Git-repo: https://github.com/kvalo/ath.git


CRs-Fixed: 982882
Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
parent d274d80b
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -839,6 +839,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
			struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
			u16 id = le16_to_cpu(wmi->id);
			u32 tstamp = le32_to_cpu(wmi->timestamp);
			spin_lock_irqsave(&wil->wmi_ev_lock, flags);
			if (wil->reply_id && wil->reply_id == id) {
				if (wil->reply_buf) {
					memcpy(wil->reply_buf, wmi,
@@ -846,6 +847,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
					immed_reply = true;
				}
			}
			spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);

			wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
				    id, wmi->mid, tstamp);
@@ -889,13 +891,16 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,

	mutex_lock(&wil->wmi_mutex);

	spin_lock(&wil->wmi_ev_lock);
	wil->reply_id = reply_id;
	wil->reply_buf = reply;
	wil->reply_size = reply_size;
	spin_unlock(&wil->wmi_ev_lock);

	rc = __wmi_send(wil, cmdid, buf, len);
	if (rc)
		goto out;

	wil->reply_id = reply_id;
	wil->reply_buf = reply;
	wil->reply_size = reply_size;
	remain = wait_for_completion_timeout(&wil->wmi_call,
					     msecs_to_jiffies(to_msec));
	if (0 == remain) {
@@ -908,10 +913,14 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
			    cmdid, reply_id,
			    to_msec - jiffies_to_msecs(remain));
	}

out:
	spin_lock(&wil->wmi_ev_lock);
	wil->reply_id = 0;
	wil->reply_buf = NULL;
	wil->reply_size = 0;
 out:
	spin_unlock(&wil->wmi_ev_lock);

	mutex_unlock(&wil->wmi_mutex);

	return rc;