[PATCH v2 09/20] staging: wfx: add support for start-up indication

From: Jerome Pouiller
Date: Thu Sep 19 2019 - 09:53:57 EST


From: JÃrÃme Pouiller <jerome.pouiller@xxxxxxxxxx>

Once firmware is loaded, it send a first indication to host. This
indication signalize that host can start to communicate with firmware.
In add, it contains information about chip and firmware (MAC addresses,
firmware version, etc...).

Signed-off-by: JÃrÃme Pouiller <jerome.pouiller@xxxxxxxxxx>
---
drivers/staging/wfx/Makefile | 1 +
drivers/staging/wfx/bh.c | 4 ++-
drivers/staging/wfx/hif_rx.c | 57 ++++++++++++++++++++++++++++++++++++
drivers/staging/wfx/hif_rx.h | 18 ++++++++++++
drivers/staging/wfx/main.c | 45 ++++++++++++++++++++++++++++
drivers/staging/wfx/wfx.h | 5 ++++
6 files changed, 129 insertions(+), 1 deletion(-)
create mode 100644 drivers/staging/wfx/hif_rx.c
create mode 100644 drivers/staging/wfx/hif_rx.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 1abd3115f11d..35670b86c64f 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -7,6 +7,7 @@ wfx-y := \
bh.o \
hwio.o \
fwio.o \
+ hif_rx.o \
main.o \
debug.o
wfx-$(CONFIG_SPI) += bus_spi.o
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index 76afecdf579d..c40da3f1f25d 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -12,6 +12,7 @@
#include "wfx.h"
#include "hwio.h"
#include "traces.h"
+#include "hif_rx.h"
#include "hif_api_cmd.h"

static void device_wakeup(struct wfx_dev *wdev)
@@ -107,7 +108,8 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
}

skb_put(skb, hif->len);
- dev_kfree_skb(skb); /* FIXME: handle received data */
+ // wfx_handle_rx takes care on SKB livetime
+ wfx_handle_rx(wdev, skb);

return piggyback;

diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
new file mode 100644
index 000000000000..5c207e6d4348
--- /dev/null
+++ b/drivers/staging/wfx/hif_rx.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
+ * (WSM) API.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+
+#include "hif_rx.h"
+#include "wfx.h"
+#include "hif_api_cmd.h"
+
+static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
+{
+ struct hif_ind_startup *body = buf;
+
+ if (body->status || body->firmware_type > 4) {
+ dev_err(wdev->dev, "received invalid startup indication");
+ return -EINVAL;
+ }
+ memcpy(&wdev->hw_caps, body, sizeof(struct hif_ind_startup));
+ le32_to_cpus(&wdev->hw_caps.status);
+ le16_to_cpus(&wdev->hw_caps.hardware_id);
+ le16_to_cpus(&wdev->hw_caps.num_inp_ch_bufs);
+ le16_to_cpus(&wdev->hw_caps.size_inp_ch_buf);
+
+ complete(&wdev->firmware_ready);
+ return 0;
+}
+
+static const struct {
+ int msg_id;
+ int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
+} hif_handlers[] = {
+ { HIF_IND_ID_STARTUP, hif_startup_indication },
+};
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
+{
+ int i;
+ struct hif_msg *hif = (struct hif_msg *) skb->data;
+ int hif_id = hif->id;
+
+ for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) {
+ if (hif_handlers[i].msg_id == hif_id) {
+ if (hif_handlers[i].handler)
+ hif_handlers[i].handler(wdev, hif, hif->body);
+ goto free;
+ }
+ }
+ dev_err(wdev->dev, "unsupported HIF ID %02x\n", hif_id);
+free:
+ dev_kfree_skb(skb);
+}
diff --git a/drivers/staging/wfx/hif_rx.h b/drivers/staging/wfx/hif_rx.h
new file mode 100644
index 000000000000..f07c10c8c6bd
--- /dev/null
+++ b/drivers/staging/wfx/hif_rx.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
+ * (WSM) API.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ * Copyright (C) 2010, ST-Ericsson SA
+ */
+#ifndef WFX_HIF_RX_H
+#define WFX_HIF_RX_H
+
+struct wfx_dev;
+struct sk_buff;
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb);
+
+#endif
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index f0bea053a0d9..5e7e7225f068 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -12,6 +12,7 @@
*/
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_net.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/mmc/sdio_func.h>
@@ -87,6 +88,9 @@ struct wfx_dev *wfx_init_common(struct device *dev,
wdev->hwbus_ops = hwbus_ops;
wdev->hwbus_priv = hwbus_priv;
memcpy(&wdev->pdata, pdata, sizeof(*pdata));
+
+ init_completion(&wdev->firmware_ready);
+
return wdev;
}

