diff options
author | Jérôme Pouiller <jerome.pouiller@silabs.com> | 2019-09-19 14:25:42 +0000 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-10-04 10:46:10 +0200 |
commit | 4f8b7fabb15df3658564a98971fc67029be1815d (patch) | |
tree | 6817489a4dd84c269891c56763f99a5386ea40b1 /drivers/staging/wfx/hif_rx.c | |
parent | e16e7f0716a6ba9a690fc5229a6e35e00e03b805 (diff) |
staging: wfx: allow to send commands to chip
Chip has multiple input buffers and can handle multiple 802.11 frames
in parallel. However, other HIF command must be sent sequentially.
wsm_send_cmd() handles these requests.
This commit also add send_hif_cmd in debugfs. This file allows to send
arbitrary commands to chip. It can be used for debug and testing.
Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
Link: https://lore.kernel.org/r/20190919142527.31797-12-Jerome.Pouiller@silabs.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/wfx/hif_rx.c')
-rw-r--r-- | drivers/staging/wfx/hif_rx.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c index 5c207e6d4348..ba8ea4f3c91b 100644 --- a/drivers/staging/wfx/hif_rx.c +++ b/drivers/staging/wfx/hif_rx.c @@ -13,6 +13,43 @@ #include "wfx.h" #include "hif_api_cmd.h" +static int hif_generic_confirm(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + // All confirm messages start with status + int status = le32_to_cpu(*((__le32 *) buf)); + int cmd = hif->id; + int len = hif->len - 4; // drop header + + WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); + + if (!wdev->hif_cmd.buf_send) { + dev_warn(wdev->dev, "unexpected confirmation: 0x%.2x\n", cmd); + return -EINVAL; + } + + if (cmd != wdev->hif_cmd.buf_send->id) { + dev_warn(wdev->dev, "chip response mismatch request: 0x%.2x vs 0x%.2x\n", + cmd, wdev->hif_cmd.buf_send->id); + return -EINVAL; + } + + if (wdev->hif_cmd.buf_recv) { + if (wdev->hif_cmd.len_recv >= len) + memcpy(wdev->hif_cmd.buf_recv, buf, len); + else + status = -ENOMEM; + } + wdev->hif_cmd.ret = status; + + if (!wdev->hif_cmd.async) { + complete(&wdev->hif_cmd.done); + } else { + wdev->hif_cmd.buf_send = NULL; + mutex_unlock(&wdev->hif_cmd.lock); + } + return status; +} + static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) { struct hif_ind_startup *body = buf; @@ -44,6 +81,14 @@ void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb) struct hif_msg *hif = (struct hif_msg *) skb->data; int hif_id = hif->id; + // Note: mutex_is_lock cause an implicit memory barrier that protect + // buf_send + if (mutex_is_locked(&wdev->hif_cmd.lock) + && wdev->hif_cmd.buf_send + && wdev->hif_cmd.buf_send->id == hif_id) { + hif_generic_confirm(wdev, hif, hif->body); + goto free; + } for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) { if (hif_handlers[i].msg_id == hif_id) { if (hif_handlers[i].handler) |