aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/wfx/hif_rx.c
diff options
context:
space:
mode:
authorJérôme Pouiller <jerome.pouiller@silabs.com>2019-09-19 14:25:42 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-10-04 10:46:10 +0200
commit4f8b7fabb15df3658564a98971fc67029be1815d (patch)
tree6817489a4dd84c269891c56763f99a5386ea40b1 /drivers/staging/wfx/hif_rx.c
parentstaging: wfx: instantiate mac80211 data (diff)
downloadlinux-dev-4f8b7fabb15df3658564a98971fc67029be1815d.tar.xz
linux-dev-4f8b7fabb15df3658564a98971fc67029be1815d.zip
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.c45
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)