@@ -96,7 +100,9 @@ void wfx_free_common(struct wfx_dev *wdev)

int wfx_probe(struct wfx_dev *wdev)
{
+ int i;
int err;
+ const void *macaddr;

wfx_bh_register(wdev);

@@ -104,6 +110,45 @@ int wfx_probe(struct wfx_dev *wdev)
if (err)
goto err1;

+ err = wait_for_completion_interruptible_timeout(&wdev->firmware_ready, 10 * HZ);
+ if (err <= 0) {
+ if (err == 0) {
+ dev_err(wdev->dev, "timeout while waiting for startup indication. IRQ configuration error?\n");
+ err = -ETIMEDOUT;
+ } else if (err == -ERESTARTSYS) {
+ dev_info(wdev->dev, "probe interrupted by user\n");
+ }
+ goto err1;
+ }
+
+ // FIXME: fill wiphy::hw_version
+ dev_info(wdev->dev, "started firmware %d.%d.%d \"%s\" (API: %d.%d, keyset: %02X, caps: 0x%.8X)\n",
+ wdev->hw_caps.firmware_major, wdev->hw_caps.firmware_minor,
+ wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label,
+ wdev->hw_caps.api_version_major, wdev->hw_caps.api_version_minor,
+ wdev->keyset, *((u32 *) &wdev->hw_caps.capabilities));
+
+ if (wfx_api_older_than(wdev, 1, 0)) {
+ dev_err(wdev->dev, "unsupported firmware API version (expect 1 while firmware returns %d)\n",
+ wdev->hw_caps.api_version_major);
+ err = -ENOTSUPP;
+ goto err1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
+ eth_zero_addr(wdev->addresses[i].addr);
+ macaddr = of_get_mac_address(wdev->dev->of_node);
+ if (macaddr) {
+ ether_addr_copy(wdev->addresses[i].addr, macaddr);
+ wdev->addresses[i].addr[ETH_ALEN - 1] += i;
+ }
+ ether_addr_copy(wdev->addresses[i].addr, wdev->hw_caps.mac_addr[i]);
+ if (!is_valid_ether_addr(wdev->addresses[i].addr)) {
+ dev_warn(wdev->dev, "using random MAC address\n");
+ eth_random_addr(wdev->addresses[i].addr);
+ }
+ dev_info(wdev->dev, "MAC address %d: %pM\n", i, wdev->addresses[i].addr);
+ }

return 0;

diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
index 4f28938fa3a6..f5f9a337d828 100644
--- a/drivers/staging/wfx/wfx.h
+++ b/drivers/staging/wfx/wfx.h
@@ -10,6 +10,9 @@
#ifndef WFX_H
#define WFX_H

+#include <linux/completion.h>
+#include <net/mac80211.h>
+
#include "bh.h"
#include "main.h"
#include "hif_api_general.h"
@@ -19,10 +22,12 @@ struct hwbus_ops;
struct wfx_dev {
struct wfx_platform_data pdata;
struct device *dev;
+ struct mac_address addresses[2];
const struct hwbus_ops *hwbus_ops;
void *hwbus_priv;

u8 keyset;
+ struct completion firmware_ready;
struct hif_ind_startup hw_caps;
struct wfx_hif hif;
};
--
2.20.1