2020-12-23 15:41:05

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 00/24] wfx: get out from the staging area

From: Jérôme Pouiller <[email protected]>

I think the wfx driver is now mature enough to be accepted in the
drivers/net/wireless directory.

The firmware associated with this driver is available here[1]. It is not yet
available in linux-firmware, but I am working on the PR.

[1]: https://github.com/SiliconLabs/wfx-firmware

As requested by Kalle[2], I send one file per patch. At the end, all the
patches (or at least the patches 3 to 24) will be squashed (therefore, I
didn't bother to write real commit messages).

[2]: https://lore.kernel.org/lkml/[email protected]/

Here is a diagram of the global architecture that may help to understand
the code:

,------------------------------------.
| mac80211 |
`------------------------------------'
,------------+-----------+-----------.
| sta | | |
| scan | | |
| main | | |
+------------+ data_tx | |
| key | | data_rx |
| hif_tx_mib | queue | |
| hif_tx | | |
| hif_rx | | |
| hif_api_* | | |
+------------+-----------+-----------+--------.
| bh | fwio |
+------------------------------------+--------+
| hwio |
+---------------------------------------------+
| bus_sdio |
| bus_spi |
`---------------------------------------------'
,---------------------------------------------.
| spi / sdio |
`---------------------------------------------'

Roughly, I have sent the files from the bottom to the top.


Below the differences with the files from drivers/staging/wfx/:

v4:
- Rebase on last staging tree
- Add 'additionalProperties: false' to the DT specification (I have made
that change blindly because I am able to reproduce the Rob's error)
(Rob)
- Replace C++ comments with Ansi C comments (Kalle)
- Check that existing Ansi C comments comply with net/ "compact" style
- Drop one obsolete comment
- Remove comments after '#endif' in header files
- Remove macro redefinitions in hif_api_general.h (Kalle)
- Replace compiletime_assert() with BUILD_BUG_ON_MSG() (Kalle)
- Rename ieee80211_is_action_back() (Kalle)
- Add a comment explaining how the PDS isent to the device (Kalle)
- Add a comment about case where CONFIG_MMC==m in the Makefile (Kalle)
- Fix irrelevant comment about CONFIG_VMAP_STACK (Kalle)
- Talk about the unreliable SDIO Vendor ID in the Kconfig help (Kalle)
- Mention the firmware status in the cover letter (Kalle)
- Fix misaligned function arguments in key.c

v3:
- dt-bindings: Rename config-file property (Rob)
- dt-bindings: No additional properties are allowed (spi-max-frequency is
already listed) (Rob)
- dt-bindings: Remove references for mac-address properties (Rob)
- Rebase on staging/staging-next

v2:
- dt-bindings: Improve device description and add link to the datasheet
(Rob)
- dt-bindings: Add blank lines between each DT property (Rob)
- dt-bindings: Explicitly mention mac-address and local-mac-address and
add references to ethernet-controller.yaml (Rob)
- dt-bindings: "config-file" is not for development/debug (Rob)
- dt-bindings: Remove description of "spi-max-frequency" (Rob)
- dt-bindings: Use "folded scalar" syntax instead of escaping the colons
- bus_sdio.c: A compatible node in the DT is now mandatory to probe the
device. Also change documentation of dt-bindings accordingly (Pali,
Ulf)
- bus_sdio.c: Move SDIO IDs to sdio_ids.h (Pali)
- bh.c: Import patch "staging: wfx: fix test on return value of
gpiod_get_value()" (Nathan)
- data_tx.c: Import patch "staging: wfx: fix use of uninitialized
pointer"
- sta.c: Import patch "staging: wfx: make a const array static, makes
object smaller" (Colin)

v1:
- Drop the function name in the warning message (Kalle)
- Replace goto by return in wfx_send_pdata_pds() (Kalle, Dan)
- Improve error label in wfx_send_pdata_pds() (Kalle)


Jérôme Pouiller (24):
mmc: sdio: add SDIO IDs for Silabs WF200 chip
dt-bindings: introduce silabs,wfx.yaml
wfx: add Makefile/Kconfig
wfx: add wfx.h
wfx: add main.c/main.h
wfx: add bus.h
wfx: add bus_spi.c
wfx: add bus_sdio.c
wfx: add hwio.c/hwio.h
wfx: add fwio.c/fwio.h
wfx: add bh.c/bh.h
wfx: add hif_api_*.h
wfx: add hif_tx*.c/hif_tx*.h
wfx: add key.c/key.h
wfx: add hif_rx.c/hif_rx.h
wfx: add data_rx.c/data_rx.h
wfx: add queue.c/queue.h
wfx: add data_tx.c/data_tx.h
wfx: add sta.c/sta.h
wfx: add scan.c/scan.h
wfx: add debug.c/debug.h
wfx: add traces.h
wfx: remove from the staging area
wfx: get out from the staging area

.../bindings/net/wireless/silabs,wfx.yaml | 68 +++++++++-------
MAINTAINERS | 3 +-
drivers/net/wireless/Kconfig | 1 +
drivers/net/wireless/Makefile | 1 +
drivers/net/wireless/silabs/Kconfig | 18 +++++
drivers/net/wireless/silabs/Makefile | 3 +
.../wireless/silabs}/wfx/Kconfig | 4 +
.../wireless/silabs}/wfx/Makefile | 1 +
.../{staging => net/wireless/silabs}/wfx/bh.c | 31 ++++----
.../{staging => net/wireless/silabs}/wfx/bh.h | 2 +-
.../wireless/silabs}/wfx/bus.h | 0
.../wireless/silabs}/wfx/bus_sdio.c | 23 ++----
.../wireless/silabs}/wfx/bus_spi.c | 18 ++---
.../wireless/silabs}/wfx/data_rx.c | 5 +-
.../wireless/silabs}/wfx/data_rx.h | 2 +-
.../wireless/silabs}/wfx/data_tx.c | 65 +++++++++-------
.../wireless/silabs}/wfx/data_tx.h | 4 +-
.../wireless/silabs}/wfx/debug.c | 12 +--
.../wireless/silabs}/wfx/debug.h | 2 +-
.../wireless/silabs}/wfx/fwio.c | 26 +++----
.../wireless/silabs}/wfx/fwio.h | 2 +-
.../wireless/silabs}/wfx/hif_api_cmd.h | 12 +--
.../wireless/silabs}/wfx/hif_api_general.h | 23 +++---
.../wireless/silabs}/wfx/hif_api_mib.h | 2 +-
.../wireless/silabs}/wfx/hif_rx.c | 17 ++--
.../wireless/silabs}/wfx/hif_rx.h | 0
.../wireless/silabs}/wfx/hif_tx.c | 32 ++++----
.../wireless/silabs}/wfx/hif_tx.h | 0
.../wireless/silabs}/wfx/hif_tx_mib.c | 4 +-
.../wireless/silabs}/wfx/hif_tx_mib.h | 0
.../wireless/silabs}/wfx/hwio.c | 18 +----
.../wireless/silabs}/wfx/hwio.h | 22 +++---
.../wireless/silabs}/wfx/key.c | 30 +++----
.../wireless/silabs}/wfx/key.h | 2 +-
.../wireless/silabs}/wfx/main.c | 37 ++++++---
.../wireless/silabs}/wfx/main.h | 3 +-
.../wireless/silabs}/wfx/queue.c | 27 ++++---
.../wireless/silabs}/wfx/queue.h | 4 +-
.../wireless/silabs}/wfx/scan.c | 3 +-
.../wireless/silabs}/wfx/scan.h | 2 +-
.../wireless/silabs}/wfx/sta.c | 78 ++++++++++---------
.../wireless/silabs}/wfx/sta.h | 8 +-
.../wireless/silabs}/wfx/traces.h | 2 +-
.../wireless/silabs}/wfx/wfx.h | 4 +-
drivers/staging/Kconfig | 2 -
drivers/staging/Makefile | 1 -
drivers/staging/wfx/TODO | 6 --
include/linux/mmc/sdio_ids.h | 7 ++
48 files changed, 339 insertions(+), 298 deletions(-)
rename {drivers/staging/wfx/Documentation => Documentation}/devicetree/bindings/net/wireless/silabs,wfx.yaml (71%)
create mode 100644 drivers/net/wireless/silabs/Kconfig
create mode 100644 drivers/net/wireless/silabs/Makefile
rename drivers/{staging => net/wireless/silabs}/wfx/Kconfig (65%)
rename drivers/{staging => net/wireless/silabs}/wfx/Makefile (85%)
rename drivers/{staging => net/wireless/silabs}/wfx/bh.c (93%)
rename drivers/{staging => net/wireless/silabs}/wfx/bh.h (97%)
rename drivers/{staging => net/wireless/silabs}/wfx/bus.h (100%)
rename drivers/{staging => net/wireless/silabs}/wfx/bus_sdio.c (89%)
rename drivers/{staging => net/wireless/silabs}/wfx/bus_spi.c (94%)
rename drivers/{staging => net/wireless/silabs}/wfx/data_rx.c (95%)
rename drivers/{staging => net/wireless/silabs}/wfx/data_rx.h (93%)
rename drivers/{staging => net/wireless/silabs}/wfx/data_tx.c (91%)
rename drivers/{staging => net/wireless/silabs}/wfx/data_tx.h (94%)
rename drivers/{staging => net/wireless/silabs}/wfx/debug.c (96%)
rename drivers/{staging => net/wireless/silabs}/wfx/debug.h (94%)
rename drivers/{staging => net/wireless/silabs}/wfx/fwio.c (95%)
rename drivers/{staging => net/wireless/silabs}/wfx/fwio.h (91%)
rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_cmd.h (97%)
rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_general.h (93%)
rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_mib.h (99%)
rename drivers/{staging => net/wireless/silabs}/wfx/hif_rx.c (96%)
rename drivers/{staging => net/wireless/silabs}/wfx/hif_rx.h (100%)
rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx.c (95%)
rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx.h (100%)
rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx_mib.c (98%)
rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx_mib.h (100%)
rename drivers/{staging => net/wireless/silabs}/wfx/hwio.c (93%)
rename drivers/{staging => net/wireless/silabs}/wfx/hwio.h (77%)
rename drivers/{staging => net/wireless/silabs}/wfx/key.c (91%)
rename drivers/{staging => net/wireless/silabs}/wfx/key.h (94%)
rename drivers/{staging => net/wireless/silabs}/wfx/main.c (92%)
rename drivers/{staging => net/wireless/silabs}/wfx/main.h (94%)
rename drivers/{staging => net/wireless/silabs}/wfx/queue.c (92%)
rename drivers/{staging => net/wireless/silabs}/wfx/queue.h (94%)
rename drivers/{staging => net/wireless/silabs}/wfx/scan.c (98%)
rename drivers/{staging => net/wireless/silabs}/wfx/scan.h (95%)
rename drivers/{staging => net/wireless/silabs}/wfx/sta.c (91%)
rename drivers/{staging => net/wireless/silabs}/wfx/sta.h (97%)
rename drivers/{staging => net/wireless/silabs}/wfx/traces.h (99%)
rename drivers/{staging => net/wireless/silabs}/wfx/wfx.h (97%)
delete mode 100644 drivers/staging/wfx/TODO

--
2.29.2


2020-12-23 15:41:18

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 04/24] wfx: add wfx.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/wfx.h | 166 ++++++++++++++++++++++++++
1 file changed, 166 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/wfx.h

diff --git a/drivers/net/wireless/silabs/wfx/wfx.h b/drivers/net/wireless/silabs/wfx/wfx.h
new file mode 100644
index 000000000000..ba18bbfacd2b
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/wfx.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Common private data for Silicon Labs WFx chips.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ * Copyright (c) 2006, Michael Wu <[email protected]>
+ * Copyright 2004-2006 Jean-Baptiste Note <[email protected]>, et al.
+ */
+#ifndef WFX_H
+#define WFX_H
+
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/nospec.h>
+#include <net/mac80211.h>
+
+#include "bh.h"
+#include "data_tx.h"
+#include "main.h"
+#include "queue.h"
+#include "hif_tx.h"
+
+#define USEC_PER_TXOP 32 /* see struct ieee80211_tx_queue_params */
+#define USEC_PER_TU 1024
+
+struct hwbus_ops;
+
+struct wfx_dev {
+ struct wfx_platform_data pdata;
+ struct device *dev;
+ struct ieee80211_hw *hw;
+ struct ieee80211_vif *vif[2];
+ 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;
+ struct delayed_work cooling_timeout_work;
+ bool poll_irq;
+ bool chip_frozen;
+ struct mutex conf_mutex;
+
+ struct wfx_hif_cmd hif_cmd;
+ struct sk_buff_head tx_pending;
+ wait_queue_head_t tx_dequeue;
+ atomic_t tx_lock;
+
+ atomic_t packet_id;
+ u32 key_map;
+
+ struct hif_rx_stats rx_stats;
+ struct mutex rx_stats_lock;
+ struct hif_tx_power_loop_info tx_power_loop_info;
+ struct mutex tx_power_loop_info_lock;
+ int force_ps_timeout;
+};
+
+struct wfx_vif {
+ struct wfx_dev *wdev;
+ struct ieee80211_vif *vif;
+ struct ieee80211_channel *channel;
+ int id;
+
+ u32 link_id_map;
+
+ bool after_dtim_tx_allowed;
+ bool join_in_progress;
+
+ struct delayed_work beacon_loss_work;
+
+ struct wfx_queue tx_queue[4];
+ struct tx_policy_cache tx_policy_cache;
+ struct work_struct tx_policy_upload_work;
+
+ struct work_struct update_tim_work;
+
+ unsigned long uapsd_mask;
+
+ /* avoid some operations in parallel with scan */
+ struct mutex scan_lock;
+ struct work_struct scan_work;
+ struct completion scan_complete;
+ bool scan_abort;
+ struct ieee80211_scan_request *scan_req;
+
+ struct completion set_pm_mode_complete;
+};
+
+static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id)
+{
+ if (vif_id >= ARRAY_SIZE(wdev->vif)) {
+ dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id);
+ return NULL;
+ }
+ vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif));
+ if (!wdev->vif[vif_id]) {
+ dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n",
+ vif_id);
+ return NULL;
+ }
+ return (struct wfx_vif *) wdev->vif[vif_id]->drv_priv;
+}
+
+static inline struct wfx_vif *wvif_iterate(struct wfx_dev *wdev,
+ struct wfx_vif *cur)
+{
+ int i;
+ int mark = 0;
+ struct wfx_vif *tmp;
+
+ if (!cur)
+ mark = 1;
+ for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) {
+ tmp = wdev_to_wvif(wdev, i);
+ if (mark && tmp)
+ return tmp;
+ if (tmp == cur)
+ mark = 1;
+ }
+ return NULL;
+}
+
+static inline int wvif_count(struct wfx_dev *wdev)
+{
+ int i;
+ int ret = 0;
+ struct wfx_vif *wvif;
+
+ for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) {
+ wvif = wdev_to_wvif(wdev, i);
+ if (wvif)
+ ret++;
+ }
+ return ret;
+}
+
+static inline void memreverse(u8 *src, u8 length)
+{
+ u8 *lo = src;
+ u8 *hi = src + length - 1;
+ u8 swap;
+
+ while (lo < hi) {
+ swap = *lo;
+ *lo++ = *hi;
+ *hi-- = swap;
+ }
+}
+
+static inline int memzcmp(void *src, unsigned int size)
+{
+ u8 *buf = src;
+
+ if (!size)
+ return 0;
+ if (*buf)
+ return 1;
+ return memcmp(buf, buf + 1, size - 1);
+}
+
+#endif
--
2.29.2

2020-12-23 15:41:32

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 08/24] wfx: add bus_sdio.c

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/bus_sdio.c | 258 +++++++++++++++++++++
1 file changed, 258 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/bus_sdio.c

diff --git a/drivers/net/wireless/silabs/wfx/bus_sdio.c b/drivers/net/wireless/silabs/wfx/bus_sdio.c
new file mode 100644
index 000000000000..2f6488e36e86
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/bus_sdio.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SDIO interface.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/module.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/irq.h>
+
+#include "bus.h"
+#include "wfx.h"
+#include "hwio.h"
+#include "main.h"
+#include "bh.h"
+
+static const struct wfx_platform_data wfx_sdio_pdata = {
+ .file_fw = "wfm_wf200",
+ .file_pds = "wf200.pds",
+};
+
+struct wfx_sdio_priv {
+ struct sdio_func *func;
+ struct wfx_dev *core;
+ u8 buf_id_tx;
+ u8 buf_id_rx;
+ int of_irq;
+};
+
+static int wfx_sdio_copy_from_io(void *priv, unsigned int reg_id,
+ void *dst, size_t count)
+{
+ struct wfx_sdio_priv *bus = priv;
+ unsigned int sdio_addr = reg_id << 2;
+ int ret;
+
+ WARN(reg_id > 7, "chip only has 7 registers");
+ WARN(((uintptr_t)dst) & 3, "unaligned buffer size");
+ WARN(count & 3, "unaligned buffer address");
+
+ /* Use queue mode buffers */
+ if (reg_id == WFX_REG_IN_OUT_QUEUE)
+ sdio_addr |= (bus->buf_id_rx + 1) << 7;
+ ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count);
+ if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
+ bus->buf_id_rx = (bus->buf_id_rx + 1) % 4;
+
+ return ret;
+}
+
+static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id,
+ const void *src, size_t count)
+{
+ struct wfx_sdio_priv *bus = priv;
+ unsigned int sdio_addr = reg_id << 2;
+ int ret;
+
+ WARN(reg_id > 7, "chip only has 7 registers");
+ WARN(((uintptr_t)src) & 3, "unaligned buffer size");
+ WARN(count & 3, "unaligned buffer address");
+
+ /* Use queue mode buffers */
+ if (reg_id == WFX_REG_IN_OUT_QUEUE)
+ sdio_addr |= bus->buf_id_tx << 7;
+ /* FIXME: discards 'const' qualifier for src */
+ ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *)src, count);
+ if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
+ bus->buf_id_tx = (bus->buf_id_tx + 1) % 32;
+
+ return ret;
+}
+
+static void wfx_sdio_lock(void *priv)
+{
+ struct wfx_sdio_priv *bus = priv;
+
+ sdio_claim_host(bus->func);
+}
+
+static void wfx_sdio_unlock(void *priv)
+{
+ struct wfx_sdio_priv *bus = priv;
+
+ sdio_release_host(bus->func);
+}
+
+static void wfx_sdio_irq_handler(struct sdio_func *func)
+{
+ struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
+
+ wfx_bh_request_rx(bus->core);
+}
+
+static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv)
+{
+ struct wfx_sdio_priv *bus = priv;
+
+ sdio_claim_host(bus->func);
+ wfx_bh_request_rx(bus->core);
+ sdio_release_host(bus->func);
+ return IRQ_HANDLED;
+}
+
+static int wfx_sdio_irq_subscribe(void *priv)
+{
+ struct wfx_sdio_priv *bus = priv;
+ u32 flags;
+ int ret;
+ u8 cccr;
+
+ if (!bus->of_irq) {
+ sdio_claim_host(bus->func);
+ ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler);
+ sdio_release_host(bus->func);
+ return ret;
+ }
+
+ sdio_claim_host(bus->func);
+ cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL);
+ cccr |= BIT(0);
+ cccr |= BIT(bus->func->num);
+ sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL);
+ sdio_release_host(bus->func);
+ flags = irq_get_trigger_type(bus->of_irq);
+ if (!flags)
+ flags = IRQF_TRIGGER_HIGH;
+ flags |= IRQF_ONESHOT;
+ return devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL,
+ wfx_sdio_irq_handler_ext, flags,
+ "wfx", bus);
+}
+
+static int wfx_sdio_irq_unsubscribe(void *priv)
+{
+ struct wfx_sdio_priv *bus = priv;
+ int ret;
+
+ if (bus->of_irq)
+ devm_free_irq(&bus->func->dev, bus->of_irq, bus);
+ sdio_claim_host(bus->func);
+ ret = sdio_release_irq(bus->func);
+ sdio_release_host(bus->func);
+ return ret;
+}
+
+static size_t wfx_sdio_align_size(void *priv, size_t size)
+{
+ struct wfx_sdio_priv *bus = priv;
+
+ return sdio_align_size(bus->func, size);
+}
+
+static const struct hwbus_ops wfx_sdio_hwbus_ops = {
+ .copy_from_io = wfx_sdio_copy_from_io,
+ .copy_to_io = wfx_sdio_copy_to_io,
+ .irq_subscribe = wfx_sdio_irq_subscribe,
+ .irq_unsubscribe = wfx_sdio_irq_unsubscribe,
+ .lock = wfx_sdio_lock,
+ .unlock = wfx_sdio_unlock,
+ .align_size = wfx_sdio_align_size,
+};
+
+static const struct of_device_id wfx_sdio_of_match[] = {
+ { .compatible = "silabs,wfx-sdio" },
+ { .compatible = "silabs,wf200" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, wfx_sdio_of_match);
+
+static int wfx_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct device_node *np = func->dev.of_node;
+ struct wfx_sdio_priv *bus;
+ int ret;
+
+ if (func->num != 1) {
+ dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n",
+ func->num);
+ return -ENODEV;
+ }
+
+ bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+ if (!np || !of_match_node(wfx_sdio_of_match, np)) {
+ dev_warn(&func->dev, "no compatible device found in DT\n");
+ return -ENODEV;
+ }
+
+ bus->func = func;
+ bus->of_irq = irq_of_parse_and_map(np, 0);
+ sdio_set_drvdata(func, bus);
+ func->card->quirks |= MMC_QUIRK_LENIENT_FN0 |
+ MMC_QUIRK_BLKSZ_FOR_BYTE_MODE |
+ MMC_QUIRK_BROKEN_BYTE_MODE_512;
+
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ /* Block of 64 bytes is more efficient than 512B for frame sizes < 4k */
+ sdio_set_block_size(func, 64);
+ sdio_release_host(func);
+ if (ret)
+ goto err0;
+
+ bus->core = wfx_init_common(&func->dev, &wfx_sdio_pdata,
+ &wfx_sdio_hwbus_ops, bus);
+ if (!bus->core) {
+ ret = -EIO;
+ goto err1;
+ }
+
+ ret = wfx_probe(bus->core);
+ if (ret)
+ goto err1;
+
+ return 0;
+
+err1:
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+err0:
+ return ret;
+}
+
+static void wfx_sdio_remove(struct sdio_func *func)
+{
+ struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
+
+ wfx_release(bus->core);
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+}
+
+static const struct sdio_device_id wfx_sdio_ids[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_SILABS, SDIO_DEVICE_ID_SILABS_WF200) },
+ { },
+};
+MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids);
+
+struct sdio_driver wfx_sdio_driver = {
+ .name = "wfx-sdio",
+ .id_table = wfx_sdio_ids,
+ .probe = wfx_sdio_probe,
+ .remove = wfx_sdio_remove,
+ .drv = {
+ .owner = THIS_MODULE,
+ .of_match_table = wfx_sdio_of_match,
+ }
+};
--
2.29.2

2020-12-23 15:41:45

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 10/24] wfx: add fwio.c/fwio.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/fwio.c | 405 +++++++++++++++++++++++++
drivers/net/wireless/silabs/wfx/fwio.h | 15 +
2 files changed, 420 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/fwio.c
create mode 100644 drivers/net/wireless/silabs/wfx/fwio.h

diff --git a/drivers/net/wireless/silabs/wfx/fwio.c b/drivers/net/wireless/silabs/wfx/fwio.c
new file mode 100644
index 000000000000..3c8b0b787f42
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/fwio.c
@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Firmware loading.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/bitfield.h>
+
+#include "fwio.h"
+#include "wfx.h"
+#include "hwio.h"
+
+/* Addresses below are in SRAM area */
+#define WFX_DNLD_FIFO 0x09004000
+#define DNLD_BLOCK_SIZE 0x0400
+#define DNLD_FIFO_SIZE 0x8000 /* (32 * DNLD_BLOCK_SIZE) */
+/* Download Control Area (DCA) */
+#define WFX_DCA_IMAGE_SIZE 0x0900C000
+#define WFX_DCA_PUT 0x0900C004
+#define WFX_DCA_GET 0x0900C008
+#define WFX_DCA_HOST_STATUS 0x0900C00C
+#define HOST_READY 0x87654321
+#define HOST_INFO_READ 0xA753BD99
+#define HOST_UPLOAD_PENDING 0xABCDDCBA
+#define HOST_UPLOAD_COMPLETE 0xD4C64A99
+#define HOST_OK_TO_JUMP 0x174FC882
+#define WFX_DCA_NCP_STATUS 0x0900C010
+#define NCP_NOT_READY 0x12345678
+#define NCP_READY 0x87654321
+#define NCP_INFO_READY 0xBD53EF99
+#define NCP_DOWNLOAD_PENDING 0xABCDDCBA
+#define NCP_DOWNLOAD_COMPLETE 0xCAFEFECA
+#define NCP_AUTH_OK 0xD4C64A99
+#define NCP_AUTH_FAIL 0x174FC882
+#define NCP_PUB_KEY_RDY 0x7AB41D19
+#define WFX_DCA_FW_SIGNATURE 0x0900C014
+#define FW_SIGNATURE_SIZE 0x40
+#define WFX_DCA_FW_HASH 0x0900C054
+#define FW_HASH_SIZE 0x08
+#define WFX_DCA_FW_VERSION 0x0900C05C
+#define FW_VERSION_SIZE 0x04
+#define WFX_DCA_RESERVED 0x0900C060
+#define DCA_RESERVED_SIZE 0x20
+#define WFX_STATUS_INFO 0x0900C080
+#define WFX_BOOTLOADER_LABEL 0x0900C084
+#define BOOTLOADER_LABEL_SIZE 0x3C
+#define WFX_PTE_INFO 0x0900C0C0
+#define PTE_INFO_KEYSET_IDX 0x0D
+#define PTE_INFO_SIZE 0x10
+#define WFX_ERR_INFO 0x0900C0D0
+#define ERR_INVALID_SEC_TYPE 0x05
+#define ERR_SIG_VERIF_FAILED 0x0F
+#define ERR_AES_CTRL_KEY 0x10
+#define ERR_ECC_PUB_KEY 0x11
+#define ERR_MAC_KEY 0x18
+
+#define DCA_TIMEOUT 50 /* milliseconds */
+#define WAKEUP_TIMEOUT 200 /* milliseconds */
+
+static const char * const fwio_errors[] = {
+ [ERR_INVALID_SEC_TYPE] = "Invalid section type or wrong encryption",
+ [ERR_SIG_VERIF_FAILED] = "Signature verification failed",
+ [ERR_AES_CTRL_KEY] = "AES control key not initialized",
+ [ERR_ECC_PUB_KEY] = "ECC public key not initialized",
+ [ERR_MAC_KEY] = "MAC key not initialized",
+};
+
+/* request_firmware() allocate data using vmalloc(). It is not compatible with
+ * underlying hardware that use DMA. Function below detect this case and
+ * allocate a bounce buffer if necessary.
+ *
+ * Notice that, in doubt, you can enable CONFIG_DEBUG_SG to ask kernel to
+ * detect this problem at runtime (else, kernel silently fail).
+ *
+ * NOTE: it may also be possible to use 'pages' from struct firmware and avoid
+ * bounce buffer
+ */
+static int sram_write_dma_safe(struct wfx_dev *wdev, u32 addr, const u8 *buf,
+ size_t len)
+{
+ int ret;
+ const u8 *tmp;
+
+ if (!virt_addr_valid(buf)) {
+ tmp = kmemdup(buf, len, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+ } else {
+ tmp = buf;
+ }
+ ret = sram_buf_write(wdev, addr, tmp, len);
+ if (tmp != buf)
+ kfree(tmp);
+ return ret;
+}
+
+static int get_firmware(struct wfx_dev *wdev, u32 keyset_chip,
+ const struct firmware **fw, int *file_offset)
+{
+ int keyset_file;
+ char filename[256];
+ const char *data;
+ int ret;
+
+ snprintf(filename, sizeof(filename), "%s_%02X.sec",
+ wdev->pdata.file_fw, keyset_chip);
+ ret = firmware_request_nowarn(fw, filename, wdev->dev);
+ if (ret) {
+ dev_info(wdev->dev, "can't load %s, falling back to %s.sec\n",
+ filename, wdev->pdata.file_fw);
+ snprintf(filename, sizeof(filename), "%s.sec",
+ wdev->pdata.file_fw);
+ ret = request_firmware(fw, filename, wdev->dev);
+ if (ret) {
+ dev_err(wdev->dev, "can't load %s\n", filename);
+ *fw = NULL;
+ return ret;
+ }
+ }
+
+ data = (*fw)->data;
+ if (memcmp(data, "KEYSET", 6) != 0) {
+ /* Legacy firmware format */
+ *file_offset = 0;
+ keyset_file = 0x90;
+ } else {
+ *file_offset = 8;
+ keyset_file = (hex_to_bin(data[6]) * 16) | hex_to_bin(data[7]);
+ if (keyset_file < 0) {
+ dev_err(wdev->dev, "%s corrupted\n", filename);
+ release_firmware(*fw);
+ *fw = NULL;
+ return -EINVAL;
+ }
+ }
+ if (keyset_file != keyset_chip) {
+ dev_err(wdev->dev, "firmware keyset is incompatible with chip (file: 0x%02X, chip: 0x%02X)\n",
+ keyset_file, keyset_chip);
+ release_firmware(*fw);
+ *fw = NULL;
+ return -ENODEV;
+ }
+ wdev->keyset = keyset_file;
+ return 0;
+}
+
+static int wait_ncp_status(struct wfx_dev *wdev, u32 status)
+{
+ ktime_t now, start;
+ u32 reg;
+ int ret;
+
+ start = ktime_get();
+ for (;;) {
+ ret = sram_reg_read(wdev, WFX_DCA_NCP_STATUS, &reg);
+ if (ret < 0)
+ return -EIO;
+ now = ktime_get();
+ if (reg == status)
+ break;
+ if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT)))
+ return -ETIMEDOUT;
+ }
+ if (ktime_compare(now, start))
+ dev_dbg(wdev->dev, "chip answer after %lldus\n",
+ ktime_us_delta(now, start));
+ else
+ dev_dbg(wdev->dev, "chip answer immediately\n");
+ return 0;
+}
+
+static int upload_firmware(struct wfx_dev *wdev, const u8 *data, size_t len)
+{
+ int ret;
+ u32 offs, bytes_done = 0;
+ ktime_t now, start;
+
+ if (len % DNLD_BLOCK_SIZE) {
+ dev_err(wdev->dev, "firmware size is not aligned. Buffer overrun will occur\n");
+ return -EIO;
+ }
+ offs = 0;
+ while (offs < len) {
+ start = ktime_get();
+ for (;;) {
+ now = ktime_get();
+ if (offs + DNLD_BLOCK_SIZE - bytes_done < DNLD_FIFO_SIZE)
+ break;
+ if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT)))
+ return -ETIMEDOUT;
+ ret = sram_reg_read(wdev, WFX_DCA_GET, &bytes_done);
+ if (ret < 0)
+ return ret;
+ }
+ if (ktime_compare(now, start))
+ dev_dbg(wdev->dev, "answer after %lldus\n",
+ ktime_us_delta(now, start));
+
+ ret = sram_write_dma_safe(wdev, WFX_DNLD_FIFO +
+ (offs % DNLD_FIFO_SIZE),
+ data + offs, DNLD_BLOCK_SIZE);
+ if (ret < 0)
+ return ret;
+
+ /* WFx seems to not support writing 0 in this register during
+ * first loop
+ */
+ offs += DNLD_BLOCK_SIZE;
+ ret = sram_reg_write(wdev, WFX_DCA_PUT, offs);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static void print_boot_status(struct wfx_dev *wdev)
+{
+ u32 reg;
+
+ sram_reg_read(wdev, WFX_STATUS_INFO, &reg);
+ if (reg == 0x12345678)
+ return;
+ sram_reg_read(wdev, WFX_ERR_INFO, &reg);
+ if (reg < ARRAY_SIZE(fwio_errors) && fwio_errors[reg])
+ dev_info(wdev->dev, "secure boot: %s\n", fwio_errors[reg]);
+ else
+ dev_info(wdev->dev, "secure boot: Error %#02x\n", reg);
+}
+
+static int load_firmware_secure(struct wfx_dev *wdev)
+{
+ const struct firmware *fw = NULL;
+ int header_size;
+ int fw_offset;
+ ktime_t start;
+ u8 *buf;
+ int ret;
+
+ BUILD_BUG_ON(PTE_INFO_SIZE > BOOTLOADER_LABEL_SIZE);
+ buf = kmalloc(BOOTLOADER_LABEL_SIZE + 1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_READY);
+ ret = wait_ncp_status(wdev, NCP_INFO_READY);
+ if (ret)
+ goto error;
+
+ sram_buf_read(wdev, WFX_BOOTLOADER_LABEL, buf, BOOTLOADER_LABEL_SIZE);
+ buf[BOOTLOADER_LABEL_SIZE] = 0;
+ dev_dbg(wdev->dev, "bootloader: \"%s\"\n", buf);
+
+ sram_buf_read(wdev, WFX_PTE_INFO, buf, PTE_INFO_SIZE);
+ ret = get_firmware(wdev, buf[PTE_INFO_KEYSET_IDX], &fw, &fw_offset);
+ if (ret)
+ goto error;
+ header_size = fw_offset + FW_SIGNATURE_SIZE + FW_HASH_SIZE;
+
+ sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_INFO_READ);
+ ret = wait_ncp_status(wdev, NCP_READY);
+ if (ret)
+ goto error;
+
+ sram_reg_write(wdev, WFX_DNLD_FIFO, 0xFFFFFFFF); /* Fifo init */
+ sram_write_dma_safe(wdev, WFX_DCA_FW_VERSION, "\x01\x00\x00\x00",
+ FW_VERSION_SIZE);
+ sram_write_dma_safe(wdev, WFX_DCA_FW_SIGNATURE, fw->data + fw_offset,
+ FW_SIGNATURE_SIZE);
+ sram_write_dma_safe(wdev, WFX_DCA_FW_HASH,
+ fw->data + fw_offset + FW_SIGNATURE_SIZE,
+ FW_HASH_SIZE);
+ sram_reg_write(wdev, WFX_DCA_IMAGE_SIZE, fw->size - header_size);
+ sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_PENDING);
+ ret = wait_ncp_status(wdev, NCP_DOWNLOAD_PENDING);
+ if (ret)
+ goto error;
+
+ start = ktime_get();
+ ret = upload_firmware(wdev, fw->data + header_size,
+ fw->size - header_size);
+ if (ret)
+ goto error;
+ dev_dbg(wdev->dev, "firmware load after %lldus\n",
+ ktime_us_delta(ktime_get(), start));
+
+ sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_COMPLETE);
+ ret = wait_ncp_status(wdev, NCP_AUTH_OK);
+ /* Legacy ROM support */
+ if (ret < 0)
+ ret = wait_ncp_status(wdev, NCP_PUB_KEY_RDY);
+ if (ret < 0)
+ goto error;
+ sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_OK_TO_JUMP);
+
+error:
+ kfree(buf);
+ if (fw)
+ release_firmware(fw);
+ if (ret)
+ print_boot_status(wdev);
+ return ret;
+}
+
+static int init_gpr(struct wfx_dev *wdev)
+{
+ int ret, i;
+ static const struct {
+ int index;
+ u32 value;
+ } gpr_init[] = {
+ { 0x07, 0x208775 },
+ { 0x08, 0x2EC020 },
+ { 0x09, 0x3C3C3C },
+ { 0x0B, 0x322C44 },
+ { 0x0C, 0xA06497 },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(gpr_init); i++) {
+ ret = igpr_reg_write(wdev, gpr_init[i].index,
+ gpr_init[i].value);
+ if (ret < 0)
+ return ret;
+ dev_dbg(wdev->dev, " index %02x: %08x\n",
+ gpr_init[i].index, gpr_init[i].value);
+ }
+ return 0;
+}
+
+int wfx_init_device(struct wfx_dev *wdev)
+{
+ int ret;
+ int hw_revision, hw_type;
+ int wakeup_timeout = 50; /* ms */
+ ktime_t now, start;
+ u32 reg;
+
+ reg = CFG_DIRECT_ACCESS_MODE | CFG_CPU_RESET | CFG_BYTE_ORDER_ABCD;
+ if (wdev->pdata.use_rising_clk)
+ reg |= CFG_CLK_RISE_EDGE;
+ ret = config_reg_write(wdev, reg);
+ if (ret < 0) {
+ dev_err(wdev->dev, "bus returned an error during first write access. Host configuration error?\n");
+ return -EIO;
+ }
+
+ ret = config_reg_read(wdev, &reg);
+ if (ret < 0) {
+ dev_err(wdev->dev, "bus returned an error during first read access. Bus configuration error?\n");
+ return -EIO;
+ }
+ if (reg == 0 || reg == ~0) {
+ dev_err(wdev->dev, "chip mute. Bus configuration error or chip wasn't reset?\n");
+ return -EIO;
+ }
+ dev_dbg(wdev->dev, "initial config register value: %08x\n", reg);
+
+ hw_revision = FIELD_GET(CFG_DEVICE_ID_MAJOR, reg);
+ if (hw_revision == 0) {
+ dev_err(wdev->dev, "bad hardware revision number: %d\n",
+ hw_revision);
+ return -ENODEV;
+ }
+ hw_type = FIELD_GET(CFG_DEVICE_ID_TYPE, reg);
+ if (hw_type == 1) {
+ dev_notice(wdev->dev, "development hardware detected\n");
+ wakeup_timeout = 2000;
+ }
+
+ ret = init_gpr(wdev);
+ if (ret < 0)
+ return ret;
+
+ ret = control_reg_write(wdev, CTRL_WLAN_WAKEUP);
+ if (ret < 0)
+ return -EIO;
+ start = ktime_get();
+ for (;;) {
+ ret = control_reg_read(wdev, &reg);
+ now = ktime_get();
+ if (reg & CTRL_WLAN_READY)
+ break;
+ if (ktime_after(now, ktime_add_ms(start, wakeup_timeout))) {
+ dev_err(wdev->dev, "chip didn't wake up. Chip wasn't reset?\n");
+ return -ETIMEDOUT;
+ }
+ }
+ dev_dbg(wdev->dev, "chip wake up after %lldus\n",
+ ktime_us_delta(now, start));
+
+ ret = config_reg_write_bits(wdev, CFG_CPU_RESET, 0);
+ if (ret < 0)
+ return ret;
+ ret = load_firmware_secure(wdev);
+ if (ret < 0)
+ return ret;
+ return config_reg_write_bits(wdev,
+ CFG_DIRECT_ACCESS_MODE |
+ CFG_IRQ_ENABLE_DATA |
+ CFG_IRQ_ENABLE_WRDY,
+ CFG_IRQ_ENABLE_DATA);
+}
diff --git a/drivers/net/wireless/silabs/wfx/fwio.h b/drivers/net/wireless/silabs/wfx/fwio.h
new file mode 100644
index 000000000000..eeea61210eca
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/fwio.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Firmware loading.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#ifndef WFX_FWIO_H
+#define WFX_FWIO_H
+
+struct wfx_dev;
+
+int wfx_init_device(struct wfx_dev *wdev);
+
+#endif
--
2.29.2

2020-12-23 15:41:59

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 06/24] wfx: add bus.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/bus.h | 38 +++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/bus.h

diff --git a/drivers/net/wireless/silabs/wfx/bus.h b/drivers/net/wireless/silabs/wfx/bus.h
new file mode 100644
index 000000000000..ca04b3da6204
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/bus.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Common bus abstraction layer.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#ifndef WFX_BUS_H
+#define WFX_BUS_H
+
+#include <linux/mmc/sdio_func.h>
+#include <linux/spi/spi.h>
+
+#define WFX_REG_CONFIG 0x0
+#define WFX_REG_CONTROL 0x1
+#define WFX_REG_IN_OUT_QUEUE 0x2
+#define WFX_REG_AHB_DPORT 0x3
+#define WFX_REG_BASE_ADDR 0x4
+#define WFX_REG_SRAM_DPORT 0x5
+#define WFX_REG_SET_GEN_R_W 0x6
+#define WFX_REG_FRAME_OUT 0x7
+
+struct hwbus_ops {
+ int (*copy_from_io)(void *bus_priv, unsigned int addr,
+ void *dst, size_t count);
+ int (*copy_to_io)(void *bus_priv, unsigned int addr,
+ const void *src, size_t count);
+ int (*irq_subscribe)(void *bus_priv);
+ int (*irq_unsubscribe)(void *bus_priv);
+ void (*lock)(void *bus_priv);
+ void (*unlock)(void *bus_priv);
+ size_t (*align_size)(void *bus_priv, size_t size);
+};
+
+extern struct sdio_driver wfx_sdio_driver;
+extern struct spi_driver wfx_spi_driver;
+
+#endif
--
2.29.2

2020-12-23 15:42:06

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 02/24] dt-bindings: introduce silabs,wfx.yaml

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
.../bindings/net/wireless/silabs,wfx.yaml | 133 ++++++++++++++++++
1 file changed, 133 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml

diff --git a/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml b/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml
new file mode 100644
index 000000000000..487d46c5fdc0
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml
@@ -0,0 +1,133 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2020, Silicon Laboratories, Inc.
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/net/wireless/silabs,wfx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Silicon Labs WFxxx devicetree bindings
+
+maintainers:
+ - Jérôme Pouiller <[email protected]>
+
+description: >
+ Support for the Wifi chip WFxxx from Silicon Labs. Currently, the only device
+ from the WFxxx series is the WF200 described here:
+ https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf
+
+ The WF200 can be connected via SPI or via SDIO.
+
+ For SDIO:
+
+ Declaring the WFxxx chip in device tree is mandatory (usually, the VID/PID is
+ sufficient for the SDIO devices).
+
+ It is recommended to declare a mmc-pwrseq on SDIO host above WFx. Without
+ it, you may encounter issues during reboot. The mmc-pwrseq should be
+ compatible with mmc-pwrseq-simple. Please consult
+ Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt for more
+ information.
+
+ For SPI:
+
+ In add of the properties below, please consult
+ Documentation/devicetree/bindings/spi/spi-controller.yaml for optional SPI
+ related properties.
+
+properties:
+ compatible:
+ const: silabs,wf200
+
+ reg:
+ description:
+ When used on SDIO bus, <reg> must be set to 1. When used on SPI bus, it is
+ the chip select address of the device as defined in the SPI devices
+ bindings.
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ interrupts:
+ description: The interrupt line. Triggers IRQ_TYPE_LEVEL_HIGH and
+ IRQ_TYPE_EDGE_RISING are both supported by the chip and the driver. When
+ SPI is used, this property is required. When SDIO is used, the "in-band"
+ interrupt provided by the SDIO bus is used unless an interrupt is defined
+ in the Device Tree.
+ maxItems: 1
+
+ reset-gpios:
+ description: (SPI only) Phandle of gpio that will be used to reset chip
+ during probe. Without this property, you may encounter issues with warm
+ boot. (For legacy purpose, the gpio in inverted when compatible ==
+ "silabs,wfx-spi")
+
+ For SDIO, the reset gpio should declared using a mmc-pwrseq.
+ maxItems: 1
+
+ wakeup-gpios:
+ description: Phandle of gpio that will be used to wake-up chip. Without this
+ property, driver will disable most of power saving features.
+ maxItems: 1
+
+ silabs,antenna-config-file:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: Use an alternative file for antenna configuration (aka
+ "Platform Data Set" in Silabs jargon). Default is 'wf200.pds'.
+
+ local-mac-address: true
+
+ mac-address: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ spi0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wifi@0 {
+ compatible = "silabs,wf200";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wfx_irq &wfx_gpios>;
+ reg = <0>;
+ interrupts-extended = <&gpio 16 IRQ_TYPE_EDGE_RISING>;
+ wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>;
+ spi-max-frequency = <42000000>;
+ };
+ };
+
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ wfx_pwrseq: wfx_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wfx_reset>;
+ reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>;
+ };
+
+ mmc0 {
+ mmc-pwrseq = <&wfx_pwrseq>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wifi@1 {
+ compatible = "silabs,wf200";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wfx_wakeup>;
+ reg = <1>;
+ wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>;
+ };
+ };
+...
--
2.29.2

2020-12-23 15:42:18

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 07/24] wfx: add bus_spi.c

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/bus_spi.c | 271 ++++++++++++++++++++++
1 file changed, 271 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/bus_spi.c

diff --git a/drivers/net/wireless/silabs/wfx/bus_spi.c b/drivers/net/wireless/silabs/wfx/bus_spi.c
new file mode 100644
index 000000000000..56375004c920
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/bus_spi.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SPI interface.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2011, Sagrad Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+
+#include "bus.h"
+#include "wfx.h"
+#include "hwio.h"
+#include "main.h"
+#include "bh.h"
+
+#define SET_WRITE 0x7FFF /* usage: and operation */
+#define SET_READ 0x8000 /* usage: or operation */
+
+#define WFX_RESET_INVERTED 1
+
+static const struct wfx_platform_data wfx_spi_pdata = {
+ .file_fw = "wfm_wf200",
+ .file_pds = "wf200.pds",
+ .use_rising_clk = true,
+};
+
+struct wfx_spi_priv {
+ struct spi_device *func;
+ struct wfx_dev *core;
+ struct gpio_desc *gpio_reset;
+ bool need_swab;
+};
+
+/* WFx chip read data 16bits at time and place them directly into (little
+ * endian) CPU register. So, chip expect byte order like "B1 B0 B3 B2" (while
+ * LE is "B0 B1 B2 B3" and BE is "B3 B2 B1 B0")
+ *
+ * A little endian host with bits_per_word == 16 should do the right job
+ * natively. The code below to support big endian host and commonly used SPI
+ * 8bits.
+ */
+static int wfx_spi_copy_from_io(void *priv, unsigned int addr,
+ void *dst, size_t count)
+{
+ struct wfx_spi_priv *bus = priv;
+ u16 regaddr = (addr << 12) | (count / 2) | SET_READ;
+ struct spi_message m;
+ struct spi_transfer t_addr = {
+ .tx_buf = &regaddr,
+ .len = sizeof(regaddr),
+ };
+ struct spi_transfer t_msg = {
+ .rx_buf = dst,
+ .len = count,
+ };
+ u16 *dst16 = dst;
+ int ret, i;
+
+ WARN(count % 2, "buffer size must be a multiple of 2");
+
+ cpu_to_le16s(&regaddr);
+ if (bus->need_swab)
+ swab16s(&regaddr);
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_addr, &m);
+ spi_message_add_tail(&t_msg, &m);
+ ret = spi_sync(bus->func, &m);
+
+ if (bus->need_swab && addr == WFX_REG_CONFIG)
+ for (i = 0; i < count / 2; i++)
+ swab16s(&dst16[i]);
+ return ret;
+}
+
+static int wfx_spi_copy_to_io(void *priv, unsigned int addr,
+ const void *src, size_t count)
+{
+ struct wfx_spi_priv *bus = priv;
+ u16 regaddr = (addr << 12) | (count / 2);
+ /* FIXME: use a bounce buffer */
+ u16 *src16 = (void *)src;
+ int ret, i;
+ struct spi_message m;
+ struct spi_transfer t_addr = {
+ .tx_buf = &regaddr,
+ .len = sizeof(regaddr),
+ };
+ struct spi_transfer t_msg = {
+ .tx_buf = src,
+ .len = count,
+ };
+
+ WARN(count % 2, "buffer size must be a multiple of 2");
+ WARN(regaddr & SET_READ, "bad addr or size overflow");
+
+ cpu_to_le16s(&regaddr);
+
+ /* Register address and CONFIG content always use 16bit big endian
+ * ("BADC" order)
+ */
+ if (bus->need_swab)
+ swab16s(&regaddr);
+ if (bus->need_swab && addr == WFX_REG_CONFIG)
+ for (i = 0; i < count / 2; i++)
+ swab16s(&src16[i]);
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_addr, &m);
+ spi_message_add_tail(&t_msg, &m);
+ ret = spi_sync(bus->func, &m);
+
+ if (bus->need_swab && addr == WFX_REG_CONFIG)
+ for (i = 0; i < count / 2; i++)
+ swab16s(&src16[i]);
+ return ret;
+}
+
+static void wfx_spi_lock(void *priv)
+{
+}
+
+static void wfx_spi_unlock(void *priv)
+{
+}
+
+static irqreturn_t wfx_spi_irq_handler(int irq, void *priv)
+{
+ struct wfx_spi_priv *bus = priv;
+
+ wfx_bh_request_rx(bus->core);
+ return IRQ_HANDLED;
+}
+
+static int wfx_spi_irq_subscribe(void *priv)
+{
+ struct wfx_spi_priv *bus = priv;
+ u32 flags;
+
+ flags = irq_get_trigger_type(bus->func->irq);
+ if (!flags)
+ flags = IRQF_TRIGGER_HIGH;
+ flags |= IRQF_ONESHOT;
+ return devm_request_threaded_irq(&bus->func->dev, bus->func->irq, NULL,
+ wfx_spi_irq_handler, IRQF_ONESHOT,
+ "wfx", bus);
+}
+
+static int wfx_spi_irq_unsubscribe(void *priv)
+{
+ struct wfx_spi_priv *bus = priv;
+
+ devm_free_irq(&bus->func->dev, bus->func->irq, bus);
+ return 0;
+}
+
+static size_t wfx_spi_align_size(void *priv, size_t size)
+{
+ /* Most of SPI controllers avoid DMA if buffer size is not 32bit aligned
+ */
+ return ALIGN(size, 4);
+}
+
+static const struct hwbus_ops wfx_spi_hwbus_ops = {
+ .copy_from_io = wfx_spi_copy_from_io,
+ .copy_to_io = wfx_spi_copy_to_io,
+ .irq_subscribe = wfx_spi_irq_subscribe,
+ .irq_unsubscribe = wfx_spi_irq_unsubscribe,
+ .lock = wfx_spi_lock,
+ .unlock = wfx_spi_unlock,
+ .align_size = wfx_spi_align_size,
+};
+
+static int wfx_spi_probe(struct spi_device *func)
+{
+ struct wfx_spi_priv *bus;
+ int ret;
+
+ if (!func->bits_per_word)
+ func->bits_per_word = 16;
+ ret = spi_setup(func);
+ if (ret)
+ return ret;
+ /* Trace below is also displayed by spi_setup() if compiled with DEBUG */
+ dev_dbg(&func->dev, "SPI params: CS=%d, mode=%d bits/word=%d speed=%d\n",
+ func->chip_select, func->mode, func->bits_per_word,
+ func->max_speed_hz);
+ if (func->bits_per_word != 16 && func->bits_per_word != 8)
+ dev_warn(&func->dev, "unusual bits/word value: %d\n",
+ func->bits_per_word);
+ if (func->max_speed_hz > 50000000)
+ dev_warn(&func->dev, "%dHz is a very high speed\n",
+ func->max_speed_hz);
+
+ bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+ bus->func = func;
+ if (func->bits_per_word == 8 || IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ bus->need_swab = true;
+ spi_set_drvdata(func, bus);
+
+ bus->gpio_reset = devm_gpiod_get_optional(&func->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(bus->gpio_reset))
+ return PTR_ERR(bus->gpio_reset);
+ if (!bus->gpio_reset) {
+ dev_warn(&func->dev,
+ "gpio reset is not defined, trying to load firmware anyway\n");
+ } else {
+ gpiod_set_consumer_name(bus->gpio_reset, "wfx reset");
+ if (spi_get_device_id(func)->driver_data & WFX_RESET_INVERTED)
+ gpiod_toggle_active_low(bus->gpio_reset);
+ gpiod_set_value_cansleep(bus->gpio_reset, 1);
+ usleep_range(100, 150);
+ gpiod_set_value_cansleep(bus->gpio_reset, 0);
+ usleep_range(2000, 2500);
+ }
+
+ bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata,
+ &wfx_spi_hwbus_ops, bus);
+ if (!bus->core)
+ return -EIO;
+
+ return wfx_probe(bus->core);
+}
+
+static int wfx_spi_remove(struct spi_device *func)
+{
+ struct wfx_spi_priv *bus = spi_get_drvdata(func);
+
+ wfx_release(bus->core);
+ return 0;
+}
+
+/* For dynamic driver binding, kernel does not use OF to match driver. It only
+ * use modalias and modalias is a copy of 'compatible' DT node with vendor
+ * stripped.
+ */
+static const struct spi_device_id wfx_spi_id[] = {
+ { "wfx-spi", WFX_RESET_INVERTED },
+ { "wf200", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, wfx_spi_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id wfx_spi_of_match[] = {
+ { .compatible = "silabs,wfx-spi", .data = (void *)WFX_RESET_INVERTED },
+ { .compatible = "silabs,wf200" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, wfx_spi_of_match);
+#endif
+
+struct spi_driver wfx_spi_driver = {
+ .driver = {
+ .name = "wfx-spi",
+ .of_match_table = of_match_ptr(wfx_spi_of_match),
+ },
+ .id_table = wfx_spi_id,
+ .probe = wfx_spi_probe,
+ .remove = wfx_spi_remove,
+};
--
2.29.2

2020-12-23 15:42:18

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 14/24] wfx: add key.c/key.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/key.c | 241 ++++++++++++++++++++++++++
drivers/net/wireless/silabs/wfx/key.h | 20 +++
2 files changed, 261 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/key.c
create mode 100644 drivers/net/wireless/silabs/wfx/key.h

diff --git a/drivers/net/wireless/silabs/wfx/key.c b/drivers/net/wireless/silabs/wfx/key.c
new file mode 100644
index 000000000000..65134a174683
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/key.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Key management related functions.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+
+#include "key.h"
+#include "wfx.h"
+#include "hif_tx_mib.h"
+
+static int wfx_alloc_key(struct wfx_dev *wdev)
+{
+ int idx;
+
+ idx = ffs(~wdev->key_map) - 1;
+ if (idx < 0 || idx >= MAX_KEY_ENTRIES)
+ return -1;
+
+ wdev->key_map |= BIT(idx);
+ return idx;
+}
+
+static void wfx_free_key(struct wfx_dev *wdev, int idx)
+{
+ WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation");
+ wdev->key_map &= ~BIT(idx);
+}
+
+static u8 fill_wep_pair(struct hif_wep_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+ WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
+ msg->key_length = key->keylen;
+ memcpy(msg->key_data, key->key, key->keylen);
+ ether_addr_copy(msg->peer_address, peer_addr);
+ return HIF_KEY_TYPE_WEP_PAIRWISE;
+}
+
+static u8 fill_wep_group(struct hif_wep_group_key *msg,
+ struct ieee80211_key_conf *key)
+{
+ WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
+ msg->key_id = key->keyidx;
+ msg->key_length = key->keylen;
+ memcpy(msg->key_data, key->key, key->keylen);
+ return HIF_KEY_TYPE_WEP_DEFAULT;
+}
+
+static u8 fill_tkip_pair(struct hif_tkip_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+ u8 *keybuf = key->key;
+
+ WARN(key->keylen != sizeof(msg->tkip_key_data)
+ + sizeof(msg->tx_mic_key)
+ + sizeof(msg->rx_mic_key), "inconsistent data");
+ memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
+ keybuf += sizeof(msg->tkip_key_data);
+ memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key));
+ keybuf += sizeof(msg->tx_mic_key);
+ memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key));
+ ether_addr_copy(msg->peer_address, peer_addr);
+ return HIF_KEY_TYPE_TKIP_PAIRWISE;
+}
+
+static u8 fill_tkip_group(struct hif_tkip_group_key *msg,
+ struct ieee80211_key_conf *key,
+ struct ieee80211_key_seq *seq,
+ enum nl80211_iftype iftype)
+{
+ u8 *keybuf = key->key;
+
+ WARN(key->keylen != sizeof(msg->tkip_key_data)
+ + 2 * sizeof(msg->rx_mic_key), "inconsistent data");
+ msg->key_id = key->keyidx;
+ memcpy(msg->rx_sequence_counter,
+ &seq->tkip.iv16, sizeof(seq->tkip.iv16));
+ memcpy(msg->rx_sequence_counter + sizeof(u16),
+ &seq->tkip.iv32, sizeof(seq->tkip.iv32));
+ memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
+ keybuf += sizeof(msg->tkip_key_data);
+ if (iftype == NL80211_IFTYPE_AP)
+ /* Use Tx MIC Key */
+ memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key));
+ else
+ /* Use Rx MIC Key */
+ memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key));
+ return HIF_KEY_TYPE_TKIP_GROUP;
+}
+
+static u8 fill_ccmp_pair(struct hif_aes_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+ WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
+ ether_addr_copy(msg->peer_address, peer_addr);
+ memcpy(msg->aes_key_data, key->key, key->keylen);
+ return HIF_KEY_TYPE_AES_PAIRWISE;
+}
+
+static u8 fill_ccmp_group(struct hif_aes_group_key *msg,
+ struct ieee80211_key_conf *key,
+ struct ieee80211_key_seq *seq)
+{
+ WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
+ memcpy(msg->aes_key_data, key->key, key->keylen);
+ memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn));
+ memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn));
+ msg->key_id = key->keyidx;
+ return HIF_KEY_TYPE_AES_GROUP;
+}
+
+static u8 fill_sms4_pair(struct hif_wapi_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+ u8 *keybuf = key->key;
+
+ WARN(key->keylen != sizeof(msg->wapi_key_data)
+ + sizeof(msg->mic_key_data), "inconsistent data");
+ ether_addr_copy(msg->peer_address, peer_addr);
+ memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
+ keybuf += sizeof(msg->wapi_key_data);
+ memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
+ msg->key_id = key->keyidx;
+ return HIF_KEY_TYPE_WAPI_PAIRWISE;
+}
+
+static u8 fill_sms4_group(struct hif_wapi_group_key *msg,
+ struct ieee80211_key_conf *key)
+{
+ u8 *keybuf = key->key;
+
+ WARN(key->keylen != sizeof(msg->wapi_key_data)
+ + sizeof(msg->mic_key_data), "inconsistent data");
+ memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
+ keybuf += sizeof(msg->wapi_key_data);
+ memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
+ msg->key_id = key->keyidx;
+ return HIF_KEY_TYPE_WAPI_GROUP;
+}
+
+static u8 fill_aes_cmac_group(struct hif_igtk_group_key *msg,
+ struct ieee80211_key_conf *key,
+ struct ieee80211_key_seq *seq)
+{
+ WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data");
+ memcpy(msg->igtk_key_data, key->key, key->keylen);
+ memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn));
+ memreverse(msg->ipn, sizeof(seq->aes_cmac.pn));
+ msg->key_id = key->keyidx;
+ return HIF_KEY_TYPE_IGTK_GROUP;
+}
+
+static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ int ret;
+ struct hif_req_add_key k = { };
+ struct ieee80211_key_seq seq;
+ struct wfx_dev *wdev = wvif->wdev;
+ int idx = wfx_alloc_key(wvif->wdev);
+ bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE;
+
+ WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data");
+ ieee80211_get_key_rx_seq(key, 0, &seq);
+ if (idx < 0)
+ return -EINVAL;
+ k.int_id = wvif->id;
+ k.entry_index = idx;
+ if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ key->cipher == WLAN_CIPHER_SUITE_WEP104) {
+ if (pairwise)
+ k.type = fill_wep_pair(&k.key.wep_pairwise_key, key,
+ sta->addr);
+ else
+ k.type = fill_wep_group(&k.key.wep_group_key, key);
+ } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ if (pairwise)
+ k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key,
+ sta->addr);
+ else
+ k.type = fill_tkip_group(&k.key.tkip_group_key, key,
+ &seq, wvif->vif->type);
+ } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) {
+ if (pairwise)
+ k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key,
+ sta->addr);
+ else
+ k.type = fill_ccmp_group(&k.key.aes_group_key, key,
+ &seq);
+ } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) {
+ if (pairwise)
+ k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key,
+ sta->addr);
+ else
+ k.type = fill_sms4_group(&k.key.wapi_group_key, key);
+ } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, &seq);
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
+ } else {
+ dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher);
+ wfx_free_key(wdev, idx);
+ return -EOPNOTSUPP;
+ }
+ ret = hif_add_key(wdev, &k);
+ if (ret) {
+ wfx_free_key(wdev, idx);
+ return -EOPNOTSUPP;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE |
+ IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
+ key->hw_key_idx = idx;
+ return 0;
+}
+
+static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key)
+{
+ WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx");
+ wfx_free_key(wvif->wdev, key->hw_key_idx);
+ return hif_remove_key(wvif->wdev, key->hw_key_idx);
+}
+
+int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ int ret = -EOPNOTSUPP;
+ struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
+
+ mutex_lock(&wvif->wdev->conf_mutex);
+ if (cmd == SET_KEY)
+ ret = wfx_add_key(wvif, sta, key);
+ if (cmd == DISABLE_KEY)
+ ret = wfx_remove_key(wvif, key);
+ mutex_unlock(&wvif->wdev->conf_mutex);
+ return ret;
+}
+
diff --git a/drivers/net/wireless/silabs/wfx/key.h b/drivers/net/wireless/silabs/wfx/key.h
new file mode 100644
index 000000000000..eba7ac56080c
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/key.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Implementation of mac80211 API.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#ifndef WFX_KEY_H
+#define WFX_KEY_H
+
+#include <net/mac80211.h>
+
+struct wfx_dev;
+struct wfx_vif;
+
+int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
+
+#endif
--
2.29.2

2020-12-23 15:42:21

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 11/24] wfx: add bh.c/bh.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/bh.c | 332 +++++++++++++++++++++++++++
drivers/net/wireless/silabs/wfx/bh.h | 33 +++
2 files changed, 365 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/bh.c
create mode 100644 drivers/net/wireless/silabs/wfx/bh.h

diff --git a/drivers/net/wireless/silabs/wfx/bh.c b/drivers/net/wireless/silabs/wfx/bh.c
new file mode 100644
index 000000000000..80de528ce974
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/bh.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Interrupt bottom half (BH).
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/gpio/consumer.h>
+#include <net/mac80211.h>
+
+#include "bh.h"
+#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)
+{
+ int max_retry = 3;
+
+ if (!wdev->pdata.gpio_wakeup)
+ return;
+ if (gpiod_get_value_cansleep(wdev->pdata.gpio_wakeup) > 0)
+ return;
+
+ if (wfx_api_older_than(wdev, 1, 4)) {
+ gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1);
+ if (!completion_done(&wdev->hif.ctrl_ready))
+ usleep_range(2000, 2500);
+ return;
+ }
+ for (;;) {
+ gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1);
+ /* completion.h does not provide any function to wait
+ * completion without consume it (a kind of
+ * wait_for_completion_done_timeout()). So we have to emulate
+ * it.
+ */
+ if (wait_for_completion_timeout(&wdev->hif.ctrl_ready,
+ msecs_to_jiffies(2))) {
+ complete(&wdev->hif.ctrl_ready);
+ return;
+ } else if (max_retry-- > 0) {
+ /* Older firmwares have a race in sleep/wake-up process.
+ * Redo the process is sufficient to unfreeze the
+ * chip.
+ */
+ dev_err(wdev->dev, "timeout while wake up chip\n");
+ gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0);
+ usleep_range(2000, 2500);
+ } else {
+ dev_err(wdev->dev, "max wake-up retries reached\n");
+ return;
+ }
+ }
+}
+
+static void device_release(struct wfx_dev *wdev)
+{
+ if (!wdev->pdata.gpio_wakeup)
+ return;
+
+ gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0);
+}
+
+static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
+{
+ struct sk_buff *skb;
+ struct hif_msg *hif;
+ size_t alloc_len;
+ size_t computed_len;
+ int release_count;
+ int piggyback = 0;
+
+ WARN(read_len > round_down(0xFFF, 2) * sizeof(u16),
+ "%s: request exceed WFx capability", __func__);
+
+ /* Add 2 to take into account piggyback size */
+ alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2);
+ skb = dev_alloc_skb(alloc_len);
+ if (!skb)
+ return -ENOMEM;
+
+ if (wfx_data_read(wdev, skb->data, alloc_len))
+ goto err;
+
+ piggyback = le16_to_cpup((__le16 *)(skb->data + alloc_len - 2));
+ _trace_piggyback(piggyback, false);
+
+ hif = (struct hif_msg *)skb->data;
+ WARN(hif->encrypted & 0x3, "encryption is unsupported");
+ if (WARN(read_len < sizeof(struct hif_msg), "corrupted read"))
+ goto err;
+ computed_len = le16_to_cpu(hif->len);
+ computed_len = round_up(computed_len, 2);
+ if (computed_len != read_len) {
+ dev_err(wdev->dev, "inconsistent message length: %zu != %zu\n",
+ computed_len, read_len);
+ print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, 16, 1,
+ hif, read_len, true);
+ goto err;
+ }
+
+ if (!(hif->id & HIF_ID_IS_INDICATION)) {
+ (*is_cnf)++;
+ if (hif->id == HIF_CNF_ID_MULTI_TRANSMIT)
+ release_count = ((struct hif_cnf_multi_transmit *)hif->body)->num_tx_confs;
+ else
+ release_count = 1;
+ WARN(wdev->hif.tx_buffers_used < release_count, "corrupted buffer counter");
+ wdev->hif.tx_buffers_used -= release_count;
+ }
+ _trace_hif_recv(hif, wdev->hif.tx_buffers_used);
+
+ if (hif->id != HIF_IND_ID_EXCEPTION && hif->id != HIF_IND_ID_ERROR) {
+ if (hif->seqnum != wdev->hif.rx_seqnum)
+ dev_warn(wdev->dev, "wrong message sequence: %d != %d\n",
+ hif->seqnum, wdev->hif.rx_seqnum);
+ wdev->hif.rx_seqnum = (hif->seqnum + 1) % (HIF_COUNTER_MAX + 1);
+ }
+
+ skb_put(skb, le16_to_cpu(hif->len));
+ /* wfx_handle_rx takes care on SKB livetime */
+ wfx_handle_rx(wdev, skb);
+ if (!wdev->hif.tx_buffers_used)
+ wake_up(&wdev->hif.tx_buffers_empty);
+
+ return piggyback;
+
+err:
+ if (skb)
+ dev_kfree_skb(skb);
+ return -EIO;
+}
+
+static int bh_work_rx(struct wfx_dev *wdev, int max_msg, int *num_cnf)
+{
+ size_t len;
+ int i;
+ int ctrl_reg, piggyback;
+
+ piggyback = 0;
+ for (i = 0; i < max_msg; i++) {
+ if (piggyback & CTRL_NEXT_LEN_MASK)
+ ctrl_reg = piggyback;
+ else if (try_wait_for_completion(&wdev->hif.ctrl_ready))
+ ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, 0);
+ else
+ ctrl_reg = 0;
+ if (!(ctrl_reg & CTRL_NEXT_LEN_MASK))
+ return i;
+ /* ctrl_reg units are 16bits words */
+ len = (ctrl_reg & CTRL_NEXT_LEN_MASK) * 2;
+ piggyback = rx_helper(wdev, len, num_cnf);
+ if (piggyback < 0)
+ return i;
+ if (!(piggyback & CTRL_WLAN_READY))
+ dev_err(wdev->dev, "unexpected piggyback value: ready bit not set: %04x\n",
+ piggyback);
+ }
+ if (piggyback & CTRL_NEXT_LEN_MASK) {
+ ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, piggyback);
+ complete(&wdev->hif.ctrl_ready);
+ if (ctrl_reg)
+ dev_err(wdev->dev, "unexpected IRQ happened: %04x/%04x\n",
+ ctrl_reg, piggyback);
+ }
+ return i;
+}
+
+static void tx_helper(struct wfx_dev *wdev, struct hif_msg *hif)
+{
+ int ret;
+ void *data;
+ bool is_encrypted = false;
+ size_t len = le16_to_cpu(hif->len);
+
+ WARN(len < sizeof(*hif), "try to send corrupted data");
+
+ hif->seqnum = wdev->hif.tx_seqnum;
+ wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1);
+
+ data = hif;
+ WARN(len > wdev->hw_caps.size_inp_ch_buf,
+ "%s: request exceed WFx capability: %zu > %d\n", __func__,
+ len, wdev->hw_caps.size_inp_ch_buf);
+ len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, len);
+ ret = wfx_data_write(wdev, data, len);
+ if (ret)
+ goto end;
+
+ wdev->hif.tx_buffers_used++;
+ _trace_hif_send(hif, wdev->hif.tx_buffers_used);
+end:
+ if (is_encrypted)
+ kfree(data);
+}
+
+static int bh_work_tx(struct wfx_dev *wdev, int max_msg)
+{
+ struct hif_msg *hif;
+ int i;
+
+ for (i = 0; i < max_msg; i++) {
+ hif = NULL;
+ if (wdev->hif.tx_buffers_used < wdev->hw_caps.num_inp_ch_bufs) {
+ if (try_wait_for_completion(&wdev->hif_cmd.ready)) {
+ WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error");
+ hif = wdev->hif_cmd.buf_send;
+ } else {
+ hif = wfx_tx_queues_get(wdev);
+ }
+ }
+ if (!hif)
+ return i;
+ tx_helper(wdev, hif);
+ }
+ return i;
+}
+
+/* In SDIO mode, it is necessary to make an access to a register to acknowledge
+ * last received message. It could be possible to restrict this acknowledge to
+ * SDIO mode and only if last operation was rx.
+ */
+static void ack_sdio_data(struct wfx_dev *wdev)
+{
+ u32 cfg_reg;
+
+ config_reg_read(wdev, &cfg_reg);
+ if (cfg_reg & 0xFF) {
+ dev_warn(wdev->dev, "chip reports errors: %02x\n",
+ cfg_reg & 0xFF);
+ config_reg_write_bits(wdev, 0xFF, 0x00);
+ }
+}
+
+static void bh_work(struct work_struct *work)
+{
+ struct wfx_dev *wdev = container_of(work, struct wfx_dev, hif.bh);
+ int stats_req = 0, stats_cnf = 0, stats_ind = 0;
+ bool release_chip = false, last_op_is_rx = false;
+ int num_tx, num_rx;
+
+ device_wakeup(wdev);
+ do {
+ num_tx = bh_work_tx(wdev, 32);
+ stats_req += num_tx;
+ if (num_tx)
+ last_op_is_rx = false;
+ num_rx = bh_work_rx(wdev, 32, &stats_cnf);
+ stats_ind += num_rx;
+ if (num_rx)
+ last_op_is_rx = true;
+ } while (num_rx || num_tx);
+ stats_ind -= stats_cnf;
+
+ if (last_op_is_rx)
+ ack_sdio_data(wdev);
+ if (!wdev->hif.tx_buffers_used && !work_pending(work)) {
+ device_release(wdev);
+ release_chip = true;
+ }
+ _trace_bh_stats(stats_ind, stats_req, stats_cnf,
+ wdev->hif.tx_buffers_used, release_chip);
+}
+
+/* An IRQ from chip did occur
+ */
+void wfx_bh_request_rx(struct wfx_dev *wdev)
+{
+ u32 cur, prev;
+
+ control_reg_read(wdev, &cur);
+ prev = atomic_xchg(&wdev->hif.ctrl_reg, cur);
+ complete(&wdev->hif.ctrl_ready);
+ queue_work(system_highpri_wq, &wdev->hif.bh);
+
+ if (!(cur & CTRL_NEXT_LEN_MASK))
+ dev_err(wdev->dev, "unexpected control register value: length field is 0: %04x\n",
+ cur);
+ if (prev != 0)
+ dev_err(wdev->dev, "received IRQ but previous data was not (yet) read: %04x/%04x\n",
+ prev, cur);
+}
+
+/* Driver want to send data
+ */
+void wfx_bh_request_tx(struct wfx_dev *wdev)
+{
+ queue_work(system_highpri_wq, &wdev->hif.bh);
+}
+
+/* If IRQ is not available, this function allow to manually poll the control
+ * register and simulate an IRQ ahen an event happened.
+ *
+ * Note that the device has a bug: If an IRQ raise while host read control
+ * register, the IRQ is lost. So, use this function carefully (only duing
+ * device initialisation).
+ */
+void wfx_bh_poll_irq(struct wfx_dev *wdev)
+{
+ ktime_t now, start;
+ u32 reg;
+
+ WARN(!wdev->poll_irq, "unexpected IRQ polling can mask IRQ");
+ start = ktime_get();
+ for (;;) {
+ control_reg_read(wdev, &reg);
+ now = ktime_get();
+ if (reg & 0xFFF)
+ break;
+ if (ktime_after(now, ktime_add_ms(start, 1000))) {
+ dev_err(wdev->dev, "time out while polling control register\n");
+ return;
+ }
+ udelay(200);
+ }
+ wfx_bh_request_rx(wdev);
+}
+
+void wfx_bh_register(struct wfx_dev *wdev)
+{
+ INIT_WORK(&wdev->hif.bh, bh_work);
+ init_completion(&wdev->hif.ctrl_ready);
+ init_waitqueue_head(&wdev->hif.tx_buffers_empty);
+}
+
+void wfx_bh_unregister(struct wfx_dev *wdev)
+{
+ flush_work(&wdev->hif.bh);
+}
diff --git a/drivers/net/wireless/silabs/wfx/bh.h b/drivers/net/wireless/silabs/wfx/bh.h
new file mode 100644
index 000000000000..4bcbfa9ffc2b
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/bh.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Interrupt bottom half.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#ifndef WFX_BH_H
+#define WFX_BH_H
+
+#include <linux/atomic.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+struct wfx_dev;
+
+struct wfx_hif {
+ struct work_struct bh;
+ struct completion ctrl_ready;
+ wait_queue_head_t tx_buffers_empty;
+ atomic_t ctrl_reg;
+ int rx_seqnum;
+ int tx_seqnum;
+ int tx_buffers_used;
+};
+
+void wfx_bh_register(struct wfx_dev *wdev);
+void wfx_bh_unregister(struct wfx_dev *wdev);
+void wfx_bh_request_rx(struct wfx_dev *wdev);
+void wfx_bh_request_tx(struct wfx_dev *wdev);
+void wfx_bh_poll_irq(struct wfx_dev *wdev);
+
+#endif
--
2.29.2

2020-12-23 15:42:33

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 12/24] wfx: add hif_api_*.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/hif_api_cmd.h | 555 ++++++++++++++++++
.../net/wireless/silabs/wfx/hif_api_general.h | 262 +++++++++
drivers/net/wireless/silabs/wfx/hif_api_mib.h | 343 +++++++++++
3 files changed, 1160 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/hif_api_cmd.h
create mode 100644 drivers/net/wireless/silabs/wfx/hif_api_general.h
create mode 100644 drivers/net/wireless/silabs/wfx/hif_api_mib.h

diff --git a/drivers/net/wireless/silabs/wfx/hif_api_cmd.h b/drivers/net/wireless/silabs/wfx/hif_api_cmd.h
new file mode 100644
index 000000000000..fcd4fe8b4672
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_api_cmd.h
@@ -0,0 +1,555 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * WFx hardware interface definitions
+ *
+ * Copyright (c) 2018-2020, Silicon Laboratories Inc.
+ */
+
+#ifndef WFX_HIF_API_CMD_H
+#define WFX_HIF_API_CMD_H
+
+#include <linux/ieee80211.h>
+
+#include "hif_api_general.h"
+
+enum hif_requests_ids {
+ HIF_REQ_ID_RESET = 0x0a,
+ HIF_REQ_ID_READ_MIB = 0x05,
+ HIF_REQ_ID_WRITE_MIB = 0x06,
+ HIF_REQ_ID_START_SCAN = 0x07,
+ HIF_REQ_ID_STOP_SCAN = 0x08,
+ HIF_REQ_ID_TX = 0x04,
+ HIF_REQ_ID_JOIN = 0x0b,
+ HIF_REQ_ID_SET_PM_MODE = 0x10,
+ HIF_REQ_ID_SET_BSS_PARAMS = 0x11,
+ HIF_REQ_ID_ADD_KEY = 0x0c,
+ HIF_REQ_ID_REMOVE_KEY = 0x0d,
+ HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13,
+ HIF_REQ_ID_START = 0x17,
+ HIF_REQ_ID_BEACON_TRANSMIT = 0x18,
+ HIF_REQ_ID_UPDATE_IE = 0x1b,
+ HIF_REQ_ID_MAP_LINK = 0x1c,
+};
+
+enum hif_confirmations_ids {
+ HIF_CNF_ID_RESET = 0x0a,
+ HIF_CNF_ID_READ_MIB = 0x05,
+ HIF_CNF_ID_WRITE_MIB = 0x06,
+ HIF_CNF_ID_START_SCAN = 0x07,
+ HIF_CNF_ID_STOP_SCAN = 0x08,
+ HIF_CNF_ID_TX = 0x04,
+ HIF_CNF_ID_MULTI_TRANSMIT = 0x1e,
+ HIF_CNF_ID_JOIN = 0x0b,
+ HIF_CNF_ID_SET_PM_MODE = 0x10,
+ HIF_CNF_ID_SET_BSS_PARAMS = 0x11,
+ HIF_CNF_ID_ADD_KEY = 0x0c,
+ HIF_CNF_ID_REMOVE_KEY = 0x0d,
+ HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13,
+ HIF_CNF_ID_START = 0x17,
+ HIF_CNF_ID_BEACON_TRANSMIT = 0x18,
+ HIF_CNF_ID_UPDATE_IE = 0x1b,
+ HIF_CNF_ID_MAP_LINK = 0x1c,
+};
+
+enum hif_indications_ids {
+ HIF_IND_ID_RX = 0x84,
+ HIF_IND_ID_SCAN_CMPL = 0x86,
+ HIF_IND_ID_JOIN_COMPLETE = 0x8f,
+ HIF_IND_ID_SET_PM_MODE_CMPL = 0x89,
+ HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c,
+ HIF_IND_ID_EVENT = 0x85
+};
+
+struct hif_req_reset {
+ u8 reset_stat:1;
+ u8 reset_all_int:1;
+ u8 reserved1:6;
+ u8 reserved2[3];
+} __packed;
+
+struct hif_cnf_reset {
+ __le32 status;
+} __packed;
+
+struct hif_req_read_mib {
+ __le16 mib_id;
+ __le16 reserved;
+} __packed;
+
+struct hif_cnf_read_mib {
+ __le32 status;
+ __le16 mib_id;
+ __le16 length;
+ u8 mib_data[];
+} __packed;
+
+struct hif_req_write_mib {
+ __le16 mib_id;
+ __le16 length;
+ u8 mib_data[];
+} __packed;
+
+struct hif_cnf_write_mib {
+ __le32 status;
+} __packed;
+
+struct hif_req_update_ie {
+ u8 beacon:1;
+ u8 probe_resp:1;
+ u8 probe_req:1;
+ u8 reserved1:5;
+ u8 reserved2;
+ __le16 num_ies;
+ struct element ie[];
+} __packed;
+
+struct hif_cnf_update_ie {
+ __le32 status;
+} __packed;
+
+struct hif_ssid_def {
+ __le32 ssid_length;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+} __packed;
+
+#define HIF_API_MAX_NB_SSIDS 2
+#define HIF_API_MAX_NB_CHANNELS 14
+
+struct hif_req_start_scan_alt {
+ u8 band;
+ u8 maintain_current_bss:1;
+ u8 periodic:1;
+ u8 reserved1:6;
+ u8 disallow_ps:1;
+ u8 reserved2:1;
+ u8 short_preamble:1;
+ u8 reserved3:5;
+ u8 max_transmit_rate;
+ __le16 periodic_interval;
+ u8 reserved4;
+ s8 periodic_rssi_thr;
+ u8 num_of_probe_requests;
+ u8 probe_delay;
+ u8 num_of_ssids;
+ u8 num_of_channels;
+ __le32 min_channel_time;
+ __le32 max_channel_time;
+ __le32 tx_power_level; /* signed value */
+ struct hif_ssid_def ssid_def[HIF_API_MAX_NB_SSIDS];
+ u8 channel_list[];
+} __packed;
+
+struct hif_cnf_start_scan {
+ __le32 status;
+} __packed;
+
+struct hif_cnf_stop_scan {
+ __le32 status;
+} __packed;
+
+enum hif_pm_mode_status {
+ HIF_PM_MODE_ACTIVE = 0x0,
+ HIF_PM_MODE_PS = 0x1,
+ HIF_PM_MODE_UNDETERMINED = 0x2
+};
+
+struct hif_ind_scan_cmpl {
+ __le32 status;
+ u8 pm_mode;
+ u8 num_channels_completed;
+ __le16 reserved;
+} __packed;
+
+enum hif_queue_id {
+ HIF_QUEUE_ID_BACKGROUND = 0x0,
+ HIF_QUEUE_ID_BESTEFFORT = 0x1,
+ HIF_QUEUE_ID_VIDEO = 0x2,
+ HIF_QUEUE_ID_VOICE = 0x3
+};
+
+enum hif_frame_format {
+ HIF_FRAME_FORMAT_NON_HT = 0x0,
+ HIF_FRAME_FORMAT_MIXED_FORMAT_HT = 0x1,
+ HIF_FRAME_FORMAT_GF_HT_11N = 0x2
+};
+
+struct hif_req_tx {
+ /* packet_id is not interpreted by the device, so it is not necessary to
+ * declare it little endian
+ */
+ u32 packet_id;
+ u8 max_tx_rate;
+ u8 queue_id:2;
+ u8 peer_sta_id:4;
+ u8 reserved1:2;
+ u8 more:1;
+ u8 fc_offset:3;
+ u8 after_dtim:1;
+ u8 reserved2:3;
+ u8 start_exp:1;
+ u8 reserved3:3;
+ u8 retry_policy_index:4;
+ __le32 reserved4;
+ __le32 expire_time;
+ u8 frame_format:4;
+ u8 fec_coding:1;
+ u8 short_gi:1;
+ u8 reserved5:1;
+ u8 stbc:1;
+ u8 reserved6;
+ u8 aggregation:1;
+ u8 reserved7:7;
+ u8 reserved8;
+ u8 frame[];
+} __packed;
+
+enum hif_qos_ackplcy {
+ HIF_QOS_ACKPLCY_NORMAL = 0x0,
+ HIF_QOS_ACKPLCY_TXNOACK = 0x1,
+ HIF_QOS_ACKPLCY_NOEXPACK = 0x2,
+ HIF_QOS_ACKPLCY_BLCKACK = 0x3
+};
+
+struct hif_cnf_tx {
+ __le32 status;
+ /* packet_id is copied from struct hif_req_tx without been interpreted
+ * by the device, so it is not necessary to declare it little endian
+ */
+ u32 packet_id;
+ u8 txed_rate;
+ u8 ack_failures;
+ u8 aggr:1;
+ u8 requeue:1;
+ u8 ack_policy:2;
+ u8 txop_limit:1;
+ u8 reserved1:3;
+ u8 reserved2;
+ __le32 media_delay;
+ __le32 tx_queue_delay;
+} __packed;
+
+struct hif_cnf_multi_transmit {
+ u8 num_tx_confs;
+ u8 reserved[3];
+ struct hif_cnf_tx tx_conf_payload[];
+} __packed;
+
+enum hif_ri_flags_encrypt {
+ HIF_RI_FLAGS_UNENCRYPTED = 0x0,
+ HIF_RI_FLAGS_WEP_ENCRYPTED = 0x1,
+ HIF_RI_FLAGS_TKIP_ENCRYPTED = 0x2,
+ HIF_RI_FLAGS_AES_ENCRYPTED = 0x3,
+ HIF_RI_FLAGS_WAPI_ENCRYPTED = 0x4
+};
+
+struct hif_ind_rx {
+ __le32 status;
+ u8 channel_number;
+ u8 reserved1;
+ u8 rxed_rate;
+ u8 rcpi_rssi;
+ u8 encryp:3;
+ u8 in_aggr:1;
+ u8 first_aggr:1;
+ u8 last_aggr:1;
+ u8 defrag:1;
+ u8 beacon:1;
+ u8 tim:1;
+ u8 bitmap:1;
+ u8 match_ssid:1;
+ u8 match_bssid:1;
+ u8 more:1;
+ u8 reserved2:1;
+ u8 ht:1;
+ u8 stbc:1;
+ u8 match_uc_addr:1;
+ u8 match_mc_addr:1;
+ u8 match_bc_addr:1;
+ u8 key_type:1;
+ u8 key_index:4;
+ u8 reserved3:1;
+ u8 peer_sta_id:4;
+ u8 reserved4:2;
+ u8 reserved5:1;
+ u8 frame[];
+} __packed;
+
+struct hif_req_edca_queue_params {
+ u8 queue_id;
+ u8 reserved1;
+ u8 aifsn;
+ u8 reserved2;
+ __le16 cw_min;
+ __le16 cw_max;
+ __le16 tx_op_limit;
+ __le16 allowed_medium_time;
+ __le32 reserved3;
+} __packed;
+
+struct hif_cnf_edca_queue_params {
+ __le32 status;
+} __packed;
+
+struct hif_req_join {
+ u8 infrastructure_bss_mode:1;
+ u8 reserved1:7;
+ u8 band;
+ u8 channel_number;
+ u8 reserved2;
+ u8 bssid[ETH_ALEN];
+ __le16 atim_window;
+ u8 short_preamble:1;
+ u8 reserved3:7;
+ u8 probe_for_join;
+ u8 reserved4;
+ u8 reserved5:2;
+ u8 force_no_beacon:1;
+ u8 force_with_ind:1;
+ u8 reserved6:4;
+ __le32 ssid_length;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ __le32 beacon_interval;
+ __le32 basic_rate_set;
+} __packed;
+
+struct hif_cnf_join {
+ __le32 status;
+} __packed;
+
+struct hif_ind_join_complete {
+ __le32 status;
+} __packed;
+
+struct hif_req_set_bss_params {
+ u8 lost_count_only:1;
+ u8 reserved:7;
+ u8 beacon_lost_count;
+ __le16 aid;
+ __le32 operational_rate_set;
+} __packed;
+
+struct hif_cnf_set_bss_params {
+ __le32 status;
+} __packed;
+
+struct hif_req_set_pm_mode {
+ u8 enter_psm:1;
+ u8 reserved:6;
+ u8 fast_psm:1;
+ u8 fast_psm_idle_period;
+ u8 ap_psm_change_period;
+ u8 min_auto_ps_poll_period;
+} __packed;
+
+struct hif_cnf_set_pm_mode {
+ __le32 status;
+} __packed;
+
+struct hif_ind_set_pm_mode_cmpl {
+ __le32 status;
+ u8 pm_mode;
+ u8 reserved[3];
+} __packed;
+
+struct hif_req_start {
+ u8 mode;
+ u8 band;
+ u8 channel_number;
+ u8 reserved1;
+ __le32 reserved2;
+ __le32 beacon_interval;
+ u8 dtim_period;
+ u8 short_preamble:1;
+ u8 reserved3:7;
+ u8 reserved4;
+ u8 ssid_length;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ __le32 basic_rate_set;
+} __packed;
+
+struct hif_cnf_start {
+ __le32 status;
+} __packed;
+
+struct hif_req_beacon_transmit {
+ u8 enable_beaconing;
+ u8 reserved[3];
+} __packed;
+
+struct hif_cnf_beacon_transmit {
+ __le32 status;
+} __packed;
+
+#define HIF_LINK_ID_MAX 14
+#define HIF_LINK_ID_NOT_ASSOCIATED (HIF_LINK_ID_MAX + 1)
+
+struct hif_req_map_link {
+ u8 mac_addr[ETH_ALEN];
+ u8 unmap:1;
+ u8 mfpc:1;
+ u8 reserved:6;
+ u8 peer_sta_id;
+} __packed;
+
+struct hif_cnf_map_link {
+ __le32 status;
+} __packed;
+
+struct hif_ind_suspend_resume_tx {
+ u8 resume:1;
+ u8 reserved1:2;
+ u8 bc_mc_only:1;
+ u8 reserved2:4;
+ u8 reserved3;
+ __le16 peer_sta_set;
+} __packed;
+
+
+#define MAX_KEY_ENTRIES 24
+#define HIF_API_WEP_KEY_DATA_SIZE 16
+#define HIF_API_TKIP_KEY_DATA_SIZE 16
+#define HIF_API_RX_MIC_KEY_SIZE 8
+#define HIF_API_TX_MIC_KEY_SIZE 8
+#define HIF_API_AES_KEY_DATA_SIZE 16
+#define HIF_API_WAPI_KEY_DATA_SIZE 16
+#define HIF_API_MIC_KEY_DATA_SIZE 16
+#define HIF_API_IGTK_KEY_DATA_SIZE 16
+#define HIF_API_RX_SEQUENCE_COUNTER_SIZE 8
+#define HIF_API_IPN_SIZE 8
+
+enum hif_key_type {
+ HIF_KEY_TYPE_WEP_DEFAULT = 0x0,
+ HIF_KEY_TYPE_WEP_PAIRWISE = 0x1,
+ HIF_KEY_TYPE_TKIP_GROUP = 0x2,
+ HIF_KEY_TYPE_TKIP_PAIRWISE = 0x3,
+ HIF_KEY_TYPE_AES_GROUP = 0x4,
+ HIF_KEY_TYPE_AES_PAIRWISE = 0x5,
+ HIF_KEY_TYPE_WAPI_GROUP = 0x6,
+ HIF_KEY_TYPE_WAPI_PAIRWISE = 0x7,
+ HIF_KEY_TYPE_IGTK_GROUP = 0x8,
+ HIF_KEY_TYPE_NONE = 0x9
+};
+
+struct hif_wep_pairwise_key {
+ u8 peer_address[ETH_ALEN];
+ u8 reserved;
+ u8 key_length;
+ u8 key_data[HIF_API_WEP_KEY_DATA_SIZE];
+} __packed;
+
+struct hif_wep_group_key {
+ u8 key_id;
+ u8 key_length;
+ u8 reserved[2];
+ u8 key_data[HIF_API_WEP_KEY_DATA_SIZE];
+} __packed;
+
+struct hif_tkip_pairwise_key {
+ u8 peer_address[ETH_ALEN];
+ u8 reserved[2];
+ u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE];
+ u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE];
+ u8 tx_mic_key[HIF_API_TX_MIC_KEY_SIZE];
+} __packed;
+
+struct hif_tkip_group_key {
+ u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE];
+ u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE];
+ u8 key_id;
+ u8 reserved[3];
+ u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE];
+} __packed;
+
+struct hif_aes_pairwise_key {
+ u8 peer_address[ETH_ALEN];
+ u8 reserved[2];
+ u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE];
+} __packed;
+
+struct hif_aes_group_key {
+ u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE];
+ u8 key_id;
+ u8 reserved[3];
+ u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE];
+} __packed;
+
+struct hif_wapi_pairwise_key {
+ u8 peer_address[ETH_ALEN];
+ u8 key_id;
+ u8 reserved;
+ u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE];
+ u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE];
+} __packed;
+
+struct hif_wapi_group_key {
+ u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE];
+ u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE];
+ u8 key_id;
+ u8 reserved[3];
+} __packed;
+
+struct hif_igtk_group_key {
+ u8 igtk_key_data[HIF_API_IGTK_KEY_DATA_SIZE];
+ u8 key_id;
+ u8 reserved[3];
+ u8 ipn[HIF_API_IPN_SIZE];
+} __packed;
+
+struct hif_req_add_key {
+ u8 type;
+ u8 entry_index;
+ u8 int_id:2;
+ u8 reserved1:6;
+ u8 reserved2;
+ union {
+ struct hif_wep_pairwise_key wep_pairwise_key;
+ struct hif_wep_group_key wep_group_key;
+ struct hif_tkip_pairwise_key tkip_pairwise_key;
+ struct hif_tkip_group_key tkip_group_key;
+ struct hif_aes_pairwise_key aes_pairwise_key;
+ struct hif_aes_group_key aes_group_key;
+ struct hif_wapi_pairwise_key wapi_pairwise_key;
+ struct hif_wapi_group_key wapi_group_key;
+ struct hif_igtk_group_key igtk_group_key;
+ } key;
+} __packed;
+
+struct hif_cnf_add_key {
+ __le32 status;
+} __packed;
+
+struct hif_req_remove_key {
+ u8 entry_index;
+ u8 reserved[3];
+} __packed;
+
+struct hif_cnf_remove_key {
+ __le32 status;
+} __packed;
+
+enum hif_event_ind {
+ HIF_EVENT_IND_BSSLOST = 0x1,
+ HIF_EVENT_IND_BSSREGAINED = 0x2,
+ HIF_EVENT_IND_RCPI_RSSI = 0x3,
+ HIF_EVENT_IND_PS_MODE_ERROR = 0x4,
+ HIF_EVENT_IND_INACTIVITY = 0x5
+};
+
+enum hif_ps_mode_error {
+ HIF_PS_ERROR_NO_ERROR = 0,
+ HIF_PS_ERROR_AP_NOT_RESP_TO_POLL = 1,
+ HIF_PS_ERROR_AP_NOT_RESP_TO_UAPSD_TRIGGER = 2,
+ HIF_PS_ERROR_AP_SENT_UNICAST_IN_DOZE = 3,
+ HIF_PS_ERROR_AP_NO_DATA_AFTER_TIM = 4
+};
+
+struct hif_ind_event {
+ __le32 event_id;
+ union {
+ u8 rcpi_rssi;
+ __le32 ps_mode_error;
+ __le32 peer_sta_set;
+ } event_data;
+} __packed;
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/hif_api_general.h b/drivers/net/wireless/silabs/wfx/hif_api_general.h
new file mode 100644
index 000000000000..8ccd58b023d0
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_api_general.h
@@ -0,0 +1,262 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * WFx hardware interface definitions
+ *
+ * Copyright (c) 2018-2020, Silicon Laboratories Inc.
+ */
+
+#ifndef WFX_HIF_API_GENERAL_H
+#define WFX_HIF_API_GENERAL_H
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+
+#define HIF_ID_IS_INDICATION 0x80
+#define HIF_COUNTER_MAX 7
+
+struct hif_msg {
+ __le16 len;
+ u8 id;
+ u8 reserved:1;
+ u8 interface:2;
+ u8 seqnum:3;
+ u8 encrypted:2;
+ u8 body[];
+} __packed;
+
+enum hif_general_requests_ids {
+ HIF_REQ_ID_CONFIGURATION = 0x09,
+ HIF_REQ_ID_CONTROL_GPIO = 0x26,
+ HIF_REQ_ID_SET_SL_MAC_KEY = 0x27,
+ HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS = 0x28,
+ HIF_REQ_ID_SL_CONFIGURE = 0x29,
+ HIF_REQ_ID_PREVENT_ROLLBACK = 0x2a,
+ HIF_REQ_ID_PTA_SETTINGS = 0x2b,
+ HIF_REQ_ID_PTA_PRIORITY = 0x2c,
+ HIF_REQ_ID_PTA_STATE = 0x2d,
+ HIF_REQ_ID_SHUT_DOWN = 0x32,
+};
+
+enum hif_general_confirmations_ids {
+ HIF_CNF_ID_CONFIGURATION = 0x09,
+ HIF_CNF_ID_CONTROL_GPIO = 0x26,
+ HIF_CNF_ID_SET_SL_MAC_KEY = 0x27,
+ HIF_CNF_ID_SL_EXCHANGE_PUB_KEYS = 0x28,
+ HIF_CNF_ID_SL_CONFIGURE = 0x29,
+ HIF_CNF_ID_PREVENT_ROLLBACK = 0x2a,
+ HIF_CNF_ID_PTA_SETTINGS = 0x2b,
+ HIF_CNF_ID_PTA_PRIORITY = 0x2c,
+ HIF_CNF_ID_PTA_STATE = 0x2d,
+ HIF_CNF_ID_SHUT_DOWN = 0x32,
+};
+
+enum hif_general_indications_ids {
+ HIF_IND_ID_EXCEPTION = 0xe0,
+ HIF_IND_ID_STARTUP = 0xe1,
+ HIF_IND_ID_WAKEUP = 0xe2,
+ HIF_IND_ID_GENERIC = 0xe3,
+ HIF_IND_ID_ERROR = 0xe4,
+ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS = 0xe5
+};
+
+#define HIF_STATUS_SUCCESS (cpu_to_le32(0x0000))
+#define HIF_STATUS_FAIL (cpu_to_le32(0x0001))
+#define HIF_STATUS_INVALID_PARAMETER (cpu_to_le32(0x0002))
+#define HIF_STATUS_WARNING (cpu_to_le32(0x0003))
+#define HIF_STATUS_UNKNOWN_REQUEST (cpu_to_le32(0x0004))
+#define HIF_STATUS_RX_FAIL_DECRYPT (cpu_to_le32(0x0010))
+#define HIF_STATUS_RX_FAIL_MIC (cpu_to_le32(0x0011))
+#define HIF_STATUS_RX_FAIL_NO_KEY (cpu_to_le32(0x0012))
+#define HIF_STATUS_TX_FAIL_RETRIES (cpu_to_le32(0x0013))
+#define HIF_STATUS_TX_FAIL_TIMEOUT (cpu_to_le32(0x0014))
+#define HIF_STATUS_TX_FAIL_REQUEUE (cpu_to_le32(0x0015))
+#define HIF_STATUS_REFUSED (cpu_to_le32(0x0016))
+#define HIF_STATUS_BUSY (cpu_to_le32(0x0017))
+#define HIF_STATUS_SLK_SET_KEY_SUCCESS (cpu_to_le32(0x005A))
+#define HIF_STATUS_SLK_SET_KEY_ALREADY_BURNED (cpu_to_le32(0x006B))
+#define HIF_STATUS_SLK_SET_KEY_DISALLOWED_MODE (cpu_to_le32(0x007C))
+#define HIF_STATUS_SLK_SET_KEY_UNKNOWN_MODE (cpu_to_le32(0x008D))
+#define HIF_STATUS_SLK_NEGO_SUCCESS (cpu_to_le32(0x009E))
+#define HIF_STATUS_SLK_NEGO_FAILED (cpu_to_le32(0x00AF))
+#define HIF_STATUS_ROLLBACK_SUCCESS (cpu_to_le32(0x1234))
+#define HIF_STATUS_ROLLBACK_FAIL (cpu_to_le32(0x1256))
+
+enum hif_api_rate_index {
+ API_RATE_INDEX_B_1MBPS = 0,
+ API_RATE_INDEX_B_2MBPS = 1,
+ API_RATE_INDEX_B_5P5MBPS = 2,
+ API_RATE_INDEX_B_11MBPS = 3,
+ API_RATE_INDEX_PBCC_22MBPS = 4,
+ API_RATE_INDEX_PBCC_33MBPS = 5,
+ API_RATE_INDEX_G_6MBPS = 6,
+ API_RATE_INDEX_G_9MBPS = 7,
+ API_RATE_INDEX_G_12MBPS = 8,
+ API_RATE_INDEX_G_18MBPS = 9,
+ API_RATE_INDEX_G_24MBPS = 10,
+ API_RATE_INDEX_G_36MBPS = 11,
+ API_RATE_INDEX_G_48MBPS = 12,
+ API_RATE_INDEX_G_54MBPS = 13,
+ API_RATE_INDEX_N_6P5MBPS = 14,
+ API_RATE_INDEX_N_13MBPS = 15,
+ API_RATE_INDEX_N_19P5MBPS = 16,
+ API_RATE_INDEX_N_26MBPS = 17,
+ API_RATE_INDEX_N_39MBPS = 18,
+ API_RATE_INDEX_N_52MBPS = 19,
+ API_RATE_INDEX_N_58P5MBPS = 20,
+ API_RATE_INDEX_N_65MBPS = 21,
+ API_RATE_NUM_ENTRIES = 22
+};
+
+enum hif_fw_type {
+ HIF_FW_TYPE_ETF = 0x0,
+ HIF_FW_TYPE_WFM = 0x1,
+ HIF_FW_TYPE_WSM = 0x2
+};
+
+struct hif_ind_startup {
+ /* As the others, this struct is interpreted as little endian by the
+ * device. However, this struct is also used by the driver. We prefer to
+ * declare it in native order and doing byte swap on reception.
+ */
+ __le32 status;
+ u16 hardware_id;
+ u8 opn[14];
+ u8 uid[8];
+ u16 num_inp_ch_bufs;
+ u16 size_inp_ch_buf;
+ u8 num_links_ap;
+ u8 num_interfaces;
+ u8 mac_addr[2][ETH_ALEN];
+ u8 api_version_minor;
+ u8 api_version_major;
+ u8 link_mode:2;
+ u8 reserved1:6;
+ u8 reserved2;
+ u8 reserved3;
+ u8 reserved4;
+ u8 firmware_build;
+ u8 firmware_minor;
+ u8 firmware_major;
+ u8 firmware_type;
+ u8 disabled_channel_list[2];
+ u8 region_sel_mode:4;
+ u8 reserved5:4;
+ u8 phy1_region:3;
+ u8 phy0_region:3;
+ u8 otp_phy_ver:2;
+ u32 supported_rate_mask;
+ u8 firmware_label[128];
+} __packed;
+
+struct hif_ind_wakeup {
+} __packed;
+
+struct hif_req_configuration {
+ __le16 length;
+ u8 pds_data[];
+} __packed;
+
+struct hif_cnf_configuration {
+ __le32 status;
+} __packed;
+
+enum hif_gpio_mode {
+ HIF_GPIO_MODE_D0 = 0x0,
+ HIF_GPIO_MODE_D1 = 0x1,
+ HIF_GPIO_MODE_OD0 = 0x2,
+ HIF_GPIO_MODE_OD1 = 0x3,
+ HIF_GPIO_MODE_TRISTATE = 0x4,
+ HIF_GPIO_MODE_TOGGLE = 0x5,
+ HIF_GPIO_MODE_READ = 0x6
+};
+
+struct hif_req_control_gpio {
+ u8 gpio_label;
+ u8 gpio_mode;
+} __packed;
+
+struct hif_cnf_control_gpio {
+ __le32 status;
+ __le32 value;
+} __packed;
+
+enum hif_generic_indication_type {
+ HIF_GENERIC_INDICATION_TYPE_RAW = 0x0,
+ HIF_GENERIC_INDICATION_TYPE_STRING = 0x1,
+ HIF_GENERIC_INDICATION_TYPE_RX_STATS = 0x2,
+ HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO = 0x3,
+};
+
+struct hif_rx_stats {
+ __le32 nb_rx_frame;
+ __le32 nb_crc_frame;
+ __le32 per_total;
+ __le32 throughput;
+ __le32 nb_rx_by_rate[API_RATE_NUM_ENTRIES];
+ __le16 per[API_RATE_NUM_ENTRIES];
+ __le16 snr[API_RATE_NUM_ENTRIES]; /* signed value */
+ __le16 rssi[API_RATE_NUM_ENTRIES]; /* signed value */
+ __le16 cfo[API_RATE_NUM_ENTRIES]; /* signed value */
+ __le32 date;
+ __le32 pwr_clk_freq;
+ u8 is_ext_pwr_clk;
+ s8 current_temp;
+} __packed;
+
+struct hif_tx_power_loop_info {
+ __le16 tx_gain_dig;
+ __le16 tx_gain_pa;
+ __le16 target_pout; /* signed value */
+ __le16 p_estimation; /* signed value */
+ __le16 vpdet;
+ u8 measurement_index;
+ u8 reserved;
+} __packed;
+
+struct hif_ind_generic {
+ __le32 type;
+ union {
+ struct hif_rx_stats rx_stats;
+ struct hif_tx_power_loop_info tx_power_loop_info;
+ } data;
+} __packed;
+
+enum hif_error {
+ HIF_ERROR_FIRMWARE_ROLLBACK = 0x00,
+ HIF_ERROR_FIRMWARE_DEBUG_ENABLED = 0x01,
+ HIF_ERROR_SLK_OUTDATED_SESSION_KEY = 0x02,
+ HIF_ERROR_SLK_SESSION_KEY = 0x03,
+ HIF_ERROR_OOR_VOLTAGE = 0x04,
+ HIF_ERROR_PDS_PAYLOAD = 0x05,
+ HIF_ERROR_OOR_TEMPERATURE = 0x06,
+ HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE = 0x07,
+ HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED = 0x08,
+ HIF_ERROR_SLK_OVERFLOW = 0x09,
+ HIF_ERROR_SLK_DECRYPTION = 0x0a,
+ HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE = 0x0b,
+ HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW = 0x0c,
+ HIF_ERROR_HIF_RX_DATA_TOO_LARGE = 0x0e,
+ HIF_ERROR_HIF_TX_QUEUE_FULL = 0x0d,
+ HIF_ERROR_HIF_BUS = 0x0f,
+ HIF_ERROR_PDS_TESTFEATURE = 0x10,
+ HIF_ERROR_SLK_UNCONFIGURED = 0x11,
+};
+
+struct hif_ind_error {
+ __le32 type;
+ u8 data[];
+} __packed;
+
+struct hif_ind_exception {
+ __le32 type;
+ u8 data[];
+} __packed;
+
+enum hif_secure_link_state {
+ SEC_LINK_UNAVAILABLE = 0x0,
+ SEC_LINK_RESERVED = 0x1,
+ SEC_LINK_EVAL = 0x2,
+ SEC_LINK_ENFORCED = 0x3
+};
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/hif_api_mib.h b/drivers/net/wireless/silabs/wfx/hif_api_mib.h
new file mode 100644
index 000000000000..e50afb014e76
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_api_mib.h
@@ -0,0 +1,343 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * WFx hardware interface definitions
+ *
+ * Copyright (c) 2018-2020, Silicon Laboratories Inc.
+ */
+
+#ifndef WFX_HIF_API_MIB_H
+#define WFX_HIF_API_MIB_H
+
+#include "hif_api_general.h"
+
+#define HIF_API_IPV4_ADDRESS_SIZE 4
+#define HIF_API_IPV6_ADDRESS_SIZE 16
+
+enum hif_mib_ids {
+ HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE = 0x2000,
+ HIF_MIB_ID_GL_BLOCK_ACK_INFO = 0x2001,
+ HIF_MIB_ID_GL_SET_MULTI_MSG = 0x2002,
+ HIF_MIB_ID_CCA_CONFIG = 0x2003,
+ HIF_MIB_ID_ETHERTYPE_DATAFRAME_CONDITION = 0x2010,
+ HIF_MIB_ID_PORT_DATAFRAME_CONDITION = 0x2011,
+ HIF_MIB_ID_MAGIC_DATAFRAME_CONDITION = 0x2012,
+ HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION = 0x2013,
+ HIF_MIB_ID_IPV4_ADDR_DATAFRAME_CONDITION = 0x2014,
+ HIF_MIB_ID_IPV6_ADDR_DATAFRAME_CONDITION = 0x2015,
+ HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION = 0x2016,
+ HIF_MIB_ID_CONFIG_DATA_FILTER = 0x2017,
+ HIF_MIB_ID_SET_DATA_FILTERING = 0x2018,
+ HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE = 0x2019,
+ HIF_MIB_ID_NS_IP_ADDRESSES_TABLE = 0x201A,
+ HIF_MIB_ID_RX_FILTER = 0x201B,
+ HIF_MIB_ID_BEACON_FILTER_TABLE = 0x201C,
+ HIF_MIB_ID_BEACON_FILTER_ENABLE = 0x201D,
+ HIF_MIB_ID_GRP_SEQ_COUNTER = 0x2030,
+ HIF_MIB_ID_TSF_COUNTER = 0x2031,
+ HIF_MIB_ID_STATISTICS_TABLE = 0x2032,
+ HIF_MIB_ID_COUNTERS_TABLE = 0x2033,
+ HIF_MIB_ID_MAX_TX_POWER_LEVEL = 0x2034,
+ HIF_MIB_ID_EXTENDED_COUNTERS_TABLE = 0x2035,
+ HIF_MIB_ID_DOT11_MAC_ADDRESS = 0x2040,
+ HIF_MIB_ID_DOT11_MAX_TRANSMIT_MSDU_LIFETIME = 0x2041,
+ HIF_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME = 0x2042,
+ HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID = 0x2043,
+ HIF_MIB_ID_DOT11_RTS_THRESHOLD = 0x2044,
+ HIF_MIB_ID_SLOT_TIME = 0x2045,
+ HIF_MIB_ID_CURRENT_TX_POWER_LEVEL = 0x2046,
+ HIF_MIB_ID_NON_ERP_PROTECTION = 0x2047,
+ HIF_MIB_ID_TEMPLATE_FRAME = 0x2048,
+ HIF_MIB_ID_BEACON_WAKEUP_PERIOD = 0x2049,
+ HIF_MIB_ID_RCPI_RSSI_THRESHOLD = 0x204A,
+ HIF_MIB_ID_BLOCK_ACK_POLICY = 0x204B,
+ HIF_MIB_ID_OVERRIDE_INTERNAL_TX_RATE = 0x204C,
+ HIF_MIB_ID_SET_ASSOCIATION_MODE = 0x204D,
+ HIF_MIB_ID_SET_UAPSD_INFORMATION = 0x204E,
+ HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY = 0x204F,
+ HIF_MIB_ID_PROTECTED_MGMT_POLICY = 0x2050,
+ HIF_MIB_ID_SET_HT_PROTECTION = 0x2051,
+ HIF_MIB_ID_KEEP_ALIVE_PERIOD = 0x2052,
+ HIF_MIB_ID_ARP_KEEP_ALIVE_PERIOD = 0x2053,
+ HIF_MIB_ID_INACTIVITY_TIMER = 0x2054,
+ HIF_MIB_ID_INTERFACE_PROTECTION = 0x2055,
+ HIF_MIB_ID_BEACON_STATS = 0x2056,
+};
+
+enum hif_op_power_mode {
+ HIF_OP_POWER_MODE_ACTIVE = 0x0,
+ HIF_OP_POWER_MODE_DOZE = 0x1,
+ HIF_OP_POWER_MODE_QUIESCENT = 0x2
+};
+
+struct hif_mib_gl_operational_power_mode {
+ u8 power_mode:4;
+ u8 reserved1:3;
+ u8 wup_ind_activation:1;
+ u8 reserved2[3];
+} __packed;
+
+struct hif_mib_gl_set_multi_msg {
+ u8 enable_multi_tx_conf:1;
+ u8 reserved1:7;
+ u8 reserved2[3];
+} __packed;
+
+enum hif_arp_ns_frame_treatment {
+ HIF_ARP_NS_FILTERING_DISABLE = 0x0,
+ HIF_ARP_NS_FILTERING_ENABLE = 0x1,
+ HIF_ARP_NS_REPLY_ENABLE = 0x2
+};
+
+struct hif_mib_arp_ip_addr_table {
+ u8 condition_idx;
+ u8 arp_enable;
+ u8 reserved[2];
+ u8 ipv4_address[HIF_API_IPV4_ADDRESS_SIZE];
+} __packed;
+
+struct hif_mib_rx_filter {
+ u8 reserved1:1;
+ u8 bssid_filter:1;
+ u8 reserved2:1;
+ u8 fwd_probe_req:1;
+ u8 keep_alive_filter:1;
+ u8 reserved3:3;
+ u8 reserved4[3];
+} __packed;
+
+struct hif_ie_table_entry {
+ u8 ie_id;
+ u8 has_changed:1;
+ u8 no_longer:1;
+ u8 has_appeared:1;
+ u8 reserved:1;
+ u8 num_match_data:4;
+ u8 oui[3];
+ u8 match_data[3];
+} __packed;
+
+struct hif_mib_bcn_filter_table {
+ __le32 num_of_info_elmts;
+ struct hif_ie_table_entry ie_table[];
+} __packed;
+
+enum hif_beacon_filter {
+ HIF_BEACON_FILTER_DISABLE = 0x0,
+ HIF_BEACON_FILTER_ENABLE = 0x1,
+ HIF_BEACON_FILTER_AUTO_ERP = 0x2
+};
+
+struct hif_mib_bcn_filter_enable {
+ __le32 enable;
+ __le32 bcn_count;
+} __packed;
+
+struct hif_mib_extended_count_table {
+ __le32 count_plcp_errors;
+ __le32 count_fcs_errors;
+ __le32 count_tx_packets;
+ __le32 count_rx_packets;
+ __le32 count_rx_packet_errors;
+ __le32 count_rx_decryption_failures;
+ __le32 count_rx_mic_failures;
+ __le32 count_rx_no_key_failures;
+ __le32 count_tx_multicast_frames;
+ __le32 count_tx_frames_success;
+ __le32 count_tx_frame_failures;
+ __le32 count_tx_frames_retried;
+ __le32 count_tx_frames_multi_retried;
+ __le32 count_rx_frame_duplicates;
+ __le32 count_rts_success;
+ __le32 count_rts_failures;
+ __le32 count_ack_failures;
+ __le32 count_rx_multicast_frames;
+ __le32 count_rx_frames_success;
+ __le32 count_rx_cmacicv_errors;
+ __le32 count_rx_cmac_replays;
+ __le32 count_rx_mgmt_ccmp_replays;
+ __le32 count_rx_bipmic_errors;
+ __le32 count_rx_beacon;
+ __le32 count_miss_beacon;
+ __le32 reserved[15];
+} __packed;
+
+struct hif_mib_count_table {
+ __le32 count_plcp_errors;
+ __le32 count_fcs_errors;
+ __le32 count_tx_packets;
+ __le32 count_rx_packets;
+ __le32 count_rx_packet_errors;
+ __le32 count_rx_decryption_failures;
+ __le32 count_rx_mic_failures;
+ __le32 count_rx_no_key_failures;
+ __le32 count_tx_multicast_frames;
+ __le32 count_tx_frames_success;
+ __le32 count_tx_frame_failures;
+ __le32 count_tx_frames_retried;
+ __le32 count_tx_frames_multi_retried;
+ __le32 count_rx_frame_duplicates;
+ __le32 count_rts_success;
+ __le32 count_rts_failures;
+ __le32 count_ack_failures;
+ __le32 count_rx_multicast_frames;
+ __le32 count_rx_frames_success;
+ __le32 count_rx_cmacicv_errors;
+ __le32 count_rx_cmac_replays;
+ __le32 count_rx_mgmt_ccmp_replays;
+ __le32 count_rx_bipmic_errors;
+} __packed;
+
+struct hif_mib_mac_address {
+ u8 mac_addr[ETH_ALEN];
+ __le16 reserved;
+} __packed;
+
+struct hif_mib_wep_default_key_id {
+ u8 wep_default_key_id;
+ u8 reserved[3];
+} __packed;
+
+struct hif_mib_dot11_rts_threshold {
+ __le32 threshold;
+} __packed;
+
+struct hif_mib_slot_time {
+ __le32 slot_time;
+} __packed;
+
+struct hif_mib_current_tx_power_level {
+ __le32 power_level; /* signed value */
+} __packed;
+
+struct hif_mib_non_erp_protection {
+ u8 use_cts_to_self:1;
+ u8 reserved1:7;
+ u8 reserved2[3];
+} __packed;
+
+enum hif_tmplt {
+ HIF_TMPLT_PRBREQ = 0x0,
+ HIF_TMPLT_BCN = 0x1,
+ HIF_TMPLT_NULL = 0x2,
+ HIF_TMPLT_QOSNUL = 0x3,
+ HIF_TMPLT_PSPOLL = 0x4,
+ HIF_TMPLT_PRBRES = 0x5,
+ HIF_TMPLT_ARP = 0x6,
+ HIF_TMPLT_NA = 0x7
+};
+
+#define HIF_API_MAX_TEMPLATE_FRAME_SIZE 700
+
+struct hif_mib_template_frame {
+ u8 frame_type;
+ u8 init_rate:7;
+ u8 mode:1;
+ __le16 frame_length;
+ u8 frame[];
+} __packed;
+
+struct hif_mib_beacon_wake_up_period {
+ u8 wakeup_period_min;
+ u8 receive_dtim:1;
+ u8 reserved1:7;
+ u8 wakeup_period_max;
+ u8 reserved2;
+} __packed;
+
+struct hif_mib_rcpi_rssi_threshold {
+ u8 detection:1;
+ u8 rcpi_rssi:1;
+ u8 upperthresh:1;
+ u8 lowerthresh:1;
+ u8 reserved:4;
+ u8 lower_threshold;
+ u8 upper_threshold;
+ u8 rolling_average_count;
+} __packed;
+
+#define DEFAULT_BA_MAX_RX_BUFFER_SIZE 16
+
+struct hif_mib_block_ack_policy {
+ u8 block_ack_tx_tid_policy;
+ u8 reserved1;
+ u8 block_ack_rx_tid_policy;
+ u8 block_ack_rx_max_buffer_size;
+} __packed;
+
+enum hif_mpdu_start_spacing {
+ HIF_MPDU_START_SPACING_NO_RESTRIC = 0x0,
+ HIF_MPDU_START_SPACING_QUARTER = 0x1,
+ HIF_MPDU_START_SPACING_HALF = 0x2,
+ HIF_MPDU_START_SPACING_ONE = 0x3,
+ HIF_MPDU_START_SPACING_TWO = 0x4,
+ HIF_MPDU_START_SPACING_FOUR = 0x5,
+ HIF_MPDU_START_SPACING_EIGHT = 0x6,
+ HIF_MPDU_START_SPACING_SIXTEEN = 0x7
+};
+
+struct hif_mib_set_association_mode {
+ u8 preambtype_use:1;
+ u8 mode:1;
+ u8 rateset:1;
+ u8 spacing:1;
+ u8 reserved1:4;
+ u8 short_preamble:1;
+ u8 reserved2:7;
+ u8 greenfield:1;
+ u8 reserved3:7;
+ u8 mpdu_start_spacing;
+ __le32 basic_rate_set;
+} __packed;
+
+struct hif_mib_set_uapsd_information {
+ u8 trig_bckgrnd:1;
+ u8 trig_be:1;
+ u8 trig_video:1;
+ u8 trig_voice:1;
+ u8 reserved1:4;
+ u8 deliv_bckgrnd:1;
+ u8 deliv_be:1;
+ u8 deliv_video:1;
+ u8 deliv_voice:1;
+ u8 reserved2:4;
+ __le16 min_auto_trigger_interval;
+ __le16 max_auto_trigger_interval;
+ __le16 auto_trigger_step;
+} __packed;
+
+struct hif_tx_rate_retry_policy {
+ u8 policy_index;
+ u8 short_retry_count;
+ u8 long_retry_count;
+ u8 first_rate_sel:2;
+ u8 terminate:1;
+ u8 count_init:1;
+ u8 reserved1:4;
+ u8 rate_recovery_count;
+ u8 reserved2[3];
+ u8 rates[12];
+} __packed;
+
+#define HIF_TX_RETRY_POLICY_MAX 15
+#define HIF_TX_RETRY_POLICY_INVALID HIF_TX_RETRY_POLICY_MAX
+
+struct hif_mib_set_tx_rate_retry_policy {
+ u8 num_tx_rate_policies;
+ u8 reserved[3];
+ struct hif_tx_rate_retry_policy tx_rate_retry_policy[];
+} __packed;
+
+struct hif_mib_protected_mgmt_policy {
+ u8 pmf_enable:1;
+ u8 unpmf_allowed:1;
+ u8 host_enc_auth_frames:1;
+ u8 reserved1:5;
+ u8 reserved2[3];
+} __packed;
+
+struct hif_mib_keep_alive_period {
+ __le16 keep_alive_period;
+ u8 reserved[2];
+} __packed;
+
+#endif
--
2.29.2

2020-12-23 15:42:36

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 01/24] mmc: sdio: add SDIO IDs for Silabs WF200 chip

From: Jérôme Pouiller <[email protected]>

Add Silabs SDIO ID to sdio_ids.h.

Note that the values used by Silabs are uncommon. A driver cannot fully
rely on the SDIO PnP. It should also check if the device is declared in
the DT.

Signed-off-by: Jérôme Pouiller <[email protected]>
---
include/linux/mmc/sdio_ids.h | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h
index 12036619346c..734918fbf164 100644
--- a/include/linux/mmc/sdio_ids.h
+++ b/include/linux/mmc/sdio_ids.h
@@ -25,6 +25,13 @@
* Vendors and devices. Sort key: vendor first, device next.
*/

+/*
+ * Silabs does not use a reliable vendor ID. To avoid conflicts, the driver
+ * won't probe the device if it is not also declared in the DT.
+ */
+#define SDIO_VENDOR_ID_SILABS 0x0000
+#define SDIO_DEVICE_ID_SILABS_WF200 0x1000
+
#define SDIO_VENDOR_ID_STE 0x0020
#define SDIO_DEVICE_ID_STE_CW1200 0x2280

--
2.29.2

2020-12-23 15:43:47

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 17/24] wfx: add queue.c/queue.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/queue.c | 307 ++++++++++++++++++++++++
drivers/net/wireless/silabs/wfx/queue.h | 45 ++++
2 files changed, 352 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/queue.c
create mode 100644 drivers/net/wireless/silabs/wfx/queue.h

diff --git a/drivers/net/wireless/silabs/wfx/queue.c b/drivers/net/wireless/silabs/wfx/queue.c
new file mode 100644
index 000000000000..4dc161f5ff71
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/queue.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * O(1) TX queue with built-in allocator.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/sched.h>
+#include <net/mac80211.h>
+
+#include "queue.h"
+#include "wfx.h"
+#include "sta.h"
+#include "data_tx.h"
+#include "traces.h"
+
+void wfx_tx_lock(struct wfx_dev *wdev)
+{
+ atomic_inc(&wdev->tx_lock);
+}
+
+void wfx_tx_unlock(struct wfx_dev *wdev)
+{
+ int tx_lock = atomic_dec_return(&wdev->tx_lock);
+
+ WARN(tx_lock < 0, "inconsistent tx_lock value");
+ if (!tx_lock)
+ wfx_bh_request_tx(wdev);
+}
+
+void wfx_tx_flush(struct wfx_dev *wdev)
+{
+ int ret;
+
+ /* Do not wait for any reply if chip is frozen */
+ if (wdev->chip_frozen)
+ return;
+
+ wfx_tx_lock(wdev);
+ mutex_lock(&wdev->hif_cmd.lock);
+ ret = wait_event_timeout(wdev->hif.tx_buffers_empty,
+ !wdev->hif.tx_buffers_used,
+ msecs_to_jiffies(3000));
+ if (!ret) {
+ dev_warn(wdev->dev, "cannot flush tx buffers (%d still busy)\n",
+ wdev->hif.tx_buffers_used);
+ wfx_pending_dump_old_frames(wdev, 3000);
+ /* FIXME: drop pending frames here */
+ wdev->chip_frozen = true;
+ }
+ mutex_unlock(&wdev->hif_cmd.lock);
+ wfx_tx_unlock(wdev);
+}
+
+void wfx_tx_lock_flush(struct wfx_dev *wdev)
+{
+ wfx_tx_lock(wdev);
+ wfx_tx_flush(wdev);
+}
+
+void wfx_tx_queues_init(struct wfx_vif *wvif)
+{
+ /* The device is in charge to respect the details of the QoS parameters.
+ * The driver just ensure that it roughtly respect the priorities to
+ * avoid any shortage.
+ */
+ const int priorities[IEEE80211_NUM_ACS] = { 1, 2, 64, 128 };
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
+ skb_queue_head_init(&wvif->tx_queue[i].normal);
+ skb_queue_head_init(&wvif->tx_queue[i].cab);
+ wvif->tx_queue[i].priority = priorities[i];
+ }
+}
+
+void wfx_tx_queues_check_empty(struct wfx_vif *wvif)
+{
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
+ WARN_ON(atomic_read(&wvif->tx_queue[i].pending_frames));
+ WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].normal));
+ WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].cab));
+ }
+}
+
+bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue)
+{
+ return skb_queue_empty(&queue->normal) && skb_queue_empty(&queue->cab);
+}
+
+static void __wfx_tx_queue_drop(struct wfx_vif *wvif,
+ struct sk_buff_head *skb_queue,
+ struct sk_buff_head *dropped)
+{
+ struct sk_buff *skb, *tmp;
+
+ spin_lock_bh(&skb_queue->lock);
+ skb_queue_walk_safe(skb_queue, skb, tmp) {
+ __skb_unlink(skb, skb_queue);
+ skb_queue_head(dropped, skb);
+ }
+ spin_unlock_bh(&skb_queue->lock);
+}
+
+void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue,
+ struct sk_buff_head *dropped)
+{
+ __wfx_tx_queue_drop(wvif, &queue->cab, dropped);
+ __wfx_tx_queue_drop(wvif, &queue->normal, dropped);
+ wake_up(&wvif->wdev->tx_dequeue);
+}
+
+void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb)
+{
+ struct wfx_queue *queue = &wvif->tx_queue[skb_get_queue_mapping(skb)];
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+
+ if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)
+ skb_queue_tail(&queue->cab, skb);
+ else
+ skb_queue_tail(&queue->normal, skb);
+}
+
+void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped)
+{
+ struct wfx_queue *queue;
+ struct wfx_vif *wvif;
+ struct hif_msg *hif;
+ struct sk_buff *skb;
+
+ WARN(!wdev->chip_frozen, "%s should only be used to recover a frozen device",
+ __func__);
+ while ((skb = skb_dequeue(&wdev->tx_pending)) != NULL) {
+ hif = (struct hif_msg *)skb->data;
+ wvif = wdev_to_wvif(wdev, hif->interface);
+ if (wvif) {
+ queue = &wvif->tx_queue[skb_get_queue_mapping(skb)];
+ WARN_ON(skb_get_queue_mapping(skb) > 3);
+ WARN_ON(!atomic_read(&queue->pending_frames));
+ atomic_dec(&queue->pending_frames);
+ }
+ skb_queue_head(dropped, skb);
+ }
+}
+
+struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id)
+{
+ struct wfx_queue *queue;
+ struct hif_req_tx *req;
+ struct wfx_vif *wvif;
+ struct hif_msg *hif;
+ struct sk_buff *skb;
+
+ spin_lock_bh(&wdev->tx_pending.lock);
+ skb_queue_walk(&wdev->tx_pending, skb) {
+ hif = (struct hif_msg *)skb->data;
+ req = (struct hif_req_tx *)hif->body;
+ if (req->packet_id != packet_id)
+ continue;
+ spin_unlock_bh(&wdev->tx_pending.lock);
+ wvif = wdev_to_wvif(wdev, hif->interface);
+ if (wvif) {
+ queue = &wvif->tx_queue[skb_get_queue_mapping(skb)];
+ WARN_ON(skb_get_queue_mapping(skb) > 3);
+ WARN_ON(!atomic_read(&queue->pending_frames));
+ atomic_dec(&queue->pending_frames);
+ }
+ skb_unlink(skb, &wdev->tx_pending);
+ return skb;
+ }
+ spin_unlock_bh(&wdev->tx_pending.lock);
+ WARN(1, "cannot find packet in pending queue");
+ return NULL;
+}
+
+void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms)
+{
+ ktime_t now = ktime_get();
+ struct wfx_tx_priv *tx_priv;
+ struct hif_req_tx *req;
+ struct sk_buff *skb;
+ bool first = true;
+
+ spin_lock_bh(&wdev->tx_pending.lock);
+ skb_queue_walk(&wdev->tx_pending, skb) {
+ tx_priv = wfx_skb_tx_priv(skb);
+ req = wfx_skb_txreq(skb);
+ if (ktime_after(now, ktime_add_ms(tx_priv->xmit_timestamp,
+ limit_ms))) {
+ if (first) {
+ dev_info(wdev->dev, "frames stuck in firmware since %dms or more:\n",
+ limit_ms);
+ first = false;
+ }
+ dev_info(wdev->dev, " id %08x sent %lldms ago\n",
+ req->packet_id,
+ ktime_ms_delta(now, tx_priv->xmit_timestamp));
+ }
+ }
+ spin_unlock_bh(&wdev->tx_pending.lock);
+}
+
+unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev,
+ struct sk_buff *skb)
+{
+ ktime_t now = ktime_get();
+ struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb);
+
+ return ktime_us_delta(now, tx_priv->xmit_timestamp);
+}
+
+bool wfx_tx_queues_has_cab(struct wfx_vif *wvif)
+{
+ int i;
+
+ if (wvif->vif->type != NL80211_IFTYPE_AP)
+ return false;
+ for (i = 0; i < IEEE80211_NUM_ACS; ++i)
+ /* Note: since only AP can have mcast frames in queue and only
+ * one vif can be AP, all queued frames has same interface id
+ */
+ if (!skb_queue_empty_lockless(&wvif->tx_queue[i].cab))
+ return true;
+ return false;
+}
+
+static int wfx_tx_queue_get_weight(struct wfx_queue *queue)
+{
+ return atomic_read(&queue->pending_frames) * queue->priority;
+}
+
+static struct sk_buff *wfx_tx_queues_get_skb(struct wfx_dev *wdev)
+{
+ struct wfx_queue *queues[IEEE80211_NUM_ACS * ARRAY_SIZE(wdev->vif)];
+ int i, j, num_queues = 0;
+ struct wfx_vif *wvif;
+ struct hif_msg *hif;
+ struct sk_buff *skb;
+
+ /* sort the queues */
+ wvif = NULL;
+ while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ WARN_ON(num_queues >= ARRAY_SIZE(queues));
+ queues[num_queues] = &wvif->tx_queue[i];
+ for (j = num_queues; j > 0; j--)
+ if (wfx_tx_queue_get_weight(queues[j]) <
+ wfx_tx_queue_get_weight(queues[j - 1]))
+ swap(queues[j - 1], queues[j]);
+ num_queues++;
+ }
+ }
+
+ wvif = NULL;
+ while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
+ if (!wvif->after_dtim_tx_allowed)
+ continue;
+ for (i = 0; i < num_queues; i++) {
+ skb = skb_dequeue(&queues[i]->cab);
+ if (!skb)
+ continue;
+ /* Note: since only AP can have mcast frames in queue
+ * and only one vif can be AP, all queued frames has
+ * same interface id
+ */
+ hif = (struct hif_msg *)skb->data;
+ WARN_ON(hif->interface != wvif->id);
+ WARN_ON(queues[i] !=
+ &wvif->tx_queue[skb_get_queue_mapping(skb)]);
+ atomic_inc(&queues[i]->pending_frames);
+ trace_queues_stats(wdev, queues[i]);
+ return skb;
+ }
+ /* No more multicast to sent */
+ wvif->after_dtim_tx_allowed = false;
+ schedule_work(&wvif->update_tim_work);
+ }
+
+ for (i = 0; i < num_queues; i++) {
+ skb = skb_dequeue(&queues[i]->normal);
+ if (skb) {
+ atomic_inc(&queues[i]->pending_frames);
+ trace_queues_stats(wdev, queues[i]);
+ return skb;
+ }
+ }
+ return NULL;
+}
+
+struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev)
+{
+ struct wfx_tx_priv *tx_priv;
+ struct sk_buff *skb;
+
+ if (atomic_read(&wdev->tx_lock))
+ return NULL;
+ skb = wfx_tx_queues_get_skb(wdev);
+ if (!skb)
+ return NULL;
+ skb_queue_tail(&wdev->tx_pending, skb);
+ wake_up(&wdev->tx_dequeue);
+ tx_priv = wfx_skb_tx_priv(skb);
+ tx_priv->xmit_timestamp = ktime_get();
+ return (struct hif_msg *)skb->data;
+}
diff --git a/drivers/net/wireless/silabs/wfx/queue.h b/drivers/net/wireless/silabs/wfx/queue.h
new file mode 100644
index 000000000000..a4842cab669c
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/queue.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * O(1) TX queue with built-in allocator.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#ifndef WFX_QUEUE_H
+#define WFX_QUEUE_H
+
+#include <linux/skbuff.h>
+#include <linux/atomic.h>
+
+struct wfx_dev;
+struct wfx_vif;
+
+struct wfx_queue {
+ struct sk_buff_head normal;
+ struct sk_buff_head cab; /* Content After (DTIM) Beacon */
+ atomic_t pending_frames;
+ int priority;
+};
+
+void wfx_tx_lock(struct wfx_dev *wdev);
+void wfx_tx_unlock(struct wfx_dev *wdev);
+void wfx_tx_flush(struct wfx_dev *wdev);
+void wfx_tx_lock_flush(struct wfx_dev *wdev);
+
+void wfx_tx_queues_init(struct wfx_vif *wvif);
+void wfx_tx_queues_check_empty(struct wfx_vif *wvif);
+bool wfx_tx_queues_has_cab(struct wfx_vif *wvif);
+void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb);
+struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev);
+
+bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue);
+void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue,
+ struct sk_buff_head *dropped);
+
+struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id);
+void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped);
+unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev,
+ struct sk_buff *skb);
+void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms);
+
+#endif
--
2.29.2

2020-12-23 15:43:55

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 20/24] wfx: add scan.c/scan.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/scan.c | 131 +++++++++++++++++++++++++
drivers/net/wireless/silabs/wfx/scan.h | 22 +++++
2 files changed, 153 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/scan.c
create mode 100644 drivers/net/wireless/silabs/wfx/scan.h

diff --git a/drivers/net/wireless/silabs/wfx/scan.c b/drivers/net/wireless/silabs/wfx/scan.c
new file mode 100644
index 000000000000..3d5f13c89bac
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/scan.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Scan related functions.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <net/mac80211.h>
+
+#include "scan.h"
+#include "wfx.h"
+#include "sta.h"
+#include "hif_tx_mib.h"
+
+static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw,
+ bool aborted)
+{
+ struct cfg80211_scan_info info = {
+ .aborted = aborted,
+ };
+
+ ieee80211_scan_completed(hw, &info);
+}
+
+static int update_probe_tmpl(struct wfx_vif *wvif,
+ struct cfg80211_scan_request *req)
+{
+ struct sk_buff *skb;
+
+ skb = ieee80211_probereq_get(wvif->wdev->hw, wvif->vif->addr,
+ NULL, 0, req->ie_len);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put_data(skb, req->ie, req->ie_len);
+ hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBREQ, 0);
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static int send_scan_req(struct wfx_vif *wvif,
+ struct cfg80211_scan_request *req, int start_idx)
+{
+ int i, ret, timeout;
+ struct ieee80211_channel *ch_start, *ch_cur;
+
+ for (i = start_idx; i < req->n_channels; i++) {
+ ch_start = req->channels[start_idx];
+ ch_cur = req->channels[i];
+ WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported");
+ if (ch_cur->max_power != ch_start->max_power)
+ break;
+ if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR)
+ break;
+ }
+ wfx_tx_lock_flush(wvif->wdev);
+ wvif->scan_abort = false;
+ reinit_completion(&wvif->scan_complete);
+ ret = hif_scan(wvif, req, start_idx, i - start_idx, &timeout);
+ if (ret) {
+ wfx_tx_unlock(wvif->wdev);
+ return -EIO;
+ }
+ ret = wait_for_completion_timeout(&wvif->scan_complete, timeout);
+ if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower)
+ hif_set_output_power(wvif, wvif->vif->bss_conf.txpower);
+ wfx_tx_unlock(wvif->wdev);
+ if (!ret) {
+ dev_notice(wvif->wdev->dev, "scan timeout\n");
+ hif_stop_scan(wvif);
+ return -ETIMEDOUT;
+ }
+ if (wvif->scan_abort) {
+ dev_notice(wvif->wdev->dev, "scan abort\n");
+ return -ECONNABORTED;
+ }
+ return i - start_idx;
+}
+
+/* It is not really necessary to run scan request asynchronously. However,
+ * there is a bug in "iw scan" when ieee80211_scan_completed() is called before
+ * wfx_hw_scan() return
+ */
+void wfx_hw_scan_work(struct work_struct *work)
+{
+ struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work);
+ struct ieee80211_scan_request *hw_req = wvif->scan_req;
+ int chan_cur, ret;
+
+ mutex_lock(&wvif->wdev->conf_mutex);
+ mutex_lock(&wvif->scan_lock);
+ if (wvif->join_in_progress) {
+ dev_info(wvif->wdev->dev, "%s: abort in-progress REQ_JOIN",
+ __func__);
+ wfx_reset(wvif);
+ }
+ update_probe_tmpl(wvif, &hw_req->req);
+ chan_cur = 0;
+ do {
+ ret = send_scan_req(wvif, &hw_req->req, chan_cur);
+ if (ret > 0)
+ chan_cur += ret;
+ } while (ret > 0 && chan_cur < hw_req->req.n_channels);
+ mutex_unlock(&wvif->scan_lock);
+ mutex_unlock(&wvif->wdev->conf_mutex);
+ __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0);
+}
+
+int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_scan_request *hw_req)
+{
+ struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
+
+ WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS);
+ wvif->scan_req = hw_req;
+ schedule_work(&wvif->scan_work);
+ return 0;
+}
+
+void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
+
+ wvif->scan_abort = true;
+ hif_stop_scan(wvif);
+}
+
+void wfx_scan_complete(struct wfx_vif *wvif)
+{
+ complete(&wvif->scan_complete);
+}
diff --git a/drivers/net/wireless/silabs/wfx/scan.h b/drivers/net/wireless/silabs/wfx/scan.h
new file mode 100644
index 000000000000..6d70717f2bf7
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/scan.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Scan related functions.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#ifndef WFX_SCAN_H
+#define WFX_SCAN_H
+
+#include <net/mac80211.h>
+
+struct wfx_dev;
+struct wfx_vif;
+
+void wfx_hw_scan_work(struct work_struct *work);
+int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_scan_request *req);
+void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void wfx_scan_complete(struct wfx_vif *wvif);
+
+#endif
--
2.29.2

2020-12-23 15:43:55

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 03/24] wfx: add Makefile/Kconfig

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/Kconfig | 12 +++++++++++
drivers/net/wireless/silabs/wfx/Makefile | 26 ++++++++++++++++++++++++
2 files changed, 38 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/Kconfig
create mode 100644 drivers/net/wireless/silabs/wfx/Makefile

diff --git a/drivers/net/wireless/silabs/wfx/Kconfig b/drivers/net/wireless/silabs/wfx/Kconfig
new file mode 100644
index 000000000000..3be4b1e735e1
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/Kconfig
@@ -0,0 +1,12 @@
+config WFX
+ tristate "Silicon Labs wireless chips WF200 and further"
+ depends on MAC80211
+ depends on MMC || !MMC # do not allow WFX=y if MMC=m
+ depends on (SPI || MMC)
+ help
+ This is a driver for Silicons Labs WFxxx series (WF200 and further)
+ chipsets. This chip can be found on SPI or SDIO buses.
+
+ Silabs does not use a reliable SDIO vendor ID. So, to avoid conflicts,
+ the driver won't probe the device if it is not also declared in the
+ Device Tree.
diff --git a/drivers/net/wireless/silabs/wfx/Makefile b/drivers/net/wireless/silabs/wfx/Makefile
new file mode 100644
index 000000000000..f399962c8619
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/Makefile
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Necessary for CREATE_TRACE_POINTS
+CFLAGS_debug.o = -I$(src)
+
+wfx-y := \
+ bh.o \
+ hwio.o \
+ fwio.o \
+ hif_tx_mib.o \
+ hif_tx.o \
+ hif_rx.o \
+ queue.o \
+ data_tx.o \
+ data_rx.o \
+ scan.o \
+ sta.o \
+ key.o \
+ main.o \
+ sta.o \
+ debug.o
+wfx-$(CONFIG_SPI) += bus_spi.o
+# When CONFIG_MMC == m, append to 'wfx-y' (and not to 'wfx-m')
+wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
+
+obj-$(CONFIG_WFX) += wfx.o
--
2.29.2

2020-12-23 15:43:57

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 16/24] wfx: add data_rx.c/data_rx.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/data_rx.c | 94 +++++++++++++++++++++++
drivers/net/wireless/silabs/wfx/data_rx.h | 18 +++++
2 files changed, 112 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/data_rx.c
create mode 100644 drivers/net/wireless/silabs/wfx/data_rx.h

diff --git a/drivers/net/wireless/silabs/wfx/data_rx.c b/drivers/net/wireless/silabs/wfx/data_rx.c
new file mode 100644
index 000000000000..e6d9d8746d4d
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/data_rx.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Datapath implementation.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+
+#include "data_rx.h"
+#include "wfx.h"
+#include "bh.h"
+#include "sta.h"
+
+static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt)
+{
+ int params, tid;
+
+ if (wfx_api_older_than(wvif->wdev, 3, 6))
+ return;
+
+ switch (mgmt->u.action.u.addba_req.action_code) {
+ case WLAN_ACTION_ADDBA_REQ:
+ params = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+ tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+ ieee80211_start_rx_ba_session_offl(wvif->vif, mgmt->sa, tid);
+ break;
+ case WLAN_ACTION_DELBA:
+ params = le16_to_cpu(mgmt->u.action.u.delba.params);
+ tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
+ ieee80211_stop_rx_ba_session_offl(wvif->vif, mgmt->sa, tid);
+ break;
+ }
+}
+
+void wfx_rx_cb(struct wfx_vif *wvif,
+ const struct hif_ind_rx *arg, struct sk_buff *skb)
+{
+ struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb);
+ struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+
+ memset(hdr, 0, sizeof(*hdr));
+
+ if (arg->status == HIF_STATUS_RX_FAIL_MIC)
+ hdr->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_IV_STRIPPED;
+ else if (arg->status)
+ goto drop;
+
+ if (skb->len < sizeof(struct ieee80211_pspoll)) {
+ dev_warn(wvif->wdev->dev, "malformed SDU received\n");
+ goto drop;
+ }
+
+ hdr->band = NL80211_BAND_2GHZ;
+ hdr->freq = ieee80211_channel_to_frequency(arg->channel_number,
+ hdr->band);
+
+ if (arg->rxed_rate >= 14) {
+ hdr->encoding = RX_ENC_HT;
+ hdr->rate_idx = arg->rxed_rate - 14;
+ } else if (arg->rxed_rate >= 4) {
+ hdr->rate_idx = arg->rxed_rate - 2;
+ } else {
+ hdr->rate_idx = arg->rxed_rate;
+ }
+
+ if (!arg->rcpi_rssi) {
+ hdr->flag |= RX_FLAG_NO_SIGNAL_VAL;
+ dev_info(wvif->wdev->dev, "received frame without RSSI data\n");
+ }
+ hdr->signal = arg->rcpi_rssi / 2 - 110;
+ hdr->antenna = 0;
+
+ if (arg->encryp)
+ hdr->flag |= RX_FLAG_DECRYPTED;
+
+ /* Block ack negotiation is offloaded by the firmware. However,
+ * re-ordering must be done by the mac80211.
+ */
+ if (ieee80211_is_action(frame->frame_control) &&
+ mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+ skb->len > IEEE80211_MIN_ACTION_SIZE) {
+ wfx_rx_handle_ba(wvif, mgmt);
+ goto drop;
+ }
+
+ ieee80211_rx_irqsafe(wvif->wdev->hw, skb);
+ return;
+
+drop:
+ dev_kfree_skb(skb);
+}
diff --git a/drivers/net/wireless/silabs/wfx/data_rx.h b/drivers/net/wireless/silabs/wfx/data_rx.h
new file mode 100644
index 000000000000..a320cd858273
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/data_rx.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Datapath implementation.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#ifndef WFX_DATA_RX_H
+#define WFX_DATA_RX_H
+
+struct wfx_vif;
+struct sk_buff;
+struct hif_ind_rx;
+
+void wfx_rx_cb(struct wfx_vif *wvif,
+ const struct hif_ind_rx *arg, struct sk_buff *skb);
+
+#endif
--
2.29.2

2020-12-23 15:43:58

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 22/24] wfx: add traces.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/traces.h | 501 +++++++++++++++++++++++
1 file changed, 501 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/traces.h

diff --git a/drivers/net/wireless/silabs/wfx/traces.h b/drivers/net/wireless/silabs/wfx/traces.h
new file mode 100644
index 000000000000..e90dc73c4b01
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/traces.h
@@ -0,0 +1,501 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Tracepoints definitions.
+ *
+ * Copyright (c) 2018-2020, Silicon Laboratories, Inc.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM wfx
+
+#if !defined(_WFX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _WFX_TRACE_H
+
+#include <linux/tracepoint.h>
+#include <net/mac80211.h>
+
+#include "bus.h"
+#include "hif_api_cmd.h"
+#include "hif_api_mib.h"
+
+/* The hell below need some explanations. For each symbolic number, we need to
+ * define it with TRACE_DEFINE_ENUM() and in a list for __print_symbolic.
+ *
+ * 1. Define a new macro that call TRACE_DEFINE_ENUM():
+ *
+ * #define xxx_name(sym) TRACE_DEFINE_ENUM(sym);
+ *
+ * 2. Define list of all symbols:
+ *
+ * #define list_names \
+ * ... \
+ * xxx_name(XXX) \
+ * ...
+ *
+ * 3. Instantiate that list_names:
+ *
+ * list_names
+ *
+ * 4. Redefine xxx_name() as an entry of array for __print_symbolic()
+ *
+ * #undef xxx_name
+ * #define xxx_name(msg) { msg, #msg },
+ *
+ * 5. list_name can now nearly be used with __print_symbolic() but,
+ * __print_symbolic() dislike last comma of list. So we define a new list
+ * with a dummy element:
+ *
+ * #define list_for_print_symbolic list_names { -1, NULL }
+ */
+
+#define _hif_msg_list \
+ hif_cnf_name(ADD_KEY) \
+ hif_cnf_name(BEACON_TRANSMIT) \
+ hif_cnf_name(EDCA_QUEUE_PARAMS) \
+ hif_cnf_name(JOIN) \
+ hif_cnf_name(MAP_LINK) \
+ hif_cnf_name(READ_MIB) \
+ hif_cnf_name(REMOVE_KEY) \
+ hif_cnf_name(RESET) \
+ hif_cnf_name(SET_BSS_PARAMS) \
+ hif_cnf_name(SET_PM_MODE) \
+ hif_cnf_name(START) \
+ hif_cnf_name(START_SCAN) \
+ hif_cnf_name(STOP_SCAN) \
+ hif_cnf_name(TX) \
+ hif_cnf_name(MULTI_TRANSMIT) \
+ hif_cnf_name(UPDATE_IE) \
+ hif_cnf_name(WRITE_MIB) \
+ hif_cnf_name(CONFIGURATION) \
+ hif_cnf_name(CONTROL_GPIO) \
+ hif_cnf_name(PREVENT_ROLLBACK) \
+ hif_cnf_name(SET_SL_MAC_KEY) \
+ hif_cnf_name(SL_CONFIGURE) \
+ hif_cnf_name(SL_EXCHANGE_PUB_KEYS) \
+ hif_cnf_name(SHUT_DOWN) \
+ hif_ind_name(EVENT) \
+ hif_ind_name(JOIN_COMPLETE) \
+ hif_ind_name(RX) \
+ hif_ind_name(SCAN_CMPL) \
+ hif_ind_name(SET_PM_MODE_CMPL) \
+ hif_ind_name(SUSPEND_RESUME_TX) \
+ hif_ind_name(SL_EXCHANGE_PUB_KEYS) \
+ hif_ind_name(ERROR) \
+ hif_ind_name(EXCEPTION) \
+ hif_ind_name(GENERIC) \
+ hif_ind_name(WAKEUP) \
+ hif_ind_name(STARTUP)
+
+#define hif_msg_list_enum _hif_msg_list
+
+#undef hif_cnf_name
+#undef hif_ind_name
+#define hif_cnf_name(msg) TRACE_DEFINE_ENUM(HIF_CNF_ID_##msg);
+#define hif_ind_name(msg) TRACE_DEFINE_ENUM(HIF_IND_ID_##msg);
+hif_msg_list_enum
+#undef hif_cnf_name
+#undef hif_ind_name
+#define hif_cnf_name(msg) { HIF_CNF_ID_##msg, #msg },
+#define hif_ind_name(msg) { HIF_IND_ID_##msg, #msg },
+#define hif_msg_list hif_msg_list_enum { -1, NULL }
+
+#define _hif_mib_list \
+ hif_mib_name(ARP_IP_ADDRESSES_TABLE) \
+ hif_mib_name(ARP_KEEP_ALIVE_PERIOD) \
+ hif_mib_name(BEACON_FILTER_ENABLE) \
+ hif_mib_name(BEACON_FILTER_TABLE) \
+ hif_mib_name(BEACON_STATS) \
+ hif_mib_name(BEACON_WAKEUP_PERIOD) \
+ hif_mib_name(BLOCK_ACK_POLICY) \
+ hif_mib_name(CCA_CONFIG) \
+ hif_mib_name(CONFIG_DATA_FILTER) \
+ hif_mib_name(COUNTERS_TABLE) \
+ hif_mib_name(CURRENT_TX_POWER_LEVEL) \
+ hif_mib_name(DOT11_MAC_ADDRESS) \
+ hif_mib_name(DOT11_MAX_RECEIVE_LIFETIME) \
+ hif_mib_name(DOT11_MAX_TRANSMIT_MSDU_LIFETIME) \
+ hif_mib_name(DOT11_RTS_THRESHOLD) \
+ hif_mib_name(DOT11_WEP_DEFAULT_KEY_ID) \
+ hif_mib_name(ETHERTYPE_DATAFRAME_CONDITION) \
+ hif_mib_name(EXTENDED_COUNTERS_TABLE) \
+ hif_mib_name(GL_BLOCK_ACK_INFO) \
+ hif_mib_name(GL_OPERATIONAL_POWER_MODE) \
+ hif_mib_name(GL_SET_MULTI_MSG) \
+ hif_mib_name(GRP_SEQ_COUNTER) \
+ hif_mib_name(INACTIVITY_TIMER) \
+ hif_mib_name(INTERFACE_PROTECTION) \
+ hif_mib_name(IPV4_ADDR_DATAFRAME_CONDITION) \
+ hif_mib_name(IPV6_ADDR_DATAFRAME_CONDITION) \
+ hif_mib_name(KEEP_ALIVE_PERIOD) \
+ hif_mib_name(MAC_ADDR_DATAFRAME_CONDITION) \
+ hif_mib_name(MAGIC_DATAFRAME_CONDITION) \
+ hif_mib_name(MAX_TX_POWER_LEVEL) \
+ hif_mib_name(NON_ERP_PROTECTION) \
+ hif_mib_name(NS_IP_ADDRESSES_TABLE) \
+ hif_mib_name(OVERRIDE_INTERNAL_TX_RATE) \
+ hif_mib_name(PORT_DATAFRAME_CONDITION) \
+ hif_mib_name(PROTECTED_MGMT_POLICY) \
+ hif_mib_name(RCPI_RSSI_THRESHOLD) \
+ hif_mib_name(RX_FILTER) \
+ hif_mib_name(SET_ASSOCIATION_MODE) \
+ hif_mib_name(SET_DATA_FILTERING) \
+ hif_mib_name(SET_HT_PROTECTION) \
+ hif_mib_name(SET_TX_RATE_RETRY_POLICY) \
+ hif_mib_name(SET_UAPSD_INFORMATION) \
+ hif_mib_name(SLOT_TIME) \
+ hif_mib_name(STATISTICS_TABLE) \
+ hif_mib_name(TEMPLATE_FRAME) \
+ hif_mib_name(TSF_COUNTER) \
+ hif_mib_name(UC_MC_BC_DATAFRAME_CONDITION)
+
+#define hif_mib_list_enum _hif_mib_list
+
+#undef hif_mib_name
+#define hif_mib_name(mib) TRACE_DEFINE_ENUM(HIF_MIB_ID_##mib);
+hif_mib_list_enum
+#undef hif_mib_name
+#define hif_mib_name(mib) { HIF_MIB_ID_##mib, #mib },
+#define hif_mib_list hif_mib_list_enum { -1, NULL }
+
+DECLARE_EVENT_CLASS(hif_data,
+ TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv),
+ TP_ARGS(hif, tx_fill_level, is_recv),
+ TP_STRUCT__entry(
+ __field(int, tx_fill_level)
+ __field(int, msg_id)
+ __field(const char *, msg_type)
+ __field(int, msg_len)
+ __field(int, buf_len)
+ __field(int, if_id)
+ __field(int, mib)
+ __array(u8, buf, 128)
+ ),
+ TP_fast_assign(
+ int header_len;
+
+ __entry->tx_fill_level = tx_fill_level;
+ __entry->msg_len = le16_to_cpu(hif->len);
+ __entry->msg_id = hif->id;
+ __entry->if_id = hif->interface;
+ if (is_recv)
+ __entry->msg_type = __entry->msg_id & 0x80 ? "IND" : "CNF";
+ else
+ __entry->msg_type = "REQ";
+ if (!is_recv &&
+ (__entry->msg_id == HIF_REQ_ID_READ_MIB ||
+ __entry->msg_id == HIF_REQ_ID_WRITE_MIB)) {
+ __entry->mib = le16_to_cpup((__le16 *)hif->body);
+ header_len = 4;
+ } else {
+ __entry->mib = -1;
+ header_len = 0;
+ }
+ __entry->buf_len = min_t(int, __entry->msg_len,
+ sizeof(__entry->buf))
+ - sizeof(struct hif_msg) - header_len;
+ memcpy(__entry->buf, hif->body + header_len, __entry->buf_len);
+ ),
+ TP_printk("%d:%d:%s_%s%s%s: %s%s (%d bytes)",
+ __entry->tx_fill_level,
+ __entry->if_id,
+ __entry->msg_type,
+ __print_symbolic(__entry->msg_id, hif_msg_list),
+ __entry->mib != -1 ? "/" : "",
+ __entry->mib != -1 ? __print_symbolic(__entry->mib, hif_mib_list) : "",
+ __print_hex(__entry->buf, __entry->buf_len),
+ __entry->msg_len > sizeof(__entry->buf) ? " ..." : "",
+ __entry->msg_len
+ )
+);
+DEFINE_EVENT(hif_data, hif_send,
+ TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv),
+ TP_ARGS(hif, tx_fill_level, is_recv));
+#define _trace_hif_send(hif, tx_fill_level)\
+ trace_hif_send(hif, tx_fill_level, false)
+DEFINE_EVENT(hif_data, hif_recv,
+ TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv),
+ TP_ARGS(hif, tx_fill_level, is_recv));
+#define _trace_hif_recv(hif, tx_fill_level)\
+ trace_hif_recv(hif, tx_fill_level, true)
+
+#define wfx_reg_list_enum \
+ wfx_reg_name(WFX_REG_CONFIG, "CONFIG") \
+ wfx_reg_name(WFX_REG_CONTROL, "CONTROL") \
+ wfx_reg_name(WFX_REG_IN_OUT_QUEUE, "QUEUE") \
+ wfx_reg_name(WFX_REG_AHB_DPORT, "AHB") \
+ wfx_reg_name(WFX_REG_BASE_ADDR, "BASE_ADDR") \
+ wfx_reg_name(WFX_REG_SRAM_DPORT, "SRAM") \
+ wfx_reg_name(WFX_REG_SET_GEN_R_W, "SET_GEN_R_W") \
+ wfx_reg_name(WFX_REG_FRAME_OUT, "FRAME_OUT")
+
+#undef wfx_reg_name
+#define wfx_reg_name(sym, name) TRACE_DEFINE_ENUM(sym);
+wfx_reg_list_enum
+#undef wfx_reg_name
+#define wfx_reg_name(sym, name) { sym, name },
+#define wfx_reg_list wfx_reg_list_enum { -1, NULL }
+
+DECLARE_EVENT_CLASS(io_data,
+ TP_PROTO(int reg, int addr, const void *io_buf, size_t len),
+ TP_ARGS(reg, addr, io_buf, len),
+ TP_STRUCT__entry(
+ __field(int, reg)
+ __field(int, addr)
+ __field(int, msg_len)
+ __field(int, buf_len)
+ __array(u8, buf, 32)
+ __array(u8, addr_str, 10)
+ ),
+ TP_fast_assign(
+ __entry->reg = reg;
+ __entry->addr = addr;
+ __entry->msg_len = len;
+ __entry->buf_len = min_t(int, sizeof(__entry->buf),
+ __entry->msg_len);
+ memcpy(__entry->buf, io_buf, __entry->buf_len);
+ if (addr >= 0)
+ snprintf(__entry->addr_str, 10, "/%08x", addr);
+ else
+ __entry->addr_str[0] = 0;
+ ),
+ TP_printk("%s%s: %s%s (%d bytes)",
+ __print_symbolic(__entry->reg, wfx_reg_list),
+ __entry->addr_str,
+ __print_hex(__entry->buf, __entry->buf_len),
+ __entry->msg_len > sizeof(__entry->buf) ? " ..." : "",
+ __entry->msg_len
+ )
+);
+DEFINE_EVENT(io_data, io_write,
+ TP_PROTO(int reg, int addr, const void *io_buf, size_t len),
+ TP_ARGS(reg, addr, io_buf, len));
+#define _trace_io_ind_write(reg, addr, io_buf, len)\
+ trace_io_write(reg, addr, io_buf, len)
+#define _trace_io_write(reg, io_buf, len) trace_io_write(reg, -1, io_buf, len)
+DEFINE_EVENT(io_data, io_read,
+ TP_PROTO(int reg, int addr, const void *io_buf, size_t len),
+ TP_ARGS(reg, addr, io_buf, len));
+#define _trace_io_ind_read(reg, addr, io_buf, len)\
+ trace_io_read(reg, addr, io_buf, len)
+#define _trace_io_read(reg, io_buf, len) trace_io_read(reg, -1, io_buf, len)
+
+DECLARE_EVENT_CLASS(io_data32,
+ TP_PROTO(int reg, int addr, u32 val),
+ TP_ARGS(reg, addr, val),
+ TP_STRUCT__entry(
+ __field(int, reg)
+ __field(int, addr)
+ __field(int, val)
+ __array(u8, addr_str, 10)
+ ),
+ TP_fast_assign(
+ __entry->reg = reg;
+ __entry->addr = addr;
+ __entry->val = val;
+ if (addr >= 0)
+ snprintf(__entry->addr_str, 10, "/%08x", addr);
+ else
+ __entry->addr_str[0] = 0;
+ ),
+ TP_printk("%s%s: %08x",
+ __print_symbolic(__entry->reg, wfx_reg_list),
+ __entry->addr_str,
+ __entry->val
+ )
+);
+DEFINE_EVENT(io_data32, io_write32,
+ TP_PROTO(int reg, int addr, u32 val),
+ TP_ARGS(reg, addr, val));
+#define _trace_io_ind_write32(reg, addr, val) trace_io_write32(reg, addr, val)
+#define _trace_io_write32(reg, val) trace_io_write32(reg, -1, val)
+DEFINE_EVENT(io_data32, io_read32,
+ TP_PROTO(int reg, int addr, u32 val),
+ TP_ARGS(reg, addr, val));
+#define _trace_io_ind_read32(reg, addr, val) trace_io_read32(reg, addr, val)
+#define _trace_io_read32(reg, val) trace_io_read32(reg, -1, val)
+
+DECLARE_EVENT_CLASS(piggyback,
+ TP_PROTO(u32 val, bool ignored),
+ TP_ARGS(val, ignored),
+ TP_STRUCT__entry(
+ __field(int, val)
+ __field(bool, ignored)
+ ),
+ TP_fast_assign(
+ __entry->val = val;
+ __entry->ignored = ignored;
+ ),
+ TP_printk("CONTROL: %08x%s",
+ __entry->val,
+ __entry->ignored ? " (ignored)" : ""
+ )
+);
+DEFINE_EVENT(piggyback, piggyback,
+ TP_PROTO(u32 val, bool ignored),
+ TP_ARGS(val, ignored));
+#define _trace_piggyback(val, ignored) trace_piggyback(val, ignored)
+
+TRACE_EVENT(bh_stats,
+ TP_PROTO(int ind, int req, int cnf, int busy, bool release),
+ TP_ARGS(ind, req, cnf, busy, release),
+ TP_STRUCT__entry(
+ __field(int, ind)
+ __field(int, req)
+ __field(int, cnf)
+ __field(int, busy)
+ __field(bool, release)
+ ),
+ TP_fast_assign(
+ __entry->ind = ind;
+ __entry->req = req;
+ __entry->cnf = cnf;
+ __entry->busy = busy;
+ __entry->release = release;
+ ),
+ TP_printk("IND/REQ/CNF:%3d/%3d/%3d, REQ in progress:%3d, WUP: %s",
+ __entry->ind,
+ __entry->req,
+ __entry->cnf,
+ __entry->busy,
+ __entry->release ? "release" : "keep"
+ )
+);
+#define _trace_bh_stats(ind, req, cnf, busy, release)\
+ trace_bh_stats(ind, req, cnf, busy, release)
+
+TRACE_EVENT(tx_stats,
+ TP_PROTO(const struct hif_cnf_tx *tx_cnf, const struct sk_buff *skb,
+ int delay),
+ TP_ARGS(tx_cnf, skb, delay),
+ TP_STRUCT__entry(
+ __field(int, pkt_id)
+ __field(int, delay_media)
+ __field(int, delay_queue)
+ __field(int, delay_fw)
+ __field(int, ack_failures)
+ __field(int, flags)
+ __array(int, rate, 4)
+ __array(int, tx_count, 4)
+ ),
+ TP_fast_assign(
+ /* Keep sync with wfx_rates definition in main.c */
+ static const int hw_rate[] = { 0, 1, 2, 3, 6, 7, 8, 9,
+ 10, 11, 12, 13 };
+ const struct ieee80211_tx_info *tx_info =
+ (const struct ieee80211_tx_info *)skb->cb;
+ const struct ieee80211_tx_rate *rates = tx_info->driver_rates;
+ int i;
+
+ __entry->pkt_id = tx_cnf->packet_id;
+ __entry->delay_media = le32_to_cpu(tx_cnf->media_delay);
+ __entry->delay_queue = le32_to_cpu(tx_cnf->tx_queue_delay);
+ __entry->delay_fw = delay;
+ __entry->ack_failures = tx_cnf->ack_failures;
+ if (!tx_cnf->status || __entry->ack_failures)
+ __entry->ack_failures += 1;
+
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ if (rates[0].flags & IEEE80211_TX_RC_MCS)
+ __entry->rate[i] = rates[i].idx;
+ else
+ __entry->rate[i] = hw_rate[rates[i].idx];
+ __entry->tx_count[i] = rates[i].count;
+ }
+ __entry->flags = 0;
+ if (rates[0].flags & IEEE80211_TX_RC_MCS)
+ __entry->flags |= 0x01;
+ if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
+ __entry->flags |= 0x02;
+ if (rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)
+ __entry->flags |= 0x04;
+ if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+ __entry->flags |= 0x08;
+ if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)
+ __entry->flags |= 0x10;
+ if (tx_cnf->status)
+ __entry->flags |= 0x20;
+ if (tx_cnf->status == HIF_STATUS_TX_FAIL_REQUEUE)
+ __entry->flags |= 0x40;
+ ),
+ TP_printk("packet ID: %08x, rate policy: %s %d|%d %d|%d %d|%d %d|%d -> %d attempt, Delays media/queue/total: %4dus/%4dus/%4dus",
+ __entry->pkt_id,
+ __print_flags(__entry->flags, NULL,
+ { 0x01, "M" }, { 0x02, "S" }, { 0x04, "G" },
+ { 0x08, "R" }, { 0x10, "D" }, { 0x20, "F" },
+ { 0x40, "Q" }),
+ __entry->rate[0],
+ __entry->tx_count[0],
+ __entry->rate[1],
+ __entry->tx_count[1],
+ __entry->rate[2],
+ __entry->tx_count[2],
+ __entry->rate[3],
+ __entry->tx_count[3],
+ __entry->ack_failures,
+ __entry->delay_media,
+ __entry->delay_queue,
+ __entry->delay_fw
+ )
+);
+#define _trace_tx_stats(tx_cnf, skb, delay) trace_tx_stats(tx_cnf, skb, delay)
+
+TRACE_EVENT(queues_stats,
+ TP_PROTO(struct wfx_dev *wdev, const struct wfx_queue *elected_queue),
+ TP_ARGS(wdev, elected_queue),
+ TP_STRUCT__entry(
+ __field(int, vif_id)
+ __field(int, queue_id)
+ __array(int, hw, IEEE80211_NUM_ACS * 2)
+ __array(int, drv, IEEE80211_NUM_ACS * 2)
+ __array(int, cab, IEEE80211_NUM_ACS * 2)
+ ),
+ TP_fast_assign(
+ const struct wfx_queue *queue;
+ struct wfx_vif *wvif;
+ int i, j;
+
+ for (j = 0; j < IEEE80211_NUM_ACS * 2; j++) {
+ __entry->hw[j] = -1;
+ __entry->drv[j] = -1;
+ __entry->cab[j] = -1;
+ }
+ __entry->vif_id = -1;
+ __entry->queue_id = -1;
+ wvif = NULL;
+ while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ j = wvif->id * IEEE80211_NUM_ACS + i;
+ WARN_ON(j >= IEEE80211_NUM_ACS * 2);
+ queue = &wvif->tx_queue[i];
+ __entry->hw[j] = atomic_read(&queue->pending_frames);
+ __entry->drv[j] = skb_queue_len(&queue->normal);
+ __entry->cab[j] = skb_queue_len(&queue->cab);
+ if (queue == elected_queue) {
+ __entry->vif_id = wvif->id;
+ __entry->queue_id = i;
+ }
+ }
+ }
+ ),
+ TP_printk("got skb from %d/%d, pend. hw/norm/cab: [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ] [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ]",
+ __entry->vif_id, __entry->queue_id,
+ __entry->hw[0], __entry->drv[0], __entry->cab[0],
+ __entry->hw[1], __entry->drv[1], __entry->cab[1],
+ __entry->hw[2], __entry->drv[2], __entry->cab[2],
+ __entry->hw[3], __entry->drv[3], __entry->cab[3],
+ __entry->hw[4], __entry->drv[4], __entry->cab[4],
+ __entry->hw[5], __entry->drv[5], __entry->cab[5],
+ __entry->hw[6], __entry->drv[6], __entry->cab[6],
+ __entry->hw[7], __entry->drv[7], __entry->cab[7]
+ )
+);
+
+#endif
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE traces
+
+#include <trace/define_trace.h>
--
2.29.2

2020-12-23 15:44:04

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 21/24] wfx: add debug.c/debug.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/debug.c | 361 ++++++++++++++++++++++++
drivers/net/wireless/silabs/wfx/debug.h | 19 ++
2 files changed, 380 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/debug.c
create mode 100644 drivers/net/wireless/silabs/wfx/debug.h

diff --git a/drivers/net/wireless/silabs/wfx/debug.c b/drivers/net/wireless/silabs/wfx/debug.c
new file mode 100644
index 000000000000..3f7101213df3
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/debug.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Debugfs interface.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/crc32.h>
+
+#include "debug.h"
+#include "wfx.h"
+#include "sta.h"
+#include "main.h"
+#include "hif_tx.h"
+#include "hif_tx_mib.h"
+
+#define CREATE_TRACE_POINTS
+#include "traces.h"
+
+static const struct trace_print_flags hif_msg_print_map[] = {
+ hif_msg_list,
+};
+
+static const struct trace_print_flags hif_mib_print_map[] = {
+ hif_mib_list,
+};
+
+static const struct trace_print_flags wfx_reg_print_map[] = {
+ wfx_reg_list,
+};
+
+static const char *get_symbol(unsigned long val,
+ const struct trace_print_flags *symbol_array)
+{
+ int i;
+
+ for (i = 0; symbol_array[i].mask != -1; i++) {
+ if (val == symbol_array[i].mask)
+ return symbol_array[i].name;
+ }
+
+ return "unknown";
+}
+
+const char *get_hif_name(unsigned long id)
+{
+ return get_symbol(id, hif_msg_print_map);
+}
+
+const char *get_mib_name(unsigned long id)
+{
+ return get_symbol(id, hif_mib_print_map);
+}
+
+const char *get_reg_name(unsigned long id)
+{
+ return get_symbol(id, wfx_reg_print_map);
+}
+
+static int wfx_counters_show(struct seq_file *seq, void *v)
+{
+ int ret, i;
+ struct wfx_dev *wdev = seq->private;
+ struct hif_mib_extended_count_table counters[3];
+
+ for (i = 0; i < ARRAY_SIZE(counters); i++) {
+ ret = hif_get_counters_table(wdev, i, counters + i);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ return -EIO;
+ }
+
+ seq_printf(seq, "%-24s %12s %12s %12s\n",
+ "", "global", "iface 0", "iface 1");
+
+#define PUT_COUNTER(name) \
+ seq_printf(seq, "%-24s %12d %12d %12d\n", #name, \
+ le32_to_cpu(counters[2].count_##name), \
+ le32_to_cpu(counters[0].count_##name), \
+ le32_to_cpu(counters[1].count_##name))
+
+ PUT_COUNTER(tx_packets);
+ PUT_COUNTER(tx_multicast_frames);
+ PUT_COUNTER(tx_frames_success);
+ PUT_COUNTER(tx_frame_failures);
+ PUT_COUNTER(tx_frames_retried);
+ PUT_COUNTER(tx_frames_multi_retried);
+
+ PUT_COUNTER(rts_success);
+ PUT_COUNTER(rts_failures);
+ PUT_COUNTER(ack_failures);
+
+ PUT_COUNTER(rx_packets);
+ PUT_COUNTER(rx_frames_success);
+ PUT_COUNTER(rx_packet_errors);
+ PUT_COUNTER(plcp_errors);
+ PUT_COUNTER(fcs_errors);
+ PUT_COUNTER(rx_decryption_failures);
+ PUT_COUNTER(rx_mic_failures);
+ PUT_COUNTER(rx_no_key_failures);
+ PUT_COUNTER(rx_frame_duplicates);
+ PUT_COUNTER(rx_multicast_frames);
+ PUT_COUNTER(rx_cmacicv_errors);
+ PUT_COUNTER(rx_cmac_replays);
+ PUT_COUNTER(rx_mgmt_ccmp_replays);
+
+ PUT_COUNTER(rx_beacon);
+ PUT_COUNTER(miss_beacon);
+
+#undef PUT_COUNTER
+
+ for (i = 0; i < ARRAY_SIZE(counters[0].reserved); i++)
+ seq_printf(seq, "reserved[%02d]%12s %12d %12d %12d\n", i, "",
+ le32_to_cpu(counters[2].reserved[i]),
+ le32_to_cpu(counters[0].reserved[i]),
+ le32_to_cpu(counters[1].reserved[i]));
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_counters);
+
+static const char * const channel_names[] = {
+ [0] = "1M",
+ [1] = "2M",
+ [2] = "5.5M",
+ [3] = "11M",
+ /* Entries 4 and 5 does not exist */
+ [6] = "6M",
+ [7] = "9M",
+ [8] = "12M",
+ [9] = "18M",
+ [10] = "24M",
+ [11] = "36M",
+ [12] = "48M",
+ [13] = "54M",
+ [14] = "MCS0",
+ [15] = "MCS1",
+ [16] = "MCS2",
+ [17] = "MCS3",
+ [18] = "MCS4",
+ [19] = "MCS5",
+ [20] = "MCS6",
+ [21] = "MCS7",
+};
+
+static int wfx_rx_stats_show(struct seq_file *seq, void *v)
+{
+ struct wfx_dev *wdev = seq->private;
+ struct hif_rx_stats *st = &wdev->rx_stats;
+ int i;
+
+ mutex_lock(&wdev->rx_stats_lock);
+ seq_printf(seq, "Timestamp: %dus\n", st->date);
+ seq_printf(seq, "Low power clock: frequency %uHz, external %s\n",
+ le32_to_cpu(st->pwr_clk_freq),
+ st->is_ext_pwr_clk ? "yes" : "no");
+ seq_printf(seq,
+ "Num. of frames: %d, PER (x10e4): %d, Throughput: %dKbps/s\n",
+ st->nb_rx_frame, st->per_total, st->throughput);
+ seq_puts(seq, " Num. of PER RSSI SNR CFO\n");
+ seq_puts(seq, " frames (x10e4) (dBm) (dB) (kHz)\n");
+ for (i = 0; i < ARRAY_SIZE(channel_names); i++) {
+ if (channel_names[i])
+ seq_printf(seq, "%5s %8d %8d %8d %8d %8d\n",
+ channel_names[i],
+ le32_to_cpu(st->nb_rx_by_rate[i]),
+ le16_to_cpu(st->per[i]),
+ (s16)le16_to_cpu(st->rssi[i]) / 100,
+ (s16)le16_to_cpu(st->snr[i]) / 100,
+ (s16)le16_to_cpu(st->cfo[i]));
+ }
+ mutex_unlock(&wdev->rx_stats_lock);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats);
+
+static int wfx_tx_power_loop_show(struct seq_file *seq, void *v)
+{
+ struct wfx_dev *wdev = seq->private;
+ struct hif_tx_power_loop_info *st = &wdev->tx_power_loop_info;
+ int tmp;
+
+ mutex_lock(&wdev->tx_power_loop_info_lock);
+ tmp = le16_to_cpu(st->tx_gain_dig);
+ seq_printf(seq, "Tx gain digital: %d\n", tmp);
+ tmp = le16_to_cpu(st->tx_gain_pa);
+ seq_printf(seq, "Tx gain PA: %d\n", tmp);
+ tmp = (s16)le16_to_cpu(st->target_pout);
+ seq_printf(seq, "Target Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25);
+ tmp = (s16)le16_to_cpu(st->p_estimation);
+ seq_printf(seq, "FEM Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25);
+ tmp = le16_to_cpu(st->vpdet);
+ seq_printf(seq, "Vpdet: %d mV\n", tmp);
+ seq_printf(seq, "Measure index: %d\n", st->measurement_index);
+ mutex_unlock(&wdev->tx_power_loop_info_lock);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_tx_power_loop);
+
+static ssize_t wfx_send_pds_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wfx_dev *wdev = file->private_data;
+ char *buf;
+ int ret;
+
+ if (*ppos != 0) {
+ dev_dbg(wdev->dev, "PDS data must be written in one transaction");
+ return -EBUSY;
+ }
+ buf = memdup_user(user_buf, count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+ *ppos = *ppos + count;
+ ret = wfx_send_pds(wdev, buf, count);
+ kfree(buf);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+static const struct file_operations wfx_send_pds_fops = {
+ .open = simple_open,
+ .write = wfx_send_pds_write,
+};
+
+struct dbgfs_hif_msg {
+ struct wfx_dev *wdev;
+ struct completion complete;
+ u8 reply[1024];
+ int ret;
+};
+
+static ssize_t wfx_send_hif_msg_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct dbgfs_hif_msg *context = file->private_data;
+ struct wfx_dev *wdev = context->wdev;
+ struct hif_msg *request;
+
+ if (completion_done(&context->complete)) {
+ dev_dbg(wdev->dev, "read previous result before start a new one\n");
+ return -EBUSY;
+ }
+ if (count < sizeof(struct hif_msg))
+ return -EINVAL;
+
+ /* wfx_cmd_send() checks that reply buffer is wide enough, but does not
+ * return precise length read. User have to know how many bytes should
+ * be read. Filling reply buffer with a memory pattern may help user.
+ */
+ memset(context->reply, 0xFF, sizeof(context->reply));
+ request = memdup_user(user_buf, count);
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ if (le16_to_cpu(request->len) != count) {
+ kfree(request);
+ return -EINVAL;
+ }
+ context->ret = wfx_cmd_send(wdev, request, context->reply,
+ sizeof(context->reply), false);
+
+ kfree(request);
+ complete(&context->complete);
+ return count;
+}
+
+static ssize_t wfx_send_hif_msg_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct dbgfs_hif_msg *context = file->private_data;
+ int ret;
+
+ if (count > sizeof(context->reply))
+ return -EINVAL;
+ ret = wait_for_completion_interruptible(&context->complete);
+ if (ret)
+ return ret;
+ if (context->ret < 0)
+ return context->ret;
+ /* Be careful, write() is waiting for a full message while read()
+ * only returns a payload
+ */
+ if (copy_to_user(user_buf, context->reply, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static int wfx_send_hif_msg_open(struct inode *inode, struct file *file)
+{
+ struct dbgfs_hif_msg *context = kzalloc(sizeof(*context), GFP_KERNEL);
+
+ if (!context)
+ return -ENOMEM;
+ context->wdev = inode->i_private;
+ init_completion(&context->complete);
+ file->private_data = context;
+ return 0;
+}
+
+static int wfx_send_hif_msg_release(struct inode *inode, struct file *file)
+{
+ struct dbgfs_hif_msg *context = file->private_data;
+
+ kfree(context);
+ return 0;
+}
+
+static const struct file_operations wfx_send_hif_msg_fops = {
+ .open = wfx_send_hif_msg_open,
+ .release = wfx_send_hif_msg_release,
+ .write = wfx_send_hif_msg_write,
+ .read = wfx_send_hif_msg_read,
+};
+
+static int wfx_ps_timeout_set(void *data, u64 val)
+{
+ struct wfx_dev *wdev = (struct wfx_dev *)data;
+ struct wfx_vif *wvif;
+
+ wdev->force_ps_timeout = val;
+ wvif = NULL;
+ while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
+ wfx_update_pm(wvif);
+ return 0;
+}
+
+static int wfx_ps_timeout_get(void *data, u64 *val)
+{
+ struct wfx_dev *wdev = (struct wfx_dev *)data;
+
+ *val = wdev->force_ps_timeout;
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(wfx_ps_timeout_fops, wfx_ps_timeout_get, wfx_ps_timeout_set, "%lld\n");
+
+int wfx_debug_init(struct wfx_dev *wdev)
+{
+ struct dentry *d;
+
+ d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+ debugfs_create_file("counters", 0444, d, wdev, &wfx_counters_fops);
+ debugfs_create_file("rx_stats", 0444, d, wdev, &wfx_rx_stats_fops);
+ debugfs_create_file("tx_power_loop", 0444, d, wdev,
+ &wfx_tx_power_loop_fops);
+ debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops);
+ debugfs_create_file("send_hif_msg", 0600, d, wdev,
+ &wfx_send_hif_msg_fops);
+ debugfs_create_file("ps_timeout", 0600, d, wdev, &wfx_ps_timeout_fops);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/silabs/wfx/debug.h b/drivers/net/wireless/silabs/wfx/debug.h
new file mode 100644
index 000000000000..4b9c49a9fffb
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/debug.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Debugfs interface.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2011, ST-Ericsson
+ */
+#ifndef WFX_DEBUG_H
+#define WFX_DEBUG_H
+
+struct wfx_dev;
+
+int wfx_debug_init(struct wfx_dev *wdev);
+
+const char *get_hif_name(unsigned long id);
+const char *get_mib_name(unsigned long id);
+const char *get_reg_name(unsigned long id);
+
+#endif
--
2.29.2

2020-12-23 15:44:41

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 23/24] wfx: remove from the staging area

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
.../bindings/net/wireless/silabs,wfx.yaml | 125 ---
drivers/staging/wfx/Kconfig | 8 -
drivers/staging/wfx/Makefile | 25 -
drivers/staging/wfx/bh.c | 333 --------
drivers/staging/wfx/bh.h | 33 -
drivers/staging/wfx/bus.h | 38 -
drivers/staging/wfx/bus_sdio.c | 269 ------
drivers/staging/wfx/bus_spi.c | 271 ------
drivers/staging/wfx/data_rx.c | 93 --
drivers/staging/wfx/data_rx.h | 18 -
drivers/staging/wfx/data_tx.c | 585 -------------
drivers/staging/wfx/data_tx.h | 67 --
drivers/staging/wfx/debug.c | 359 --------
drivers/staging/wfx/debug.h | 19 -
drivers/staging/wfx/fwio.c | 405 ---------
drivers/staging/wfx/fwio.h | 15 -
drivers/staging/wfx/hif_api_cmd.h | 553 ------------
drivers/staging/wfx/hif_api_general.h | 267 ------
drivers/staging/wfx/hif_api_mib.h | 343 --------
drivers/staging/wfx/hif_rx.c | 415 ---------
drivers/staging/wfx/hif_rx.h | 18 -
drivers/staging/wfx/hif_tx.c | 523 ------------
drivers/staging/wfx/hif_tx.h | 60 --
drivers/staging/wfx/hif_tx_mib.c | 324 -------
drivers/staging/wfx/hif_tx_mib.h | 49 --
drivers/staging/wfx/hwio.c | 352 --------
drivers/staging/wfx/hwio.h | 75 --
drivers/staging/wfx/key.c | 241 ------
drivers/staging/wfx/key.h | 20 -
drivers/staging/wfx/main.c | 490 -----------
drivers/staging/wfx/main.h | 44 -
drivers/staging/wfx/queue.c | 304 -------
drivers/staging/wfx/queue.h | 45 -
drivers/staging/wfx/scan.c | 132 ---
drivers/staging/wfx/scan.h | 22 -
drivers/staging/wfx/sta.c | 807 ------------------
drivers/staging/wfx/sta.h | 73 --
drivers/staging/wfx/traces.h | 501 -----------
drivers/staging/wfx/wfx.h | 166 ----
39 files changed, 8487 deletions(-)
delete mode 100644 drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml
delete mode 100644 drivers/staging/wfx/Kconfig
delete mode 100644 drivers/staging/wfx/Makefile
delete mode 100644 drivers/staging/wfx/bh.c
delete mode 100644 drivers/staging/wfx/bh.h
delete mode 100644 drivers/staging/wfx/bus.h
delete mode 100644 drivers/staging/wfx/bus_sdio.c
delete mode 100644 drivers/staging/wfx/bus_spi.c
delete mode 100644 drivers/staging/wfx/data_rx.c
delete mode 100644 drivers/staging/wfx/data_rx.h
delete mode 100644 drivers/staging/wfx/data_tx.c
delete mode 100644 drivers/staging/wfx/data_tx.h
delete mode 100644 drivers/staging/wfx/debug.c
delete mode 100644 drivers/staging/wfx/debug.h
delete mode 100644 drivers/staging/wfx/fwio.c
delete mode 100644 drivers/staging/wfx/fwio.h
delete mode 100644 drivers/staging/wfx/hif_api_cmd.h
delete mode 100644 drivers/staging/wfx/hif_api_general.h
delete mode 100644 drivers/staging/wfx/hif_api_mib.h
delete mode 100644 drivers/staging/wfx/hif_rx.c
delete mode 100644 drivers/staging/wfx/hif_rx.h
delete mode 100644 drivers/staging/wfx/hif_tx.c
delete mode 100644 drivers/staging/wfx/hif_tx.h
delete mode 100644 drivers/staging/wfx/hif_tx_mib.c
delete mode 100644 drivers/staging/wfx/hif_tx_mib.h
delete mode 100644 drivers/staging/wfx/hwio.c
delete mode 100644 drivers/staging/wfx/hwio.h
delete mode 100644 drivers/staging/wfx/key.c
delete mode 100644 drivers/staging/wfx/key.h
delete mode 100644 drivers/staging/wfx/main.c
delete mode 100644 drivers/staging/wfx/main.h
delete mode 100644 drivers/staging/wfx/queue.c
delete mode 100644 drivers/staging/wfx/queue.h
delete mode 100644 drivers/staging/wfx/scan.c
delete mode 100644 drivers/staging/wfx/scan.h
delete mode 100644 drivers/staging/wfx/sta.c
delete mode 100644 drivers/staging/wfx/sta.h
delete mode 100644 drivers/staging/wfx/traces.h
delete mode 100644 drivers/staging/wfx/wfx.h

diff --git a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml
deleted file mode 100644
index 510edd12ed19..000000000000
--- a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml
+++ /dev/null
@@ -1,125 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-# Copyright (c) 2020, Silicon Laboratories, Inc.
-%YAML 1.2
----
-
-$id: http://devicetree.org/schemas/net/wireless/silabs,wfx.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Silicon Labs WFxxx devicetree bindings
-
-maintainers:
- - Jérôme Pouiller <[email protected]>
-
-description:
- The WFxxx chip series can be connected via SPI or via SDIO.
-
- For SDIO':'
-
- The driver is able to detect a WFxxx chip on SDIO bus by matching its Vendor
- ID and Product ID. However, driver will only provide limited features in
- this case. Thus declaring WFxxx chip in device tree is recommended (and may
- become mandatory in the future).
-
- In addition, it is recommended to declare a mmc-pwrseq on SDIO host above
- WFx. Without it, you may encounter issues with warm boot. The mmc-pwrseq
- should be compatible with mmc-pwrseq-simple. Please consult
- Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.yaml for more
- information.
-
- For SPI':'
-
- In add of the properties below, please consult
- Documentation/devicetree/bindings/spi/spi-controller.yaml for optional SPI
- related properties.
-
- Note that in add of the properties below, the WFx driver also supports
- `mac-address` and `local-mac-address` as described in
- Documentation/devicetree/bindings/net/ethernet.txt
-
-properties:
- compatible:
- const: silabs,wf200
- reg:
- description:
- When used on SDIO bus, <reg> must be set to 1. When used on SPI bus, it is
- the chip select address of the device as defined in the SPI devices
- bindings.
- maxItems: 1
- spi-max-frequency:
- description: (SPI only) Maximum SPI clocking speed of device in Hz.
- maxItems: 1
- interrupts:
- description: The interrupt line. Triggers IRQ_TYPE_LEVEL_HIGH and
- IRQ_TYPE_EDGE_RISING are both supported by the chip and the driver. When
- SPI is used, this property is required. When SDIO is used, the "in-band"
- interrupt provided by the SDIO bus is used unless an interrupt is defined
- in the Device Tree.
- maxItems: 1
- reset-gpios:
- description: (SPI only) Phandle of gpio that will be used to reset chip
- during probe. Without this property, you may encounter issues with warm
- boot. (For legacy purpose, the gpio in inverted when compatible ==
- "silabs,wfx-spi")
-
- For SDIO, the reset gpio should declared using a mmc-pwrseq.
- maxItems: 1
- wakeup-gpios:
- description: Phandle of gpio that will be used to wake-up chip. Without this
- property, driver will disable most of power saving features.
- maxItems: 1
- config-file:
- description: Use an alternative file as PDS. Default is `wf200.pds`. Only
- necessary for development/debug purpose.
- maxItems: 1
-
-required:
- - compatible
- - reg
-
-examples:
- - |
- #include <dt-bindings/gpio/gpio.h>
- #include <dt-bindings/interrupt-controller/irq.h>
-
- spi0 {
- #address-cells = <1>;
- #size-cells = <0>;
-
- wfx@0 {
- compatible = "silabs,wf200";
- pinctrl-names = "default";
- pinctrl-0 = <&wfx_irq &wfx_gpios>;
- reg = <0>;
- interrupts-extended = <&gpio 16 IRQ_TYPE_EDGE_RISING>;
- wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>;
- spi-max-frequency = <42000000>;
- };
- };
-
- - |
- #include <dt-bindings/gpio/gpio.h>
- #include <dt-bindings/interrupt-controller/irq.h>
-
- wfx_pwrseq: wfx_pwrseq {
- compatible = "mmc-pwrseq-simple";
- pinctrl-names = "default";
- pinctrl-0 = <&wfx_reset>;
- reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>;
- };
-
- mmc0 {
- mmc-pwrseq = <&wfx_pwrseq>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- mmc@1 {
- compatible = "silabs,wf200";
- pinctrl-names = "default";
- pinctrl-0 = <&wfx_wakeup>;
- reg = <1>;
- wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>;
- };
- };
-...
diff --git a/drivers/staging/wfx/Kconfig b/drivers/staging/wfx/Kconfig
deleted file mode 100644
index 83ee4d0ca8c6..000000000000
--- a/drivers/staging/wfx/Kconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-config WFX
- tristate "Silicon Labs wireless chips WF200 and further"
- depends on MAC80211
- depends on MMC || !MMC # do not allow WFX=y if MMC=m
- depends on (SPI || MMC)
- help
- This is a driver for Silicons Labs WFxxx series (WF200 and further)
- chipsets. This chip can be found on SPI or SDIO buses.
diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
deleted file mode 100644
index 0e0cc982ceab..000000000000
--- a/drivers/staging/wfx/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-# Necessary for CREATE_TRACE_POINTS
-CFLAGS_debug.o = -I$(src)
-
-wfx-y := \
- bh.o \
- hwio.o \
- fwio.o \
- hif_tx_mib.o \
- hif_tx.o \
- hif_rx.o \
- queue.o \
- data_tx.o \
- data_rx.o \
- scan.o \
- sta.o \
- key.o \
- main.o \
- sta.o \
- debug.o
-wfx-$(CONFIG_SPI) += bus_spi.o
-wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
-
-obj-$(CONFIG_WFX) += wfx.o
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
deleted file mode 100644
index ed53d0b45592..000000000000
--- a/drivers/staging/wfx/bh.c
+++ /dev/null
@@ -1,333 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Interrupt bottom half (BH).
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/gpio/consumer.h>
-#include <net/mac80211.h>
-
-#include "bh.h"
-#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)
-{
- int max_retry = 3;
-
- if (!wdev->pdata.gpio_wakeup)
- return;
- if (gpiod_get_value_cansleep(wdev->pdata.gpio_wakeup) > 0)
- return;
-
- if (wfx_api_older_than(wdev, 1, 4)) {
- gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1);
- if (!completion_done(&wdev->hif.ctrl_ready))
- usleep_range(2000, 2500);
- return;
- }
- for (;;) {
- gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1);
- // completion.h does not provide any function to wait
- // completion without consume it (a kind of
- // wait_for_completion_done_timeout()). So we have to emulate
- // it.
- if (wait_for_completion_timeout(&wdev->hif.ctrl_ready,
- msecs_to_jiffies(2))) {
- complete(&wdev->hif.ctrl_ready);
- return;
- } else if (max_retry-- > 0) {
- // Older firmwares have a race in sleep/wake-up process.
- // Redo the process is sufficient to unfreeze the
- // chip.
- dev_err(wdev->dev, "timeout while wake up chip\n");
- gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0);
- usleep_range(2000, 2500);
- } else {
- dev_err(wdev->dev, "max wake-up retries reached\n");
- return;
- }
- }
-}
-
-static void device_release(struct wfx_dev *wdev)
-{
- if (!wdev->pdata.gpio_wakeup)
- return;
-
- gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0);
-}
-
-static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
-{
- struct sk_buff *skb;
- struct hif_msg *hif;
- size_t alloc_len;
- size_t computed_len;
- int release_count;
- int piggyback = 0;
-
- WARN(read_len > round_down(0xFFF, 2) * sizeof(u16),
- "%s: request exceed WFx capability", __func__);
-
- // Add 2 to take into account piggyback size
- alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2);
- skb = dev_alloc_skb(alloc_len);
- if (!skb)
- return -ENOMEM;
-
- if (wfx_data_read(wdev, skb->data, alloc_len))
- goto err;
-
- piggyback = le16_to_cpup((__le16 *)(skb->data + alloc_len - 2));
- _trace_piggyback(piggyback, false);
-
- hif = (struct hif_msg *)skb->data;
- WARN(hif->encrypted & 0x3, "encryption is unsupported");
- if (WARN(read_len < sizeof(struct hif_msg), "corrupted read"))
- goto err;
- computed_len = le16_to_cpu(hif->len);
- computed_len = round_up(computed_len, 2);
- if (computed_len != read_len) {
- dev_err(wdev->dev, "inconsistent message length: %zu != %zu\n",
- computed_len, read_len);
- print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, 16, 1,
- hif, read_len, true);
- goto err;
- }
-
- if (!(hif->id & HIF_ID_IS_INDICATION)) {
- (*is_cnf)++;
- if (hif->id == HIF_CNF_ID_MULTI_TRANSMIT)
- release_count = ((struct hif_cnf_multi_transmit *)hif->body)->num_tx_confs;
- else
- release_count = 1;
- WARN(wdev->hif.tx_buffers_used < release_count, "corrupted buffer counter");
- wdev->hif.tx_buffers_used -= release_count;
- }
- _trace_hif_recv(hif, wdev->hif.tx_buffers_used);
-
- if (hif->id != HIF_IND_ID_EXCEPTION && hif->id != HIF_IND_ID_ERROR) {
- if (hif->seqnum != wdev->hif.rx_seqnum)
- dev_warn(wdev->dev, "wrong message sequence: %d != %d\n",
- hif->seqnum, wdev->hif.rx_seqnum);
- wdev->hif.rx_seqnum = (hif->seqnum + 1) % (HIF_COUNTER_MAX + 1);
- }
-
- skb_put(skb, le16_to_cpu(hif->len));
- // wfx_handle_rx takes care on SKB livetime
- wfx_handle_rx(wdev, skb);
- if (!wdev->hif.tx_buffers_used)
- wake_up(&wdev->hif.tx_buffers_empty);
-
- return piggyback;
-
-err:
- if (skb)
- dev_kfree_skb(skb);
- return -EIO;
-}
-
-static int bh_work_rx(struct wfx_dev *wdev, int max_msg, int *num_cnf)
-{
- size_t len;
- int i;
- int ctrl_reg, piggyback;
-
- piggyback = 0;
- for (i = 0; i < max_msg; i++) {
- if (piggyback & CTRL_NEXT_LEN_MASK)
- ctrl_reg = piggyback;
- else if (try_wait_for_completion(&wdev->hif.ctrl_ready))
- ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, 0);
- else
- ctrl_reg = 0;
- if (!(ctrl_reg & CTRL_NEXT_LEN_MASK))
- return i;
- // ctrl_reg units are 16bits words
- len = (ctrl_reg & CTRL_NEXT_LEN_MASK) * 2;
- piggyback = rx_helper(wdev, len, num_cnf);
- if (piggyback < 0)
- return i;
- if (!(piggyback & CTRL_WLAN_READY))
- dev_err(wdev->dev, "unexpected piggyback value: ready bit not set: %04x\n",
- piggyback);
- }
- if (piggyback & CTRL_NEXT_LEN_MASK) {
- ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, piggyback);
- complete(&wdev->hif.ctrl_ready);
- if (ctrl_reg)
- dev_err(wdev->dev, "unexpected IRQ happened: %04x/%04x\n",
- ctrl_reg, piggyback);
- }
- return i;
-}
-
-static void tx_helper(struct wfx_dev *wdev, struct hif_msg *hif)
-{
- int ret;
- void *data;
- bool is_encrypted = false;
- size_t len = le16_to_cpu(hif->len);
-
- WARN(len < sizeof(*hif), "try to send corrupted data");
-
- hif->seqnum = wdev->hif.tx_seqnum;
- wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1);
-
- data = hif;
- WARN(len > wdev->hw_caps.size_inp_ch_buf,
- "%s: request exceed WFx capability: %zu > %d\n", __func__,
- len, wdev->hw_caps.size_inp_ch_buf);
- len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, len);
- ret = wfx_data_write(wdev, data, len);
- if (ret)
- goto end;
-
- wdev->hif.tx_buffers_used++;
- _trace_hif_send(hif, wdev->hif.tx_buffers_used);
-end:
- if (is_encrypted)
- kfree(data);
-}
-
-static int bh_work_tx(struct wfx_dev *wdev, int max_msg)
-{
- struct hif_msg *hif;
- int i;
-
- for (i = 0; i < max_msg; i++) {
- hif = NULL;
- if (wdev->hif.tx_buffers_used < wdev->hw_caps.num_inp_ch_bufs) {
- if (try_wait_for_completion(&wdev->hif_cmd.ready)) {
- WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error");
- hif = wdev->hif_cmd.buf_send;
- } else {
- hif = wfx_tx_queues_get(wdev);
- }
- }
- if (!hif)
- return i;
- tx_helper(wdev, hif);
- }
- return i;
-}
-
-/* In SDIO mode, it is necessary to make an access to a register to acknowledge
- * last received message. It could be possible to restrict this acknowledge to
- * SDIO mode and only if last operation was rx.
- */
-static void ack_sdio_data(struct wfx_dev *wdev)
-{
- u32 cfg_reg;
-
- config_reg_read(wdev, &cfg_reg);
- if (cfg_reg & 0xFF) {
- dev_warn(wdev->dev, "chip reports errors: %02x\n",
- cfg_reg & 0xFF);
- config_reg_write_bits(wdev, 0xFF, 0x00);
- }
-}
-
-static void bh_work(struct work_struct *work)
-{
- struct wfx_dev *wdev = container_of(work, struct wfx_dev, hif.bh);
- int stats_req = 0, stats_cnf = 0, stats_ind = 0;
- bool release_chip = false, last_op_is_rx = false;
- int num_tx, num_rx;
-
- device_wakeup(wdev);
- do {
- num_tx = bh_work_tx(wdev, 32);
- stats_req += num_tx;
- if (num_tx)
- last_op_is_rx = false;
- num_rx = bh_work_rx(wdev, 32, &stats_cnf);
- stats_ind += num_rx;
- if (num_rx)
- last_op_is_rx = true;
- } while (num_rx || num_tx);
- stats_ind -= stats_cnf;
-
- if (last_op_is_rx)
- ack_sdio_data(wdev);
- if (!wdev->hif.tx_buffers_used && !work_pending(work)) {
- device_release(wdev);
- release_chip = true;
- }
- _trace_bh_stats(stats_ind, stats_req, stats_cnf,
- wdev->hif.tx_buffers_used, release_chip);
-}
-
-/*
- * An IRQ from chip did occur
- */
-void wfx_bh_request_rx(struct wfx_dev *wdev)
-{
- u32 cur, prev;
-
- control_reg_read(wdev, &cur);
- prev = atomic_xchg(&wdev->hif.ctrl_reg, cur);
- complete(&wdev->hif.ctrl_ready);
- queue_work(system_highpri_wq, &wdev->hif.bh);
-
- if (!(cur & CTRL_NEXT_LEN_MASK))
- dev_err(wdev->dev, "unexpected control register value: length field is 0: %04x\n",
- cur);
- if (prev != 0)
- dev_err(wdev->dev, "received IRQ but previous data was not (yet) read: %04x/%04x\n",
- prev, cur);
-}
-
-/*
- * Driver want to send data
- */
-void wfx_bh_request_tx(struct wfx_dev *wdev)
-{
- queue_work(system_highpri_wq, &wdev->hif.bh);
-}
-
-/*
- * If IRQ is not available, this function allow to manually poll the control
- * register and simulate an IRQ ahen an event happened.
- *
- * Note that the device has a bug: If an IRQ raise while host read control
- * register, the IRQ is lost. So, use this function carefully (only duing
- * device initialisation).
- */
-void wfx_bh_poll_irq(struct wfx_dev *wdev)
-{
- ktime_t now, start;
- u32 reg;
-
- WARN(!wdev->poll_irq, "unexpected IRQ polling can mask IRQ");
- start = ktime_get();
- for (;;) {
- control_reg_read(wdev, &reg);
- now = ktime_get();
- if (reg & 0xFFF)
- break;
- if (ktime_after(now, ktime_add_ms(start, 1000))) {
- dev_err(wdev->dev, "time out while polling control register\n");
- return;
- }
- udelay(200);
- }
- wfx_bh_request_rx(wdev);
-}
-
-void wfx_bh_register(struct wfx_dev *wdev)
-{
- INIT_WORK(&wdev->hif.bh, bh_work);
- init_completion(&wdev->hif.ctrl_ready);
- init_waitqueue_head(&wdev->hif.tx_buffers_empty);
-}
-
-void wfx_bh_unregister(struct wfx_dev *wdev)
-{
- flush_work(&wdev->hif.bh);
-}
diff --git a/drivers/staging/wfx/bh.h b/drivers/staging/wfx/bh.h
deleted file mode 100644
index 78c49329e22a..000000000000
--- a/drivers/staging/wfx/bh.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Interrupt bottom half.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_BH_H
-#define WFX_BH_H
-
-#include <linux/atomic.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-
-struct wfx_dev;
-
-struct wfx_hif {
- struct work_struct bh;
- struct completion ctrl_ready;
- wait_queue_head_t tx_buffers_empty;
- atomic_t ctrl_reg;
- int rx_seqnum;
- int tx_seqnum;
- int tx_buffers_used;
-};
-
-void wfx_bh_register(struct wfx_dev *wdev);
-void wfx_bh_unregister(struct wfx_dev *wdev);
-void wfx_bh_request_rx(struct wfx_dev *wdev);
-void wfx_bh_request_tx(struct wfx_dev *wdev);
-void wfx_bh_poll_irq(struct wfx_dev *wdev);
-
-#endif /* WFX_BH_H */
diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h
deleted file mode 100644
index ca04b3da6204..000000000000
--- a/drivers/staging/wfx/bus.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Common bus abstraction layer.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_BUS_H
-#define WFX_BUS_H
-
-#include <linux/mmc/sdio_func.h>
-#include <linux/spi/spi.h>
-
-#define WFX_REG_CONFIG 0x0
-#define WFX_REG_CONTROL 0x1
-#define WFX_REG_IN_OUT_QUEUE 0x2
-#define WFX_REG_AHB_DPORT 0x3
-#define WFX_REG_BASE_ADDR 0x4
-#define WFX_REG_SRAM_DPORT 0x5
-#define WFX_REG_SET_GEN_R_W 0x6
-#define WFX_REG_FRAME_OUT 0x7
-
-struct hwbus_ops {
- int (*copy_from_io)(void *bus_priv, unsigned int addr,
- void *dst, size_t count);
- int (*copy_to_io)(void *bus_priv, unsigned int addr,
- const void *src, size_t count);
- int (*irq_subscribe)(void *bus_priv);
- int (*irq_unsubscribe)(void *bus_priv);
- void (*lock)(void *bus_priv);
- void (*unlock)(void *bus_priv);
- size_t (*align_size)(void *bus_priv, size_t size);
-};
-
-extern struct sdio_driver wfx_sdio_driver;
-extern struct spi_driver wfx_spi_driver;
-
-#endif
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
deleted file mode 100644
index e06d7e1ebe9c..000000000000
--- a/drivers/staging/wfx/bus_sdio.c
+++ /dev/null
@@ -1,269 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * SDIO interface.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/module.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/card.h>
-#include <linux/interrupt.h>
-#include <linux/of_irq.h>
-#include <linux/irq.h>
-
-#include "bus.h"
-#include "wfx.h"
-#include "hwio.h"
-#include "main.h"
-#include "bh.h"
-
-static const struct wfx_platform_data wfx_sdio_pdata = {
- .file_fw = "wfm_wf200",
- .file_pds = "wf200.pds",
-};
-
-struct wfx_sdio_priv {
- struct sdio_func *func;
- struct wfx_dev *core;
- u8 buf_id_tx;
- u8 buf_id_rx;
- int of_irq;
-};
-
-static int wfx_sdio_copy_from_io(void *priv, unsigned int reg_id,
- void *dst, size_t count)
-{
- struct wfx_sdio_priv *bus = priv;
- unsigned int sdio_addr = reg_id << 2;
- int ret;
-
- WARN(reg_id > 7, "chip only has 7 registers");
- WARN(((uintptr_t)dst) & 3, "unaligned buffer size");
- WARN(count & 3, "unaligned buffer address");
-
- /* Use queue mode buffers */
- if (reg_id == WFX_REG_IN_OUT_QUEUE)
- sdio_addr |= (bus->buf_id_rx + 1) << 7;
- ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count);
- if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
- bus->buf_id_rx = (bus->buf_id_rx + 1) % 4;
-
- return ret;
-}
-
-static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id,
- const void *src, size_t count)
-{
- struct wfx_sdio_priv *bus = priv;
- unsigned int sdio_addr = reg_id << 2;
- int ret;
-
- WARN(reg_id > 7, "chip only has 7 registers");
- WARN(((uintptr_t)src) & 3, "unaligned buffer size");
- WARN(count & 3, "unaligned buffer address");
-
- /* Use queue mode buffers */
- if (reg_id == WFX_REG_IN_OUT_QUEUE)
- sdio_addr |= bus->buf_id_tx << 7;
- // FIXME: discards 'const' qualifier for src
- ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *)src, count);
- if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
- bus->buf_id_tx = (bus->buf_id_tx + 1) % 32;
-
- return ret;
-}
-
-static void wfx_sdio_lock(void *priv)
-{
- struct wfx_sdio_priv *bus = priv;
-
- sdio_claim_host(bus->func);
-}
-
-static void wfx_sdio_unlock(void *priv)
-{
- struct wfx_sdio_priv *bus = priv;
-
- sdio_release_host(bus->func);
-}
-
-static void wfx_sdio_irq_handler(struct sdio_func *func)
-{
- struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
-
- wfx_bh_request_rx(bus->core);
-}
-
-static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv)
-{
- struct wfx_sdio_priv *bus = priv;
-
- sdio_claim_host(bus->func);
- wfx_bh_request_rx(bus->core);
- sdio_release_host(bus->func);
- return IRQ_HANDLED;
-}
-
-static int wfx_sdio_irq_subscribe(void *priv)
-{
- struct wfx_sdio_priv *bus = priv;
- u32 flags;
- int ret;
- u8 cccr;
-
- if (!bus->of_irq) {
- sdio_claim_host(bus->func);
- ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler);
- sdio_release_host(bus->func);
- return ret;
- }
-
- sdio_claim_host(bus->func);
- cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL);
- cccr |= BIT(0);
- cccr |= BIT(bus->func->num);
- sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL);
- sdio_release_host(bus->func);
- flags = irq_get_trigger_type(bus->of_irq);
- if (!flags)
- flags = IRQF_TRIGGER_HIGH;
- flags |= IRQF_ONESHOT;
- return devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL,
- wfx_sdio_irq_handler_ext, flags,
- "wfx", bus);
-}
-
-static int wfx_sdio_irq_unsubscribe(void *priv)
-{
- struct wfx_sdio_priv *bus = priv;
- int ret;
-
- if (bus->of_irq)
- devm_free_irq(&bus->func->dev, bus->of_irq, bus);
- sdio_claim_host(bus->func);
- ret = sdio_release_irq(bus->func);
- sdio_release_host(bus->func);
- return ret;
-}
-
-static size_t wfx_sdio_align_size(void *priv, size_t size)
-{
- struct wfx_sdio_priv *bus = priv;
-
- return sdio_align_size(bus->func, size);
-}
-
-static const struct hwbus_ops wfx_sdio_hwbus_ops = {
- .copy_from_io = wfx_sdio_copy_from_io,
- .copy_to_io = wfx_sdio_copy_to_io,
- .irq_subscribe = wfx_sdio_irq_subscribe,
- .irq_unsubscribe = wfx_sdio_irq_unsubscribe,
- .lock = wfx_sdio_lock,
- .unlock = wfx_sdio_unlock,
- .align_size = wfx_sdio_align_size,
-};
-
-static const struct of_device_id wfx_sdio_of_match[] = {
- { .compatible = "silabs,wfx-sdio" },
- { .compatible = "silabs,wf200" },
- { },
-};
-MODULE_DEVICE_TABLE(of, wfx_sdio_of_match);
-
-static int wfx_sdio_probe(struct sdio_func *func,
- const struct sdio_device_id *id)
-{
- struct device_node *np = func->dev.of_node;
- struct wfx_sdio_priv *bus;
- int ret;
-
- if (func->num != 1) {
- dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n",
- func->num);
- return -ENODEV;
- }
-
- bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL);
- if (!bus)
- return -ENOMEM;
-
- if (np) {
- if (!of_match_node(wfx_sdio_of_match, np)) {
- dev_warn(&func->dev, "no compatible device found in DT\n");
- return -ENODEV;
- }
- bus->of_irq = irq_of_parse_and_map(np, 0);
- } else {
- dev_warn(&func->dev,
- "device is not declared in DT, features will be limited\n");
- // FIXME: ignore VID/PID and only rely on device tree
- // return -ENODEV;
- }
-
- bus->func = func;
- sdio_set_drvdata(func, bus);
- func->card->quirks |= MMC_QUIRK_LENIENT_FN0 |
- MMC_QUIRK_BLKSZ_FOR_BYTE_MODE |
- MMC_QUIRK_BROKEN_BYTE_MODE_512;
-
- sdio_claim_host(func);
- ret = sdio_enable_func(func);
- // Block of 64 bytes is more efficient than 512B for frame sizes < 4k
- sdio_set_block_size(func, 64);
- sdio_release_host(func);
- if (ret)
- goto err0;
-
- bus->core = wfx_init_common(&func->dev, &wfx_sdio_pdata,
- &wfx_sdio_hwbus_ops, bus);
- if (!bus->core) {
- ret = -EIO;
- goto err1;
- }
-
- ret = wfx_probe(bus->core);
- if (ret)
- goto err1;
-
- return 0;
-
-err1:
- sdio_claim_host(func);
- sdio_disable_func(func);
- sdio_release_host(func);
-err0:
- return ret;
-}
-
-static void wfx_sdio_remove(struct sdio_func *func)
-{
- struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
-
- wfx_release(bus->core);
- sdio_claim_host(func);
- sdio_disable_func(func);
- sdio_release_host(func);
-}
-
-#define SDIO_VENDOR_ID_SILABS 0x0000
-#define SDIO_DEVICE_ID_SILABS_WF200 0x1000
-static const struct sdio_device_id wfx_sdio_ids[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_SILABS, SDIO_DEVICE_ID_SILABS_WF200) },
- // FIXME: ignore VID/PID and only rely on device tree
- // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) },
- { },
-};
-MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids);
-
-struct sdio_driver wfx_sdio_driver = {
- .name = "wfx-sdio",
- .id_table = wfx_sdio_ids,
- .probe = wfx_sdio_probe,
- .remove = wfx_sdio_remove,
- .drv = {
- .owner = THIS_MODULE,
- .of_match_table = wfx_sdio_of_match,
- }
-};
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
deleted file mode 100644
index a99125d1a30d..000000000000
--- a/drivers/staging/wfx/bus_spi.c
+++ /dev/null
@@ -1,271 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * SPI interface.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2011, Sagrad Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
-#include <linux/spi/spi.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/of.h>
-
-#include "bus.h"
-#include "wfx.h"
-#include "hwio.h"
-#include "main.h"
-#include "bh.h"
-
-#define SET_WRITE 0x7FFF /* usage: and operation */
-#define SET_READ 0x8000 /* usage: or operation */
-
-#define WFX_RESET_INVERTED 1
-
-static const struct wfx_platform_data wfx_spi_pdata = {
- .file_fw = "wfm_wf200",
- .file_pds = "wf200.pds",
- .use_rising_clk = true,
-};
-
-struct wfx_spi_priv {
- struct spi_device *func;
- struct wfx_dev *core;
- struct gpio_desc *gpio_reset;
- bool need_swab;
-};
-
-/*
- * WFx chip read data 16bits at time and place them directly into (little
- * endian) CPU register. So, chip expect byte order like "B1 B0 B3 B2" (while
- * LE is "B0 B1 B2 B3" and BE is "B3 B2 B1 B0")
- *
- * A little endian host with bits_per_word == 16 should do the right job
- * natively. The code below to support big endian host and commonly used SPI
- * 8bits.
- */
-static int wfx_spi_copy_from_io(void *priv, unsigned int addr,
- void *dst, size_t count)
-{
- struct wfx_spi_priv *bus = priv;
- u16 regaddr = (addr << 12) | (count / 2) | SET_READ;
- struct spi_message m;
- struct spi_transfer t_addr = {
- .tx_buf = &regaddr,
- .len = sizeof(regaddr),
- };
- struct spi_transfer t_msg = {
- .rx_buf = dst,
- .len = count,
- };
- u16 *dst16 = dst;
- int ret, i;
-
- WARN(count % 2, "buffer size must be a multiple of 2");
-
- cpu_to_le16s(&regaddr);
- if (bus->need_swab)
- swab16s(&regaddr);
-
- spi_message_init(&m);
- spi_message_add_tail(&t_addr, &m);
- spi_message_add_tail(&t_msg, &m);
- ret = spi_sync(bus->func, &m);
-
- if (bus->need_swab && addr == WFX_REG_CONFIG)
- for (i = 0; i < count / 2; i++)
- swab16s(&dst16[i]);
- return ret;
-}
-
-static int wfx_spi_copy_to_io(void *priv, unsigned int addr,
- const void *src, size_t count)
-{
- struct wfx_spi_priv *bus = priv;
- u16 regaddr = (addr << 12) | (count / 2);
- // FIXME: use a bounce buffer
- u16 *src16 = (void *)src;
- int ret, i;
- struct spi_message m;
- struct spi_transfer t_addr = {
- .tx_buf = &regaddr,
- .len = sizeof(regaddr),
- };
- struct spi_transfer t_msg = {
- .tx_buf = src,
- .len = count,
- };
-
- WARN(count % 2, "buffer size must be a multiple of 2");
- WARN(regaddr & SET_READ, "bad addr or size overflow");
-
- cpu_to_le16s(&regaddr);
-
- // Register address and CONFIG content always use 16bit big endian
- // ("BADC" order)
- if (bus->need_swab)
- swab16s(&regaddr);
- if (bus->need_swab && addr == WFX_REG_CONFIG)
- for (i = 0; i < count / 2; i++)
- swab16s(&src16[i]);
-
- spi_message_init(&m);
- spi_message_add_tail(&t_addr, &m);
- spi_message_add_tail(&t_msg, &m);
- ret = spi_sync(bus->func, &m);
-
- if (bus->need_swab && addr == WFX_REG_CONFIG)
- for (i = 0; i < count / 2; i++)
- swab16s(&src16[i]);
- return ret;
-}
-
-static void wfx_spi_lock(void *priv)
-{
-}
-
-static void wfx_spi_unlock(void *priv)
-{
-}
-
-static irqreturn_t wfx_spi_irq_handler(int irq, void *priv)
-{
- struct wfx_spi_priv *bus = priv;
-
- wfx_bh_request_rx(bus->core);
- return IRQ_HANDLED;
-}
-
-static int wfx_spi_irq_subscribe(void *priv)
-{
- struct wfx_spi_priv *bus = priv;
- u32 flags;
-
- flags = irq_get_trigger_type(bus->func->irq);
- if (!flags)
- flags = IRQF_TRIGGER_HIGH;
- flags |= IRQF_ONESHOT;
- return devm_request_threaded_irq(&bus->func->dev, bus->func->irq, NULL,
- wfx_spi_irq_handler, IRQF_ONESHOT,
- "wfx", bus);
-}
-
-static int wfx_spi_irq_unsubscribe(void *priv)
-{
- struct wfx_spi_priv *bus = priv;
-
- devm_free_irq(&bus->func->dev, bus->func->irq, bus);
- return 0;
-}
-
-static size_t wfx_spi_align_size(void *priv, size_t size)
-{
- // Most of SPI controllers avoid DMA if buffer size is not 32bit aligned
- return ALIGN(size, 4);
-}
-
-static const struct hwbus_ops wfx_spi_hwbus_ops = {
- .copy_from_io = wfx_spi_copy_from_io,
- .copy_to_io = wfx_spi_copy_to_io,
- .irq_subscribe = wfx_spi_irq_subscribe,
- .irq_unsubscribe = wfx_spi_irq_unsubscribe,
- .lock = wfx_spi_lock,
- .unlock = wfx_spi_unlock,
- .align_size = wfx_spi_align_size,
-};
-
-static int wfx_spi_probe(struct spi_device *func)
-{
- struct wfx_spi_priv *bus;
- int ret;
-
- if (!func->bits_per_word)
- func->bits_per_word = 16;
- ret = spi_setup(func);
- if (ret)
- return ret;
- // Trace below is also displayed by spi_setup() if compiled with DEBUG
- dev_dbg(&func->dev, "SPI params: CS=%d, mode=%d bits/word=%d speed=%d\n",
- func->chip_select, func->mode, func->bits_per_word,
- func->max_speed_hz);
- if (func->bits_per_word != 16 && func->bits_per_word != 8)
- dev_warn(&func->dev, "unusual bits/word value: %d\n",
- func->bits_per_word);
- if (func->max_speed_hz > 50000000)
- dev_warn(&func->dev, "%dHz is a very high speed\n",
- func->max_speed_hz);
-
- bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL);
- if (!bus)
- return -ENOMEM;
- bus->func = func;
- if (func->bits_per_word == 8 || IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
- bus->need_swab = true;
- spi_set_drvdata(func, bus);
-
- bus->gpio_reset = devm_gpiod_get_optional(&func->dev, "reset",
- GPIOD_OUT_LOW);
- if (IS_ERR(bus->gpio_reset))
- return PTR_ERR(bus->gpio_reset);
- if (!bus->gpio_reset) {
- dev_warn(&func->dev,
- "gpio reset is not defined, trying to load firmware anyway\n");
- } else {
- gpiod_set_consumer_name(bus->gpio_reset, "wfx reset");
- if (spi_get_device_id(func)->driver_data & WFX_RESET_INVERTED)
- gpiod_toggle_active_low(bus->gpio_reset);
- gpiod_set_value_cansleep(bus->gpio_reset, 1);
- usleep_range(100, 150);
- gpiod_set_value_cansleep(bus->gpio_reset, 0);
- usleep_range(2000, 2500);
- }
-
- bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata,
- &wfx_spi_hwbus_ops, bus);
- if (!bus->core)
- return -EIO;
-
- return wfx_probe(bus->core);
-}
-
-static int wfx_spi_remove(struct spi_device *func)
-{
- struct wfx_spi_priv *bus = spi_get_drvdata(func);
-
- wfx_release(bus->core);
- return 0;
-}
-
-/*
- * For dynamic driver binding, kernel does not use OF to match driver. It only
- * use modalias and modalias is a copy of 'compatible' DT node with vendor
- * stripped.
- */
-static const struct spi_device_id wfx_spi_id[] = {
- { "wfx-spi", WFX_RESET_INVERTED },
- { "wf200", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(spi, wfx_spi_id);
-
-#ifdef CONFIG_OF
-static const struct of_device_id wfx_spi_of_match[] = {
- { .compatible = "silabs,wfx-spi", .data = (void *)WFX_RESET_INVERTED },
- { .compatible = "silabs,wf200" },
- { },
-};
-MODULE_DEVICE_TABLE(of, wfx_spi_of_match);
-#endif
-
-struct spi_driver wfx_spi_driver = {
- .driver = {
- .name = "wfx-spi",
- .of_match_table = of_match_ptr(wfx_spi_of_match),
- },
- .id_table = wfx_spi_id,
- .probe = wfx_spi_probe,
- .remove = wfx_spi_remove,
-};
diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c
deleted file mode 100644
index 385f2d42a0e2..000000000000
--- a/drivers/staging/wfx/data_rx.c
+++ /dev/null
@@ -1,93 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Datapath implementation.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/etherdevice.h>
-#include <net/mac80211.h>
-
-#include "data_rx.h"
-#include "wfx.h"
-#include "bh.h"
-#include "sta.h"
-
-static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt)
-{
- int params, tid;
-
- if (wfx_api_older_than(wvif->wdev, 3, 6))
- return;
-
- switch (mgmt->u.action.u.addba_req.action_code) {
- case WLAN_ACTION_ADDBA_REQ:
- params = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
- tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
- ieee80211_start_rx_ba_session_offl(wvif->vif, mgmt->sa, tid);
- break;
- case WLAN_ACTION_DELBA:
- params = le16_to_cpu(mgmt->u.action.u.delba.params);
- tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
- ieee80211_stop_rx_ba_session_offl(wvif->vif, mgmt->sa, tid);
- break;
- }
-}
-
-void wfx_rx_cb(struct wfx_vif *wvif,
- const struct hif_ind_rx *arg, struct sk_buff *skb)
-{
- struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb);
- struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data;
- struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
-
- memset(hdr, 0, sizeof(*hdr));
-
- if (arg->status == HIF_STATUS_RX_FAIL_MIC)
- hdr->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_IV_STRIPPED;
- else if (arg->status)
- goto drop;
-
- if (skb->len < sizeof(struct ieee80211_pspoll)) {
- dev_warn(wvif->wdev->dev, "malformed SDU received\n");
- goto drop;
- }
-
- hdr->band = NL80211_BAND_2GHZ;
- hdr->freq = ieee80211_channel_to_frequency(arg->channel_number,
- hdr->band);
-
- if (arg->rxed_rate >= 14) {
- hdr->encoding = RX_ENC_HT;
- hdr->rate_idx = arg->rxed_rate - 14;
- } else if (arg->rxed_rate >= 4) {
- hdr->rate_idx = arg->rxed_rate - 2;
- } else {
- hdr->rate_idx = arg->rxed_rate;
- }
-
- if (!arg->rcpi_rssi) {
- hdr->flag |= RX_FLAG_NO_SIGNAL_VAL;
- dev_info(wvif->wdev->dev, "received frame without RSSI data\n");
- }
- hdr->signal = arg->rcpi_rssi / 2 - 110;
- hdr->antenna = 0;
-
- if (arg->encryp)
- hdr->flag |= RX_FLAG_DECRYPTED;
-
- // Block ack negotiation is offloaded by the firmware. However,
- // re-ordering must be done by the mac80211.
- if (ieee80211_is_action(frame->frame_control) &&
- mgmt->u.action.category == WLAN_CATEGORY_BACK &&
- skb->len > IEEE80211_MIN_ACTION_SIZE) {
- wfx_rx_handle_ba(wvif, mgmt);
- goto drop;
- }
-
- ieee80211_rx_irqsafe(wvif->wdev->hw, skb);
- return;
-
-drop:
- dev_kfree_skb(skb);
-}
diff --git a/drivers/staging/wfx/data_rx.h b/drivers/staging/wfx/data_rx.h
deleted file mode 100644
index 4c0da37f2084..000000000000
--- a/drivers/staging/wfx/data_rx.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Datapath implementation.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_DATA_RX_H
-#define WFX_DATA_RX_H
-
-struct wfx_vif;
-struct sk_buff;
-struct hif_ind_rx;
-
-void wfx_rx_cb(struct wfx_vif *wvif,
- const struct hif_ind_rx *arg, struct sk_buff *skb);
-
-#endif /* WFX_DATA_RX_H */
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
deleted file mode 100644
index 36b36ef39d05..000000000000
--- a/drivers/staging/wfx/data_tx.c
+++ /dev/null
@@ -1,585 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Datapath implementation.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <net/mac80211.h>
-#include <linux/etherdevice.h>
-
-#include "data_tx.h"
-#include "wfx.h"
-#include "bh.h"
-#include "sta.h"
-#include "queue.h"
-#include "debug.h"
-#include "traces.h"
-#include "hif_tx_mib.h"
-
-static int wfx_get_hw_rate(struct wfx_dev *wdev,
- const struct ieee80211_tx_rate *rate)
-{
- struct ieee80211_supported_band *band;
-
- if (rate->idx < 0)
- return -1;
- if (rate->flags & IEEE80211_TX_RC_MCS) {
- if (rate->idx > 7) {
- WARN(1, "wrong rate->idx value: %d", rate->idx);
- return -1;
- }
- return rate->idx + 14;
- }
- // WFx only support 2GHz, else band information should be retrieved
- // from ieee80211_tx_info
- band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ];
- if (rate->idx >= band->n_bitrates) {
- WARN(1, "wrong rate->idx value: %d", rate->idx);
- return -1;
- }
- return band->bitrates[rate->idx].hw_value;
-}
-
-/* TX policy cache implementation */
-
-static void wfx_tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy,
- struct ieee80211_tx_rate *rates)
-{
- struct wfx_dev *wdev = wvif->wdev;
- int i, rateid;
- u8 count;
-
- WARN(rates[0].idx < 0, "invalid rate policy");
- memset(policy, 0, sizeof(*policy));
- for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) {
- if (rates[i].idx < 0)
- break;
- WARN_ON(rates[i].count > 15);
- rateid = wfx_get_hw_rate(wdev, &rates[i]);
- // Pack two values in each byte of policy->rates
- count = rates[i].count;
- if (rateid % 2)
- count <<= 4;
- policy->rates[rateid / 2] |= count;
- }
-}
-
-static bool tx_policy_is_equal(const struct tx_policy *a,
- const struct tx_policy *b)
-{
- return !memcmp(a->rates, b->rates, sizeof(a->rates));
-}
-
-static int wfx_tx_policy_find(struct tx_policy_cache *cache,
- struct tx_policy *wanted)
-{
- struct tx_policy *it;
-
- list_for_each_entry(it, &cache->used, link)
- if (tx_policy_is_equal(wanted, it))
- return it - cache->cache;
- list_for_each_entry(it, &cache->free, link)
- if (tx_policy_is_equal(wanted, it))
- return it - cache->cache;
- return -1;
-}
-
-static void wfx_tx_policy_use(struct tx_policy_cache *cache,
- struct tx_policy *entry)
-{
- ++entry->usage_count;
- list_move(&entry->link, &cache->used);
-}
-
-static int wfx_tx_policy_release(struct tx_policy_cache *cache,
- struct tx_policy *entry)
-{
- int ret = --entry->usage_count;
-
- if (!ret)
- list_move(&entry->link, &cache->free);
- return ret;
-}
-
-static int wfx_tx_policy_get(struct wfx_vif *wvif,
- struct ieee80211_tx_rate *rates, bool *renew)
-{
- int idx;
- struct tx_policy_cache *cache = &wvif->tx_policy_cache;
- struct tx_policy wanted;
-
- wfx_tx_policy_build(wvif, &wanted, rates);
-
- spin_lock_bh(&cache->lock);
- if (list_empty(&cache->free)) {
- WARN(1, "unable to get a valid Tx policy");
- spin_unlock_bh(&cache->lock);
- return HIF_TX_RETRY_POLICY_INVALID;
- }
- idx = wfx_tx_policy_find(cache, &wanted);
- if (idx >= 0) {
- *renew = false;
- } else {
- struct tx_policy *entry;
- *renew = true;
- /* If policy is not found create a new one
- * using the oldest entry in "free" list
- */
- entry = list_entry(cache->free.prev, struct tx_policy, link);
- memcpy(entry->rates, wanted.rates, sizeof(entry->rates));
- entry->uploaded = false;
- entry->usage_count = 0;
- idx = entry - cache->cache;
- }
- wfx_tx_policy_use(cache, &cache->cache[idx]);
- if (list_empty(&cache->free))
- ieee80211_stop_queues(wvif->wdev->hw);
- spin_unlock_bh(&cache->lock);
- return idx;
-}
-
-static void wfx_tx_policy_put(struct wfx_vif *wvif, int idx)
-{
- int usage, locked;
- struct tx_policy_cache *cache = &wvif->tx_policy_cache;
-
- if (idx == HIF_TX_RETRY_POLICY_INVALID)
- return;
- spin_lock_bh(&cache->lock);
- locked = list_empty(&cache->free);
- usage = wfx_tx_policy_release(cache, &cache->cache[idx]);
- if (locked && !usage)
- ieee80211_wake_queues(wvif->wdev->hw);
- spin_unlock_bh(&cache->lock);
-}
-
-static int wfx_tx_policy_upload(struct wfx_vif *wvif)
-{
- struct tx_policy *policies = wvif->tx_policy_cache.cache;
- u8 tmp_rates[12];
- int i, is_used;
-
- do {
- spin_lock_bh(&wvif->tx_policy_cache.lock);
- for (i = 0; i < ARRAY_SIZE(wvif->tx_policy_cache.cache); ++i) {
- is_used = memzcmp(policies[i].rates,
- sizeof(policies[i].rates));
- if (!policies[i].uploaded && is_used)
- break;
- }
- if (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)) {
- policies[i].uploaded = true;
- memcpy(tmp_rates, policies[i].rates, sizeof(tmp_rates));
- spin_unlock_bh(&wvif->tx_policy_cache.lock);
- hif_set_tx_rate_retry_policy(wvif, i, tmp_rates);
- } else {
- spin_unlock_bh(&wvif->tx_policy_cache.lock);
- }
- } while (i < ARRAY_SIZE(wvif->tx_policy_cache.cache));
- return 0;
-}
-
-void wfx_tx_policy_upload_work(struct work_struct *work)
-{
- struct wfx_vif *wvif =
- container_of(work, struct wfx_vif, tx_policy_upload_work);
-
- wfx_tx_policy_upload(wvif);
- wfx_tx_unlock(wvif->wdev);
-}
-
-void wfx_tx_policy_init(struct wfx_vif *wvif)
-{
- struct tx_policy_cache *cache = &wvif->tx_policy_cache;
- int i;
-
- memset(cache, 0, sizeof(*cache));
-
- spin_lock_init(&cache->lock);
- INIT_LIST_HEAD(&cache->used);
- INIT_LIST_HEAD(&cache->free);
-
- for (i = 0; i < ARRAY_SIZE(cache->cache); ++i)
- list_add(&cache->cache[i].link, &cache->free);
-}
-
-/* Tx implementation */
-
-static bool ieee80211_is_action_back(struct ieee80211_hdr *hdr)
-{
- struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr;
-
- if (!ieee80211_is_action(mgmt->frame_control))
- return false;
- if (mgmt->u.action.category != WLAN_CATEGORY_BACK)
- return false;
- return true;
-}
-
-static u8 wfx_tx_get_link_id(struct wfx_vif *wvif, struct ieee80211_sta *sta,
- struct ieee80211_hdr *hdr)
-{
- struct wfx_sta_priv *sta_priv =
- sta ? (struct wfx_sta_priv *)&sta->drv_priv : NULL;
- const u8 *da = ieee80211_get_DA(hdr);
-
- if (sta_priv && sta_priv->link_id)
- return sta_priv->link_id;
- if (wvif->vif->type != NL80211_IFTYPE_AP)
- return 0;
- if (is_multicast_ether_addr(da))
- return 0;
- return HIF_LINK_ID_NOT_ASSOCIATED;
-}
-
-static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates)
-{
- int i;
- bool finished;
-
- // Firmware is not able to mix rates with different flags
- for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
- if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
- rates[i].flags |= IEEE80211_TX_RC_SHORT_GI;
- if (!(rates[0].flags & IEEE80211_TX_RC_SHORT_GI))
- rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI;
- if (!(rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS))
- rates[i].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
- }
-
- // Sort rates and remove duplicates
- do {
- finished = true;
- for (i = 0; i < IEEE80211_TX_MAX_RATES - 1; i++) {
- if (rates[i + 1].idx == rates[i].idx &&
- rates[i].idx != -1) {
- rates[i].count += rates[i + 1].count;
- if (rates[i].count > 15)
- rates[i].count = 15;
- rates[i + 1].idx = -1;
- rates[i + 1].count = 0;
-
- finished = false;
- }
- if (rates[i + 1].idx > rates[i].idx) {
- swap(rates[i + 1], rates[i]);
- finished = false;
- }
- }
- } while (!finished);
- // Ensure that MCS0 or 1Mbps is present at the end of the retry list
- for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
- if (rates[i].idx == 0)
- break;
- if (rates[i].idx == -1) {
- rates[i].idx = 0;
- rates[i].count = 8; // == hw->max_rate_tries
- rates[i].flags = rates[i - 1].flags &
- IEEE80211_TX_RC_MCS;
- break;
- }
- }
- // All retries use long GI
- for (i = 1; i < IEEE80211_TX_MAX_RATES; i++)
- rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI;
-}
-
-static u8 wfx_tx_get_rate_id(struct wfx_vif *wvif,
- struct ieee80211_tx_info *tx_info)
-{
- bool tx_policy_renew = false;
- u8 rate_id;
-
- rate_id = wfx_tx_policy_get(wvif,
- tx_info->driver_rates, &tx_policy_renew);
- if (rate_id == HIF_TX_RETRY_POLICY_INVALID)
- dev_warn(wvif->wdev->dev, "unable to get a valid Tx policy");
-
- if (tx_policy_renew) {
- wfx_tx_lock(wvif->wdev);
- if (!schedule_work(&wvif->tx_policy_upload_work))
- wfx_tx_unlock(wvif->wdev);
- }
- return rate_id;
-}
-
-static int wfx_tx_get_frame_format(struct ieee80211_tx_info *tx_info)
-{
- if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_MCS))
- return HIF_FRAME_FORMAT_NON_HT;
- else if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD))
- return HIF_FRAME_FORMAT_MIXED_FORMAT_HT;
- else
- return HIF_FRAME_FORMAT_GF_HT_11N;
-}
-
-static int wfx_tx_get_icv_len(struct ieee80211_key_conf *hw_key)
-{
- int mic_space;
-
- if (!hw_key)
- return 0;
- if (hw_key->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
- return 0;
- mic_space = (hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) ? 8 : 0;
- return hw_key->icv_len + mic_space;
-}
-
-static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta,
- struct sk_buff *skb)
-{
- struct hif_msg *hif_msg;
- struct hif_req_tx *req;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- int queue_id = skb_get_queue_mapping(skb);
- size_t offset = (size_t)skb->data & 3;
- int wmsg_len = sizeof(struct hif_msg) +
- sizeof(struct hif_req_tx) + offset;
-
- WARN(queue_id >= IEEE80211_NUM_ACS, "unsupported queue_id");
- wfx_tx_fixup_rates(tx_info->driver_rates);
-
- // From now tx_info->control is unusable
- memset(tx_info->rate_driver_data, 0, sizeof(struct wfx_tx_priv));
-
- // Fill hif_msg
- WARN(skb_headroom(skb) < wmsg_len, "not enough space in skb");
- WARN(offset & 1, "attempt to transmit an unaligned frame");
- skb_put(skb, wfx_tx_get_icv_len(hw_key));
- skb_push(skb, wmsg_len);
- memset(skb->data, 0, wmsg_len);
- hif_msg = (struct hif_msg *)skb->data;
- hif_msg->len = cpu_to_le16(skb->len);
- hif_msg->id = HIF_REQ_ID_TX;
- hif_msg->interface = wvif->id;
- if (skb->len > wvif->wdev->hw_caps.size_inp_ch_buf) {
- dev_warn(wvif->wdev->dev,
- "requested frame size (%d) is larger than maximum supported (%d)\n",
- skb->len, wvif->wdev->hw_caps.size_inp_ch_buf);
- skb_pull(skb, wmsg_len);
- return -EIO;
- }
-
- // Fill tx request
- req = (struct hif_req_tx *)hif_msg->body;
- // packet_id just need to be unique on device. 32bits are more than
- // necessary for that task, so we tae advantage of it to add some extra
- // data for debug.
- req->packet_id = atomic_add_return(1, &wvif->wdev->packet_id) & 0xFFFF;
- req->packet_id |= IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)) << 16;
- req->packet_id |= queue_id << 28;
-
- req->fc_offset = offset;
- if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)
- req->after_dtim = 1;
- req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr);
- // Queue index are inverted between firmware and Linux
- req->queue_id = 3 - queue_id;
- req->retry_policy_index = wfx_tx_get_rate_id(wvif, tx_info);
- req->frame_format = wfx_tx_get_frame_format(tx_info);
- if (tx_info->driver_rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
- req->short_gi = 1;
-
- // Auxiliary operations
- wfx_tx_queues_put(wvif, skb);
- if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)
- schedule_work(&wvif->update_tim_work);
- wfx_bh_request_tx(wvif->wdev);
- return 0;
-}
-
-void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
- struct sk_buff *skb)
-{
- struct wfx_dev *wdev = hw->priv;
- struct wfx_vif *wvif;
- struct ieee80211_sta *sta = control ? control->sta : NULL;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- size_t driver_data_room = sizeof_field(struct ieee80211_tx_info,
- rate_driver_data);
-
- compiletime_assert(sizeof(struct wfx_tx_priv) <= driver_data_room,
- "struct tx_priv is too large");
- WARN(skb->next || skb->prev, "skb is already member of a list");
- // control.vif can be NULL for injected frames
- if (tx_info->control.vif)
- wvif = (struct wfx_vif *)tx_info->control.vif->drv_priv;
- else
- wvif = wvif_iterate(wdev, NULL);
- if (WARN_ON(!wvif))
- goto drop;
- // Because of TX_AMPDU_SETUP_IN_HW, mac80211 does not try to send any
- // BlockAck session management frame. The check below exist just in case.
- if (ieee80211_is_action_back(hdr)) {
- dev_info(wdev->dev, "drop BA action\n");
- goto drop;
- }
- if (wfx_tx_inner(wvif, sta, skb))
- goto drop;
-
- return;
-
-drop:
- ieee80211_tx_status_irqsafe(wdev->hw, skb);
-}
-
-static void wfx_skb_dtor(struct wfx_vif *wvif, struct sk_buff *skb)
-{
- struct hif_msg *hif = (struct hif_msg *)skb->data;
- struct hif_req_tx *req = (struct hif_req_tx *)hif->body;
- unsigned int offset = sizeof(struct hif_msg) +
- sizeof(struct hif_req_tx) +
- req->fc_offset;
-
- if (!wvif) {
- pr_warn("%s: vif associated with the skb does not exist anymore\n", __func__);
- return;
- }
- wfx_tx_policy_put(wvif, req->retry_policy_index);
- skb_pull(skb, offset);
- ieee80211_tx_status_irqsafe(wvif->wdev->hw, skb);
-}
-
-static void wfx_tx_fill_rates(struct wfx_dev *wdev,
- struct ieee80211_tx_info *tx_info,
- const struct hif_cnf_tx *arg)
-{
- struct ieee80211_tx_rate *rate;
- int tx_count;
- int i;
-
- tx_count = arg->ack_failures;
- if (!arg->status || arg->ack_failures)
- tx_count += 1; // Also report success
- for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
- rate = &tx_info->status.rates[i];
- if (rate->idx < 0)
- break;
- if (tx_count < rate->count &&
- arg->status == HIF_STATUS_TX_FAIL_RETRIES &&
- arg->ack_failures)
- dev_dbg(wdev->dev, "all retries were not consumed: %d != %d\n",
- rate->count, tx_count);
- if (tx_count <= rate->count && tx_count &&
- arg->txed_rate != wfx_get_hw_rate(wdev, rate))
- dev_dbg(wdev->dev, "inconsistent tx_info rates: %d != %d\n",
- arg->txed_rate, wfx_get_hw_rate(wdev, rate));
- if (tx_count > rate->count) {
- tx_count -= rate->count;
- } else if (!tx_count) {
- rate->count = 0;
- rate->idx = -1;
- } else {
- rate->count = tx_count;
- tx_count = 0;
- }
- }
- if (tx_count)
- dev_dbg(wdev->dev, "%d more retries than expected\n", tx_count);
-}
-
-void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg)
-{
- struct ieee80211_tx_info *tx_info;
- struct wfx_vif *wvif;
- struct sk_buff *skb;
-
- skb = wfx_pending_get(wdev, arg->packet_id);
- if (!skb) {
- dev_warn(wdev->dev, "received unknown packet_id (%#.8x) from chip\n",
- arg->packet_id);
- return;
- }
- tx_info = IEEE80211_SKB_CB(skb);
- wvif = wdev_to_wvif(wdev, ((struct hif_msg *)skb->data)->interface);
- WARN_ON(!wvif);
- if (!wvif)
- return;
-
- // Note that wfx_pending_get_pkt_us_delay() get data from tx_info
- _trace_tx_stats(arg, skb, wfx_pending_get_pkt_us_delay(wdev, skb));
- wfx_tx_fill_rates(wdev, tx_info, arg);
- // From now, you can touch to tx_info->status, but do not touch to
- // tx_priv anymore
- // FIXME: use ieee80211_tx_info_clear_status()
- memset(tx_info->rate_driver_data, 0, sizeof(tx_info->rate_driver_data));
- memset(tx_info->pad, 0, sizeof(tx_info->pad));
-
- if (!arg->status) {
- tx_info->status.tx_time =
- le32_to_cpu(arg->media_delay) -
- le32_to_cpu(arg->tx_queue_delay);
- if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
- tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
- else
- tx_info->flags |= IEEE80211_TX_STAT_ACK;
- } else if (arg->status == HIF_STATUS_TX_FAIL_REQUEUE) {
- WARN(!arg->requeue, "incoherent status and result_flags");
- if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
- wvif->after_dtim_tx_allowed = false; // DTIM period elapsed
- schedule_work(&wvif->update_tim_work);
- }
- tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- }
- wfx_skb_dtor(wvif, skb);
-}
-
-static void wfx_flush_vif(struct wfx_vif *wvif, u32 queues,
- struct sk_buff_head *dropped)
-{
- struct wfx_queue *queue;
- int i;
-
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- if (!(BIT(i) & queues))
- continue;
- queue = &wvif->tx_queue[i];
- if (dropped)
- wfx_tx_queue_drop(wvif, queue, dropped);
- }
- if (wvif->wdev->chip_frozen)
- return;
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- if (!(BIT(i) & queues))
- continue;
- queue = &wvif->tx_queue[i];
- if (wait_event_timeout(wvif->wdev->tx_dequeue,
- wfx_tx_queue_empty(wvif, queue),
- msecs_to_jiffies(1000)) <= 0)
- dev_warn(wvif->wdev->dev,
- "frames queued while flushing tx queues?");
- }
-}
-
-void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u32 queues, bool drop)
-{
- struct wfx_dev *wdev = hw->priv;
- struct sk_buff_head dropped;
- struct wfx_vif *wvif;
- struct hif_msg *hif;
- struct sk_buff *skb;
-
- skb_queue_head_init(&dropped);
- if (vif) {
- wvif = (struct wfx_vif *)vif->drv_priv;
- wfx_flush_vif(wvif, queues, drop ? &dropped : NULL);
- } else {
- wvif = NULL;
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
- wfx_flush_vif(wvif, queues, drop ? &dropped : NULL);
- }
- wfx_tx_flush(wdev);
- if (wdev->chip_frozen)
- wfx_pending_drop(wdev, &dropped);
- while ((skb = skb_dequeue(&dropped)) != NULL) {
- hif = (struct hif_msg *)skb->data;
- wvif = wdev_to_wvif(wdev, hif->interface);
- ieee80211_tx_info_clear_status(IEEE80211_SKB_CB(skb));
- wfx_skb_dtor(wvif, skb);
- }
-}
diff --git a/drivers/staging/wfx/data_tx.h b/drivers/staging/wfx/data_tx.h
deleted file mode 100644
index 46c9fff7a870..000000000000
--- a/drivers/staging/wfx/data_tx.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Datapath implementation.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_DATA_TX_H
-#define WFX_DATA_TX_H
-
-#include <linux/list.h>
-#include <net/mac80211.h>
-
-#include "hif_api_cmd.h"
-#include "hif_api_mib.h"
-
-struct wfx_tx_priv;
-struct wfx_dev;
-struct wfx_vif;
-
-struct tx_policy {
- struct list_head link;
- int usage_count;
- u8 rates[12];
- bool uploaded;
-};
-
-struct tx_policy_cache {
- struct tx_policy cache[HIF_TX_RETRY_POLICY_MAX];
- // FIXME: use a trees and drop hash from tx_policy
- struct list_head used;
- struct list_head free;
- spinlock_t lock;
-};
-
-struct wfx_tx_priv {
- ktime_t xmit_timestamp;
-};
-
-void wfx_tx_policy_init(struct wfx_vif *wvif);
-void wfx_tx_policy_upload_work(struct work_struct *work);
-
-void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
- struct sk_buff *skb);
-void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg);
-void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u32 queues, bool drop);
-
-static inline struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb)
-{
- struct ieee80211_tx_info *tx_info;
-
- if (!skb)
- return NULL;
- tx_info = IEEE80211_SKB_CB(skb);
- return (struct wfx_tx_priv *)tx_info->rate_driver_data;
-}
-
-static inline struct hif_req_tx *wfx_skb_txreq(struct sk_buff *skb)
-{
- struct hif_msg *hif = (struct hif_msg *)skb->data;
- struct hif_req_tx *req = (struct hif_req_tx *)hif->body;
-
- return req;
-}
-
-#endif /* WFX_DATA_TX_H */
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
deleted file mode 100644
index eedada78c25f..000000000000
--- a/drivers/staging/wfx/debug.c
+++ /dev/null
@@ -1,359 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Debugfs interface.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/crc32.h>
-
-#include "debug.h"
-#include "wfx.h"
-#include "sta.h"
-#include "main.h"
-#include "hif_tx.h"
-#include "hif_tx_mib.h"
-
-#define CREATE_TRACE_POINTS
-#include "traces.h"
-
-static const struct trace_print_flags hif_msg_print_map[] = {
- hif_msg_list,
-};
-
-static const struct trace_print_flags hif_mib_print_map[] = {
- hif_mib_list,
-};
-
-static const struct trace_print_flags wfx_reg_print_map[] = {
- wfx_reg_list,
-};
-
-static const char *get_symbol(unsigned long val,
- const struct trace_print_flags *symbol_array)
-{
- int i;
-
- for (i = 0; symbol_array[i].mask != -1; i++) {
- if (val == symbol_array[i].mask)
- return symbol_array[i].name;
- }
-
- return "unknown";
-}
-
-const char *get_hif_name(unsigned long id)
-{
- return get_symbol(id, hif_msg_print_map);
-}
-
-const char *get_mib_name(unsigned long id)
-{
- return get_symbol(id, hif_mib_print_map);
-}
-
-const char *get_reg_name(unsigned long id)
-{
- return get_symbol(id, wfx_reg_print_map);
-}
-
-static int wfx_counters_show(struct seq_file *seq, void *v)
-{
- int ret, i;
- struct wfx_dev *wdev = seq->private;
- struct hif_mib_extended_count_table counters[3];
-
- for (i = 0; i < ARRAY_SIZE(counters); i++) {
- ret = hif_get_counters_table(wdev, i, counters + i);
- if (ret < 0)
- return ret;
- if (ret > 0)
- return -EIO;
- }
-
- seq_printf(seq, "%-24s %12s %12s %12s\n",
- "", "global", "iface 0", "iface 1");
-
-#define PUT_COUNTER(name) \
- seq_printf(seq, "%-24s %12d %12d %12d\n", #name, \
- le32_to_cpu(counters[2].count_##name), \
- le32_to_cpu(counters[0].count_##name), \
- le32_to_cpu(counters[1].count_##name))
-
- PUT_COUNTER(tx_packets);
- PUT_COUNTER(tx_multicast_frames);
- PUT_COUNTER(tx_frames_success);
- PUT_COUNTER(tx_frame_failures);
- PUT_COUNTER(tx_frames_retried);
- PUT_COUNTER(tx_frames_multi_retried);
-
- PUT_COUNTER(rts_success);
- PUT_COUNTER(rts_failures);
- PUT_COUNTER(ack_failures);
-
- PUT_COUNTER(rx_packets);
- PUT_COUNTER(rx_frames_success);
- PUT_COUNTER(rx_packet_errors);
- PUT_COUNTER(plcp_errors);
- PUT_COUNTER(fcs_errors);
- PUT_COUNTER(rx_decryption_failures);
- PUT_COUNTER(rx_mic_failures);
- PUT_COUNTER(rx_no_key_failures);
- PUT_COUNTER(rx_frame_duplicates);
- PUT_COUNTER(rx_multicast_frames);
- PUT_COUNTER(rx_cmacicv_errors);
- PUT_COUNTER(rx_cmac_replays);
- PUT_COUNTER(rx_mgmt_ccmp_replays);
-
- PUT_COUNTER(rx_beacon);
- PUT_COUNTER(miss_beacon);
-
-#undef PUT_COUNTER
-
- for (i = 0; i < ARRAY_SIZE(counters[0].reserved); i++)
- seq_printf(seq, "reserved[%02d]%12s %12d %12d %12d\n", i, "",
- le32_to_cpu(counters[2].reserved[i]),
- le32_to_cpu(counters[0].reserved[i]),
- le32_to_cpu(counters[1].reserved[i]));
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(wfx_counters);
-
-static const char * const channel_names[] = {
- [0] = "1M",
- [1] = "2M",
- [2] = "5.5M",
- [3] = "11M",
- /* Entries 4 and 5 does not exist */
- [6] = "6M",
- [7] = "9M",
- [8] = "12M",
- [9] = "18M",
- [10] = "24M",
- [11] = "36M",
- [12] = "48M",
- [13] = "54M",
- [14] = "MCS0",
- [15] = "MCS1",
- [16] = "MCS2",
- [17] = "MCS3",
- [18] = "MCS4",
- [19] = "MCS5",
- [20] = "MCS6",
- [21] = "MCS7",
-};
-
-static int wfx_rx_stats_show(struct seq_file *seq, void *v)
-{
- struct wfx_dev *wdev = seq->private;
- struct hif_rx_stats *st = &wdev->rx_stats;
- int i;
-
- mutex_lock(&wdev->rx_stats_lock);
- seq_printf(seq, "Timestamp: %dus\n", st->date);
- seq_printf(seq, "Low power clock: frequency %uHz, external %s\n",
- le32_to_cpu(st->pwr_clk_freq),
- st->is_ext_pwr_clk ? "yes" : "no");
- seq_printf(seq,
- "Num. of frames: %d, PER (x10e4): %d, Throughput: %dKbps/s\n",
- st->nb_rx_frame, st->per_total, st->throughput);
- seq_puts(seq, " Num. of PER RSSI SNR CFO\n");
- seq_puts(seq, " frames (x10e4) (dBm) (dB) (kHz)\n");
- for (i = 0; i < ARRAY_SIZE(channel_names); i++) {
- if (channel_names[i])
- seq_printf(seq, "%5s %8d %8d %8d %8d %8d\n",
- channel_names[i],
- le32_to_cpu(st->nb_rx_by_rate[i]),
- le16_to_cpu(st->per[i]),
- (s16)le16_to_cpu(st->rssi[i]) / 100,
- (s16)le16_to_cpu(st->snr[i]) / 100,
- (s16)le16_to_cpu(st->cfo[i]));
- }
- mutex_unlock(&wdev->rx_stats_lock);
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats);
-
-static int wfx_tx_power_loop_show(struct seq_file *seq, void *v)
-{
- struct wfx_dev *wdev = seq->private;
- struct hif_tx_power_loop_info *st = &wdev->tx_power_loop_info;
- int tmp;
-
- mutex_lock(&wdev->tx_power_loop_info_lock);
- tmp = le16_to_cpu(st->tx_gain_dig);
- seq_printf(seq, "Tx gain digital: %d\n", tmp);
- tmp = le16_to_cpu(st->tx_gain_pa);
- seq_printf(seq, "Tx gain PA: %d\n", tmp);
- tmp = (s16)le16_to_cpu(st->target_pout);
- seq_printf(seq, "Target Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25);
- tmp = (s16)le16_to_cpu(st->p_estimation);
- seq_printf(seq, "FEM Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25);
- tmp = le16_to_cpu(st->vpdet);
- seq_printf(seq, "Vpdet: %d mV\n", tmp);
- seq_printf(seq, "Measure index: %d\n", st->measurement_index);
- mutex_unlock(&wdev->tx_power_loop_info_lock);
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(wfx_tx_power_loop);
-
-static ssize_t wfx_send_pds_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct wfx_dev *wdev = file->private_data;
- char *buf;
- int ret;
-
- if (*ppos != 0) {
- dev_dbg(wdev->dev, "PDS data must be written in one transaction");
- return -EBUSY;
- }
- buf = memdup_user(user_buf, count);
- if (IS_ERR(buf))
- return PTR_ERR(buf);
- *ppos = *ppos + count;
- ret = wfx_send_pds(wdev, buf, count);
- kfree(buf);
- if (ret < 0)
- return ret;
- return count;
-}
-
-static const struct file_operations wfx_send_pds_fops = {
- .open = simple_open,
- .write = wfx_send_pds_write,
-};
-
-struct dbgfs_hif_msg {
- struct wfx_dev *wdev;
- struct completion complete;
- u8 reply[1024];
- int ret;
-};
-
-static ssize_t wfx_send_hif_msg_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct dbgfs_hif_msg *context = file->private_data;
- struct wfx_dev *wdev = context->wdev;
- struct hif_msg *request;
-
- if (completion_done(&context->complete)) {
- dev_dbg(wdev->dev, "read previous result before start a new one\n");
- return -EBUSY;
- }
- if (count < sizeof(struct hif_msg))
- return -EINVAL;
-
- // wfx_cmd_send() checks that reply buffer is wide enough, but does not
- // return precise length read. User have to know how many bytes should
- // be read. Filling reply buffer with a memory pattern may help user.
- memset(context->reply, 0xFF, sizeof(context->reply));
- request = memdup_user(user_buf, count);
- if (IS_ERR(request))
- return PTR_ERR(request);
- if (le16_to_cpu(request->len) != count) {
- kfree(request);
- return -EINVAL;
- }
- context->ret = wfx_cmd_send(wdev, request, context->reply,
- sizeof(context->reply), false);
-
- kfree(request);
- complete(&context->complete);
- return count;
-}
-
-static ssize_t wfx_send_hif_msg_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct dbgfs_hif_msg *context = file->private_data;
- int ret;
-
- if (count > sizeof(context->reply))
- return -EINVAL;
- ret = wait_for_completion_interruptible(&context->complete);
- if (ret)
- return ret;
- if (context->ret < 0)
- return context->ret;
- // Be careful, write() is waiting for a full message while read()
- // only returns a payload
- if (copy_to_user(user_buf, context->reply, count))
- return -EFAULT;
-
- return count;
-}
-
-static int wfx_send_hif_msg_open(struct inode *inode, struct file *file)
-{
- struct dbgfs_hif_msg *context = kzalloc(sizeof(*context), GFP_KERNEL);
-
- if (!context)
- return -ENOMEM;
- context->wdev = inode->i_private;
- init_completion(&context->complete);
- file->private_data = context;
- return 0;
-}
-
-static int wfx_send_hif_msg_release(struct inode *inode, struct file *file)
-{
- struct dbgfs_hif_msg *context = file->private_data;
-
- kfree(context);
- return 0;
-}
-
-static const struct file_operations wfx_send_hif_msg_fops = {
- .open = wfx_send_hif_msg_open,
- .release = wfx_send_hif_msg_release,
- .write = wfx_send_hif_msg_write,
- .read = wfx_send_hif_msg_read,
-};
-
-static int wfx_ps_timeout_set(void *data, u64 val)
-{
- struct wfx_dev *wdev = (struct wfx_dev *)data;
- struct wfx_vif *wvif;
-
- wdev->force_ps_timeout = val;
- wvif = NULL;
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
- wfx_update_pm(wvif);
- return 0;
-}
-
-static int wfx_ps_timeout_get(void *data, u64 *val)
-{
- struct wfx_dev *wdev = (struct wfx_dev *)data;
-
- *val = wdev->force_ps_timeout;
- return 0;
-}
-
-DEFINE_DEBUGFS_ATTRIBUTE(wfx_ps_timeout_fops, wfx_ps_timeout_get, wfx_ps_timeout_set, "%lld\n");
-
-int wfx_debug_init(struct wfx_dev *wdev)
-{
- struct dentry *d;
-
- d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
- debugfs_create_file("counters", 0444, d, wdev, &wfx_counters_fops);
- debugfs_create_file("rx_stats", 0444, d, wdev, &wfx_rx_stats_fops);
- debugfs_create_file("tx_power_loop", 0444, d, wdev,
- &wfx_tx_power_loop_fops);
- debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops);
- debugfs_create_file("send_hif_msg", 0600, d, wdev,
- &wfx_send_hif_msg_fops);
- debugfs_create_file("ps_timeout", 0600, d, wdev, &wfx_ps_timeout_fops);
-
- return 0;
-}
diff --git a/drivers/staging/wfx/debug.h b/drivers/staging/wfx/debug.h
deleted file mode 100644
index 6f2f84d64c9e..000000000000
--- a/drivers/staging/wfx/debug.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Debugfs interface.
- *
- * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
- * Copyright (c) 2011, ST-Ericsson
- */
-#ifndef WFX_DEBUG_H
-#define WFX_DEBUG_H
-
-struct wfx_dev;
-
-int wfx_debug_init(struct wfx_dev *wdev);
-
-const char *get_hif_name(unsigned long id);
-const char *get_mib_name(unsigned long id);
-const char *get_reg_name(unsigned long id);
-
-#endif /* WFX_DEBUG_H */
diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c
deleted file mode 100644
index 1b8aec02d169..000000000000
--- a/drivers/staging/wfx/fwio.c
+++ /dev/null
@@ -1,405 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Firmware loading.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/bitfield.h>
-
-#include "fwio.h"
-#include "wfx.h"
-#include "hwio.h"
-
-// Addresses below are in SRAM area
-#define WFX_DNLD_FIFO 0x09004000
-#define DNLD_BLOCK_SIZE 0x0400
-#define DNLD_FIFO_SIZE 0x8000 // (32 * DNLD_BLOCK_SIZE)
-// Download Control Area (DCA)
-#define WFX_DCA_IMAGE_SIZE 0x0900C000
-#define WFX_DCA_PUT 0x0900C004
-#define WFX_DCA_GET 0x0900C008
-#define WFX_DCA_HOST_STATUS 0x0900C00C
-#define HOST_READY 0x87654321
-#define HOST_INFO_READ 0xA753BD99
-#define HOST_UPLOAD_PENDING 0xABCDDCBA
-#define HOST_UPLOAD_COMPLETE 0xD4C64A99
-#define HOST_OK_TO_JUMP 0x174FC882
-#define WFX_DCA_NCP_STATUS 0x0900C010
-#define NCP_NOT_READY 0x12345678
-#define NCP_READY 0x87654321
-#define NCP_INFO_READY 0xBD53EF99
-#define NCP_DOWNLOAD_PENDING 0xABCDDCBA
-#define NCP_DOWNLOAD_COMPLETE 0xCAFEFECA
-#define NCP_AUTH_OK 0xD4C64A99
-#define NCP_AUTH_FAIL 0x174FC882
-#define NCP_PUB_KEY_RDY 0x7AB41D19
-#define WFX_DCA_FW_SIGNATURE 0x0900C014
-#define FW_SIGNATURE_SIZE 0x40
-#define WFX_DCA_FW_HASH 0x0900C054
-#define FW_HASH_SIZE 0x08
-#define WFX_DCA_FW_VERSION 0x0900C05C
-#define FW_VERSION_SIZE 0x04
-#define WFX_DCA_RESERVED 0x0900C060
-#define DCA_RESERVED_SIZE 0x20
-#define WFX_STATUS_INFO 0x0900C080
-#define WFX_BOOTLOADER_LABEL 0x0900C084
-#define BOOTLOADER_LABEL_SIZE 0x3C
-#define WFX_PTE_INFO 0x0900C0C0
-#define PTE_INFO_KEYSET_IDX 0x0D
-#define PTE_INFO_SIZE 0x10
-#define WFX_ERR_INFO 0x0900C0D0
-#define ERR_INVALID_SEC_TYPE 0x05
-#define ERR_SIG_VERIF_FAILED 0x0F
-#define ERR_AES_CTRL_KEY 0x10
-#define ERR_ECC_PUB_KEY 0x11
-#define ERR_MAC_KEY 0x18
-
-#define DCA_TIMEOUT 50 // milliseconds
-#define WAKEUP_TIMEOUT 200 // milliseconds
-
-static const char * const fwio_errors[] = {
- [ERR_INVALID_SEC_TYPE] = "Invalid section type or wrong encryption",
- [ERR_SIG_VERIF_FAILED] = "Signature verification failed",
- [ERR_AES_CTRL_KEY] = "AES control key not initialized",
- [ERR_ECC_PUB_KEY] = "ECC public key not initialized",
- [ERR_MAC_KEY] = "MAC key not initialized",
-};
-
-/*
- * request_firmware() allocate data using vmalloc(). It is not compatible with
- * underlying hardware that use DMA. Function below detect this case and
- * allocate a bounce buffer if necessary.
- *
- * Notice that, in doubt, you can enable CONFIG_DEBUG_SG to ask kernel to
- * detect this problem at runtime (else, kernel silently fail).
- *
- * NOTE: it may also be possible to use 'pages' from struct firmware and avoid
- * bounce buffer
- */
-static int sram_write_dma_safe(struct wfx_dev *wdev, u32 addr, const u8 *buf,
- size_t len)
-{
- int ret;
- const u8 *tmp;
-
- if (!virt_addr_valid(buf)) {
- tmp = kmemdup(buf, len, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
- } else {
- tmp = buf;
- }
- ret = sram_buf_write(wdev, addr, tmp, len);
- if (tmp != buf)
- kfree(tmp);
- return ret;
-}
-
-static int get_firmware(struct wfx_dev *wdev, u32 keyset_chip,
- const struct firmware **fw, int *file_offset)
-{
- int keyset_file;
- char filename[256];
- const char *data;
- int ret;
-
- snprintf(filename, sizeof(filename), "%s_%02X.sec",
- wdev->pdata.file_fw, keyset_chip);
- ret = firmware_request_nowarn(fw, filename, wdev->dev);
- if (ret) {
- dev_info(wdev->dev, "can't load %s, falling back to %s.sec\n",
- filename, wdev->pdata.file_fw);
- snprintf(filename, sizeof(filename), "%s.sec",
- wdev->pdata.file_fw);
- ret = request_firmware(fw, filename, wdev->dev);
- if (ret) {
- dev_err(wdev->dev, "can't load %s\n", filename);
- *fw = NULL;
- return ret;
- }
- }
-
- data = (*fw)->data;
- if (memcmp(data, "KEYSET", 6) != 0) {
- // Legacy firmware format
- *file_offset = 0;
- keyset_file = 0x90;
- } else {
- *file_offset = 8;
- keyset_file = (hex_to_bin(data[6]) * 16) | hex_to_bin(data[7]);
- if (keyset_file < 0) {
- dev_err(wdev->dev, "%s corrupted\n", filename);
- release_firmware(*fw);
- *fw = NULL;
- return -EINVAL;
- }
- }
- if (keyset_file != keyset_chip) {
- dev_err(wdev->dev, "firmware keyset is incompatible with chip (file: 0x%02X, chip: 0x%02X)\n",
- keyset_file, keyset_chip);
- release_firmware(*fw);
- *fw = NULL;
- return -ENODEV;
- }
- wdev->keyset = keyset_file;
- return 0;
-}
-
-static int wait_ncp_status(struct wfx_dev *wdev, u32 status)
-{
- ktime_t now, start;
- u32 reg;
- int ret;
-
- start = ktime_get();
- for (;;) {
- ret = sram_reg_read(wdev, WFX_DCA_NCP_STATUS, &reg);
- if (ret < 0)
- return -EIO;
- now = ktime_get();
- if (reg == status)
- break;
- if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT)))
- return -ETIMEDOUT;
- }
- if (ktime_compare(now, start))
- dev_dbg(wdev->dev, "chip answer after %lldus\n",
- ktime_us_delta(now, start));
- else
- dev_dbg(wdev->dev, "chip answer immediately\n");
- return 0;
-}
-
-static int upload_firmware(struct wfx_dev *wdev, const u8 *data, size_t len)
-{
- int ret;
- u32 offs, bytes_done = 0;
- ktime_t now, start;
-
- if (len % DNLD_BLOCK_SIZE) {
- dev_err(wdev->dev, "firmware size is not aligned. Buffer overrun will occur\n");
- return -EIO;
- }
- offs = 0;
- while (offs < len) {
- start = ktime_get();
- for (;;) {
- now = ktime_get();
- if (offs + DNLD_BLOCK_SIZE - bytes_done < DNLD_FIFO_SIZE)
- break;
- if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT)))
- return -ETIMEDOUT;
- ret = sram_reg_read(wdev, WFX_DCA_GET, &bytes_done);
- if (ret < 0)
- return ret;
- }
- if (ktime_compare(now, start))
- dev_dbg(wdev->dev, "answer after %lldus\n",
- ktime_us_delta(now, start));
-
- ret = sram_write_dma_safe(wdev, WFX_DNLD_FIFO +
- (offs % DNLD_FIFO_SIZE),
- data + offs, DNLD_BLOCK_SIZE);
- if (ret < 0)
- return ret;
-
- // WFx seems to not support writing 0 in this register during
- // first loop
- offs += DNLD_BLOCK_SIZE;
- ret = sram_reg_write(wdev, WFX_DCA_PUT, offs);
- if (ret < 0)
- return ret;
- }
- return 0;
-}
-
-static void print_boot_status(struct wfx_dev *wdev)
-{
- u32 reg;
-
- sram_reg_read(wdev, WFX_STATUS_INFO, &reg);
- if (reg == 0x12345678)
- return;
- sram_reg_read(wdev, WFX_ERR_INFO, &reg);
- if (reg < ARRAY_SIZE(fwio_errors) && fwio_errors[reg])
- dev_info(wdev->dev, "secure boot: %s\n", fwio_errors[reg]);
- else
- dev_info(wdev->dev, "secure boot: Error %#02x\n", reg);
-}
-
-static int load_firmware_secure(struct wfx_dev *wdev)
-{
- const struct firmware *fw = NULL;
- int header_size;
- int fw_offset;
- ktime_t start;
- u8 *buf;
- int ret;
-
- BUILD_BUG_ON(PTE_INFO_SIZE > BOOTLOADER_LABEL_SIZE);
- buf = kmalloc(BOOTLOADER_LABEL_SIZE + 1, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_READY);
- ret = wait_ncp_status(wdev, NCP_INFO_READY);
- if (ret)
- goto error;
-
- sram_buf_read(wdev, WFX_BOOTLOADER_LABEL, buf, BOOTLOADER_LABEL_SIZE);
- buf[BOOTLOADER_LABEL_SIZE] = 0;
- dev_dbg(wdev->dev, "bootloader: \"%s\"\n", buf);
-
- sram_buf_read(wdev, WFX_PTE_INFO, buf, PTE_INFO_SIZE);
- ret = get_firmware(wdev, buf[PTE_INFO_KEYSET_IDX], &fw, &fw_offset);
- if (ret)
- goto error;
- header_size = fw_offset + FW_SIGNATURE_SIZE + FW_HASH_SIZE;
-
- sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_INFO_READ);
- ret = wait_ncp_status(wdev, NCP_READY);
- if (ret)
- goto error;
-
- sram_reg_write(wdev, WFX_DNLD_FIFO, 0xFFFFFFFF); // Fifo init
- sram_write_dma_safe(wdev, WFX_DCA_FW_VERSION, "\x01\x00\x00\x00",
- FW_VERSION_SIZE);
- sram_write_dma_safe(wdev, WFX_DCA_FW_SIGNATURE, fw->data + fw_offset,
- FW_SIGNATURE_SIZE);
- sram_write_dma_safe(wdev, WFX_DCA_FW_HASH,
- fw->data + fw_offset + FW_SIGNATURE_SIZE,
- FW_HASH_SIZE);
- sram_reg_write(wdev, WFX_DCA_IMAGE_SIZE, fw->size - header_size);
- sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_PENDING);
- ret = wait_ncp_status(wdev, NCP_DOWNLOAD_PENDING);
- if (ret)
- goto error;
-
- start = ktime_get();
- ret = upload_firmware(wdev, fw->data + header_size,
- fw->size - header_size);
- if (ret)
- goto error;
- dev_dbg(wdev->dev, "firmware load after %lldus\n",
- ktime_us_delta(ktime_get(), start));
-
- sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_COMPLETE);
- ret = wait_ncp_status(wdev, NCP_AUTH_OK);
- // Legacy ROM support
- if (ret < 0)
- ret = wait_ncp_status(wdev, NCP_PUB_KEY_RDY);
- if (ret < 0)
- goto error;
- sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_OK_TO_JUMP);
-
-error:
- kfree(buf);
- if (fw)
- release_firmware(fw);
- if (ret)
- print_boot_status(wdev);
- return ret;
-}
-
-static int init_gpr(struct wfx_dev *wdev)
-{
- int ret, i;
- static const struct {
- int index;
- u32 value;
- } gpr_init[] = {
- { 0x07, 0x208775 },
- { 0x08, 0x2EC020 },
- { 0x09, 0x3C3C3C },
- { 0x0B, 0x322C44 },
- { 0x0C, 0xA06497 },
- };
-
- for (i = 0; i < ARRAY_SIZE(gpr_init); i++) {
- ret = igpr_reg_write(wdev, gpr_init[i].index,
- gpr_init[i].value);
- if (ret < 0)
- return ret;
- dev_dbg(wdev->dev, " index %02x: %08x\n",
- gpr_init[i].index, gpr_init[i].value);
- }
- return 0;
-}
-
-int wfx_init_device(struct wfx_dev *wdev)
-{
- int ret;
- int hw_revision, hw_type;
- int wakeup_timeout = 50; // ms
- ktime_t now, start;
- u32 reg;
-
- reg = CFG_DIRECT_ACCESS_MODE | CFG_CPU_RESET | CFG_BYTE_ORDER_ABCD;
- if (wdev->pdata.use_rising_clk)
- reg |= CFG_CLK_RISE_EDGE;
- ret = config_reg_write(wdev, reg);
- if (ret < 0) {
- dev_err(wdev->dev, "bus returned an error during first write access. Host configuration error?\n");
- return -EIO;
- }
-
- ret = config_reg_read(wdev, &reg);
- if (ret < 0) {
- dev_err(wdev->dev, "bus returned an error during first read access. Bus configuration error?\n");
- return -EIO;
- }
- if (reg == 0 || reg == ~0) {
- dev_err(wdev->dev, "chip mute. Bus configuration error or chip wasn't reset?\n");
- return -EIO;
- }
- dev_dbg(wdev->dev, "initial config register value: %08x\n", reg);
-
- hw_revision = FIELD_GET(CFG_DEVICE_ID_MAJOR, reg);
- if (hw_revision == 0) {
- dev_err(wdev->dev, "bad hardware revision number: %d\n",
- hw_revision);
- return -ENODEV;
- }
- hw_type = FIELD_GET(CFG_DEVICE_ID_TYPE, reg);
- if (hw_type == 1) {
- dev_notice(wdev->dev, "development hardware detected\n");
- wakeup_timeout = 2000;
- }
-
- ret = init_gpr(wdev);
- if (ret < 0)
- return ret;
-
- ret = control_reg_write(wdev, CTRL_WLAN_WAKEUP);
- if (ret < 0)
- return -EIO;
- start = ktime_get();
- for (;;) {
- ret = control_reg_read(wdev, &reg);
- now = ktime_get();
- if (reg & CTRL_WLAN_READY)
- break;
- if (ktime_after(now, ktime_add_ms(start, wakeup_timeout))) {
- dev_err(wdev->dev, "chip didn't wake up. Chip wasn't reset?\n");
- return -ETIMEDOUT;
- }
- }
- dev_dbg(wdev->dev, "chip wake up after %lldus\n",
- ktime_us_delta(now, start));
-
- ret = config_reg_write_bits(wdev, CFG_CPU_RESET, 0);
- if (ret < 0)
- return ret;
- ret = load_firmware_secure(wdev);
- if (ret < 0)
- return ret;
- return config_reg_write_bits(wdev,
- CFG_DIRECT_ACCESS_MODE |
- CFG_IRQ_ENABLE_DATA |
- CFG_IRQ_ENABLE_WRDY,
- CFG_IRQ_ENABLE_DATA);
-}
diff --git a/drivers/staging/wfx/fwio.h b/drivers/staging/wfx/fwio.h
deleted file mode 100644
index 6028f92503fe..000000000000
--- a/drivers/staging/wfx/fwio.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Firmware loading.
- *
- * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_FWIO_H
-#define WFX_FWIO_H
-
-struct wfx_dev;
-
-int wfx_init_device(struct wfx_dev *wdev);
-
-#endif /* WFX_FWIO_H */
diff --git a/drivers/staging/wfx/hif_api_cmd.h b/drivers/staging/wfx/hif_api_cmd.h
deleted file mode 100644
index 11bc1a58edae..000000000000
--- a/drivers/staging/wfx/hif_api_cmd.h
+++ /dev/null
@@ -1,553 +0,0 @@
-/* SPDX-License-Identifier: Apache-2.0 */
-/*
- * WFx hardware interface definitions
- *
- * Copyright (c) 2018-2020, Silicon Laboratories Inc.
- */
-
-#ifndef WFX_HIF_API_CMD_H
-#define WFX_HIF_API_CMD_H
-
-#include <linux/ieee80211.h>
-
-#include "hif_api_general.h"
-
-enum hif_requests_ids {
- HIF_REQ_ID_RESET = 0x0a,
- HIF_REQ_ID_READ_MIB = 0x05,
- HIF_REQ_ID_WRITE_MIB = 0x06,
- HIF_REQ_ID_START_SCAN = 0x07,
- HIF_REQ_ID_STOP_SCAN = 0x08,
- HIF_REQ_ID_TX = 0x04,
- HIF_REQ_ID_JOIN = 0x0b,
- HIF_REQ_ID_SET_PM_MODE = 0x10,
- HIF_REQ_ID_SET_BSS_PARAMS = 0x11,
- HIF_REQ_ID_ADD_KEY = 0x0c,
- HIF_REQ_ID_REMOVE_KEY = 0x0d,
- HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13,
- HIF_REQ_ID_START = 0x17,
- HIF_REQ_ID_BEACON_TRANSMIT = 0x18,
- HIF_REQ_ID_UPDATE_IE = 0x1b,
- HIF_REQ_ID_MAP_LINK = 0x1c,
-};
-
-enum hif_confirmations_ids {
- HIF_CNF_ID_RESET = 0x0a,
- HIF_CNF_ID_READ_MIB = 0x05,
- HIF_CNF_ID_WRITE_MIB = 0x06,
- HIF_CNF_ID_START_SCAN = 0x07,
- HIF_CNF_ID_STOP_SCAN = 0x08,
- HIF_CNF_ID_TX = 0x04,
- HIF_CNF_ID_MULTI_TRANSMIT = 0x1e,
- HIF_CNF_ID_JOIN = 0x0b,
- HIF_CNF_ID_SET_PM_MODE = 0x10,
- HIF_CNF_ID_SET_BSS_PARAMS = 0x11,
- HIF_CNF_ID_ADD_KEY = 0x0c,
- HIF_CNF_ID_REMOVE_KEY = 0x0d,
- HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13,
- HIF_CNF_ID_START = 0x17,
- HIF_CNF_ID_BEACON_TRANSMIT = 0x18,
- HIF_CNF_ID_UPDATE_IE = 0x1b,
- HIF_CNF_ID_MAP_LINK = 0x1c,
-};
-
-enum hif_indications_ids {
- HIF_IND_ID_RX = 0x84,
- HIF_IND_ID_SCAN_CMPL = 0x86,
- HIF_IND_ID_JOIN_COMPLETE = 0x8f,
- HIF_IND_ID_SET_PM_MODE_CMPL = 0x89,
- HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c,
- HIF_IND_ID_EVENT = 0x85
-};
-
-struct hif_req_reset {
- u8 reset_stat:1;
- u8 reset_all_int:1;
- u8 reserved1:6;
- u8 reserved2[3];
-} __packed;
-
-struct hif_cnf_reset {
- __le32 status;
-} __packed;
-
-struct hif_req_read_mib {
- __le16 mib_id;
- __le16 reserved;
-} __packed;
-
-struct hif_cnf_read_mib {
- __le32 status;
- __le16 mib_id;
- __le16 length;
- u8 mib_data[];
-} __packed;
-
-struct hif_req_write_mib {
- __le16 mib_id;
- __le16 length;
- u8 mib_data[];
-} __packed;
-
-struct hif_cnf_write_mib {
- __le32 status;
-} __packed;
-
-struct hif_req_update_ie {
- u8 beacon:1;
- u8 probe_resp:1;
- u8 probe_req:1;
- u8 reserved1:5;
- u8 reserved2;
- __le16 num_ies;
- struct element ie[];
-} __packed;
-
-struct hif_cnf_update_ie {
- __le32 status;
-} __packed;
-
-struct hif_ssid_def {
- __le32 ssid_length;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
-} __packed;
-
-#define HIF_API_MAX_NB_SSIDS 2
-#define HIF_API_MAX_NB_CHANNELS 14
-
-struct hif_req_start_scan_alt {
- u8 band;
- u8 maintain_current_bss:1;
- u8 periodic:1;
- u8 reserved1:6;
- u8 disallow_ps:1;
- u8 reserved2:1;
- u8 short_preamble:1;
- u8 reserved3:5;
- u8 max_transmit_rate;
- __le16 periodic_interval;
- u8 reserved4;
- s8 periodic_rssi_thr;
- u8 num_of_probe_requests;
- u8 probe_delay;
- u8 num_of_ssids;
- u8 num_of_channels;
- __le32 min_channel_time;
- __le32 max_channel_time;
- __le32 tx_power_level; // signed value
- struct hif_ssid_def ssid_def[HIF_API_MAX_NB_SSIDS];
- u8 channel_list[];
-} __packed;
-
-struct hif_cnf_start_scan {
- __le32 status;
-} __packed;
-
-struct hif_cnf_stop_scan {
- __le32 status;
-} __packed;
-
-enum hif_pm_mode_status {
- HIF_PM_MODE_ACTIVE = 0x0,
- HIF_PM_MODE_PS = 0x1,
- HIF_PM_MODE_UNDETERMINED = 0x2
-};
-
-struct hif_ind_scan_cmpl {
- __le32 status;
- u8 pm_mode;
- u8 num_channels_completed;
- __le16 reserved;
-} __packed;
-
-enum hif_queue_id {
- HIF_QUEUE_ID_BACKGROUND = 0x0,
- HIF_QUEUE_ID_BESTEFFORT = 0x1,
- HIF_QUEUE_ID_VIDEO = 0x2,
- HIF_QUEUE_ID_VOICE = 0x3
-};
-
-enum hif_frame_format {
- HIF_FRAME_FORMAT_NON_HT = 0x0,
- HIF_FRAME_FORMAT_MIXED_FORMAT_HT = 0x1,
- HIF_FRAME_FORMAT_GF_HT_11N = 0x2
-};
-
-struct hif_req_tx {
- // packet_id is not interpreted by the device, so it is not necessary to
- // declare it little endian
- u32 packet_id;
- u8 max_tx_rate;
- u8 queue_id:2;
- u8 peer_sta_id:4;
- u8 reserved1:2;
- u8 more:1;
- u8 fc_offset:3;
- u8 after_dtim:1;
- u8 reserved2:3;
- u8 start_exp:1;
- u8 reserved3:3;
- u8 retry_policy_index:4;
- __le32 reserved4;
- __le32 expire_time;
- u8 frame_format:4;
- u8 fec_coding:1;
- u8 short_gi:1;
- u8 reserved5:1;
- u8 stbc:1;
- u8 reserved6;
- u8 aggregation:1;
- u8 reserved7:7;
- u8 reserved8;
- u8 frame[];
-} __packed;
-
-enum hif_qos_ackplcy {
- HIF_QOS_ACKPLCY_NORMAL = 0x0,
- HIF_QOS_ACKPLCY_TXNOACK = 0x1,
- HIF_QOS_ACKPLCY_NOEXPACK = 0x2,
- HIF_QOS_ACKPLCY_BLCKACK = 0x3
-};
-
-struct hif_cnf_tx {
- __le32 status;
- // packet_id is copied from struct hif_req_tx without been interpreted
- // by the device, so it is not necessary to declare it little endian
- u32 packet_id;
- u8 txed_rate;
- u8 ack_failures;
- u8 aggr:1;
- u8 requeue:1;
- u8 ack_policy:2;
- u8 txop_limit:1;
- u8 reserved1:3;
- u8 reserved2;
- __le32 media_delay;
- __le32 tx_queue_delay;
-} __packed;
-
-struct hif_cnf_multi_transmit {
- u8 num_tx_confs;
- u8 reserved[3];
- struct hif_cnf_tx tx_conf_payload[];
-} __packed;
-
-enum hif_ri_flags_encrypt {
- HIF_RI_FLAGS_UNENCRYPTED = 0x0,
- HIF_RI_FLAGS_WEP_ENCRYPTED = 0x1,
- HIF_RI_FLAGS_TKIP_ENCRYPTED = 0x2,
- HIF_RI_FLAGS_AES_ENCRYPTED = 0x3,
- HIF_RI_FLAGS_WAPI_ENCRYPTED = 0x4
-};
-
-struct hif_ind_rx {
- __le32 status;
- u8 channel_number;
- u8 reserved1;
- u8 rxed_rate;
- u8 rcpi_rssi;
- u8 encryp:3;
- u8 in_aggr:1;
- u8 first_aggr:1;
- u8 last_aggr:1;
- u8 defrag:1;
- u8 beacon:1;
- u8 tim:1;
- u8 bitmap:1;
- u8 match_ssid:1;
- u8 match_bssid:1;
- u8 more:1;
- u8 reserved2:1;
- u8 ht:1;
- u8 stbc:1;
- u8 match_uc_addr:1;
- u8 match_mc_addr:1;
- u8 match_bc_addr:1;
- u8 key_type:1;
- u8 key_index:4;
- u8 reserved3:1;
- u8 peer_sta_id:4;
- u8 reserved4:2;
- u8 reserved5:1;
- u8 frame[];
-} __packed;
-
-struct hif_req_edca_queue_params {
- u8 queue_id;
- u8 reserved1;
- u8 aifsn;
- u8 reserved2;
- __le16 cw_min;
- __le16 cw_max;
- __le16 tx_op_limit;
- __le16 allowed_medium_time;
- __le32 reserved3;
-} __packed;
-
-struct hif_cnf_edca_queue_params {
- __le32 status;
-} __packed;
-
-struct hif_req_join {
- u8 infrastructure_bss_mode:1;
- u8 reserved1:7;
- u8 band;
- u8 channel_number;
- u8 reserved2;
- u8 bssid[ETH_ALEN];
- __le16 atim_window;
- u8 short_preamble:1;
- u8 reserved3:7;
- u8 probe_for_join;
- u8 reserved4;
- u8 reserved5:2;
- u8 force_no_beacon:1;
- u8 force_with_ind:1;
- u8 reserved6:4;
- __le32 ssid_length;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
- __le32 beacon_interval;
- __le32 basic_rate_set;
-} __packed;
-
-struct hif_cnf_join {
- __le32 status;
-} __packed;
-
-struct hif_ind_join_complete {
- __le32 status;
-} __packed;
-
-struct hif_req_set_bss_params {
- u8 lost_count_only:1;
- u8 reserved:7;
- u8 beacon_lost_count;
- __le16 aid;
- __le32 operational_rate_set;
-} __packed;
-
-struct hif_cnf_set_bss_params {
- __le32 status;
-} __packed;
-
-struct hif_req_set_pm_mode {
- u8 enter_psm:1;
- u8 reserved:6;
- u8 fast_psm:1;
- u8 fast_psm_idle_period;
- u8 ap_psm_change_period;
- u8 min_auto_ps_poll_period;
-} __packed;
-
-struct hif_cnf_set_pm_mode {
- __le32 status;
-} __packed;
-
-struct hif_ind_set_pm_mode_cmpl {
- __le32 status;
- u8 pm_mode;
- u8 reserved[3];
-} __packed;
-
-struct hif_req_start {
- u8 mode;
- u8 band;
- u8 channel_number;
- u8 reserved1;
- __le32 reserved2;
- __le32 beacon_interval;
- u8 dtim_period;
- u8 short_preamble:1;
- u8 reserved3:7;
- u8 reserved4;
- u8 ssid_length;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
- __le32 basic_rate_set;
-} __packed;
-
-struct hif_cnf_start {
- __le32 status;
-} __packed;
-
-struct hif_req_beacon_transmit {
- u8 enable_beaconing;
- u8 reserved[3];
-} __packed;
-
-struct hif_cnf_beacon_transmit {
- __le32 status;
-} __packed;
-
-#define HIF_LINK_ID_MAX 14
-#define HIF_LINK_ID_NOT_ASSOCIATED (HIF_LINK_ID_MAX + 1)
-
-struct hif_req_map_link {
- u8 mac_addr[ETH_ALEN];
- u8 unmap:1;
- u8 mfpc:1;
- u8 reserved:6;
- u8 peer_sta_id;
-} __packed;
-
-struct hif_cnf_map_link {
- __le32 status;
-} __packed;
-
-struct hif_ind_suspend_resume_tx {
- u8 resume:1;
- u8 reserved1:2;
- u8 bc_mc_only:1;
- u8 reserved2:4;
- u8 reserved3;
- __le16 peer_sta_set;
-} __packed;
-
-
-#define MAX_KEY_ENTRIES 24
-#define HIF_API_WEP_KEY_DATA_SIZE 16
-#define HIF_API_TKIP_KEY_DATA_SIZE 16
-#define HIF_API_RX_MIC_KEY_SIZE 8
-#define HIF_API_TX_MIC_KEY_SIZE 8
-#define HIF_API_AES_KEY_DATA_SIZE 16
-#define HIF_API_WAPI_KEY_DATA_SIZE 16
-#define HIF_API_MIC_KEY_DATA_SIZE 16
-#define HIF_API_IGTK_KEY_DATA_SIZE 16
-#define HIF_API_RX_SEQUENCE_COUNTER_SIZE 8
-#define HIF_API_IPN_SIZE 8
-
-enum hif_key_type {
- HIF_KEY_TYPE_WEP_DEFAULT = 0x0,
- HIF_KEY_TYPE_WEP_PAIRWISE = 0x1,
- HIF_KEY_TYPE_TKIP_GROUP = 0x2,
- HIF_KEY_TYPE_TKIP_PAIRWISE = 0x3,
- HIF_KEY_TYPE_AES_GROUP = 0x4,
- HIF_KEY_TYPE_AES_PAIRWISE = 0x5,
- HIF_KEY_TYPE_WAPI_GROUP = 0x6,
- HIF_KEY_TYPE_WAPI_PAIRWISE = 0x7,
- HIF_KEY_TYPE_IGTK_GROUP = 0x8,
- HIF_KEY_TYPE_NONE = 0x9
-};
-
-struct hif_wep_pairwise_key {
- u8 peer_address[ETH_ALEN];
- u8 reserved;
- u8 key_length;
- u8 key_data[HIF_API_WEP_KEY_DATA_SIZE];
-} __packed;
-
-struct hif_wep_group_key {
- u8 key_id;
- u8 key_length;
- u8 reserved[2];
- u8 key_data[HIF_API_WEP_KEY_DATA_SIZE];
-} __packed;
-
-struct hif_tkip_pairwise_key {
- u8 peer_address[ETH_ALEN];
- u8 reserved[2];
- u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE];
- u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE];
- u8 tx_mic_key[HIF_API_TX_MIC_KEY_SIZE];
-} __packed;
-
-struct hif_tkip_group_key {
- u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE];
- u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE];
- u8 key_id;
- u8 reserved[3];
- u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE];
-} __packed;
-
-struct hif_aes_pairwise_key {
- u8 peer_address[ETH_ALEN];
- u8 reserved[2];
- u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE];
-} __packed;
-
-struct hif_aes_group_key {
- u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE];
- u8 key_id;
- u8 reserved[3];
- u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE];
-} __packed;
-
-struct hif_wapi_pairwise_key {
- u8 peer_address[ETH_ALEN];
- u8 key_id;
- u8 reserved;
- u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE];
- u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE];
-} __packed;
-
-struct hif_wapi_group_key {
- u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE];
- u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE];
- u8 key_id;
- u8 reserved[3];
-} __packed;
-
-struct hif_igtk_group_key {
- u8 igtk_key_data[HIF_API_IGTK_KEY_DATA_SIZE];
- u8 key_id;
- u8 reserved[3];
- u8 ipn[HIF_API_IPN_SIZE];
-} __packed;
-
-struct hif_req_add_key {
- u8 type;
- u8 entry_index;
- u8 int_id:2;
- u8 reserved1:6;
- u8 reserved2;
- union {
- struct hif_wep_pairwise_key wep_pairwise_key;
- struct hif_wep_group_key wep_group_key;
- struct hif_tkip_pairwise_key tkip_pairwise_key;
- struct hif_tkip_group_key tkip_group_key;
- struct hif_aes_pairwise_key aes_pairwise_key;
- struct hif_aes_group_key aes_group_key;
- struct hif_wapi_pairwise_key wapi_pairwise_key;
- struct hif_wapi_group_key wapi_group_key;
- struct hif_igtk_group_key igtk_group_key;
- } key;
-} __packed;
-
-struct hif_cnf_add_key {
- __le32 status;
-} __packed;
-
-struct hif_req_remove_key {
- u8 entry_index;
- u8 reserved[3];
-} __packed;
-
-struct hif_cnf_remove_key {
- __le32 status;
-} __packed;
-
-enum hif_event_ind {
- HIF_EVENT_IND_BSSLOST = 0x1,
- HIF_EVENT_IND_BSSREGAINED = 0x2,
- HIF_EVENT_IND_RCPI_RSSI = 0x3,
- HIF_EVENT_IND_PS_MODE_ERROR = 0x4,
- HIF_EVENT_IND_INACTIVITY = 0x5
-};
-
-enum hif_ps_mode_error {
- HIF_PS_ERROR_NO_ERROR = 0,
- HIF_PS_ERROR_AP_NOT_RESP_TO_POLL = 1,
- HIF_PS_ERROR_AP_NOT_RESP_TO_UAPSD_TRIGGER = 2,
- HIF_PS_ERROR_AP_SENT_UNICAST_IN_DOZE = 3,
- HIF_PS_ERROR_AP_NO_DATA_AFTER_TIM = 4
-};
-
-struct hif_ind_event {
- __le32 event_id;
- union {
- u8 rcpi_rssi;
- __le32 ps_mode_error;
- __le32 peer_sta_set;
- } event_data;
-} __packed;
-
-#endif
diff --git a/drivers/staging/wfx/hif_api_general.h b/drivers/staging/wfx/hif_api_general.h
deleted file mode 100644
index 24188945718d..000000000000
--- a/drivers/staging/wfx/hif_api_general.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/* SPDX-License-Identifier: Apache-2.0 */
-/*
- * WFx hardware interface definitions
- *
- * Copyright (c) 2018-2020, Silicon Laboratories Inc.
- */
-
-#ifndef WFX_HIF_API_GENERAL_H
-#define WFX_HIF_API_GENERAL_H
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#include <linux/if_ether.h>
-#else
-#include <net/ethernet.h>
-#include <stdint.h>
-#define __packed __attribute__((__packed__))
-#endif
-
-#define HIF_ID_IS_INDICATION 0x80
-#define HIF_COUNTER_MAX 7
-
-struct hif_msg {
- __le16 len;
- u8 id;
- u8 reserved:1;
- u8 interface:2;
- u8 seqnum:3;
- u8 encrypted:2;
- u8 body[];
-} __packed;
-
-enum hif_general_requests_ids {
- HIF_REQ_ID_CONFIGURATION = 0x09,
- HIF_REQ_ID_CONTROL_GPIO = 0x26,
- HIF_REQ_ID_SET_SL_MAC_KEY = 0x27,
- HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS = 0x28,
- HIF_REQ_ID_SL_CONFIGURE = 0x29,
- HIF_REQ_ID_PREVENT_ROLLBACK = 0x2a,
- HIF_REQ_ID_PTA_SETTINGS = 0x2b,
- HIF_REQ_ID_PTA_PRIORITY = 0x2c,
- HIF_REQ_ID_PTA_STATE = 0x2d,
- HIF_REQ_ID_SHUT_DOWN = 0x32,
-};
-
-enum hif_general_confirmations_ids {
- HIF_CNF_ID_CONFIGURATION = 0x09,
- HIF_CNF_ID_CONTROL_GPIO = 0x26,
- HIF_CNF_ID_SET_SL_MAC_KEY = 0x27,
- HIF_CNF_ID_SL_EXCHANGE_PUB_KEYS = 0x28,
- HIF_CNF_ID_SL_CONFIGURE = 0x29,
- HIF_CNF_ID_PREVENT_ROLLBACK = 0x2a,
- HIF_CNF_ID_PTA_SETTINGS = 0x2b,
- HIF_CNF_ID_PTA_PRIORITY = 0x2c,
- HIF_CNF_ID_PTA_STATE = 0x2d,
- HIF_CNF_ID_SHUT_DOWN = 0x32,
-};
-
-enum hif_general_indications_ids {
- HIF_IND_ID_EXCEPTION = 0xe0,
- HIF_IND_ID_STARTUP = 0xe1,
- HIF_IND_ID_WAKEUP = 0xe2,
- HIF_IND_ID_GENERIC = 0xe3,
- HIF_IND_ID_ERROR = 0xe4,
- HIF_IND_ID_SL_EXCHANGE_PUB_KEYS = 0xe5
-};
-
-#define HIF_STATUS_SUCCESS (cpu_to_le32(0x0000))
-#define HIF_STATUS_FAIL (cpu_to_le32(0x0001))
-#define HIF_STATUS_INVALID_PARAMETER (cpu_to_le32(0x0002))
-#define HIF_STATUS_WARNING (cpu_to_le32(0x0003))
-#define HIF_STATUS_UNKNOWN_REQUEST (cpu_to_le32(0x0004))
-#define HIF_STATUS_RX_FAIL_DECRYPT (cpu_to_le32(0x0010))
-#define HIF_STATUS_RX_FAIL_MIC (cpu_to_le32(0x0011))
-#define HIF_STATUS_RX_FAIL_NO_KEY (cpu_to_le32(0x0012))
-#define HIF_STATUS_TX_FAIL_RETRIES (cpu_to_le32(0x0013))
-#define HIF_STATUS_TX_FAIL_TIMEOUT (cpu_to_le32(0x0014))
-#define HIF_STATUS_TX_FAIL_REQUEUE (cpu_to_le32(0x0015))
-#define HIF_STATUS_REFUSED (cpu_to_le32(0x0016))
-#define HIF_STATUS_BUSY (cpu_to_le32(0x0017))
-#define HIF_STATUS_SLK_SET_KEY_SUCCESS (cpu_to_le32(0x005A))
-#define HIF_STATUS_SLK_SET_KEY_ALREADY_BURNED (cpu_to_le32(0x006B))
-#define HIF_STATUS_SLK_SET_KEY_DISALLOWED_MODE (cpu_to_le32(0x007C))
-#define HIF_STATUS_SLK_SET_KEY_UNKNOWN_MODE (cpu_to_le32(0x008D))
-#define HIF_STATUS_SLK_NEGO_SUCCESS (cpu_to_le32(0x009E))
-#define HIF_STATUS_SLK_NEGO_FAILED (cpu_to_le32(0x00AF))
-#define HIF_STATUS_ROLLBACK_SUCCESS (cpu_to_le32(0x1234))
-#define HIF_STATUS_ROLLBACK_FAIL (cpu_to_le32(0x1256))
-
-enum hif_api_rate_index {
- API_RATE_INDEX_B_1MBPS = 0,
- API_RATE_INDEX_B_2MBPS = 1,
- API_RATE_INDEX_B_5P5MBPS = 2,
- API_RATE_INDEX_B_11MBPS = 3,
- API_RATE_INDEX_PBCC_22MBPS = 4,
- API_RATE_INDEX_PBCC_33MBPS = 5,
- API_RATE_INDEX_G_6MBPS = 6,
- API_RATE_INDEX_G_9MBPS = 7,
- API_RATE_INDEX_G_12MBPS = 8,
- API_RATE_INDEX_G_18MBPS = 9,
- API_RATE_INDEX_G_24MBPS = 10,
- API_RATE_INDEX_G_36MBPS = 11,
- API_RATE_INDEX_G_48MBPS = 12,
- API_RATE_INDEX_G_54MBPS = 13,
- API_RATE_INDEX_N_6P5MBPS = 14,
- API_RATE_INDEX_N_13MBPS = 15,
- API_RATE_INDEX_N_19P5MBPS = 16,
- API_RATE_INDEX_N_26MBPS = 17,
- API_RATE_INDEX_N_39MBPS = 18,
- API_RATE_INDEX_N_52MBPS = 19,
- API_RATE_INDEX_N_58P5MBPS = 20,
- API_RATE_INDEX_N_65MBPS = 21,
- API_RATE_NUM_ENTRIES = 22
-};
-
-enum hif_fw_type {
- HIF_FW_TYPE_ETF = 0x0,
- HIF_FW_TYPE_WFM = 0x1,
- HIF_FW_TYPE_WSM = 0x2
-};
-
-struct hif_ind_startup {
- // As the others, this struct is interpreted as little endian by the
- // device. However, this struct is also used by the driver. We prefer to
- // declare it in native order and doing byte swap on reception.
- __le32 status;
- u16 hardware_id;
- u8 opn[14];
- u8 uid[8];
- u16 num_inp_ch_bufs;
- u16 size_inp_ch_buf;
- u8 num_links_ap;
- u8 num_interfaces;
- u8 mac_addr[2][ETH_ALEN];
- u8 api_version_minor;
- u8 api_version_major;
- u8 link_mode:2;
- u8 reserved1:6;
- u8 reserved2;
- u8 reserved3;
- u8 reserved4;
- u8 firmware_build;
- u8 firmware_minor;
- u8 firmware_major;
- u8 firmware_type;
- u8 disabled_channel_list[2];
- u8 region_sel_mode:4;
- u8 reserved5:4;
- u8 phy1_region:3;
- u8 phy0_region:3;
- u8 otp_phy_ver:2;
- u32 supported_rate_mask;
- u8 firmware_label[128];
-} __packed;
-
-struct hif_ind_wakeup {
-} __packed;
-
-struct hif_req_configuration {
- __le16 length;
- u8 pds_data[];
-} __packed;
-
-struct hif_cnf_configuration {
- __le32 status;
-} __packed;
-
-enum hif_gpio_mode {
- HIF_GPIO_MODE_D0 = 0x0,
- HIF_GPIO_MODE_D1 = 0x1,
- HIF_GPIO_MODE_OD0 = 0x2,
- HIF_GPIO_MODE_OD1 = 0x3,
- HIF_GPIO_MODE_TRISTATE = 0x4,
- HIF_GPIO_MODE_TOGGLE = 0x5,
- HIF_GPIO_MODE_READ = 0x6
-};
-
-struct hif_req_control_gpio {
- u8 gpio_label;
- u8 gpio_mode;
-} __packed;
-
-struct hif_cnf_control_gpio {
- __le32 status;
- __le32 value;
-} __packed;
-
-enum hif_generic_indication_type {
- HIF_GENERIC_INDICATION_TYPE_RAW = 0x0,
- HIF_GENERIC_INDICATION_TYPE_STRING = 0x1,
- HIF_GENERIC_INDICATION_TYPE_RX_STATS = 0x2,
- HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO = 0x3,
-};
-
-struct hif_rx_stats {
- __le32 nb_rx_frame;
- __le32 nb_crc_frame;
- __le32 per_total;
- __le32 throughput;
- __le32 nb_rx_by_rate[API_RATE_NUM_ENTRIES];
- __le16 per[API_RATE_NUM_ENTRIES];
- __le16 snr[API_RATE_NUM_ENTRIES]; // signed value
- __le16 rssi[API_RATE_NUM_ENTRIES]; // signed value
- __le16 cfo[API_RATE_NUM_ENTRIES]; // signed value
- __le32 date;
- __le32 pwr_clk_freq;
- u8 is_ext_pwr_clk;
- s8 current_temp;
-} __packed;
-
-struct hif_tx_power_loop_info {
- __le16 tx_gain_dig;
- __le16 tx_gain_pa;
- __le16 target_pout; // signed value
- __le16 p_estimation; // signed value
- __le16 vpdet;
- u8 measurement_index;
- u8 reserved;
-} __packed;
-
-struct hif_ind_generic {
- __le32 type;
- union {
- struct hif_rx_stats rx_stats;
- struct hif_tx_power_loop_info tx_power_loop_info;
- } data;
-} __packed;
-
-enum hif_error {
- HIF_ERROR_FIRMWARE_ROLLBACK = 0x00,
- HIF_ERROR_FIRMWARE_DEBUG_ENABLED = 0x01,
- HIF_ERROR_SLK_OUTDATED_SESSION_KEY = 0x02,
- HIF_ERROR_SLK_SESSION_KEY = 0x03,
- HIF_ERROR_OOR_VOLTAGE = 0x04,
- HIF_ERROR_PDS_PAYLOAD = 0x05,
- HIF_ERROR_OOR_TEMPERATURE = 0x06,
- HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE = 0x07,
- HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED = 0x08,
- HIF_ERROR_SLK_OVERFLOW = 0x09,
- HIF_ERROR_SLK_DECRYPTION = 0x0a,
- HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE = 0x0b,
- HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW = 0x0c,
- HIF_ERROR_HIF_RX_DATA_TOO_LARGE = 0x0e,
- HIF_ERROR_HIF_TX_QUEUE_FULL = 0x0d,
- HIF_ERROR_HIF_BUS = 0x0f,
- HIF_ERROR_PDS_TESTFEATURE = 0x10,
- HIF_ERROR_SLK_UNCONFIGURED = 0x11,
-};
-
-struct hif_ind_error {
- __le32 type;
- u8 data[];
-} __packed;
-
-struct hif_ind_exception {
- __le32 type;
- u8 data[];
-} __packed;
-
-enum hif_secure_link_state {
- SEC_LINK_UNAVAILABLE = 0x0,
- SEC_LINK_RESERVED = 0x1,
- SEC_LINK_EVAL = 0x2,
- SEC_LINK_ENFORCED = 0x3
-};
-
-#endif
diff --git a/drivers/staging/wfx/hif_api_mib.h b/drivers/staging/wfx/hif_api_mib.h
deleted file mode 100644
index ace924720ce6..000000000000
--- a/drivers/staging/wfx/hif_api_mib.h
+++ /dev/null
@@ -1,343 +0,0 @@
-/* SPDX-License-Identifier: Apache-2.0 */
-/*
- * WFx hardware interface definitions
- *
- * Copyright (c) 2018-2020, Silicon Laboratories Inc.
- */
-
-#ifndef WFX_HIF_API_MIB_H
-#define WFX_HIF_API_MIB_H
-
-#include "hif_api_general.h"
-
-#define HIF_API_IPV4_ADDRESS_SIZE 4
-#define HIF_API_IPV6_ADDRESS_SIZE 16
-
-enum hif_mib_ids {
- HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE = 0x2000,
- HIF_MIB_ID_GL_BLOCK_ACK_INFO = 0x2001,
- HIF_MIB_ID_GL_SET_MULTI_MSG = 0x2002,
- HIF_MIB_ID_CCA_CONFIG = 0x2003,
- HIF_MIB_ID_ETHERTYPE_DATAFRAME_CONDITION = 0x2010,
- HIF_MIB_ID_PORT_DATAFRAME_CONDITION = 0x2011,
- HIF_MIB_ID_MAGIC_DATAFRAME_CONDITION = 0x2012,
- HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION = 0x2013,
- HIF_MIB_ID_IPV4_ADDR_DATAFRAME_CONDITION = 0x2014,
- HIF_MIB_ID_IPV6_ADDR_DATAFRAME_CONDITION = 0x2015,
- HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION = 0x2016,
- HIF_MIB_ID_CONFIG_DATA_FILTER = 0x2017,
- HIF_MIB_ID_SET_DATA_FILTERING = 0x2018,
- HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE = 0x2019,
- HIF_MIB_ID_NS_IP_ADDRESSES_TABLE = 0x201A,
- HIF_MIB_ID_RX_FILTER = 0x201B,
- HIF_MIB_ID_BEACON_FILTER_TABLE = 0x201C,
- HIF_MIB_ID_BEACON_FILTER_ENABLE = 0x201D,
- HIF_MIB_ID_GRP_SEQ_COUNTER = 0x2030,
- HIF_MIB_ID_TSF_COUNTER = 0x2031,
- HIF_MIB_ID_STATISTICS_TABLE = 0x2032,
- HIF_MIB_ID_COUNTERS_TABLE = 0x2033,
- HIF_MIB_ID_MAX_TX_POWER_LEVEL = 0x2034,
- HIF_MIB_ID_EXTENDED_COUNTERS_TABLE = 0x2035,
- HIF_MIB_ID_DOT11_MAC_ADDRESS = 0x2040,
- HIF_MIB_ID_DOT11_MAX_TRANSMIT_MSDU_LIFETIME = 0x2041,
- HIF_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME = 0x2042,
- HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID = 0x2043,
- HIF_MIB_ID_DOT11_RTS_THRESHOLD = 0x2044,
- HIF_MIB_ID_SLOT_TIME = 0x2045,
- HIF_MIB_ID_CURRENT_TX_POWER_LEVEL = 0x2046,
- HIF_MIB_ID_NON_ERP_PROTECTION = 0x2047,
- HIF_MIB_ID_TEMPLATE_FRAME = 0x2048,
- HIF_MIB_ID_BEACON_WAKEUP_PERIOD = 0x2049,
- HIF_MIB_ID_RCPI_RSSI_THRESHOLD = 0x204A,
- HIF_MIB_ID_BLOCK_ACK_POLICY = 0x204B,
- HIF_MIB_ID_OVERRIDE_INTERNAL_TX_RATE = 0x204C,
- HIF_MIB_ID_SET_ASSOCIATION_MODE = 0x204D,
- HIF_MIB_ID_SET_UAPSD_INFORMATION = 0x204E,
- HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY = 0x204F,
- HIF_MIB_ID_PROTECTED_MGMT_POLICY = 0x2050,
- HIF_MIB_ID_SET_HT_PROTECTION = 0x2051,
- HIF_MIB_ID_KEEP_ALIVE_PERIOD = 0x2052,
- HIF_MIB_ID_ARP_KEEP_ALIVE_PERIOD = 0x2053,
- HIF_MIB_ID_INACTIVITY_TIMER = 0x2054,
- HIF_MIB_ID_INTERFACE_PROTECTION = 0x2055,
- HIF_MIB_ID_BEACON_STATS = 0x2056,
-};
-
-enum hif_op_power_mode {
- HIF_OP_POWER_MODE_ACTIVE = 0x0,
- HIF_OP_POWER_MODE_DOZE = 0x1,
- HIF_OP_POWER_MODE_QUIESCENT = 0x2
-};
-
-struct hif_mib_gl_operational_power_mode {
- u8 power_mode:4;
- u8 reserved1:3;
- u8 wup_ind_activation:1;
- u8 reserved2[3];
-} __packed;
-
-struct hif_mib_gl_set_multi_msg {
- u8 enable_multi_tx_conf:1;
- u8 reserved1:7;
- u8 reserved2[3];
-} __packed;
-
-enum hif_arp_ns_frame_treatment {
- HIF_ARP_NS_FILTERING_DISABLE = 0x0,
- HIF_ARP_NS_FILTERING_ENABLE = 0x1,
- HIF_ARP_NS_REPLY_ENABLE = 0x2
-};
-
-struct hif_mib_arp_ip_addr_table {
- u8 condition_idx;
- u8 arp_enable;
- u8 reserved[2];
- u8 ipv4_address[HIF_API_IPV4_ADDRESS_SIZE];
-} __packed;
-
-struct hif_mib_rx_filter {
- u8 reserved1:1;
- u8 bssid_filter:1;
- u8 reserved2:1;
- u8 fwd_probe_req:1;
- u8 keep_alive_filter:1;
- u8 reserved3:3;
- u8 reserved4[3];
-} __packed;
-
-struct hif_ie_table_entry {
- u8 ie_id;
- u8 has_changed:1;
- u8 no_longer:1;
- u8 has_appeared:1;
- u8 reserved:1;
- u8 num_match_data:4;
- u8 oui[3];
- u8 match_data[3];
-} __packed;
-
-struct hif_mib_bcn_filter_table {
- __le32 num_of_info_elmts;
- struct hif_ie_table_entry ie_table[];
-} __packed;
-
-enum hif_beacon_filter {
- HIF_BEACON_FILTER_DISABLE = 0x0,
- HIF_BEACON_FILTER_ENABLE = 0x1,
- HIF_BEACON_FILTER_AUTO_ERP = 0x2
-};
-
-struct hif_mib_bcn_filter_enable {
- __le32 enable;
- __le32 bcn_count;
-} __packed;
-
-struct hif_mib_extended_count_table {
- __le32 count_plcp_errors;
- __le32 count_fcs_errors;
- __le32 count_tx_packets;
- __le32 count_rx_packets;
- __le32 count_rx_packet_errors;
- __le32 count_rx_decryption_failures;
- __le32 count_rx_mic_failures;
- __le32 count_rx_no_key_failures;
- __le32 count_tx_multicast_frames;
- __le32 count_tx_frames_success;
- __le32 count_tx_frame_failures;
- __le32 count_tx_frames_retried;
- __le32 count_tx_frames_multi_retried;
- __le32 count_rx_frame_duplicates;
- __le32 count_rts_success;
- __le32 count_rts_failures;
- __le32 count_ack_failures;
- __le32 count_rx_multicast_frames;
- __le32 count_rx_frames_success;
- __le32 count_rx_cmacicv_errors;
- __le32 count_rx_cmac_replays;
- __le32 count_rx_mgmt_ccmp_replays;
- __le32 count_rx_bipmic_errors;
- __le32 count_rx_beacon;
- __le32 count_miss_beacon;
- __le32 reserved[15];
-} __packed;
-
-struct hif_mib_count_table {
- __le32 count_plcp_errors;
- __le32 count_fcs_errors;
- __le32 count_tx_packets;
- __le32 count_rx_packets;
- __le32 count_rx_packet_errors;
- __le32 count_rx_decryption_failures;
- __le32 count_rx_mic_failures;
- __le32 count_rx_no_key_failures;
- __le32 count_tx_multicast_frames;
- __le32 count_tx_frames_success;
- __le32 count_tx_frame_failures;
- __le32 count_tx_frames_retried;
- __le32 count_tx_frames_multi_retried;
- __le32 count_rx_frame_duplicates;
- __le32 count_rts_success;
- __le32 count_rts_failures;
- __le32 count_ack_failures;
- __le32 count_rx_multicast_frames;
- __le32 count_rx_frames_success;
- __le32 count_rx_cmacicv_errors;
- __le32 count_rx_cmac_replays;
- __le32 count_rx_mgmt_ccmp_replays;
- __le32 count_rx_bipmic_errors;
-} __packed;
-
-struct hif_mib_mac_address {
- u8 mac_addr[ETH_ALEN];
- __le16 reserved;
-} __packed;
-
-struct hif_mib_wep_default_key_id {
- u8 wep_default_key_id;
- u8 reserved[3];
-} __packed;
-
-struct hif_mib_dot11_rts_threshold {
- __le32 threshold;
-} __packed;
-
-struct hif_mib_slot_time {
- __le32 slot_time;
-} __packed;
-
-struct hif_mib_current_tx_power_level {
- __le32 power_level; // signed value
-} __packed;
-
-struct hif_mib_non_erp_protection {
- u8 use_cts_to_self:1;
- u8 reserved1:7;
- u8 reserved2[3];
-} __packed;
-
-enum hif_tmplt {
- HIF_TMPLT_PRBREQ = 0x0,
- HIF_TMPLT_BCN = 0x1,
- HIF_TMPLT_NULL = 0x2,
- HIF_TMPLT_QOSNUL = 0x3,
- HIF_TMPLT_PSPOLL = 0x4,
- HIF_TMPLT_PRBRES = 0x5,
- HIF_TMPLT_ARP = 0x6,
- HIF_TMPLT_NA = 0x7
-};
-
-#define HIF_API_MAX_TEMPLATE_FRAME_SIZE 700
-
-struct hif_mib_template_frame {
- u8 frame_type;
- u8 init_rate:7;
- u8 mode:1;
- __le16 frame_length;
- u8 frame[];
-} __packed;
-
-struct hif_mib_beacon_wake_up_period {
- u8 wakeup_period_min;
- u8 receive_dtim:1;
- u8 reserved1:7;
- u8 wakeup_period_max;
- u8 reserved2;
-} __packed;
-
-struct hif_mib_rcpi_rssi_threshold {
- u8 detection:1;
- u8 rcpi_rssi:1;
- u8 upperthresh:1;
- u8 lowerthresh:1;
- u8 reserved:4;
- u8 lower_threshold;
- u8 upper_threshold;
- u8 rolling_average_count;
-} __packed;
-
-#define DEFAULT_BA_MAX_RX_BUFFER_SIZE 16
-
-struct hif_mib_block_ack_policy {
- u8 block_ack_tx_tid_policy;
- u8 reserved1;
- u8 block_ack_rx_tid_policy;
- u8 block_ack_rx_max_buffer_size;
-} __packed;
-
-enum hif_mpdu_start_spacing {
- HIF_MPDU_START_SPACING_NO_RESTRIC = 0x0,
- HIF_MPDU_START_SPACING_QUARTER = 0x1,
- HIF_MPDU_START_SPACING_HALF = 0x2,
- HIF_MPDU_START_SPACING_ONE = 0x3,
- HIF_MPDU_START_SPACING_TWO = 0x4,
- HIF_MPDU_START_SPACING_FOUR = 0x5,
- HIF_MPDU_START_SPACING_EIGHT = 0x6,
- HIF_MPDU_START_SPACING_SIXTEEN = 0x7
-};
-
-struct hif_mib_set_association_mode {
- u8 preambtype_use:1;
- u8 mode:1;
- u8 rateset:1;
- u8 spacing:1;
- u8 reserved1:4;
- u8 short_preamble:1;
- u8 reserved2:7;
- u8 greenfield:1;
- u8 reserved3:7;
- u8 mpdu_start_spacing;
- __le32 basic_rate_set;
-} __packed;
-
-struct hif_mib_set_uapsd_information {
- u8 trig_bckgrnd:1;
- u8 trig_be:1;
- u8 trig_video:1;
- u8 trig_voice:1;
- u8 reserved1:4;
- u8 deliv_bckgrnd:1;
- u8 deliv_be:1;
- u8 deliv_video:1;
- u8 deliv_voice:1;
- u8 reserved2:4;
- __le16 min_auto_trigger_interval;
- __le16 max_auto_trigger_interval;
- __le16 auto_trigger_step;
-} __packed;
-
-struct hif_tx_rate_retry_policy {
- u8 policy_index;
- u8 short_retry_count;
- u8 long_retry_count;
- u8 first_rate_sel:2;
- u8 terminate:1;
- u8 count_init:1;
- u8 reserved1:4;
- u8 rate_recovery_count;
- u8 reserved2[3];
- u8 rates[12];
-} __packed;
-
-#define HIF_TX_RETRY_POLICY_MAX 15
-#define HIF_TX_RETRY_POLICY_INVALID HIF_TX_RETRY_POLICY_MAX
-
-struct hif_mib_set_tx_rate_retry_policy {
- u8 num_tx_rate_policies;
- u8 reserved[3];
- struct hif_tx_rate_retry_policy tx_rate_retry_policy[];
-} __packed;
-
-struct hif_mib_protected_mgmt_policy {
- u8 pmf_enable:1;
- u8 unpmf_allowed:1;
- u8 host_enc_auth_frames:1;
- u8 reserved1:5;
- u8 reserved2[3];
-} __packed;
-
-struct hif_mib_keep_alive_period {
- __le16 keep_alive_period;
- u8 reserved[2];
-} __packed;
-
-#endif
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
deleted file mode 100644
index 56a5f891447b..000000000000
--- a/drivers/staging/wfx/hif_rx.c
+++ /dev/null
@@ -1,415 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
- * (WSM) API.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/skbuff.h>
-#include <linux/etherdevice.h>
-
-#include "hif_rx.h"
-#include "wfx.h"
-#include "scan.h"
-#include "bh.h"
-#include "sta.h"
-#include "data_rx.h"
-#include "hif_api_cmd.h"
-
-static int hif_generic_confirm(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf)
-{
- // All confirm messages start with status
- int status = le32_to_cpup((__le32 *)buf);
- int cmd = hif->id;
- int len = le16_to_cpu(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 && len > 0)
- memcpy(wdev->hif_cmd.buf_recv, buf, len);
- else
- status = -EIO;
- }
- wdev->hif_cmd.ret = status;
-
- complete(&wdev->hif_cmd.done);
- return status;
-}
-
-static int hif_tx_confirm(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf)
-{
- const struct hif_cnf_tx *body = buf;
-
- wfx_tx_confirm_cb(wdev, body);
- return 0;
-}
-
-static int hif_multi_tx_confirm(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf)
-{
- const struct hif_cnf_multi_transmit *body = buf;
- int i;
-
- WARN(body->num_tx_confs <= 0, "corrupted message");
- for (i = 0; i < body->num_tx_confs; i++)
- wfx_tx_confirm_cb(wdev, &body->tx_conf_payload[i]);
- return 0;
-}
-
-static int hif_startup_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf)
-{
- const 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));
- le16_to_cpus((__le16 *)&wdev->hw_caps.hardware_id);
- le16_to_cpus((__le16 *)&wdev->hw_caps.num_inp_ch_bufs);
- le16_to_cpus((__le16 *)&wdev->hw_caps.size_inp_ch_buf);
- le32_to_cpus((__le32 *)&wdev->hw_caps.supported_rate_mask);
-
- complete(&wdev->firmware_ready);
- return 0;
-}
-
-static int hif_wakeup_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf)
-{
- if (!wdev->pdata.gpio_wakeup ||
- gpiod_get_value(wdev->pdata.gpio_wakeup) == 0) {
- dev_warn(wdev->dev, "unexpected wake-up indication\n");
- return -EIO;
- }
- return 0;
-}
-
-static int hif_receive_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif,
- const void *buf, struct sk_buff *skb)
-{
- struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
- const struct hif_ind_rx *body = buf;
-
- if (!wvif) {
- dev_warn(wdev->dev, "%s: ignore rx data for non-existent vif %d\n",
- __func__, hif->interface);
- return -EIO;
- }
- skb_pull(skb, sizeof(struct hif_msg) + sizeof(struct hif_ind_rx));
- wfx_rx_cb(wvif, body, skb);
-
- return 0;
-}
-
-static int hif_event_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf)
-{
- struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
- const struct hif_ind_event *body = buf;
- int type = le32_to_cpu(body->event_id);
-
- if (!wvif) {
- dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
- return -EIO;
- }
-
- switch (type) {
- case HIF_EVENT_IND_RCPI_RSSI:
- wfx_event_report_rssi(wvif, body->event_data.rcpi_rssi);
- break;
- case HIF_EVENT_IND_BSSLOST:
- schedule_delayed_work(&wvif->beacon_loss_work, 0);
- break;
- case HIF_EVENT_IND_BSSREGAINED:
- cancel_delayed_work(&wvif->beacon_loss_work);
- dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n");
- break;
- case HIF_EVENT_IND_PS_MODE_ERROR:
- dev_warn(wdev->dev, "error while processing power save request: %d\n",
- le32_to_cpu(body->event_data.ps_mode_error));
- break;
- default:
- dev_warn(wdev->dev, "unhandled event indication: %.2x\n",
- type);
- break;
- }
- return 0;
-}
-
-static int hif_pm_mode_complete_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif,
- const void *buf)
-{
- struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
-
- if (!wvif) {
- dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
- return -EIO;
- }
- complete(&wvif->set_pm_mode_complete);
-
- return 0;
-}
-
-static int hif_scan_complete_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif,
- const void *buf)
-{
- struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
-
- if (!wvif) {
- dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
- return -EIO;
- }
-
- wfx_scan_complete(wvif);
-
- return 0;
-}
-
-static int hif_join_complete_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif,
- const void *buf)
-{
- struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
-
- if (!wvif) {
- dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
- return -EIO;
- }
- dev_warn(wdev->dev, "unattended JoinCompleteInd\n");
-
- return 0;
-}
-
-static int hif_suspend_resume_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif,
- const void *buf)
-{
- const struct hif_ind_suspend_resume_tx *body = buf;
- struct wfx_vif *wvif;
-
- if (body->bc_mc_only) {
- wvif = wdev_to_wvif(wdev, hif->interface);
- if (!wvif) {
- dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
- return -EIO;
- }
- if (body->resume)
- wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE);
- else
- wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP);
- } else {
- WARN(body->peer_sta_set, "misunderstood indication");
- WARN(hif->interface != 2, "misunderstood indication");
- if (body->resume)
- wfx_suspend_hot_dev(wdev, STA_NOTIFY_AWAKE);
- else
- wfx_suspend_hot_dev(wdev, STA_NOTIFY_SLEEP);
- }
-
- return 0;
-}
-
-static int hif_generic_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf)
-{
- const struct hif_ind_generic *body = buf;
- int type = le32_to_cpu(body->type);
-
- switch (type) {
- case HIF_GENERIC_INDICATION_TYPE_RAW:
- return 0;
- case HIF_GENERIC_INDICATION_TYPE_STRING:
- dev_info(wdev->dev, "firmware says: %s\n", (char *)&body->data);
- return 0;
- case HIF_GENERIC_INDICATION_TYPE_RX_STATS:
- mutex_lock(&wdev->rx_stats_lock);
- // Older firmware send a generic indication beside RxStats
- if (!wfx_api_older_than(wdev, 1, 4))
- dev_info(wdev->dev, "Rx test ongoing. Temperature: %d degrees C\n",
- body->data.rx_stats.current_temp);
- memcpy(&wdev->rx_stats, &body->data.rx_stats,
- sizeof(wdev->rx_stats));
- mutex_unlock(&wdev->rx_stats_lock);
- return 0;
- case HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO:
- mutex_lock(&wdev->tx_power_loop_info_lock);
- memcpy(&wdev->tx_power_loop_info,
- &body->data.tx_power_loop_info,
- sizeof(wdev->tx_power_loop_info));
- mutex_unlock(&wdev->tx_power_loop_info_lock);
- return 0;
- default:
- dev_err(wdev->dev, "generic_indication: unknown indication type: %#.8x\n",
- type);
- return -EIO;
- }
-}
-
-static const struct {
- int val;
- const char *str;
- bool has_param;
-} hif_errors[] = {
- { HIF_ERROR_FIRMWARE_ROLLBACK,
- "rollback status" },
- { HIF_ERROR_FIRMWARE_DEBUG_ENABLED,
- "debug feature enabled" },
- { HIF_ERROR_PDS_PAYLOAD,
- "PDS version is not supported" },
- { HIF_ERROR_PDS_TESTFEATURE,
- "PDS ask for an unknown test mode" },
- { HIF_ERROR_OOR_VOLTAGE,
- "out-of-range power supply voltage", true },
- { HIF_ERROR_OOR_TEMPERATURE,
- "out-of-range temperature", true },
- { HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE,
- "secure link does not expect request during key exchange" },
- { HIF_ERROR_SLK_SESSION_KEY,
- "secure link session key is invalid" },
- { HIF_ERROR_SLK_OVERFLOW,
- "secure link overflow" },
- { HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE,
- "secure link messages list does not match message encryption" },
- { HIF_ERROR_SLK_UNCONFIGURED,
- "secure link not yet configured" },
- { HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW,
- "bus clock is too slow (<1kHz)" },
- { HIF_ERROR_HIF_RX_DATA_TOO_LARGE,
- "HIF message too large" },
- // Following errors only exists in old firmware versions:
- { HIF_ERROR_HIF_TX_QUEUE_FULL,
- "HIF messages queue is full" },
- { HIF_ERROR_HIF_BUS,
- "HIF bus" },
- { HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED,
- "secure link does not support multi-tx confirmations" },
- { HIF_ERROR_SLK_OUTDATED_SESSION_KEY,
- "secure link session key is outdated" },
- { HIF_ERROR_SLK_DECRYPTION,
- "secure link params (nonce or tag) mismatch" },
-};
-
-static int hif_error_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf)
-{
- const struct hif_ind_error *body = buf;
- int type = le32_to_cpu(body->type);
- int param = (s8)body->data[0];
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hif_errors); i++)
- if (type == hif_errors[i].val)
- break;
- if (i < ARRAY_SIZE(hif_errors))
- if (hif_errors[i].has_param)
- dev_err(wdev->dev, "asynchronous error: %s: %d\n",
- hif_errors[i].str, param);
- else
- dev_err(wdev->dev, "asynchronous error: %s\n",
- hif_errors[i].str);
- else
- dev_err(wdev->dev, "asynchronous error: unknown: %08x\n", type);
- print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET,
- 16, 1, hif, le16_to_cpu(hif->len), false);
- wdev->chip_frozen = true;
-
- return 0;
-};
-
-static int hif_exception_indication(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf)
-{
- const struct hif_ind_exception *body = buf;
- int type = le32_to_cpu(body->type);
-
- if (type == 4)
- dev_err(wdev->dev, "firmware assert %d\n",
- le32_to_cpup((__le32 *)body->data));
- else
- dev_err(wdev->dev, "firmware exception\n");
- print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET,
- 16, 1, hif, le16_to_cpu(hif->len), false);
- wdev->chip_frozen = true;
-
- return -1;
-}
-
-static const struct {
- int msg_id;
- int (*handler)(struct wfx_dev *wdev,
- const struct hif_msg *hif, const void *buf);
-} hif_handlers[] = {
- /* Confirmations */
- { HIF_CNF_ID_TX, hif_tx_confirm },
- { HIF_CNF_ID_MULTI_TRANSMIT, hif_multi_tx_confirm },
- /* Indications */
- { HIF_IND_ID_STARTUP, hif_startup_indication },
- { HIF_IND_ID_WAKEUP, hif_wakeup_indication },
- { HIF_IND_ID_JOIN_COMPLETE, hif_join_complete_indication },
- { HIF_IND_ID_SET_PM_MODE_CMPL, hif_pm_mode_complete_indication },
- { HIF_IND_ID_SCAN_CMPL, hif_scan_complete_indication },
- { HIF_IND_ID_SUSPEND_RESUME_TX, hif_suspend_resume_indication },
- { HIF_IND_ID_EVENT, hif_event_indication },
- { HIF_IND_ID_GENERIC, hif_generic_indication },
- { HIF_IND_ID_ERROR, hif_error_indication },
- { HIF_IND_ID_EXCEPTION, hif_exception_indication },
- // FIXME: allocate skb_p from hif_receive_indication and make it generic
- //{ HIF_IND_ID_RX, hif_receive_indication },
-};
-
-void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
-{
- int i;
- const struct hif_msg *hif = (const struct hif_msg *)skb->data;
- int hif_id = hif->id;
-
- if (hif_id == HIF_IND_ID_RX) {
- // hif_receive_indication take care of skb lifetime
- hif_receive_indication(wdev, hif, hif->body, skb);
- return;
- }
- // 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)
- hif_handlers[i].handler(wdev, hif, hif->body);
- goto free;
- }
- }
- if (hif_id & 0x80)
- dev_err(wdev->dev, "unsupported HIF indication: ID %02x\n",
- hif_id);
- else
- dev_err(wdev->dev, "unexpected HIF confirmation: 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
deleted file mode 100644
index f07c10c8c6bd..000000000000
--- a/drivers/staging/wfx/hif_rx.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* 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/hif_tx.c b/drivers/staging/wfx/hif_tx.c
deleted file mode 100644
index 63b437261eb7..000000000000
--- a/drivers/staging/wfx/hif_tx.c
+++ /dev/null
@@ -1,523 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx
- * Split Mac (WSM) API.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/etherdevice.h>
-
-#include "hif_tx.h"
-#include "wfx.h"
-#include "bh.h"
-#include "hwio.h"
-#include "debug.h"
-#include "sta.h"
-
-void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
-{
- init_completion(&hif_cmd->ready);
- init_completion(&hif_cmd->done);
- mutex_init(&hif_cmd->lock);
-}
-
-static void wfx_fill_header(struct hif_msg *hif, int if_id,
- unsigned int cmd, size_t size)
-{
- if (if_id == -1)
- if_id = 2;
-
- WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd);
- WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size);
- WARN(if_id > 0x3, "invalid interface ID %d", if_id);
-
- hif->len = cpu_to_le16(size + 4);
- hif->id = cmd;
- hif->interface = if_id;
-}
-
-static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif)
-{
- *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL);
- if (*hif)
- return (*hif)->body;
- else
- return NULL;
-}
-
-int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request,
- void *reply, size_t reply_len, bool no_reply)
-{
- const char *mib_name = "";
- const char *mib_sep = "";
- int cmd = request->id;
- int vif = request->interface;
- int ret;
-
- // Do not wait for any reply if chip is frozen
- if (wdev->chip_frozen)
- return -ETIMEDOUT;
-
- mutex_lock(&wdev->hif_cmd.lock);
- WARN(wdev->hif_cmd.buf_send, "data locking error");
-
- // Note: call to complete() below has an implicit memory barrier that
- // hopefully protect buf_send
- wdev->hif_cmd.buf_send = request;
- wdev->hif_cmd.buf_recv = reply;
- wdev->hif_cmd.len_recv = reply_len;
- complete(&wdev->hif_cmd.ready);
-
- wfx_bh_request_tx(wdev);
-
- if (no_reply) {
- // Chip won't reply. Give enough time to the wq to send the
- // buffer.
- msleep(100);
- wdev->hif_cmd.buf_send = NULL;
- mutex_unlock(&wdev->hif_cmd.lock);
- return 0;
- }
-
- if (wdev->poll_irq)
- wfx_bh_poll_irq(wdev);
-
- ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ);
- if (!ret) {
- dev_err(wdev->dev, "chip is abnormally long to answer\n");
- reinit_completion(&wdev->hif_cmd.ready);
- ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ);
- }
- if (!ret) {
- dev_err(wdev->dev, "chip did not answer\n");
- wfx_pending_dump_old_frames(wdev, 3000);
- wdev->chip_frozen = true;
- reinit_completion(&wdev->hif_cmd.done);
- ret = -ETIMEDOUT;
- } else {
- ret = wdev->hif_cmd.ret;
- }
-
- wdev->hif_cmd.buf_send = NULL;
- mutex_unlock(&wdev->hif_cmd.lock);
-
- if (ret &&
- (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) {
- mib_name = get_mib_name(((u16 *)request)[2]);
- mib_sep = "/";
- }
- if (ret < 0)
- dev_err(wdev->dev,
- "WSM request %s%s%s (%#.2x) on vif %d returned error %d\n",
- get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
- if (ret > 0)
- dev_warn(wdev->dev,
- "WSM request %s%s%s (%#.2x) on vif %d returned status %d\n",
- get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
-
- return ret;
-}
-
-// This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any
-// request anymore. Obviously, only call this function during device unregister.
-int hif_shutdown(struct wfx_dev *wdev)
-{
- int ret;
- struct hif_msg *hif;
-
- wfx_alloc_hif(0, &hif);
- if (!hif)
- return -ENOMEM;
- wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0);
- ret = wfx_cmd_send(wdev, hif, NULL, 0, true);
- if (wdev->pdata.gpio_wakeup)
- gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
- else
- control_reg_write(wdev, 0);
- kfree(hif);
- return ret;
-}
-
-int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
-{
- int ret;
- size_t buf_len = sizeof(struct hif_req_configuration) + len;
- struct hif_msg *hif;
- struct hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif);
-
- if (!hif)
- return -ENOMEM;
- body->length = cpu_to_le16(len);
- memcpy(body->pds_data, conf, len);
- wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len);
- ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_reset(struct wfx_vif *wvif, bool reset_stat)
-{
- int ret;
- struct hif_msg *hif;
- struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif);
-
- if (!hif)
- return -ENOMEM;
- body->reset_stat = reset_stat;
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body));
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
- void *val, size_t val_len)
-{
- int ret;
- struct hif_msg *hif;
- int buf_len = sizeof(struct hif_cnf_read_mib) + val_len;
- struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif);
- struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
-
- if (!body || !reply) {
- ret = -ENOMEM;
- goto out;
- }
- body->mib_id = cpu_to_le16(mib_id);
- wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body));
- ret = wfx_cmd_send(wdev, hif, reply, buf_len, false);
-
- if (!ret && mib_id != le16_to_cpu(reply->mib_id)) {
- dev_warn(wdev->dev, "%s: confirmation mismatch request\n",
- __func__);
- ret = -EIO;
- }
- if (ret == -ENOMEM)
- dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n",
- get_mib_name(mib_id), val_len,
- le16_to_cpu(reply->length));
- if (!ret)
- memcpy(val, &reply->mib_data, le16_to_cpu(reply->length));
- else
- memset(val, 0xFF, val_len);
-out:
- kfree(hif);
- kfree(reply);
- return ret;
-}
-
-int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
- void *val, size_t val_len)
-{
- int ret;
- struct hif_msg *hif;
- int buf_len = sizeof(struct hif_req_write_mib) + val_len;
- struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif);
-
- if (!hif)
- return -ENOMEM;
- body->mib_id = cpu_to_le16(mib_id);
- body->length = cpu_to_le16(val_len);
- memcpy(&body->mib_data, val, val_len);
- wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len);
- ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req,
- int chan_start_idx, int chan_num, int *timeout)
-{
- int ret, i;
- struct hif_msg *hif;
- size_t buf_len =
- sizeof(struct hif_req_start_scan_alt) + chan_num * sizeof(u8);
- struct hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif);
- int tmo_chan_fg, tmo_chan_bg, tmo;
-
- WARN(chan_num > HIF_API_MAX_NB_CHANNELS, "invalid params");
- WARN(req->n_ssids > HIF_API_MAX_NB_SSIDS, "invalid params");
-
- if (!hif)
- return -ENOMEM;
- for (i = 0; i < req->n_ssids; i++) {
- memcpy(body->ssid_def[i].ssid, req->ssids[i].ssid,
- IEEE80211_MAX_SSID_LEN);
- body->ssid_def[i].ssid_length =
- cpu_to_le32(req->ssids[i].ssid_len);
- }
- body->num_of_ssids = HIF_API_MAX_NB_SSIDS;
- body->maintain_current_bss = 1;
- body->disallow_ps = 1;
- body->tx_power_level =
- cpu_to_le32(req->channels[chan_start_idx]->max_power);
- body->num_of_channels = chan_num;
- for (i = 0; i < chan_num; i++)
- body->channel_list[i] =
- req->channels[i + chan_start_idx]->hw_value;
- if (req->no_cck)
- body->max_transmit_rate = API_RATE_INDEX_G_6MBPS;
- else
- body->max_transmit_rate = API_RATE_INDEX_B_1MBPS;
- if (req->channels[chan_start_idx]->flags & IEEE80211_CHAN_NO_IR) {
- body->min_channel_time = cpu_to_le32(50);
- body->max_channel_time = cpu_to_le32(150);
- } else {
- body->min_channel_time = cpu_to_le32(10);
- body->max_channel_time = cpu_to_le32(50);
- body->num_of_probe_requests = 2;
- body->probe_delay = 100;
- }
- tmo_chan_bg = le32_to_cpu(body->max_channel_time) * USEC_PER_TU;
- tmo_chan_fg = 512 * USEC_PER_TU + body->probe_delay;
- tmo_chan_fg *= body->num_of_probe_requests;
- tmo = chan_num * max(tmo_chan_bg, tmo_chan_fg) + 512 * USEC_PER_TU;
- if (timeout)
- *timeout = usecs_to_jiffies(tmo);
-
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len);
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_stop_scan(struct wfx_vif *wvif)
-{
- int ret;
- struct hif_msg *hif;
- // body associated to HIF_REQ_ID_STOP_SCAN is empty
- wfx_alloc_hif(0, &hif);
-
- if (!hif)
- return -ENOMEM;
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0);
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
- struct ieee80211_channel *channel, const u8 *ssid, int ssidlen)
-{
- int ret;
- struct hif_msg *hif;
- struct hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif);
-
- WARN_ON(!conf->beacon_int);
- WARN_ON(!conf->basic_rates);
- WARN_ON(sizeof(body->ssid) < ssidlen);
- WARN(!conf->ibss_joined && !ssidlen, "joining an unknown BSS");
- if (WARN_ON(!channel))
- return -EINVAL;
- if (!hif)
- return -ENOMEM;
- body->infrastructure_bss_mode = !conf->ibss_joined;
- body->short_preamble = conf->use_short_preamble;
- if (channel->flags & IEEE80211_CHAN_NO_IR)
- body->probe_for_join = 0;
- else
- body->probe_for_join = 1;
- body->channel_number = channel->hw_value;
- body->beacon_interval = cpu_to_le32(conf->beacon_int);
- body->basic_rate_set =
- cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
- memcpy(body->bssid, conf->bssid, sizeof(body->bssid));
- if (ssid) {
- body->ssid_length = cpu_to_le32(ssidlen);
- memcpy(body->ssid, ssid, ssidlen);
- }
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body));
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count)
-{
- int ret;
- struct hif_msg *hif;
- struct hif_req_set_bss_params *body =
- wfx_alloc_hif(sizeof(*body), &hif);
-
- if (!hif)
- return -ENOMEM;
- body->aid = cpu_to_le16(aid);
- body->beacon_lost_count = beacon_lost_count;
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS,
- sizeof(*body));
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg)
-{
- int ret;
- struct hif_msg *hif;
- // FIXME: only send necessary bits
- struct hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif);
-
- if (!hif)
- return -ENOMEM;
- // FIXME: swap bytes as necessary in body
- memcpy(body, arg, sizeof(*body));
- if (wfx_api_older_than(wdev, 1, 5))
- // Legacy firmwares expect that add_key to be sent on right
- // interface.
- wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY,
- sizeof(*body));
- else
- wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body));
- ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_remove_key(struct wfx_dev *wdev, int idx)
-{
- int ret;
- struct hif_msg *hif;
- struct hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif);
-
- if (!hif)
- return -ENOMEM;
- body->entry_index = idx;
- wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body));
- ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
- const struct ieee80211_tx_queue_params *arg)
-{
- int ret;
- struct hif_msg *hif;
- struct hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body),
- &hif);
-
- if (!body)
- return -ENOMEM;
-
- WARN_ON(arg->aifs > 255);
- if (!hif)
- return -ENOMEM;
- body->aifsn = arg->aifs;
- body->cw_min = cpu_to_le16(arg->cw_min);
- body->cw_max = cpu_to_le16(arg->cw_max);
- body->tx_op_limit = cpu_to_le16(arg->txop * USEC_PER_TXOP);
- body->queue_id = 3 - queue;
- // API 2.0 has changed queue IDs values
- if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BE)
- body->queue_id = HIF_QUEUE_ID_BACKGROUND;
- if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BK)
- body->queue_id = HIF_QUEUE_ID_BESTEFFORT;
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS,
- sizeof(*body));
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout)
-{
- int ret;
- struct hif_msg *hif;
- struct hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif);
-
- if (!body)
- return -ENOMEM;
-
- if (!hif)
- return -ENOMEM;
- if (ps) {
- body->enter_psm = 1;
- // Firmware does not support more than 128ms
- body->fast_psm_idle_period = min(dynamic_ps_timeout * 2, 255);
- if (body->fast_psm_idle_period)
- body->fast_psm = 1;
- }
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body));
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
- const struct ieee80211_channel *channel)
-{
- int ret;
- struct hif_msg *hif;
- struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif);
-
- WARN_ON(!conf->beacon_int);
- if (!hif)
- return -ENOMEM;
- body->dtim_period = conf->dtim_period;
- body->short_preamble = conf->use_short_preamble;
- body->channel_number = channel->hw_value;
- body->beacon_interval = cpu_to_le32(conf->beacon_int);
- body->basic_rate_set =
- cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
- body->ssid_length = conf->ssid_len;
- memcpy(body->ssid, conf->ssid, conf->ssid_len);
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body));
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_beacon_transmit(struct wfx_vif *wvif, bool enable)
-{
- int ret;
- struct hif_msg *hif;
- struct hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body),
- &hif);
-
- if (!hif)
- return -ENOMEM;
- body->enable_beaconing = enable ? 1 : 0;
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT,
- sizeof(*body));
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp)
-{
- int ret;
- struct hif_msg *hif;
- struct hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif);
-
- if (!hif)
- return -ENOMEM;
- if (mac_addr)
- ether_addr_copy(body->mac_addr, mac_addr);
- body->mfpc = mfp ? 1 : 0;
- body->unmap = unmap ? 1 : 0;
- body->peer_sta_id = sta_id;
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body));
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
-
-int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
-{
- int ret;
- struct hif_msg *hif;
- int buf_len = sizeof(struct hif_req_update_ie) + ies_len;
- struct hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif);
-
- if (!hif)
- return -ENOMEM;
- body->beacon = 1;
- body->num_ies = cpu_to_le16(1);
- memcpy(body->ie, ies, ies_len);
- wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len);
- ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
- kfree(hif);
- return ret;
-}
diff --git a/drivers/staging/wfx/hif_tx.h b/drivers/staging/wfx/hif_tx.h
deleted file mode 100644
index 3521c545ae6b..000000000000
--- a/drivers/staging/wfx/hif_tx.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx
- * Split Mac (WSM) API.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- * Copyright (C) 2010, ST-Ericsson SA
- */
-#ifndef WFX_HIF_TX_H
-#define WFX_HIF_TX_H
-
-struct ieee80211_channel;
-struct ieee80211_bss_conf;
-struct ieee80211_tx_queue_params;
-struct cfg80211_scan_request;
-struct hif_req_add_key;
-struct wfx_dev;
-struct wfx_vif;
-
-struct wfx_hif_cmd {
- struct mutex lock;
- struct completion ready;
- struct completion done;
- struct hif_msg *buf_send;
- void *buf_recv;
- size_t len_recv;
- int ret;
-};
-
-void wfx_init_hif_cmd(struct wfx_hif_cmd *wfx_hif_cmd);
-int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request,
- void *reply, size_t reply_len, bool async);
-
-int hif_shutdown(struct wfx_dev *wdev);
-int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len);
-int hif_reset(struct wfx_vif *wvif, bool reset_stat);
-int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
- void *buf, size_t buf_size);
-int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
- void *buf, size_t buf_size);
-int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211,
- int chan_start, int chan_num, int *timeout);
-int hif_stop_scan(struct wfx_vif *wvif);
-int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
- struct ieee80211_channel *channel, const u8 *ssid, int ssidlen);
-int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout);
-int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count);
-int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg);
-int hif_remove_key(struct wfx_dev *wdev, int idx);
-int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
- const struct ieee80211_tx_queue_params *arg);
-int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
- const struct ieee80211_channel *channel);
-int hif_beacon_transmit(struct wfx_vif *wvif, bool enable);
-int hif_map_link(struct wfx_vif *wvif,
- bool unmap, u8 *mac_addr, int sta_id, bool mfp);
-int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len);
-
-#endif
diff --git a/drivers/staging/wfx/hif_tx_mib.c b/drivers/staging/wfx/hif_tx_mib.c
deleted file mode 100644
index 1926cf1b62be..000000000000
--- a/drivers/staging/wfx/hif_tx_mib.c
+++ /dev/null
@@ -1,324 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- * Copyright (C) 2010, ST-Ericsson SA
- */
-
-#include <linux/etherdevice.h>
-
-#include "wfx.h"
-#include "hif_tx.h"
-#include "hif_tx_mib.h"
-#include "hif_api_mib.h"
-
-int hif_set_output_power(struct wfx_vif *wvif, int val)
-{
- struct hif_mib_current_tx_power_level arg = {
- .power_level = cpu_to_le32(val * 10),
- };
-
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_CURRENT_TX_POWER_LEVEL,
- &arg, sizeof(arg));
-}
-
-int hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
- unsigned int dtim_interval,
- unsigned int listen_interval)
-{
- struct hif_mib_beacon_wake_up_period arg = {
- .wakeup_period_min = dtim_interval,
- .receive_dtim = 0,
- .wakeup_period_max = listen_interval,
- };
-
- if (dtim_interval > 0xFF || listen_interval > 0xFFFF)
- return -EINVAL;
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_BEACON_WAKEUP_PERIOD,
- &arg, sizeof(arg));
-}
-
-int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif,
- int rssi_thold, int rssi_hyst)
-{
- struct hif_mib_rcpi_rssi_threshold arg = {
- .rolling_average_count = 8,
- .detection = 1,
- };
-
- if (!rssi_thold && !rssi_hyst) {
- arg.upperthresh = 1;
- arg.lowerthresh = 1;
- } else {
- arg.upper_threshold = rssi_thold + rssi_hyst;
- arg.upper_threshold = (arg.upper_threshold + 110) * 2;
- arg.lower_threshold = rssi_thold;
- arg.lower_threshold = (arg.lower_threshold + 110) * 2;
- }
-
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_RCPI_RSSI_THRESHOLD, &arg, sizeof(arg));
-}
-
-int hif_get_counters_table(struct wfx_dev *wdev, int vif_id,
- struct hif_mib_extended_count_table *arg)
-{
- if (wfx_api_older_than(wdev, 1, 3)) {
- // extended_count_table is wider than count_table
- memset(arg, 0xFF, sizeof(*arg));
- return hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE,
- arg, sizeof(struct hif_mib_count_table));
- } else {
- return hif_read_mib(wdev, vif_id,
- HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, arg,
- sizeof(struct hif_mib_extended_count_table));
- }
-}
-
-int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac)
-{
- struct hif_mib_mac_address msg = { };
-
- if (mac)
- ether_addr_copy(msg.mac_addr, mac);
- return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS,
- &msg, sizeof(msg));
-}
-
-int hif_set_rx_filter(struct wfx_vif *wvif,
- bool filter_bssid, bool filter_prbreq)
-{
- struct hif_mib_rx_filter arg = { };
-
- if (filter_bssid)
- arg.bssid_filter = 1;
- if (!filter_prbreq)
- arg.fwd_probe_req = 1;
- return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER,
- &arg, sizeof(arg));
-}
-
-int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len,
- const struct hif_ie_table_entry *tbl)
-{
- int ret;
- struct hif_mib_bcn_filter_table *arg;
- int buf_len = struct_size(arg, ie_table, tbl_len);
-
- arg = kzalloc(buf_len, GFP_KERNEL);
- if (!arg)
- return -ENOMEM;
- arg->num_of_info_elmts = cpu_to_le32(tbl_len);
- memcpy(arg->ie_table, tbl, flex_array_size(arg, ie_table, tbl_len));
- ret = hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_BEACON_FILTER_TABLE, arg, buf_len);
- kfree(arg);
- return ret;
-}
-
-int hif_beacon_filter_control(struct wfx_vif *wvif,
- int enable, int beacon_count)
-{
- struct hif_mib_bcn_filter_enable arg = {
- .enable = cpu_to_le32(enable),
- .bcn_count = cpu_to_le32(beacon_count),
- };
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_BEACON_FILTER_ENABLE,
- &arg, sizeof(arg));
-}
-
-int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode)
-{
- struct hif_mib_gl_operational_power_mode arg = {
- .power_mode = mode,
- .wup_ind_activation = 1,
- };
-
- return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE,
- &arg, sizeof(arg));
-}
-
-int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb,
- u8 frame_type, int init_rate)
-{
- struct hif_mib_template_frame *arg;
-
- WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big");
- skb_push(skb, 4);
- arg = (struct hif_mib_template_frame *)skb->data;
- skb_pull(skb, 4);
- arg->init_rate = init_rate;
- arg->frame_type = frame_type;
- arg->frame_length = cpu_to_le16(skb->len);
- return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME,
- arg, sizeof(*arg) + skb->len);
-}
-
-int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required)
-{
- struct hif_mib_protected_mgmt_policy arg = { };
-
- WARN(required && !capable, "incoherent arguments");
- if (capable) {
- arg.pmf_enable = 1;
- arg.host_enc_auth_frames = 1;
- }
- if (!required)
- arg.unpmf_allowed = 1;
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_PROTECTED_MGMT_POLICY,
- &arg, sizeof(arg));
-}
-
-int hif_set_block_ack_policy(struct wfx_vif *wvif,
- u8 tx_tid_policy, u8 rx_tid_policy)
-{
- struct hif_mib_block_ack_policy arg = {
- .block_ack_tx_tid_policy = tx_tid_policy,
- .block_ack_rx_tid_policy = rx_tid_policy,
- };
-
- return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY,
- &arg, sizeof(arg));
-}
-
-int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density,
- bool greenfield, bool short_preamble)
-{
- struct hif_mib_set_association_mode arg = {
- .preambtype_use = 1,
- .mode = 1,
- .spacing = 1,
- .short_preamble = short_preamble,
- .greenfield = greenfield,
- .mpdu_start_spacing = ampdu_density,
- };
-
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_SET_ASSOCIATION_MODE, &arg, sizeof(arg));
-}
-
-int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif,
- int policy_index, u8 *rates)
-{
- struct hif_mib_set_tx_rate_retry_policy *arg;
- size_t size = struct_size(arg, tx_rate_retry_policy, 1);
- int ret;
-
- arg = kzalloc(size, GFP_KERNEL);
- if (!arg)
- return -ENOMEM;
- arg->num_tx_rate_policies = 1;
- arg->tx_rate_retry_policy[0].policy_index = policy_index;
- arg->tx_rate_retry_policy[0].short_retry_count = 255;
- arg->tx_rate_retry_policy[0].long_retry_count = 255;
- arg->tx_rate_retry_policy[0].first_rate_sel = 1;
- arg->tx_rate_retry_policy[0].terminate = 1;
- arg->tx_rate_retry_policy[0].count_init = 1;
- memcpy(&arg->tx_rate_retry_policy[0].rates, rates,
- sizeof(arg->tx_rate_retry_policy[0].rates));
- ret = hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size);
- kfree(arg);
- return ret;
-}
-
-int hif_keep_alive_period(struct wfx_vif *wvif, int period)
-{
- struct hif_mib_keep_alive_period arg = {
- .keep_alive_period = cpu_to_le16(period),
- };
-
- return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD,
- &arg, sizeof(arg));
-};
-
-int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr)
-{
- struct hif_mib_arp_ip_addr_table arg = {
- .condition_idx = idx,
- .arp_enable = HIF_ARP_NS_FILTERING_DISABLE,
- };
-
- if (addr) {
- // Caution: type of addr is __be32
- memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address));
- arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE;
- }
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE,
- &arg, sizeof(arg));
-}
-
-int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable)
-{
- struct hif_mib_gl_set_multi_msg arg = {
- .enable_multi_tx_conf = enable,
- };
-
- return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG,
- &arg, sizeof(arg));
-}
-
-int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val)
-{
- struct hif_mib_set_uapsd_information arg = { };
-
- if (val & BIT(IEEE80211_AC_VO))
- arg.trig_voice = 1;
- if (val & BIT(IEEE80211_AC_VI))
- arg.trig_video = 1;
- if (val & BIT(IEEE80211_AC_BE))
- arg.trig_be = 1;
- if (val & BIT(IEEE80211_AC_BK))
- arg.trig_bckgrnd = 1;
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_SET_UAPSD_INFORMATION,
- &arg, sizeof(arg));
-}
-
-int hif_erp_use_protection(struct wfx_vif *wvif, bool enable)
-{
- struct hif_mib_non_erp_protection arg = {
- .use_cts_to_self = enable,
- };
-
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg));
-}
-
-int hif_slot_time(struct wfx_vif *wvif, int val)
-{
- struct hif_mib_slot_time arg = {
- .slot_time = cpu_to_le32(val),
- };
-
- return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME,
- &arg, sizeof(arg));
-}
-
-int hif_wep_default_key_id(struct wfx_vif *wvif, int val)
-{
- struct hif_mib_wep_default_key_id arg = {
- .wep_default_key_id = val,
- };
-
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID,
- &arg, sizeof(arg));
-}
-
-int hif_rts_threshold(struct wfx_vif *wvif, int val)
-{
- struct hif_mib_dot11_rts_threshold arg = {
- .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF),
- };
-
- return hif_write_mib(wvif->wdev, wvif->id,
- HIF_MIB_ID_DOT11_RTS_THRESHOLD, &arg, sizeof(arg));
-}
diff --git a/drivers/staging/wfx/hif_tx_mib.h b/drivers/staging/wfx/hif_tx_mib.h
deleted file mode 100644
index 812b3ba0f00e..000000000000
--- a/drivers/staging/wfx/hif_tx_mib.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- * Copyright (C) 2010, ST-Ericsson SA
- */
-#ifndef WFX_HIF_TX_MIB_H
-#define WFX_HIF_TX_MIB_H
-
-struct wfx_vif;
-struct sk_buff;
-
-int hif_set_output_power(struct wfx_vif *wvif, int val);
-int hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
- unsigned int dtim_interval,
- unsigned int listen_interval);
-int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif,
- int rssi_thold, int rssi_hyst);
-int hif_get_counters_table(struct wfx_dev *wdev, int vif_id,
- struct hif_mib_extended_count_table *arg);
-int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac);
-int hif_set_rx_filter(struct wfx_vif *wvif,
- bool filter_bssid, bool fwd_probe_req);
-int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len,
- const struct hif_ie_table_entry *tbl);
-int hif_beacon_filter_control(struct wfx_vif *wvif,
- int enable, int beacon_count);
-int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode);
-int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb,
- u8 frame_type, int init_rate);
-int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required);
-int hif_set_block_ack_policy(struct wfx_vif *wvif,
- u8 tx_tid_policy, u8 rx_tid_policy);
-int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density,
- bool greenfield, bool short_preamble);
-int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif,
- int policy_index, u8 *rates);
-int hif_keep_alive_period(struct wfx_vif *wvif, int period);
-int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr);
-int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable);
-int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val);
-int hif_erp_use_protection(struct wfx_vif *wvif, bool enable);
-int hif_slot_time(struct wfx_vif *wvif, int val);
-int hif_wep_default_key_id(struct wfx_vif *wvif, int val);
-int hif_rts_threshold(struct wfx_vif *wvif, int val);
-
-#endif
diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c
deleted file mode 100644
index 36fbc5b5d64c..000000000000
--- a/drivers/staging/wfx/hwio.c
+++ /dev/null
@@ -1,352 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Low-level I/O functions.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-
-#include "hwio.h"
-#include "wfx.h"
-#include "bus.h"
-#include "traces.h"
-
-/*
- * Internal helpers.
- *
- * About CONFIG_VMAP_STACK:
- * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack
- * allocated data. Functions below that work with registers (aka functions
- * ending with "32") automatically reallocate buffers with kmalloc. However,
- * functions that work with arbitrary length buffers let's caller to handle
- * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located
- * buffer.
- */
-
-static int read32(struct wfx_dev *wdev, int reg, u32 *val)
-{
- int ret;
- __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
-
- *val = ~0; // Never return undefined value
- if (!tmp)
- return -ENOMEM;
- ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp,
- sizeof(u32));
- if (ret >= 0)
- *val = le32_to_cpu(*tmp);
- kfree(tmp);
- if (ret)
- dev_err(wdev->dev, "%s: bus communication error: %d\n",
- __func__, ret);
- return ret;
-}
-
-static int write32(struct wfx_dev *wdev, int reg, u32 val)
-{
- int ret;
- __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
-
- if (!tmp)
- return -ENOMEM;
- *tmp = cpu_to_le32(val);
- ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp,
- sizeof(u32));
- kfree(tmp);
- if (ret)
- dev_err(wdev->dev, "%s: bus communication error: %d\n",
- __func__, ret);
- return ret;
-}
-
-static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val)
-{
- int ret;
-
- wdev->hwbus_ops->lock(wdev->hwbus_priv);
- ret = read32(wdev, reg, val);
- _trace_io_read32(reg, *val);
- wdev->hwbus_ops->unlock(wdev->hwbus_priv);
- return ret;
-}
-
-static int write32_locked(struct wfx_dev *wdev, int reg, u32 val)
-{
- int ret;
-
- wdev->hwbus_ops->lock(wdev->hwbus_priv);
- ret = write32(wdev, reg, val);
- _trace_io_write32(reg, val);
- wdev->hwbus_ops->unlock(wdev->hwbus_priv);
- return ret;
-}
-
-static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val)
-{
- int ret;
- u32 val_r, val_w;
-
- WARN_ON(~mask & val);
- val &= mask;
- wdev->hwbus_ops->lock(wdev->hwbus_priv);
- ret = read32(wdev, reg, &val_r);
- _trace_io_read32(reg, val_r);
- if (ret < 0)
- goto err;
- val_w = (val_r & ~mask) | val;
- if (val_w != val_r) {
- ret = write32(wdev, reg, val_w);
- _trace_io_write32(reg, val_w);
- }
-err:
- wdev->hwbus_ops->unlock(wdev->hwbus_priv);
- return ret;
-}
-
-static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr,
- void *buf, size_t len)
-{
- int ret;
- int i;
- u32 cfg;
- u32 prefetch;
-
- WARN_ON(len >= 0x2000);
- WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
-
- if (reg == WFX_REG_AHB_DPORT)
- prefetch = CFG_PREFETCH_AHB;
- else if (reg == WFX_REG_SRAM_DPORT)
- prefetch = CFG_PREFETCH_SRAM;
- else
- return -ENODEV;
-
- ret = write32(wdev, WFX_REG_BASE_ADDR, addr);
- if (ret < 0)
- goto err;
-
- ret = read32(wdev, WFX_REG_CONFIG, &cfg);
- if (ret < 0)
- goto err;
-
- ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch);
- if (ret < 0)
- goto err;
-
- for (i = 0; i < 20; i++) {
- ret = read32(wdev, WFX_REG_CONFIG, &cfg);
- if (ret < 0)
- goto err;
- if (!(cfg & prefetch))
- break;
- usleep_range(200, 250);
- }
- if (i == 20) {
- ret = -ETIMEDOUT;
- goto err;
- }
-
- ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len);
-
-err:
- if (ret < 0)
- memset(buf, 0xFF, len); // Never return undefined value
- return ret;
-}
-
-static int indirect_write(struct wfx_dev *wdev, int reg, u32 addr,
- const void *buf, size_t len)
-{
- int ret;
-
- WARN_ON(len >= 0x2000);
- WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
- ret = write32(wdev, WFX_REG_BASE_ADDR, addr);
- if (ret < 0)
- return ret;
-
- return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len);
-}
-
-static int indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr,
- void *buf, size_t len)
-{
- int ret;
-
- wdev->hwbus_ops->lock(wdev->hwbus_priv);
- ret = indirect_read(wdev, reg, addr, buf, len);
- _trace_io_ind_read(reg, addr, buf, len);
- wdev->hwbus_ops->unlock(wdev->hwbus_priv);
- return ret;
-}
-
-static int indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr,
- const void *buf, size_t len)
-{
- int ret;
-
- wdev->hwbus_ops->lock(wdev->hwbus_priv);
- ret = indirect_write(wdev, reg, addr, buf, len);
- _trace_io_ind_write(reg, addr, buf, len);
- wdev->hwbus_ops->unlock(wdev->hwbus_priv);
- return ret;
-}
-
-static int indirect_read32_locked(struct wfx_dev *wdev, int reg,
- u32 addr, u32 *val)
-{
- int ret;
- __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
-
- if (!tmp)
- return -ENOMEM;
- wdev->hwbus_ops->lock(wdev->hwbus_priv);
- ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32));
- *val = le32_to_cpu(*tmp);
- _trace_io_ind_read32(reg, addr, *val);
- wdev->hwbus_ops->unlock(wdev->hwbus_priv);
- kfree(tmp);
- return ret;
-}
-
-static int indirect_write32_locked(struct wfx_dev *wdev, int reg,
- u32 addr, u32 val)
-{
- int ret;
- __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
-
- if (!tmp)
- return -ENOMEM;
- *tmp = cpu_to_le32(val);
- wdev->hwbus_ops->lock(wdev->hwbus_priv);
- ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32));
- _trace_io_ind_write32(reg, addr, val);
- wdev->hwbus_ops->unlock(wdev->hwbus_priv);
- kfree(tmp);
- return ret;
-}
-
-int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len)
-{
- int ret;
-
- WARN((long)buf & 3, "%s: unaligned buffer", __func__);
- wdev->hwbus_ops->lock(wdev->hwbus_priv);
- ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv,
- WFX_REG_IN_OUT_QUEUE, buf, len);
- _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len);
- wdev->hwbus_ops->unlock(wdev->hwbus_priv);
- if (ret)
- dev_err(wdev->dev, "%s: bus communication error: %d\n",
- __func__, ret);
- return ret;
-}
-
-int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len)
-{
- int ret;
-
- WARN((long)buf & 3, "%s: unaligned buffer", __func__);
- wdev->hwbus_ops->lock(wdev->hwbus_priv);
- ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv,
- WFX_REG_IN_OUT_QUEUE, buf, len);
- _trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len);
- wdev->hwbus_ops->unlock(wdev->hwbus_priv);
- if (ret)
- dev_err(wdev->dev, "%s: bus communication error: %d\n",
- __func__, ret);
- return ret;
-}
-
-int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
-{
- return indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
-}
-
-int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
-{
- return indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
-}
-
-int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
-{
- return indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
-}
-
-int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
-{
- return indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
-}
-
-int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
-{
- return indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
-}
-
-int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
-{
- return indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
-}
-
-int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
-{
- return indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
-}
-
-int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
-{
- return indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
-}
-
-int config_reg_read(struct wfx_dev *wdev, u32 *val)
-{
- return read32_locked(wdev, WFX_REG_CONFIG, val);
-}
-
-int config_reg_write(struct wfx_dev *wdev, u32 val)
-{
- return write32_locked(wdev, WFX_REG_CONFIG, val);
-}
-
-int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
-{
- return write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val);
-}
-
-int control_reg_read(struct wfx_dev *wdev, u32 *val)
-{
- return read32_locked(wdev, WFX_REG_CONTROL, val);
-}
-
-int control_reg_write(struct wfx_dev *wdev, u32 val)
-{
- return write32_locked(wdev, WFX_REG_CONTROL, val);
-}
-
-int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
-{
- return write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val);
-}
-
-int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val)
-{
- int ret;
-
- *val = ~0; // Never return undefined value
- ret = write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24);
- if (ret)
- return ret;
- ret = read32_locked(wdev, WFX_REG_SET_GEN_R_W, val);
- if (ret)
- return ret;
- *val &= IGPR_VALUE;
- return ret;
-}
-
-int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val)
-{
- return write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val);
-}
diff --git a/drivers/staging/wfx/hwio.h b/drivers/staging/wfx/hwio.h
deleted file mode 100644
index 0b8e4f7157df..000000000000
--- a/drivers/staging/wfx/hwio.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Low-level API.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_HWIO_H
-#define WFX_HWIO_H
-
-#include <linux/types.h>
-
-struct wfx_dev;
-
-int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t buf_len);
-int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t buf_len);
-
-int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len);
-int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len);
-
-int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len);
-int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len);
-
-int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val);
-int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val);
-
-int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val);
-int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val);
-
-#define CFG_ERR_SPI_FRAME 0x00000001 // only with SPI
-#define CFG_ERR_SDIO_BUF_MISMATCH 0x00000001 // only with SDIO
-#define CFG_ERR_BUF_UNDERRUN 0x00000002
-#define CFG_ERR_DATA_IN_TOO_LARGE 0x00000004
-#define CFG_ERR_HOST_NO_OUT_QUEUE 0x00000008
-#define CFG_ERR_BUF_OVERRUN 0x00000010
-#define CFG_ERR_DATA_OUT_TOO_LARGE 0x00000020
-#define CFG_ERR_HOST_NO_IN_QUEUE 0x00000040
-#define CFG_ERR_HOST_CRC_MISS 0x00000080 // only with SDIO
-#define CFG_SPI_IGNORE_CS 0x00000080 // only with SPI
-#define CFG_BYTE_ORDER_MASK 0x00000300 // only writable with SPI
-#define CFG_BYTE_ORDER_BADC 0x00000000
-#define CFG_BYTE_ORDER_DCBA 0x00000100
-#define CFG_BYTE_ORDER_ABCD 0x00000200 // SDIO always use this value
-#define CFG_DIRECT_ACCESS_MODE 0x00000400
-#define CFG_PREFETCH_AHB 0x00000800
-#define CFG_DISABLE_CPU_CLK 0x00001000
-#define CFG_PREFETCH_SRAM 0x00002000
-#define CFG_CPU_RESET 0x00004000
-#define CFG_SDIO_DISABLE_IRQ 0x00008000 // only with SDIO
-#define CFG_IRQ_ENABLE_DATA 0x00010000
-#define CFG_IRQ_ENABLE_WRDY 0x00020000
-#define CFG_CLK_RISE_EDGE 0x00040000
-#define CFG_SDIO_DISABLE_CRC_CHK 0x00080000 // only with SDIO
-#define CFG_RESERVED 0x00F00000
-#define CFG_DEVICE_ID_MAJOR 0x07000000
-#define CFG_DEVICE_ID_RESERVED 0x78000000
-#define CFG_DEVICE_ID_TYPE 0x80000000
-int config_reg_read(struct wfx_dev *wdev, u32 *val);
-int config_reg_write(struct wfx_dev *wdev, u32 val);
-int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val);
-
-#define CTRL_NEXT_LEN_MASK 0x00000FFF
-#define CTRL_WLAN_WAKEUP 0x00001000
-#define CTRL_WLAN_READY 0x00002000
-int control_reg_read(struct wfx_dev *wdev, u32 *val);
-int control_reg_write(struct wfx_dev *wdev, u32 val);
-int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val);
-
-#define IGPR_RW 0x80000000
-#define IGPR_INDEX 0x7F000000
-#define IGPR_VALUE 0x00FFFFFF
-int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val);
-int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val);
-
-#endif /* WFX_HWIO_H */
diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c
deleted file mode 100644
index 2ab82bed4c1b..000000000000
--- a/drivers/staging/wfx/key.c
+++ /dev/null
@@ -1,241 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Key management related functions.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/etherdevice.h>
-#include <net/mac80211.h>
-
-#include "key.h"
-#include "wfx.h"
-#include "hif_tx_mib.h"
-
-static int wfx_alloc_key(struct wfx_dev *wdev)
-{
- int idx;
-
- idx = ffs(~wdev->key_map) - 1;
- if (idx < 0 || idx >= MAX_KEY_ENTRIES)
- return -1;
-
- wdev->key_map |= BIT(idx);
- return idx;
-}
-
-static void wfx_free_key(struct wfx_dev *wdev, int idx)
-{
- WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation");
- wdev->key_map &= ~BIT(idx);
-}
-
-static u8 fill_wep_pair(struct hif_wep_pairwise_key *msg,
- struct ieee80211_key_conf *key, u8 *peer_addr)
-{
- WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
- msg->key_length = key->keylen;
- memcpy(msg->key_data, key->key, key->keylen);
- ether_addr_copy(msg->peer_address, peer_addr);
- return HIF_KEY_TYPE_WEP_PAIRWISE;
-}
-
-static u8 fill_wep_group(struct hif_wep_group_key *msg,
- struct ieee80211_key_conf *key)
-{
- WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
- msg->key_id = key->keyidx;
- msg->key_length = key->keylen;
- memcpy(msg->key_data, key->key, key->keylen);
- return HIF_KEY_TYPE_WEP_DEFAULT;
-}
-
-static u8 fill_tkip_pair(struct hif_tkip_pairwise_key *msg,
- struct ieee80211_key_conf *key, u8 *peer_addr)
-{
- u8 *keybuf = key->key;
-
- WARN(key->keylen != sizeof(msg->tkip_key_data)
- + sizeof(msg->tx_mic_key)
- + sizeof(msg->rx_mic_key), "inconsistent data");
- memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
- keybuf += sizeof(msg->tkip_key_data);
- memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key));
- keybuf += sizeof(msg->tx_mic_key);
- memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key));
- ether_addr_copy(msg->peer_address, peer_addr);
- return HIF_KEY_TYPE_TKIP_PAIRWISE;
-}
-
-static u8 fill_tkip_group(struct hif_tkip_group_key *msg,
- struct ieee80211_key_conf *key,
- struct ieee80211_key_seq *seq,
- enum nl80211_iftype iftype)
-{
- u8 *keybuf = key->key;
-
- WARN(key->keylen != sizeof(msg->tkip_key_data)
- + 2 * sizeof(msg->rx_mic_key), "inconsistent data");
- msg->key_id = key->keyidx;
- memcpy(msg->rx_sequence_counter,
- &seq->tkip.iv16, sizeof(seq->tkip.iv16));
- memcpy(msg->rx_sequence_counter + sizeof(u16),
- &seq->tkip.iv32, sizeof(seq->tkip.iv32));
- memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
- keybuf += sizeof(msg->tkip_key_data);
- if (iftype == NL80211_IFTYPE_AP)
- // Use Tx MIC Key
- memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key));
- else
- // Use Rx MIC Key
- memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key));
- return HIF_KEY_TYPE_TKIP_GROUP;
-}
-
-static u8 fill_ccmp_pair(struct hif_aes_pairwise_key *msg,
- struct ieee80211_key_conf *key, u8 *peer_addr)
-{
- WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
- ether_addr_copy(msg->peer_address, peer_addr);
- memcpy(msg->aes_key_data, key->key, key->keylen);
- return HIF_KEY_TYPE_AES_PAIRWISE;
-}
-
-static u8 fill_ccmp_group(struct hif_aes_group_key *msg,
- struct ieee80211_key_conf *key,
- struct ieee80211_key_seq *seq)
-{
- WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
- memcpy(msg->aes_key_data, key->key, key->keylen);
- memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn));
- memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn));
- msg->key_id = key->keyidx;
- return HIF_KEY_TYPE_AES_GROUP;
-}
-
-static u8 fill_sms4_pair(struct hif_wapi_pairwise_key *msg,
- struct ieee80211_key_conf *key, u8 *peer_addr)
-{
- u8 *keybuf = key->key;
-
- WARN(key->keylen != sizeof(msg->wapi_key_data)
- + sizeof(msg->mic_key_data), "inconsistent data");
- ether_addr_copy(msg->peer_address, peer_addr);
- memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
- keybuf += sizeof(msg->wapi_key_data);
- memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
- msg->key_id = key->keyidx;
- return HIF_KEY_TYPE_WAPI_PAIRWISE;
-}
-
-static u8 fill_sms4_group(struct hif_wapi_group_key *msg,
- struct ieee80211_key_conf *key)
-{
- u8 *keybuf = key->key;
-
- WARN(key->keylen != sizeof(msg->wapi_key_data)
- + sizeof(msg->mic_key_data), "inconsistent data");
- memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
- keybuf += sizeof(msg->wapi_key_data);
- memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
- msg->key_id = key->keyidx;
- return HIF_KEY_TYPE_WAPI_GROUP;
-}
-
-static u8 fill_aes_cmac_group(struct hif_igtk_group_key *msg,
- struct ieee80211_key_conf *key,
- struct ieee80211_key_seq *seq)
-{
- WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data");
- memcpy(msg->igtk_key_data, key->key, key->keylen);
- memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn));
- memreverse(msg->ipn, sizeof(seq->aes_cmac.pn));
- msg->key_id = key->keyidx;
- return HIF_KEY_TYPE_IGTK_GROUP;
-}
-
-static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- int ret;
- struct hif_req_add_key k = { };
- struct ieee80211_key_seq seq;
- struct wfx_dev *wdev = wvif->wdev;
- int idx = wfx_alloc_key(wvif->wdev);
- bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE;
-
- WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data");
- ieee80211_get_key_rx_seq(key, 0, &seq);
- if (idx < 0)
- return -EINVAL;
- k.int_id = wvif->id;
- k.entry_index = idx;
- if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
- key->cipher == WLAN_CIPHER_SUITE_WEP104) {
- if (pairwise)
- k.type = fill_wep_pair(&k.key.wep_pairwise_key, key,
- sta->addr);
- else
- k.type = fill_wep_group(&k.key.wep_group_key, key);
- } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
- if (pairwise)
- k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key,
- sta->addr);
- else
- k.type = fill_tkip_group(&k.key.tkip_group_key, key,
- &seq, wvif->vif->type);
- } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) {
- if (pairwise)
- k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key,
- sta->addr);
- else
- k.type = fill_ccmp_group(&k.key.aes_group_key, key,
- &seq);
- } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) {
- if (pairwise)
- k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key,
- sta->addr);
- else
- k.type = fill_sms4_group(&k.key.wapi_group_key, key);
- } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
- k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, &seq);
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
- } else {
- dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher);
- wfx_free_key(wdev, idx);
- return -EOPNOTSUPP;
- }
- ret = hif_add_key(wdev, &k);
- if (ret) {
- wfx_free_key(wdev, idx);
- return -EOPNOTSUPP;
- }
- key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE |
- IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
- key->hw_key_idx = idx;
- return 0;
-}
-
-static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key)
-{
- WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx");
- wfx_free_key(wvif->wdev, key->hw_key_idx);
- return hif_remove_key(wvif->wdev, key->hw_key_idx);
-}
-
-int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- int ret = -EOPNOTSUPP;
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
-
- mutex_lock(&wvif->wdev->conf_mutex);
- if (cmd == SET_KEY)
- ret = wfx_add_key(wvif, sta, key);
- if (cmd == DISABLE_KEY)
- ret = wfx_remove_key(wvif, key);
- mutex_unlock(&wvif->wdev->conf_mutex);
- return ret;
-}
-
diff --git a/drivers/staging/wfx/key.h b/drivers/staging/wfx/key.h
deleted file mode 100644
index 70a44d0ca35e..000000000000
--- a/drivers/staging/wfx/key.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Implementation of mac80211 API.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_KEY_H
-#define WFX_KEY_H
-
-#include <net/mac80211.h>
-
-struct wfx_dev;
-struct wfx_vif;
-
-int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key);
-
-#endif /* WFX_STA_H */
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
deleted file mode 100644
index e7bc1988124a..000000000000
--- a/drivers/staging/wfx/main.c
+++ /dev/null
@@ -1,490 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Device probe and register.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- * Copyright (c) 2008, Johannes Berg <[email protected]>
- * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (c) 2007-2009, Christian Lamparter <[email protected]>
- * Copyright (c) 2006, Michael Wu <[email protected]>
- * Copyright (c) 2004-2006 Jean-Baptiste Note <[email protected]>, et al.
- */
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_net.h>
-#include <linux/gpio/consumer.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/spi/spi.h>
-#include <linux/etherdevice.h>
-#include <linux/firmware.h>
-
-#include "main.h"
-#include "wfx.h"
-#include "fwio.h"
-#include "hwio.h"
-#include "bus.h"
-#include "bh.h"
-#include "sta.h"
-#include "key.h"
-#include "scan.h"
-#include "debug.h"
-#include "data_tx.h"
-#include "hif_tx_mib.h"
-#include "hif_api_cmd.h"
-
-#define WFX_PDS_MAX_SIZE 1500
-
-MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx");
-MODULE_AUTHOR("Jérôme Pouiller <[email protected]>");
-MODULE_LICENSE("GPL");
-
-#define RATETAB_ENT(_rate, _rateid, _flags) { \
- .bitrate = (_rate), \
- .hw_value = (_rateid), \
- .flags = (_flags), \
-}
-
-static struct ieee80211_rate wfx_rates[] = {
- RATETAB_ENT(10, 0, 0),
- RATETAB_ENT(20, 1, IEEE80211_RATE_SHORT_PREAMBLE),
- RATETAB_ENT(55, 2, IEEE80211_RATE_SHORT_PREAMBLE),
- RATETAB_ENT(110, 3, IEEE80211_RATE_SHORT_PREAMBLE),
- RATETAB_ENT(60, 6, 0),
- RATETAB_ENT(90, 7, 0),
- RATETAB_ENT(120, 8, 0),
- RATETAB_ENT(180, 9, 0),
- RATETAB_ENT(240, 10, 0),
- RATETAB_ENT(360, 11, 0),
- RATETAB_ENT(480, 12, 0),
- RATETAB_ENT(540, 13, 0),
-};
-
-#define CHAN2G(_channel, _freq, _flags) { \
- .band = NL80211_BAND_2GHZ, \
- .center_freq = (_freq), \
- .hw_value = (_channel), \
- .flags = (_flags), \
- .max_antenna_gain = 0, \
- .max_power = 30, \
-}
-
-static struct ieee80211_channel wfx_2ghz_chantable[] = {
- CHAN2G(1, 2412, 0),
- CHAN2G(2, 2417, 0),
- CHAN2G(3, 2422, 0),
- CHAN2G(4, 2427, 0),
- CHAN2G(5, 2432, 0),
- CHAN2G(6, 2437, 0),
- CHAN2G(7, 2442, 0),
- CHAN2G(8, 2447, 0),
- CHAN2G(9, 2452, 0),
- CHAN2G(10, 2457, 0),
- CHAN2G(11, 2462, 0),
- CHAN2G(12, 2467, 0),
- CHAN2G(13, 2472, 0),
- CHAN2G(14, 2484, 0),
-};
-
-static const struct ieee80211_supported_band wfx_band_2ghz = {
- .channels = wfx_2ghz_chantable,
- .n_channels = ARRAY_SIZE(wfx_2ghz_chantable),
- .bitrates = wfx_rates,
- .n_bitrates = ARRAY_SIZE(wfx_rates),
- .ht_cap = {
- // Receive caps
- .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
- IEEE80211_HT_CAP_MAX_AMSDU |
- (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT),
- .ht_supported = 1,
- .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
- .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
- .mcs = {
- .rx_mask = { 0xFF }, // MCS0 to MCS7
- .rx_highest = cpu_to_le16(72),
- .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
- },
- },
-};
-
-static const struct ieee80211_iface_limit wdev_iface_limits[] = {
- { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) },
- { .max = 1, .types = BIT(NL80211_IFTYPE_AP) },
-};
-
-static const struct ieee80211_iface_combination wfx_iface_combinations[] = {
- {
- .num_different_channels = 2,
- .max_interfaces = 2,
- .limits = wdev_iface_limits,
- .n_limits = ARRAY_SIZE(wdev_iface_limits),
- }
-};
-
-static const struct ieee80211_ops wfx_ops = {
- .start = wfx_start,
- .stop = wfx_stop,
- .add_interface = wfx_add_interface,
- .remove_interface = wfx_remove_interface,
- .config = wfx_config,
- .tx = wfx_tx,
- .join_ibss = wfx_join_ibss,
- .leave_ibss = wfx_leave_ibss,
- .conf_tx = wfx_conf_tx,
- .hw_scan = wfx_hw_scan,
- .cancel_hw_scan = wfx_cancel_hw_scan,
- .start_ap = wfx_start_ap,
- .stop_ap = wfx_stop_ap,
- .sta_add = wfx_sta_add,
- .sta_remove = wfx_sta_remove,
- .set_tim = wfx_set_tim,
- .set_key = wfx_set_key,
- .set_rts_threshold = wfx_set_rts_threshold,
- .set_default_unicast_key = wfx_set_default_unicast_key,
- .bss_info_changed = wfx_bss_info_changed,
- .configure_filter = wfx_configure_filter,
- .ampdu_action = wfx_ampdu_action,
- .flush = wfx_flush,
- .add_chanctx = wfx_add_chanctx,
- .remove_chanctx = wfx_remove_chanctx,
- .change_chanctx = wfx_change_chanctx,
- .assign_vif_chanctx = wfx_assign_vif_chanctx,
- .unassign_vif_chanctx = wfx_unassign_vif_chanctx,
-};
-
-bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor)
-{
- if (wdev->hw_caps.api_version_major < major)
- return true;
- if (wdev->hw_caps.api_version_major > major)
- return false;
- if (wdev->hw_caps.api_version_minor < minor)
- return true;
- return false;
-}
-
-/* NOTE: wfx_send_pds() destroy buf */
-int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len)
-{
- int ret;
- int start, brace_level, i;
-
- start = 0;
- brace_level = 0;
- if (buf[0] != '{') {
- dev_err(wdev->dev, "valid PDS start with '{'. Did you forget to compress it?\n");
- return -EINVAL;
- }
- for (i = 1; i < len - 1; i++) {
- if (buf[i] == '{')
- brace_level++;
- if (buf[i] == '}')
- brace_level--;
- if (buf[i] == '}' && !brace_level) {
- i++;
- if (i - start + 1 > WFX_PDS_MAX_SIZE)
- return -EFBIG;
- buf[start] = '{';
- buf[i] = 0;
- dev_dbg(wdev->dev, "send PDS '%s}'\n", buf + start);
- buf[i] = '}';
- ret = hif_configuration(wdev, buf + start,
- i - start + 1);
- if (ret > 0) {
- dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n",
- start, i);
- return -EINVAL;
- }
- if (ret == -ETIMEDOUT) {
- dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n",
- start, i);
- return ret;
- }
- if (ret) {
- dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n",
- start, i);
- return -EIO;
- }
- buf[i] = ',';
- start = i;
- }
- }
- return 0;
-}
-
-static int wfx_send_pdata_pds(struct wfx_dev *wdev)
-{
- int ret = 0;
- const struct firmware *pds;
- u8 *tmp_buf;
-
- ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev);
- if (ret) {
- dev_err(wdev->dev, "can't load PDS file %s\n",
- wdev->pdata.file_pds);
- goto err1;
- }
- tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL);
- if (!tmp_buf) {
- ret = -ENOMEM;
- goto err2;
- }
- ret = wfx_send_pds(wdev, tmp_buf, pds->size);
- kfree(tmp_buf);
-err2:
- release_firmware(pds);
-err1:
- return ret;
-}
-
-static void wfx_free_common(void *data)
-{
- struct wfx_dev *wdev = data;
-
- mutex_destroy(&wdev->tx_power_loop_info_lock);
- mutex_destroy(&wdev->rx_stats_lock);
- mutex_destroy(&wdev->conf_mutex);
- ieee80211_free_hw(wdev->hw);
-}
-
-struct wfx_dev *wfx_init_common(struct device *dev,
- const struct wfx_platform_data *pdata,
- const struct hwbus_ops *hwbus_ops,
- void *hwbus_priv)
-{
- struct ieee80211_hw *hw;
- struct wfx_dev *wdev;
-
- hw = ieee80211_alloc_hw(sizeof(struct wfx_dev), &wfx_ops);
- if (!hw)
- return NULL;
-
- SET_IEEE80211_DEV(hw, dev);
-
- ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
- ieee80211_hw_set(hw, AMPDU_AGGREGATION);
- ieee80211_hw_set(hw, CONNECTION_MONITOR);
- ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
- ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
- ieee80211_hw_set(hw, SIGNAL_DBM);
- ieee80211_hw_set(hw, SUPPORTS_PS);
- ieee80211_hw_set(hw, MFP_CAPABLE);
-
- hw->vif_data_size = sizeof(struct wfx_vif);
- hw->sta_data_size = sizeof(struct wfx_sta_priv);
- hw->queues = 4;
- hw->max_rates = 8;
- hw->max_rate_tries = 8;
- hw->extra_tx_headroom = sizeof(struct hif_msg)
- + sizeof(struct hif_req_tx)
- + 4 /* alignment */ + 8 /* TKIP IV */;
- hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP);
- hw->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
- NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
- NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
- NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
- hw->wiphy->features |= NL80211_FEATURE_AP_SCAN;
- hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
- hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
- hw->wiphy->max_ap_assoc_sta = HIF_LINK_ID_MAX;
- hw->wiphy->max_scan_ssids = 2;
- hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
- hw->wiphy->n_iface_combinations = ARRAY_SIZE(wfx_iface_combinations);
- hw->wiphy->iface_combinations = wfx_iface_combinations;
- hw->wiphy->bands[NL80211_BAND_2GHZ] = devm_kmalloc(dev, sizeof(wfx_band_2ghz), GFP_KERNEL);
- // FIXME: also copy wfx_rates and wfx_2ghz_chantable
- memcpy(hw->wiphy->bands[NL80211_BAND_2GHZ], &wfx_band_2ghz,
- sizeof(wfx_band_2ghz));
-
- wdev = hw->priv;
- wdev->hw = hw;
- wdev->dev = dev;
- wdev->hwbus_ops = hwbus_ops;
- wdev->hwbus_priv = hwbus_priv;
- memcpy(&wdev->pdata, pdata, sizeof(*pdata));
- of_property_read_string(dev->of_node, "config-file",
- &wdev->pdata.file_pds);
- wdev->pdata.gpio_wakeup = devm_gpiod_get_optional(dev, "wakeup",
- GPIOD_OUT_LOW);
- if (IS_ERR(wdev->pdata.gpio_wakeup))
- return NULL;
- if (wdev->pdata.gpio_wakeup)
- gpiod_set_consumer_name(wdev->pdata.gpio_wakeup, "wfx wakeup");
-
- mutex_init(&wdev->conf_mutex);
- mutex_init(&wdev->rx_stats_lock);
- mutex_init(&wdev->tx_power_loop_info_lock);
- init_completion(&wdev->firmware_ready);
- INIT_DELAYED_WORK(&wdev->cooling_timeout_work,
- wfx_cooling_timeout_work);
- skb_queue_head_init(&wdev->tx_pending);
- init_waitqueue_head(&wdev->tx_dequeue);
- wfx_init_hif_cmd(&wdev->hif_cmd);
- wdev->force_ps_timeout = -1;
-
- if (devm_add_action_or_reset(dev, wfx_free_common, wdev))
- return NULL;
-
- return wdev;
-}
-
-int wfx_probe(struct wfx_dev *wdev)
-{
- int i;
- int err;
- const void *macaddr;
- struct gpio_desc *gpio_saved;
-
- // During first part of boot, gpio_wakeup cannot yet been used. So
- // prevent bh() to touch it.
- gpio_saved = wdev->pdata.gpio_wakeup;
- wdev->pdata.gpio_wakeup = NULL;
- wdev->poll_irq = true;
-
- wfx_bh_register(wdev);
-
- err = wfx_init_device(wdev);
- if (err)
- goto err0;
-
- wfx_bh_poll_irq(wdev);
- err = wait_for_completion_timeout(&wdev->firmware_ready, 1 * HZ);
- if (err <= 0) {
- if (err == 0) {
- dev_err(wdev->dev, "timeout while waiting for startup indication\n");
- err = -ETIMEDOUT;
- } else if (err == -ERESTARTSYS) {
- dev_info(wdev->dev, "probe interrupted by user\n");
- }
- goto err0;
- }
-
- // 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, wdev->hw_caps.link_mode);
- snprintf(wdev->hw->wiphy->fw_version,
- sizeof(wdev->hw->wiphy->fw_version),
- "%d.%d.%d",
- wdev->hw_caps.firmware_major,
- wdev->hw_caps.firmware_minor,
- wdev->hw_caps.firmware_build);
-
- 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 err0;
- }
-
- if (wdev->hw_caps.link_mode == SEC_LINK_ENFORCED) {
- dev_err(wdev->dev,
- "chip require secure_link, but can't negotiate it\n");
- goto err0;
- }
-
- if (wdev->hw_caps.region_sel_mode) {
- wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[11].flags |= IEEE80211_CHAN_NO_IR;
- wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[12].flags |= IEEE80211_CHAN_NO_IR;
- wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[13].flags |= IEEE80211_CHAN_DISABLED;
- }
-
- dev_dbg(wdev->dev, "sending configuration file %s\n",
- wdev->pdata.file_pds);
- err = wfx_send_pdata_pds(wdev);
- if (err < 0)
- goto err0;
-
- wdev->poll_irq = false;
- err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv);
- if (err)
- goto err0;
-
- err = hif_use_multi_tx_conf(wdev, true);
- if (err)
- dev_err(wdev->dev, "misconfigured IRQ?\n");
-
- wdev->pdata.gpio_wakeup = gpio_saved;
- if (wdev->pdata.gpio_wakeup) {
- dev_dbg(wdev->dev,
- "enable 'quiescent' power mode with wakeup GPIO and PDS file %s\n",
- wdev->pdata.file_pds);
- gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1);
- control_reg_write(wdev, 0);
- hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT);
- } else {
- hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE);
- }
-
- 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 (!IS_ERR_OR_NULL(macaddr)) {
- ether_addr_copy(wdev->addresses[i].addr, macaddr);
- wdev->addresses[i].addr[ETH_ALEN - 1] += i;
- } else {
- 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);
- }
- wdev->hw->wiphy->n_addresses = ARRAY_SIZE(wdev->addresses);
- wdev->hw->wiphy->addresses = wdev->addresses;
-
- err = ieee80211_register_hw(wdev->hw);
- if (err)
- goto err1;
-
- err = wfx_debug_init(wdev);
- if (err)
- goto err2;
-
- return 0;
-
-err2:
- ieee80211_unregister_hw(wdev->hw);
-err1:
- wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv);
-err0:
- wfx_bh_unregister(wdev);
- return err;
-}
-
-void wfx_release(struct wfx_dev *wdev)
-{
- ieee80211_unregister_hw(wdev->hw);
- hif_shutdown(wdev);
- wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv);
- wfx_bh_unregister(wdev);
-}
-
-static int __init wfx_core_init(void)
-{
- int ret = 0;
-
- if (IS_ENABLED(CONFIG_SPI))
- ret = spi_register_driver(&wfx_spi_driver);
- if (IS_ENABLED(CONFIG_MMC) && !ret)
- ret = sdio_register_driver(&wfx_sdio_driver);
- return ret;
-}
-module_init(wfx_core_init);
-
-static void __exit wfx_core_exit(void)
-{
- if (IS_ENABLED(CONFIG_MMC))
- sdio_unregister_driver(&wfx_sdio_driver);
- if (IS_ENABLED(CONFIG_SPI))
- spi_unregister_driver(&wfx_spi_driver);
-}
-module_exit(wfx_core_exit);
diff --git a/drivers/staging/wfx/main.h b/drivers/staging/wfx/main.h
deleted file mode 100644
index a0db322383a3..000000000000
--- a/drivers/staging/wfx/main.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Device probe and register.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- * Copyright (c) 2006, Michael Wu <[email protected]>
- * Copyright 2004-2006 Jean-Baptiste Note <[email protected]>, et al.
- */
-#ifndef WFX_MAIN_H
-#define WFX_MAIN_H
-
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-
-#include "hif_api_general.h"
-
-struct wfx_dev;
-struct hwbus_ops;
-
-struct wfx_platform_data {
- /* Keyset and ".sec" extension will be appended to this string */
- const char *file_fw;
- const char *file_pds;
- struct gpio_desc *gpio_wakeup;
- /*
- * if true HIF D_out is sampled on the rising edge of the clock
- * (intended to be used in 50Mhz SDIO)
- */
- bool use_rising_clk;
-};
-
-struct wfx_dev *wfx_init_common(struct device *dev,
- const struct wfx_platform_data *pdata,
- const struct hwbus_ops *hwbus_ops,
- void *hwbus_priv);
-
-int wfx_probe(struct wfx_dev *wdev);
-void wfx_release(struct wfx_dev *wdev);
-
-bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor);
-int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len);
-
-#endif
diff --git a/drivers/staging/wfx/queue.c b/drivers/staging/wfx/queue.c
deleted file mode 100644
index 31c37f69c295..000000000000
--- a/drivers/staging/wfx/queue.c
+++ /dev/null
@@ -1,304 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * O(1) TX queue with built-in allocator.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/sched.h>
-#include <net/mac80211.h>
-
-#include "queue.h"
-#include "wfx.h"
-#include "sta.h"
-#include "data_tx.h"
-#include "traces.h"
-
-void wfx_tx_lock(struct wfx_dev *wdev)
-{
- atomic_inc(&wdev->tx_lock);
-}
-
-void wfx_tx_unlock(struct wfx_dev *wdev)
-{
- int tx_lock = atomic_dec_return(&wdev->tx_lock);
-
- WARN(tx_lock < 0, "inconsistent tx_lock value");
- if (!tx_lock)
- wfx_bh_request_tx(wdev);
-}
-
-void wfx_tx_flush(struct wfx_dev *wdev)
-{
- int ret;
-
- // Do not wait for any reply if chip is frozen
- if (wdev->chip_frozen)
- return;
-
- wfx_tx_lock(wdev);
- mutex_lock(&wdev->hif_cmd.lock);
- ret = wait_event_timeout(wdev->hif.tx_buffers_empty,
- !wdev->hif.tx_buffers_used,
- msecs_to_jiffies(3000));
- if (!ret) {
- dev_warn(wdev->dev, "cannot flush tx buffers (%d still busy)\n",
- wdev->hif.tx_buffers_used);
- wfx_pending_dump_old_frames(wdev, 3000);
- // FIXME: drop pending frames here
- wdev->chip_frozen = true;
- }
- mutex_unlock(&wdev->hif_cmd.lock);
- wfx_tx_unlock(wdev);
-}
-
-void wfx_tx_lock_flush(struct wfx_dev *wdev)
-{
- wfx_tx_lock(wdev);
- wfx_tx_flush(wdev);
-}
-
-void wfx_tx_queues_init(struct wfx_vif *wvif)
-{
- // The device is in charge to respect the details of the QoS parameters.
- // The driver just ensure that it roughtly respect the priorities to
- // avoid any shortage.
- const int priorities[IEEE80211_NUM_ACS] = { 1, 2, 64, 128 };
- int i;
-
- for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
- skb_queue_head_init(&wvif->tx_queue[i].normal);
- skb_queue_head_init(&wvif->tx_queue[i].cab);
- wvif->tx_queue[i].priority = priorities[i];
- }
-}
-
-void wfx_tx_queues_check_empty(struct wfx_vif *wvif)
-{
- int i;
-
- for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
- WARN_ON(atomic_read(&wvif->tx_queue[i].pending_frames));
- WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].normal));
- WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].cab));
- }
-}
-
-bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue)
-{
- return skb_queue_empty(&queue->normal) && skb_queue_empty(&queue->cab);
-}
-
-static void __wfx_tx_queue_drop(struct wfx_vif *wvif,
- struct sk_buff_head *skb_queue,
- struct sk_buff_head *dropped)
-{
- struct sk_buff *skb, *tmp;
-
- spin_lock_bh(&skb_queue->lock);
- skb_queue_walk_safe(skb_queue, skb, tmp) {
- __skb_unlink(skb, skb_queue);
- skb_queue_head(dropped, skb);
- }
- spin_unlock_bh(&skb_queue->lock);
-}
-
-void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue,
- struct sk_buff_head *dropped)
-{
- __wfx_tx_queue_drop(wvif, &queue->cab, dropped);
- __wfx_tx_queue_drop(wvif, &queue->normal, dropped);
- wake_up(&wvif->wdev->tx_dequeue);
-}
-
-void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb)
-{
- struct wfx_queue *queue = &wvif->tx_queue[skb_get_queue_mapping(skb)];
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-
- if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)
- skb_queue_tail(&queue->cab, skb);
- else
- skb_queue_tail(&queue->normal, skb);
-}
-
-void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped)
-{
- struct wfx_queue *queue;
- struct wfx_vif *wvif;
- struct hif_msg *hif;
- struct sk_buff *skb;
-
- WARN(!wdev->chip_frozen, "%s should only be used to recover a frozen device",
- __func__);
- while ((skb = skb_dequeue(&wdev->tx_pending)) != NULL) {
- hif = (struct hif_msg *)skb->data;
- wvif = wdev_to_wvif(wdev, hif->interface);
- if (wvif) {
- queue = &wvif->tx_queue[skb_get_queue_mapping(skb)];
- WARN_ON(skb_get_queue_mapping(skb) > 3);
- WARN_ON(!atomic_read(&queue->pending_frames));
- atomic_dec(&queue->pending_frames);
- }
- skb_queue_head(dropped, skb);
- }
-}
-
-struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id)
-{
- struct wfx_queue *queue;
- struct hif_req_tx *req;
- struct wfx_vif *wvif;
- struct hif_msg *hif;
- struct sk_buff *skb;
-
- spin_lock_bh(&wdev->tx_pending.lock);
- skb_queue_walk(&wdev->tx_pending, skb) {
- hif = (struct hif_msg *)skb->data;
- req = (struct hif_req_tx *)hif->body;
- if (req->packet_id != packet_id)
- continue;
- spin_unlock_bh(&wdev->tx_pending.lock);
- wvif = wdev_to_wvif(wdev, hif->interface);
- if (wvif) {
- queue = &wvif->tx_queue[skb_get_queue_mapping(skb)];
- WARN_ON(skb_get_queue_mapping(skb) > 3);
- WARN_ON(!atomic_read(&queue->pending_frames));
- atomic_dec(&queue->pending_frames);
- }
- skb_unlink(skb, &wdev->tx_pending);
- return skb;
- }
- spin_unlock_bh(&wdev->tx_pending.lock);
- WARN(1, "cannot find packet in pending queue");
- return NULL;
-}
-
-void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms)
-{
- ktime_t now = ktime_get();
- struct wfx_tx_priv *tx_priv;
- struct hif_req_tx *req;
- struct sk_buff *skb;
- bool first = true;
-
- spin_lock_bh(&wdev->tx_pending.lock);
- skb_queue_walk(&wdev->tx_pending, skb) {
- tx_priv = wfx_skb_tx_priv(skb);
- req = wfx_skb_txreq(skb);
- if (ktime_after(now, ktime_add_ms(tx_priv->xmit_timestamp,
- limit_ms))) {
- if (first) {
- dev_info(wdev->dev, "frames stuck in firmware since %dms or more:\n",
- limit_ms);
- first = false;
- }
- dev_info(wdev->dev, " id %08x sent %lldms ago\n",
- req->packet_id,
- ktime_ms_delta(now, tx_priv->xmit_timestamp));
- }
- }
- spin_unlock_bh(&wdev->tx_pending.lock);
-}
-
-unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev,
- struct sk_buff *skb)
-{
- ktime_t now = ktime_get();
- struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb);
-
- return ktime_us_delta(now, tx_priv->xmit_timestamp);
-}
-
-bool wfx_tx_queues_has_cab(struct wfx_vif *wvif)
-{
- int i;
-
- if (wvif->vif->type != NL80211_IFTYPE_AP)
- return false;
- for (i = 0; i < IEEE80211_NUM_ACS; ++i)
- // Note: since only AP can have mcast frames in queue and only
- // one vif can be AP, all queued frames has same interface id
- if (!skb_queue_empty_lockless(&wvif->tx_queue[i].cab))
- return true;
- return false;
-}
-
-static int wfx_tx_queue_get_weight(struct wfx_queue *queue)
-{
- return atomic_read(&queue->pending_frames) * queue->priority;
-}
-
-static struct sk_buff *wfx_tx_queues_get_skb(struct wfx_dev *wdev)
-{
- struct wfx_queue *queues[IEEE80211_NUM_ACS * ARRAY_SIZE(wdev->vif)];
- int i, j, num_queues = 0;
- struct wfx_vif *wvif;
- struct hif_msg *hif;
- struct sk_buff *skb;
-
- // sort the queues
- wvif = NULL;
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- WARN_ON(num_queues >= ARRAY_SIZE(queues));
- queues[num_queues] = &wvif->tx_queue[i];
- for (j = num_queues; j > 0; j--)
- if (wfx_tx_queue_get_weight(queues[j]) <
- wfx_tx_queue_get_weight(queues[j - 1]))
- swap(queues[j - 1], queues[j]);
- num_queues++;
- }
- }
-
- wvif = NULL;
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
- if (!wvif->after_dtim_tx_allowed)
- continue;
- for (i = 0; i < num_queues; i++) {
- skb = skb_dequeue(&queues[i]->cab);
- if (!skb)
- continue;
- // Note: since only AP can have mcast frames in queue
- // and only one vif can be AP, all queued frames has
- // same interface id
- hif = (struct hif_msg *)skb->data;
- WARN_ON(hif->interface != wvif->id);
- WARN_ON(queues[i] !=
- &wvif->tx_queue[skb_get_queue_mapping(skb)]);
- atomic_inc(&queues[i]->pending_frames);
- trace_queues_stats(wdev, queues[i]);
- return skb;
- }
- // No more multicast to sent
- wvif->after_dtim_tx_allowed = false;
- schedule_work(&wvif->update_tim_work);
- }
-
- for (i = 0; i < num_queues; i++) {
- skb = skb_dequeue(&queues[i]->normal);
- if (skb) {
- atomic_inc(&queues[i]->pending_frames);
- trace_queues_stats(wdev, queues[i]);
- return skb;
- }
- }
- return NULL;
-}
-
-struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev)
-{
- struct wfx_tx_priv *tx_priv;
- struct sk_buff *skb;
-
- if (atomic_read(&wdev->tx_lock))
- return NULL;
- skb = wfx_tx_queues_get_skb(wdev);
- if (!skb)
- return NULL;
- skb_queue_tail(&wdev->tx_pending, skb);
- wake_up(&wdev->tx_dequeue);
- tx_priv = wfx_skb_tx_priv(skb);
- tx_priv->xmit_timestamp = ktime_get();
- return (struct hif_msg *)skb->data;
-}
diff --git a/drivers/staging/wfx/queue.h b/drivers/staging/wfx/queue.h
deleted file mode 100644
index 80ba19455ef3..000000000000
--- a/drivers/staging/wfx/queue.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * O(1) TX queue with built-in allocator.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_QUEUE_H
-#define WFX_QUEUE_H
-
-#include <linux/skbuff.h>
-#include <linux/atomic.h>
-
-struct wfx_dev;
-struct wfx_vif;
-
-struct wfx_queue {
- struct sk_buff_head normal;
- struct sk_buff_head cab; // Content After (DTIM) Beacon
- atomic_t pending_frames;
- int priority;
-};
-
-void wfx_tx_lock(struct wfx_dev *wdev);
-void wfx_tx_unlock(struct wfx_dev *wdev);
-void wfx_tx_flush(struct wfx_dev *wdev);
-void wfx_tx_lock_flush(struct wfx_dev *wdev);
-
-void wfx_tx_queues_init(struct wfx_vif *wvif);
-void wfx_tx_queues_check_empty(struct wfx_vif *wvif);
-bool wfx_tx_queues_has_cab(struct wfx_vif *wvif);
-void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb);
-struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev);
-
-bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue);
-void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue,
- struct sk_buff_head *dropped);
-
-struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id);
-void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped);
-unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev,
- struct sk_buff *skb);
-void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms);
-
-#endif /* WFX_QUEUE_H */
diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c
deleted file mode 100644
index fb47c7cddf2f..000000000000
--- a/drivers/staging/wfx/scan.c
+++ /dev/null
@@ -1,132 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Scan related functions.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <net/mac80211.h>
-
-#include "scan.h"
-#include "wfx.h"
-#include "sta.h"
-#include "hif_tx_mib.h"
-
-static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw,
- bool aborted)
-{
- struct cfg80211_scan_info info = {
- .aborted = aborted,
- };
-
- ieee80211_scan_completed(hw, &info);
-}
-
-static int update_probe_tmpl(struct wfx_vif *wvif,
- struct cfg80211_scan_request *req)
-{
- struct sk_buff *skb;
-
- skb = ieee80211_probereq_get(wvif->wdev->hw, wvif->vif->addr,
- NULL, 0, req->ie_len);
- if (!skb)
- return -ENOMEM;
-
- skb_put_data(skb, req->ie, req->ie_len);
- hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBREQ, 0);
- dev_kfree_skb(skb);
- return 0;
-}
-
-static int send_scan_req(struct wfx_vif *wvif,
- struct cfg80211_scan_request *req, int start_idx)
-{
- int i, ret, timeout;
- struct ieee80211_channel *ch_start, *ch_cur;
-
- for (i = start_idx; i < req->n_channels; i++) {
- ch_start = req->channels[start_idx];
- ch_cur = req->channels[i];
- WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported");
- if (ch_cur->max_power != ch_start->max_power)
- break;
- if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR)
- break;
- }
- wfx_tx_lock_flush(wvif->wdev);
- wvif->scan_abort = false;
- reinit_completion(&wvif->scan_complete);
- ret = hif_scan(wvif, req, start_idx, i - start_idx, &timeout);
- if (ret) {
- wfx_tx_unlock(wvif->wdev);
- return -EIO;
- }
- ret = wait_for_completion_timeout(&wvif->scan_complete, timeout);
- if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower)
- hif_set_output_power(wvif, wvif->vif->bss_conf.txpower);
- wfx_tx_unlock(wvif->wdev);
- if (!ret) {
- dev_notice(wvif->wdev->dev, "scan timeout\n");
- hif_stop_scan(wvif);
- return -ETIMEDOUT;
- }
- if (wvif->scan_abort) {
- dev_notice(wvif->wdev->dev, "scan abort\n");
- return -ECONNABORTED;
- }
- return i - start_idx;
-}
-
-/*
- * It is not really necessary to run scan request asynchronously. However,
- * there is a bug in "iw scan" when ieee80211_scan_completed() is called before
- * wfx_hw_scan() return
- */
-void wfx_hw_scan_work(struct work_struct *work)
-{
- struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work);
- struct ieee80211_scan_request *hw_req = wvif->scan_req;
- int chan_cur, ret;
-
- mutex_lock(&wvif->wdev->conf_mutex);
- mutex_lock(&wvif->scan_lock);
- if (wvif->join_in_progress) {
- dev_info(wvif->wdev->dev, "%s: abort in-progress REQ_JOIN",
- __func__);
- wfx_reset(wvif);
- }
- update_probe_tmpl(wvif, &hw_req->req);
- chan_cur = 0;
- do {
- ret = send_scan_req(wvif, &hw_req->req, chan_cur);
- if (ret > 0)
- chan_cur += ret;
- } while (ret > 0 && chan_cur < hw_req->req.n_channels);
- mutex_unlock(&wvif->scan_lock);
- mutex_unlock(&wvif->wdev->conf_mutex);
- __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0);
-}
-
-int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_scan_request *hw_req)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
-
- WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS);
- wvif->scan_req = hw_req;
- schedule_work(&wvif->scan_work);
- return 0;
-}
-
-void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
-
- wvif->scan_abort = true;
- hif_stop_scan(wvif);
-}
-
-void wfx_scan_complete(struct wfx_vif *wvif)
-{
- complete(&wvif->scan_complete);
-}
diff --git a/drivers/staging/wfx/scan.h b/drivers/staging/wfx/scan.h
deleted file mode 100644
index c7496a766478..000000000000
--- a/drivers/staging/wfx/scan.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Scan related functions.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_SCAN_H
-#define WFX_SCAN_H
-
-#include <net/mac80211.h>
-
-struct wfx_dev;
-struct wfx_vif;
-
-void wfx_hw_scan_work(struct work_struct *work);
-int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req);
-void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-void wfx_scan_complete(struct wfx_vif *wvif);
-
-#endif /* WFX_SCAN_H */
diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c
deleted file mode 100644
index 196779a1b89a..000000000000
--- a/drivers/staging/wfx/sta.c
+++ /dev/null
@@ -1,807 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Implementation of mac80211 API.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#include <linux/etherdevice.h>
-#include <net/mac80211.h>
-
-#include "sta.h"
-#include "wfx.h"
-#include "fwio.h"
-#include "bh.h"
-#include "key.h"
-#include "scan.h"
-#include "debug.h"
-#include "hif_tx.h"
-#include "hif_tx_mib.h"
-
-#define HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES 2
-
-u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates)
-{
- int i;
- u32 ret = 0;
- // WFx only support 2GHz
- struct ieee80211_supported_band *sband = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ];
-
- for (i = 0; i < sband->n_bitrates; i++) {
- if (rates & BIT(i)) {
- if (i >= sband->n_bitrates)
- dev_warn(wdev->dev, "unsupported basic rate\n");
- else
- ret |= BIT(sband->bitrates[i].hw_value);
- }
- }
- return ret;
-}
-
-void wfx_cooling_timeout_work(struct work_struct *work)
-{
- struct wfx_dev *wdev = container_of(to_delayed_work(work),
- struct wfx_dev,
- cooling_timeout_work);
-
- wdev->chip_frozen = true;
- wfx_tx_unlock(wdev);
-}
-
-void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd)
-{
- if (cmd == STA_NOTIFY_AWAKE) {
- // Device recover normal temperature
- if (cancel_delayed_work(&wdev->cooling_timeout_work))
- wfx_tx_unlock(wdev);
- } else {
- // Device is too hot
- schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ);
- wfx_tx_lock(wdev);
- }
-}
-
-static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon)
-{
- static const struct hif_ie_table_entry filter_ies[] = {
- {
- .ie_id = WLAN_EID_VENDOR_SPECIFIC,
- .has_changed = 1,
- .no_longer = 1,
- .has_appeared = 1,
- .oui = { 0x50, 0x6F, 0x9A },
- }, {
- .ie_id = WLAN_EID_HT_OPERATION,
- .has_changed = 1,
- .no_longer = 1,
- .has_appeared = 1,
- }, {
- .ie_id = WLAN_EID_ERP_INFO,
- .has_changed = 1,
- .no_longer = 1,
- .has_appeared = 1,
- }
- };
-
- if (!filter_beacon) {
- hif_beacon_filter_control(wvif, 0, 1);
- } else {
- hif_set_beacon_filter_table(wvif, 3, filter_ies);
- hif_beacon_filter_control(wvif, HIF_BEACON_FILTER_ENABLE, 0);
- }
-}
-
-void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
- unsigned int *total_flags, u64 unused)
-{
- struct wfx_vif *wvif = NULL;
- struct wfx_dev *wdev = hw->priv;
- bool filter_bssid, filter_prbreq, filter_beacon;
-
- // Notes:
- // - Probe responses (FIF_BCN_PRBRESP_PROMISC) are never filtered
- // - PS-Poll (FIF_PSPOLL) are never filtered
- // - RTS, CTS and Ack (FIF_CONTROL) are always filtered
- // - Broken frames (FIF_FCSFAIL and FIF_PLCPFAIL) are always filtered
- // - Firmware does (yet) allow to forward unicast traffic sent to
- // other stations (aka. promiscuous mode)
- *total_flags &= FIF_BCN_PRBRESP_PROMISC | FIF_ALLMULTI | FIF_OTHER_BSS |
- FIF_PROBE_REQ | FIF_PSPOLL;
-
- mutex_lock(&wdev->conf_mutex);
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
- mutex_lock(&wvif->scan_lock);
-
- // Note: FIF_BCN_PRBRESP_PROMISC covers probe response and
- // beacons from other BSS
- if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
- filter_beacon = false;
- else
- filter_beacon = true;
- wfx_filter_beacon(wvif, filter_beacon);
-
- if (*total_flags & FIF_OTHER_BSS)
- filter_bssid = false;
- else
- filter_bssid = true;
-
- // In AP mode, chip can reply to probe request itself
- if (*total_flags & FIF_PROBE_REQ &&
- wvif->vif->type == NL80211_IFTYPE_AP) {
- dev_dbg(wdev->dev, "do not forward probe request in AP mode\n");
- *total_flags &= ~FIF_PROBE_REQ;
- }
-
- if (*total_flags & FIF_PROBE_REQ)
- filter_prbreq = false;
- else
- filter_prbreq = true;
- hif_set_rx_filter(wvif, filter_bssid, filter_prbreq);
-
- mutex_unlock(&wvif->scan_lock);
- }
- mutex_unlock(&wdev->conf_mutex);
-}
-
-static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps)
-{
- struct ieee80211_channel *chan0 = NULL, *chan1 = NULL;
- struct ieee80211_conf *conf = &wvif->wdev->hw->conf;
-
- WARN(!wvif->vif->bss_conf.assoc && enable_ps,
- "enable_ps is reliable only if associated");
- if (wdev_to_wvif(wvif->wdev, 0))
- chan0 = wdev_to_wvif(wvif->wdev, 0)->vif->bss_conf.chandef.chan;
- if (wdev_to_wvif(wvif->wdev, 1))
- chan1 = wdev_to_wvif(wvif->wdev, 1)->vif->bss_conf.chandef.chan;
- if (chan0 && chan1 && chan0->hw_value != chan1->hw_value &&
- wvif->vif->type != NL80211_IFTYPE_AP) {
- // It is necessary to enable powersave if channels
- // are different.
- if (enable_ps)
- *enable_ps = true;
- if (wvif->wdev->force_ps_timeout > -1)
- return wvif->wdev->force_ps_timeout;
- else if (wfx_api_older_than(wvif->wdev, 3, 2))
- return 0;
- else
- return 30;
- }
- if (enable_ps)
- *enable_ps = wvif->vif->bss_conf.ps;
- if (wvif->wdev->force_ps_timeout > -1)
- return wvif->wdev->force_ps_timeout;
- else if (wvif->vif->bss_conf.assoc && wvif->vif->bss_conf.ps)
- return conf->dynamic_ps_timeout;
- else
- return -1;
-}
-
-int wfx_update_pm(struct wfx_vif *wvif)
-{
- int ps_timeout;
- bool ps;
-
- if (!wvif->vif->bss_conf.assoc)
- return 0;
- ps_timeout = wfx_get_ps_timeout(wvif, &ps);
- if (!ps)
- ps_timeout = 0;
- WARN_ON(ps_timeout < 0);
- if (wvif->uapsd_mask)
- ps_timeout = 0;
-
- if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete,
- TU_TO_JIFFIES(512)))
- dev_warn(wvif->wdev->dev,
- "timeout while waiting of set_pm_mode_complete\n");
- return hif_set_pm(wvif, ps, ps_timeout);
-}
-
-int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params)
-{
- struct wfx_dev *wdev = hw->priv;
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
- int old_uapsd = wvif->uapsd_mask;
-
- WARN_ON(queue >= hw->queues);
-
- mutex_lock(&wdev->conf_mutex);
- assign_bit(queue, &wvif->uapsd_mask, params->uapsd);
- hif_set_edca_queue_params(wvif, queue, params);
- if (wvif->vif->type == NL80211_IFTYPE_STATION &&
- old_uapsd != wvif->uapsd_mask) {
- hif_set_uapsd_info(wvif, wvif->uapsd_mask);
- wfx_update_pm(wvif);
- }
- mutex_unlock(&wdev->conf_mutex);
- return 0;
-}
-
-int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
-{
- struct wfx_dev *wdev = hw->priv;
- struct wfx_vif *wvif = NULL;
-
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
- hif_rts_threshold(wvif, value);
- return 0;
-}
-
-/* WSM callbacks */
-
-void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi)
-{
- /* RSSI: signed Q8.0, RCPI: unsigned Q7.1
- * RSSI = RCPI / 2 - 110
- */
- int rcpi_rssi;
- int cqm_evt;
-
- rcpi_rssi = raw_rcpi_rssi / 2 - 110;
- if (rcpi_rssi <= wvif->vif->bss_conf.cqm_rssi_thold)
- cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
- else
- cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
- ieee80211_cqm_rssi_notify(wvif->vif, cqm_evt, rcpi_rssi, GFP_KERNEL);
-}
-
-static void wfx_beacon_loss_work(struct work_struct *work)
-{
- struct wfx_vif *wvif = container_of(to_delayed_work(work),
- struct wfx_vif, beacon_loss_work);
- struct ieee80211_bss_conf *bss_conf = &wvif->vif->bss_conf;
-
- ieee80211_beacon_loss(wvif->vif);
- schedule_delayed_work(to_delayed_work(work),
- msecs_to_jiffies(bss_conf->beacon_int));
-}
-
-void wfx_set_default_unicast_key(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, int idx)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
-
- hif_wep_default_key_id(wvif, idx);
-}
-
-void wfx_reset(struct wfx_vif *wvif)
-{
- struct wfx_dev *wdev = wvif->wdev;
-
- wfx_tx_lock_flush(wdev);
- hif_reset(wvif, false);
- wfx_tx_policy_init(wvif);
- if (wvif_count(wdev) <= 1)
- hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
- wfx_tx_unlock(wdev);
- wvif->join_in_progress = false;
- cancel_delayed_work_sync(&wvif->beacon_loss_work);
- wvif = NULL;
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
- wfx_update_pm(wvif);
-}
-
-int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
- struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv;
-
- sta_priv->vif_id = wvif->id;
-
- if (vif->type == NL80211_IFTYPE_STATION)
- hif_set_mfp(wvif, sta->mfp, sta->mfp);
-
- // In station mode, the firmware interprets new link-id as a TDLS peer.
- if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
- return 0;
- sta_priv->link_id = ffz(wvif->link_id_map);
- wvif->link_id_map |= BIT(sta_priv->link_id);
- WARN_ON(!sta_priv->link_id);
- WARN_ON(sta_priv->link_id >= HIF_LINK_ID_MAX);
- hif_map_link(wvif, false, sta->addr, sta_priv->link_id, sta->mfp);
-
- return 0;
-}
-
-int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
- struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv;
-
- // See note in wfx_sta_add()
- if (!sta_priv->link_id)
- return 0;
- // FIXME add a mutex?
- hif_map_link(wvif, true, sta->addr, sta_priv->link_id, false);
- wvif->link_id_map &= ~BIT(sta_priv->link_id);
- return 0;
-}
-
-static int wfx_upload_ap_templates(struct wfx_vif *wvif)
-{
- struct sk_buff *skb;
-
- skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif);
- if (!skb)
- return -ENOMEM;
- hif_set_template_frame(wvif, skb, HIF_TMPLT_BCN,
- API_RATE_INDEX_B_1MBPS);
- dev_kfree_skb(skb);
-
- skb = ieee80211_proberesp_get(wvif->wdev->hw, wvif->vif);
- if (!skb)
- return -ENOMEM;
- hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBRES,
- API_RATE_INDEX_B_1MBPS);
- dev_kfree_skb(skb);
- return 0;
-}
-
-static void wfx_set_mfp_ap(struct wfx_vif *wvif)
-{
- struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif);
- const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
- const u16 *ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN,
- skb->data + ieoffset,
- skb->len - ieoffset);
- const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16);
- const int pairwise_cipher_suite_size = 4 / sizeof(u16);
- const int akm_suite_size = 4 / sizeof(u16);
-
- if (ptr) {
- ptr += pairwise_cipher_suite_count_offset;
- if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
- return;
- ptr += 1 + pairwise_cipher_suite_size * *ptr;
- if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
- return;
- ptr += 1 + akm_suite_size * *ptr;
- if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
- return;
- hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6));
- }
-}
-
-int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
- struct wfx_dev *wdev = wvif->wdev;
- int ret;
-
- wvif = NULL;
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
- wfx_update_pm(wvif);
- wvif = (struct wfx_vif *)vif->drv_priv;
- wfx_upload_ap_templates(wvif);
- ret = hif_start(wvif, &vif->bss_conf, wvif->channel);
- if (ret > 0)
- return -EIO;
- wfx_set_mfp_ap(wvif);
- return ret;
-}
-
-void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
-
- wfx_reset(wvif);
-}
-
-static void wfx_join(struct wfx_vif *wvif)
-{
- int ret;
- struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf;
- struct cfg80211_bss *bss = NULL;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
- const u8 *ssidie = NULL;
- int ssidlen = 0;
-
- wfx_tx_lock_flush(wvif->wdev);
-
- bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel,
- conf->bssid, NULL, 0,
- IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
- if (!bss && !conf->ibss_joined) {
- wfx_tx_unlock(wvif->wdev);
- return;
- }
-
- rcu_read_lock(); // protect ssidie
- if (bss)
- ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
- if (ssidie) {
- ssidlen = ssidie[1];
- if (ssidlen > IEEE80211_MAX_SSID_LEN)
- ssidlen = IEEE80211_MAX_SSID_LEN;
- memcpy(ssid, &ssidie[2], ssidlen);
- }
- rcu_read_unlock();
-
- cfg80211_put_bss(wvif->wdev->hw->wiphy, bss);
-
- wvif->join_in_progress = true;
- ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen);
- if (ret) {
- ieee80211_connection_loss(wvif->vif);
- wfx_reset(wvif);
- } else {
- /* Due to beacon filtering it is possible that the
- * AP's beacon is not known for the mac80211 stack.
- * Disable filtering temporary to make sure the stack
- * receives at least one
- */
- wfx_filter_beacon(wvif, false);
- }
- wfx_tx_unlock(wvif->wdev);
-}
-
-static void wfx_join_finalize(struct wfx_vif *wvif,
- struct ieee80211_bss_conf *info)
-{
- struct ieee80211_sta *sta = NULL;
- int ampdu_density = 0;
- bool greenfield = false;
-
- rcu_read_lock(); // protect sta
- if (info->bssid && !info->ibss_joined)
- sta = ieee80211_find_sta(wvif->vif, info->bssid);
- if (sta && sta->ht_cap.ht_supported)
- ampdu_density = sta->ht_cap.ampdu_density;
- if (sta && sta->ht_cap.ht_supported &&
- !(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT))
- greenfield = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
- rcu_read_unlock();
-
- wvif->join_in_progress = false;
- hif_set_association_mode(wvif, ampdu_density, greenfield,
- info->use_short_preamble);
- hif_keep_alive_period(wvif, 0);
- // beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use
- // the same value.
- hif_set_bss_params(wvif, info->aid, 7);
- hif_set_beacon_wakeup_period(wvif, 1, 1);
- wfx_update_pm(wvif);
-}
-
-int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
-
- wfx_upload_ap_templates(wvif);
- wfx_join(wvif);
- return 0;
-}
-
-void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
-
- wfx_reset(wvif);
-}
-
-static void wfx_enable_beacon(struct wfx_vif *wvif, bool enable)
-{
- // Driver has Content After DTIM Beacon in queue. Driver is waiting for
- // a signal from the firmware. Since we are going to stop to send
- // beacons, this signal will never happens. See also
- // wfx_suspend_resume_mc()
- if (!enable && wfx_tx_queues_has_cab(wvif)) {
- wvif->after_dtim_tx_allowed = true;
- wfx_bh_request_tx(wvif->wdev);
- }
- hif_beacon_transmit(wvif, enable);
-}
-
-void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info, u32 changed)
-{
- struct wfx_dev *wdev = hw->priv;
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
- int i;
-
- mutex_lock(&wdev->conf_mutex);
-
- if (changed & BSS_CHANGED_BASIC_RATES ||
- changed & BSS_CHANGED_BEACON_INT ||
- changed & BSS_CHANGED_BSSID) {
- if (vif->type == NL80211_IFTYPE_STATION)
- wfx_join(wvif);
- }
-
- if (changed & BSS_CHANGED_ASSOC) {
- if (info->assoc || info->ibss_joined)
- wfx_join_finalize(wvif, info);
- else if (!info->assoc && vif->type == NL80211_IFTYPE_STATION)
- wfx_reset(wvif);
- else
- dev_warn(wdev->dev, "%s: misunderstood change: ASSOC\n",
- __func__);
- }
-
- if (changed & BSS_CHANGED_BEACON_INFO) {
- if (vif->type != NL80211_IFTYPE_STATION)
- dev_warn(wdev->dev, "%s: misunderstood change: BEACON_INFO\n",
- __func__);
- hif_set_beacon_wakeup_period(wvif, info->dtim_period,
- info->dtim_period);
- // We temporary forwarded beacon for join process. It is now no
- // more necessary.
- wfx_filter_beacon(wvif, true);
- }
-
- if (changed & BSS_CHANGED_ARP_FILTER) {
- for (i = 0; i < HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES; i++) {
- __be32 *arp_addr = &info->arp_addr_list[i];
-
- if (info->arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES)
- arp_addr = NULL;
- if (i >= info->arp_addr_cnt)
- arp_addr = NULL;
- hif_set_arp_ipv4_filter(wvif, i, arp_addr);
- }
- }
-
- if (changed & BSS_CHANGED_AP_PROBE_RESP ||
- changed & BSS_CHANGED_BEACON)
- wfx_upload_ap_templates(wvif);
-
- if (changed & BSS_CHANGED_BEACON_ENABLED)
- wfx_enable_beacon(wvif, info->enable_beacon);
-
- if (changed & BSS_CHANGED_KEEP_ALIVE)
- hif_keep_alive_period(wvif, info->max_idle_period *
- USEC_PER_TU / USEC_PER_MSEC);
-
- if (changed & BSS_CHANGED_ERP_CTS_PROT)
- hif_erp_use_protection(wvif, info->use_cts_prot);
-
- if (changed & BSS_CHANGED_ERP_SLOT)
- hif_slot_time(wvif, info->use_short_slot ? 9 : 20);
-
- if (changed & BSS_CHANGED_CQM)
- hif_set_rcpi_rssi_threshold(wvif, info->cqm_rssi_thold,
- info->cqm_rssi_hyst);
-
- if (changed & BSS_CHANGED_TXPOWER)
- hif_set_output_power(wvif, info->txpower);
-
- if (changed & BSS_CHANGED_PS)
- wfx_update_pm(wvif);
-
- mutex_unlock(&wdev->conf_mutex);
-}
-
-static int wfx_update_tim(struct wfx_vif *wvif)
-{
- struct sk_buff *skb;
- u16 tim_offset, tim_length;
- u8 *tim_ptr;
-
- skb = ieee80211_beacon_get_tim(wvif->wdev->hw, wvif->vif,
- &tim_offset, &tim_length);
- if (!skb)
- return -ENOENT;
- tim_ptr = skb->data + tim_offset;
-
- if (tim_offset && tim_length >= 6) {
- /* Ignore DTIM count from mac80211:
- * firmware handles DTIM internally.
- */
- tim_ptr[2] = 0;
-
- /* Set/reset aid0 bit */
- if (wfx_tx_queues_has_cab(wvif))
- tim_ptr[4] |= 1;
- else
- tim_ptr[4] &= ~1;
- }
-
- hif_update_ie_beacon(wvif, tim_ptr, tim_length);
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-static void wfx_update_tim_work(struct work_struct *work)
-{
- struct wfx_vif *wvif = container_of(work, struct wfx_vif, update_tim_work);
-
- wfx_update_tim(wvif);
-}
-
-int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
-{
- struct wfx_dev *wdev = hw->priv;
- struct wfx_sta_priv *sta_dev = (struct wfx_sta_priv *)&sta->drv_priv;
- struct wfx_vif *wvif = wdev_to_wvif(wdev, sta_dev->vif_id);
-
- if (!wvif) {
- dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
- return -EIO;
- }
- schedule_work(&wvif->update_tim_work);
- return 0;
-}
-
-void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd notify_cmd)
-{
- if (notify_cmd != STA_NOTIFY_AWAKE)
- return;
- WARN(!wfx_tx_queues_has_cab(wvif), "incorrect sequence");
- WARN(wvif->after_dtim_tx_allowed, "incorrect sequence");
- wvif->after_dtim_tx_allowed = true;
- wfx_bh_request_tx(wvif->wdev);
-}
-
-int wfx_ampdu_action(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_ampdu_params *params)
-{
- // Aggregation is implemented fully in firmware
- switch (params->action) {
- case IEEE80211_AMPDU_RX_START:
- case IEEE80211_AMPDU_RX_STOP:
- // Just acknowledge it to enable frame re-ordering
- return 0;
- default:
- // Leave the firmware doing its business for tx aggregation
- return -ENOTSUPP;
- }
-}
-
-int wfx_add_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *conf)
-{
- return 0;
-}
-
-void wfx_remove_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *conf)
-{
-}
-
-void wfx_change_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *conf,
- u32 changed)
-{
-}
-
-int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_chanctx_conf *conf)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
- struct ieee80211_channel *ch = conf->def.chan;
-
- WARN(wvif->channel, "channel overwrite");
- wvif->channel = ch;
-
- return 0;
-}
-
-void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_chanctx_conf *conf)
-{
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
- struct ieee80211_channel *ch = conf->def.chan;
-
- WARN(wvif->channel != ch, "channel mismatch");
- wvif->channel = NULL;
-}
-
-int wfx_config(struct ieee80211_hw *hw, u32 changed)
-{
- return 0;
-}
-
-int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- int i, ret = 0;
- struct wfx_dev *wdev = hw->priv;
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
-
- vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
- IEEE80211_VIF_SUPPORTS_UAPSD |
- IEEE80211_VIF_SUPPORTS_CQM_RSSI;
-
- mutex_lock(&wdev->conf_mutex);
-
- switch (vif->type) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_AP:
- break;
- default:
- mutex_unlock(&wdev->conf_mutex);
- return -EOPNOTSUPP;
- }
-
- // FIXME: prefer use of container_of() to get vif
- wvif->vif = vif;
- wvif->wdev = wdev;
-
- wvif->link_id_map = 1; // link-id 0 is reserved for multicast
- INIT_WORK(&wvif->update_tim_work, wfx_update_tim_work);
- INIT_DELAYED_WORK(&wvif->beacon_loss_work, wfx_beacon_loss_work);
-
- init_completion(&wvif->set_pm_mode_complete);
- complete(&wvif->set_pm_mode_complete);
- INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work);
-
- mutex_init(&wvif->scan_lock);
- init_completion(&wvif->scan_complete);
- INIT_WORK(&wvif->scan_work, wfx_hw_scan_work);
-
- wfx_tx_queues_init(wvif);
- wfx_tx_policy_init(wvif);
-
- for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) {
- if (!wdev->vif[i]) {
- wdev->vif[i] = vif;
- wvif->id = i;
- break;
- }
- }
- WARN(i == ARRAY_SIZE(wdev->vif), "try to instantiate more vif than supported");
-
- hif_set_macaddr(wvif, vif->addr);
-
- mutex_unlock(&wdev->conf_mutex);
-
- wvif = NULL;
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
- // Combo mode does not support Block Acks. We can re-enable them
- if (wvif_count(wdev) == 1)
- hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
- else
- hif_set_block_ack_policy(wvif, 0x00, 0x00);
- }
- return ret;
-}
-
-void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- struct wfx_dev *wdev = hw->priv;
- struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
-
- wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300));
- wfx_tx_queues_check_empty(wvif);
-
- mutex_lock(&wdev->conf_mutex);
- WARN(wvif->link_id_map != 1, "corrupted state");
-
- hif_reset(wvif, false);
- hif_set_macaddr(wvif, NULL);
- wfx_tx_policy_init(wvif);
-
- cancel_delayed_work_sync(&wvif->beacon_loss_work);
- wdev->vif[wvif->id] = NULL;
- wvif->vif = NULL;
-
- mutex_unlock(&wdev->conf_mutex);
-
- wvif = NULL;
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
- // Combo mode does not support Block Acks. We can re-enable them
- if (wvif_count(wdev) == 1)
- hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
- else
- hif_set_block_ack_policy(wvif, 0x00, 0x00);
- }
-}
-
-int wfx_start(struct ieee80211_hw *hw)
-{
- return 0;
-}
-
-void wfx_stop(struct ieee80211_hw *hw)
-{
- struct wfx_dev *wdev = hw->priv;
-
- WARN_ON(!skb_queue_empty_lockless(&wdev->tx_pending));
-}
diff --git a/drivers/staging/wfx/sta.h b/drivers/staging/wfx/sta.h
deleted file mode 100644
index d7b5df5ea4e6..000000000000
--- a/drivers/staging/wfx/sta.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Implementation of mac80211 API.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- */
-#ifndef WFX_STA_H
-#define WFX_STA_H
-
-#include <net/mac80211.h>
-
-struct wfx_dev;
-struct wfx_vif;
-
-struct wfx_sta_priv {
- int link_id;
- int vif_id;
-};
-
-// mac80211 interface
-int wfx_start(struct ieee80211_hw *hw);
-void wfx_stop(struct ieee80211_hw *hw);
-int wfx_config(struct ieee80211_hw *hw, u32 changed);
-int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
-void wfx_set_default_unicast_key(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, int idx);
-void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
- unsigned int *total_flags, u64 unused);
-
-int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params);
-void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info, u32 changed);
-int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd, struct ieee80211_sta *sta);
-int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set);
-int wfx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_ampdu_params *params);
-int wfx_add_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *conf);
-void wfx_remove_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *conf);
-void wfx_change_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *conf, u32 changed);
-int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_chanctx_conf *conf);
-void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_chanctx_conf *conf);
-
-// WSM Callbacks
-void wfx_cooling_timeout_work(struct work_struct *work);
-void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd);
-void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd cmd);
-void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi);
-int wfx_update_pm(struct wfx_vif *wvif);
-
-// Other Helpers
-void wfx_reset(struct wfx_vif *wvif);
-u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates);
-
-#endif /* WFX_STA_H */
diff --git a/drivers/staging/wfx/traces.h b/drivers/staging/wfx/traces.h
deleted file mode 100644
index e34c7a538c65..000000000000
--- a/drivers/staging/wfx/traces.h
+++ /dev/null
@@ -1,501 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Tracepoints definitions.
- *
- * Copyright (c) 2018-2020, Silicon Laboratories, Inc.
- */
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM wfx
-
-#if !defined(_WFX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _WFX_TRACE_H
-
-#include <linux/tracepoint.h>
-#include <net/mac80211.h>
-
-#include "bus.h"
-#include "hif_api_cmd.h"
-#include "hif_api_mib.h"
-
-/* The hell below need some explanations. For each symbolic number, we need to
- * define it with TRACE_DEFINE_ENUM() and in a list for __print_symbolic.
- *
- * 1. Define a new macro that call TRACE_DEFINE_ENUM():
- *
- * #define xxx_name(sym) TRACE_DEFINE_ENUM(sym);
- *
- * 2. Define list of all symbols:
- *
- * #define list_names \
- * ... \
- * xxx_name(XXX) \
- * ...
- *
- * 3. Instantiate that list_names:
- *
- * list_names
- *
- * 4. Redefine xxx_name() as an entry of array for __print_symbolic()
- *
- * #undef xxx_name
- * #define xxx_name(msg) { msg, #msg },
- *
- * 5. list_name can now nearly be used with __print_symbolic() but,
- * __print_symbolic() dislike last comma of list. So we define a new list
- * with a dummy element:
- *
- * #define list_for_print_symbolic list_names { -1, NULL }
- */
-
-#define _hif_msg_list \
- hif_cnf_name(ADD_KEY) \
- hif_cnf_name(BEACON_TRANSMIT) \
- hif_cnf_name(EDCA_QUEUE_PARAMS) \
- hif_cnf_name(JOIN) \
- hif_cnf_name(MAP_LINK) \
- hif_cnf_name(READ_MIB) \
- hif_cnf_name(REMOVE_KEY) \
- hif_cnf_name(RESET) \
- hif_cnf_name(SET_BSS_PARAMS) \
- hif_cnf_name(SET_PM_MODE) \
- hif_cnf_name(START) \
- hif_cnf_name(START_SCAN) \
- hif_cnf_name(STOP_SCAN) \
- hif_cnf_name(TX) \
- hif_cnf_name(MULTI_TRANSMIT) \
- hif_cnf_name(UPDATE_IE) \
- hif_cnf_name(WRITE_MIB) \
- hif_cnf_name(CONFIGURATION) \
- hif_cnf_name(CONTROL_GPIO) \
- hif_cnf_name(PREVENT_ROLLBACK) \
- hif_cnf_name(SET_SL_MAC_KEY) \
- hif_cnf_name(SL_CONFIGURE) \
- hif_cnf_name(SL_EXCHANGE_PUB_KEYS) \
- hif_cnf_name(SHUT_DOWN) \
- hif_ind_name(EVENT) \
- hif_ind_name(JOIN_COMPLETE) \
- hif_ind_name(RX) \
- hif_ind_name(SCAN_CMPL) \
- hif_ind_name(SET_PM_MODE_CMPL) \
- hif_ind_name(SUSPEND_RESUME_TX) \
- hif_ind_name(SL_EXCHANGE_PUB_KEYS) \
- hif_ind_name(ERROR) \
- hif_ind_name(EXCEPTION) \
- hif_ind_name(GENERIC) \
- hif_ind_name(WAKEUP) \
- hif_ind_name(STARTUP)
-
-#define hif_msg_list_enum _hif_msg_list
-
-#undef hif_cnf_name
-#undef hif_ind_name
-#define hif_cnf_name(msg) TRACE_DEFINE_ENUM(HIF_CNF_ID_##msg);
-#define hif_ind_name(msg) TRACE_DEFINE_ENUM(HIF_IND_ID_##msg);
-hif_msg_list_enum
-#undef hif_cnf_name
-#undef hif_ind_name
-#define hif_cnf_name(msg) { HIF_CNF_ID_##msg, #msg },
-#define hif_ind_name(msg) { HIF_IND_ID_##msg, #msg },
-#define hif_msg_list hif_msg_list_enum { -1, NULL }
-
-#define _hif_mib_list \
- hif_mib_name(ARP_IP_ADDRESSES_TABLE) \
- hif_mib_name(ARP_KEEP_ALIVE_PERIOD) \
- hif_mib_name(BEACON_FILTER_ENABLE) \
- hif_mib_name(BEACON_FILTER_TABLE) \
- hif_mib_name(BEACON_STATS) \
- hif_mib_name(BEACON_WAKEUP_PERIOD) \
- hif_mib_name(BLOCK_ACK_POLICY) \
- hif_mib_name(CCA_CONFIG) \
- hif_mib_name(CONFIG_DATA_FILTER) \
- hif_mib_name(COUNTERS_TABLE) \
- hif_mib_name(CURRENT_TX_POWER_LEVEL) \
- hif_mib_name(DOT11_MAC_ADDRESS) \
- hif_mib_name(DOT11_MAX_RECEIVE_LIFETIME) \
- hif_mib_name(DOT11_MAX_TRANSMIT_MSDU_LIFETIME) \
- hif_mib_name(DOT11_RTS_THRESHOLD) \
- hif_mib_name(DOT11_WEP_DEFAULT_KEY_ID) \
- hif_mib_name(ETHERTYPE_DATAFRAME_CONDITION) \
- hif_mib_name(EXTENDED_COUNTERS_TABLE) \
- hif_mib_name(GL_BLOCK_ACK_INFO) \
- hif_mib_name(GL_OPERATIONAL_POWER_MODE) \
- hif_mib_name(GL_SET_MULTI_MSG) \
- hif_mib_name(GRP_SEQ_COUNTER) \
- hif_mib_name(INACTIVITY_TIMER) \
- hif_mib_name(INTERFACE_PROTECTION) \
- hif_mib_name(IPV4_ADDR_DATAFRAME_CONDITION) \
- hif_mib_name(IPV6_ADDR_DATAFRAME_CONDITION) \
- hif_mib_name(KEEP_ALIVE_PERIOD) \
- hif_mib_name(MAC_ADDR_DATAFRAME_CONDITION) \
- hif_mib_name(MAGIC_DATAFRAME_CONDITION) \
- hif_mib_name(MAX_TX_POWER_LEVEL) \
- hif_mib_name(NON_ERP_PROTECTION) \
- hif_mib_name(NS_IP_ADDRESSES_TABLE) \
- hif_mib_name(OVERRIDE_INTERNAL_TX_RATE) \
- hif_mib_name(PORT_DATAFRAME_CONDITION) \
- hif_mib_name(PROTECTED_MGMT_POLICY) \
- hif_mib_name(RCPI_RSSI_THRESHOLD) \
- hif_mib_name(RX_FILTER) \
- hif_mib_name(SET_ASSOCIATION_MODE) \
- hif_mib_name(SET_DATA_FILTERING) \
- hif_mib_name(SET_HT_PROTECTION) \
- hif_mib_name(SET_TX_RATE_RETRY_POLICY) \
- hif_mib_name(SET_UAPSD_INFORMATION) \
- hif_mib_name(SLOT_TIME) \
- hif_mib_name(STATISTICS_TABLE) \
- hif_mib_name(TEMPLATE_FRAME) \
- hif_mib_name(TSF_COUNTER) \
- hif_mib_name(UC_MC_BC_DATAFRAME_CONDITION)
-
-#define hif_mib_list_enum _hif_mib_list
-
-#undef hif_mib_name
-#define hif_mib_name(mib) TRACE_DEFINE_ENUM(HIF_MIB_ID_##mib);
-hif_mib_list_enum
-#undef hif_mib_name
-#define hif_mib_name(mib) { HIF_MIB_ID_##mib, #mib },
-#define hif_mib_list hif_mib_list_enum { -1, NULL }
-
-DECLARE_EVENT_CLASS(hif_data,
- TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv),
- TP_ARGS(hif, tx_fill_level, is_recv),
- TP_STRUCT__entry(
- __field(int, tx_fill_level)
- __field(int, msg_id)
- __field(const char *, msg_type)
- __field(int, msg_len)
- __field(int, buf_len)
- __field(int, if_id)
- __field(int, mib)
- __array(u8, buf, 128)
- ),
- TP_fast_assign(
- int header_len;
-
- __entry->tx_fill_level = tx_fill_level;
- __entry->msg_len = le16_to_cpu(hif->len);
- __entry->msg_id = hif->id;
- __entry->if_id = hif->interface;
- if (is_recv)
- __entry->msg_type = __entry->msg_id & 0x80 ? "IND" : "CNF";
- else
- __entry->msg_type = "REQ";
- if (!is_recv &&
- (__entry->msg_id == HIF_REQ_ID_READ_MIB ||
- __entry->msg_id == HIF_REQ_ID_WRITE_MIB)) {
- __entry->mib = le16_to_cpup((__le16 *)hif->body);
- header_len = 4;
- } else {
- __entry->mib = -1;
- header_len = 0;
- }
- __entry->buf_len = min_t(int, __entry->msg_len,
- sizeof(__entry->buf))
- - sizeof(struct hif_msg) - header_len;
- memcpy(__entry->buf, hif->body + header_len, __entry->buf_len);
- ),
- TP_printk("%d:%d:%s_%s%s%s: %s%s (%d bytes)",
- __entry->tx_fill_level,
- __entry->if_id,
- __entry->msg_type,
- __print_symbolic(__entry->msg_id, hif_msg_list),
- __entry->mib != -1 ? "/" : "",
- __entry->mib != -1 ? __print_symbolic(__entry->mib, hif_mib_list) : "",
- __print_hex(__entry->buf, __entry->buf_len),
- __entry->msg_len > sizeof(__entry->buf) ? " ..." : "",
- __entry->msg_len
- )
-);
-DEFINE_EVENT(hif_data, hif_send,
- TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv),
- TP_ARGS(hif, tx_fill_level, is_recv));
-#define _trace_hif_send(hif, tx_fill_level)\
- trace_hif_send(hif, tx_fill_level, false)
-DEFINE_EVENT(hif_data, hif_recv,
- TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv),
- TP_ARGS(hif, tx_fill_level, is_recv));
-#define _trace_hif_recv(hif, tx_fill_level)\
- trace_hif_recv(hif, tx_fill_level, true)
-
-#define wfx_reg_list_enum \
- wfx_reg_name(WFX_REG_CONFIG, "CONFIG") \
- wfx_reg_name(WFX_REG_CONTROL, "CONTROL") \
- wfx_reg_name(WFX_REG_IN_OUT_QUEUE, "QUEUE") \
- wfx_reg_name(WFX_REG_AHB_DPORT, "AHB") \
- wfx_reg_name(WFX_REG_BASE_ADDR, "BASE_ADDR") \
- wfx_reg_name(WFX_REG_SRAM_DPORT, "SRAM") \
- wfx_reg_name(WFX_REG_SET_GEN_R_W, "SET_GEN_R_W") \
- wfx_reg_name(WFX_REG_FRAME_OUT, "FRAME_OUT")
-
-#undef wfx_reg_name
-#define wfx_reg_name(sym, name) TRACE_DEFINE_ENUM(sym);
-wfx_reg_list_enum
-#undef wfx_reg_name
-#define wfx_reg_name(sym, name) { sym, name },
-#define wfx_reg_list wfx_reg_list_enum { -1, NULL }
-
-DECLARE_EVENT_CLASS(io_data,
- TP_PROTO(int reg, int addr, const void *io_buf, size_t len),
- TP_ARGS(reg, addr, io_buf, len),
- TP_STRUCT__entry(
- __field(int, reg)
- __field(int, addr)
- __field(int, msg_len)
- __field(int, buf_len)
- __array(u8, buf, 32)
- __array(u8, addr_str, 10)
- ),
- TP_fast_assign(
- __entry->reg = reg;
- __entry->addr = addr;
- __entry->msg_len = len;
- __entry->buf_len = min_t(int, sizeof(__entry->buf),
- __entry->msg_len);
- memcpy(__entry->buf, io_buf, __entry->buf_len);
- if (addr >= 0)
- snprintf(__entry->addr_str, 10, "/%08x", addr);
- else
- __entry->addr_str[0] = 0;
- ),
- TP_printk("%s%s: %s%s (%d bytes)",
- __print_symbolic(__entry->reg, wfx_reg_list),
- __entry->addr_str,
- __print_hex(__entry->buf, __entry->buf_len),
- __entry->msg_len > sizeof(__entry->buf) ? " ..." : "",
- __entry->msg_len
- )
-);
-DEFINE_EVENT(io_data, io_write,
- TP_PROTO(int reg, int addr, const void *io_buf, size_t len),
- TP_ARGS(reg, addr, io_buf, len));
-#define _trace_io_ind_write(reg, addr, io_buf, len)\
- trace_io_write(reg, addr, io_buf, len)
-#define _trace_io_write(reg, io_buf, len) trace_io_write(reg, -1, io_buf, len)
-DEFINE_EVENT(io_data, io_read,
- TP_PROTO(int reg, int addr, const void *io_buf, size_t len),
- TP_ARGS(reg, addr, io_buf, len));
-#define _trace_io_ind_read(reg, addr, io_buf, len)\
- trace_io_read(reg, addr, io_buf, len)
-#define _trace_io_read(reg, io_buf, len) trace_io_read(reg, -1, io_buf, len)
-
-DECLARE_EVENT_CLASS(io_data32,
- TP_PROTO(int reg, int addr, u32 val),
- TP_ARGS(reg, addr, val),
- TP_STRUCT__entry(
- __field(int, reg)
- __field(int, addr)
- __field(int, val)
- __array(u8, addr_str, 10)
- ),
- TP_fast_assign(
- __entry->reg = reg;
- __entry->addr = addr;
- __entry->val = val;
- if (addr >= 0)
- snprintf(__entry->addr_str, 10, "/%08x", addr);
- else
- __entry->addr_str[0] = 0;
- ),
- TP_printk("%s%s: %08x",
- __print_symbolic(__entry->reg, wfx_reg_list),
- __entry->addr_str,
- __entry->val
- )
-);
-DEFINE_EVENT(io_data32, io_write32,
- TP_PROTO(int reg, int addr, u32 val),
- TP_ARGS(reg, addr, val));
-#define _trace_io_ind_write32(reg, addr, val) trace_io_write32(reg, addr, val)
-#define _trace_io_write32(reg, val) trace_io_write32(reg, -1, val)
-DEFINE_EVENT(io_data32, io_read32,
- TP_PROTO(int reg, int addr, u32 val),
- TP_ARGS(reg, addr, val));
-#define _trace_io_ind_read32(reg, addr, val) trace_io_read32(reg, addr, val)
-#define _trace_io_read32(reg, val) trace_io_read32(reg, -1, val)
-
-DECLARE_EVENT_CLASS(piggyback,
- TP_PROTO(u32 val, bool ignored),
- TP_ARGS(val, ignored),
- TP_STRUCT__entry(
- __field(int, val)
- __field(bool, ignored)
- ),
- TP_fast_assign(
- __entry->val = val;
- __entry->ignored = ignored;
- ),
- TP_printk("CONTROL: %08x%s",
- __entry->val,
- __entry->ignored ? " (ignored)" : ""
- )
-);
-DEFINE_EVENT(piggyback, piggyback,
- TP_PROTO(u32 val, bool ignored),
- TP_ARGS(val, ignored));
-#define _trace_piggyback(val, ignored) trace_piggyback(val, ignored)
-
-TRACE_EVENT(bh_stats,
- TP_PROTO(int ind, int req, int cnf, int busy, bool release),
- TP_ARGS(ind, req, cnf, busy, release),
- TP_STRUCT__entry(
- __field(int, ind)
- __field(int, req)
- __field(int, cnf)
- __field(int, busy)
- __field(bool, release)
- ),
- TP_fast_assign(
- __entry->ind = ind;
- __entry->req = req;
- __entry->cnf = cnf;
- __entry->busy = busy;
- __entry->release = release;
- ),
- TP_printk("IND/REQ/CNF:%3d/%3d/%3d, REQ in progress:%3d, WUP: %s",
- __entry->ind,
- __entry->req,
- __entry->cnf,
- __entry->busy,
- __entry->release ? "release" : "keep"
- )
-);
-#define _trace_bh_stats(ind, req, cnf, busy, release)\
- trace_bh_stats(ind, req, cnf, busy, release)
-
-TRACE_EVENT(tx_stats,
- TP_PROTO(const struct hif_cnf_tx *tx_cnf, const struct sk_buff *skb,
- int delay),
- TP_ARGS(tx_cnf, skb, delay),
- TP_STRUCT__entry(
- __field(int, pkt_id)
- __field(int, delay_media)
- __field(int, delay_queue)
- __field(int, delay_fw)
- __field(int, ack_failures)
- __field(int, flags)
- __array(int, rate, 4)
- __array(int, tx_count, 4)
- ),
- TP_fast_assign(
- // Keep sync with wfx_rates definition in main.c
- static const int hw_rate[] = { 0, 1, 2, 3, 6, 7, 8, 9,
- 10, 11, 12, 13 };
- const struct ieee80211_tx_info *tx_info =
- (const struct ieee80211_tx_info *)skb->cb;
- const struct ieee80211_tx_rate *rates = tx_info->driver_rates;
- int i;
-
- __entry->pkt_id = tx_cnf->packet_id;
- __entry->delay_media = le32_to_cpu(tx_cnf->media_delay);
- __entry->delay_queue = le32_to_cpu(tx_cnf->tx_queue_delay);
- __entry->delay_fw = delay;
- __entry->ack_failures = tx_cnf->ack_failures;
- if (!tx_cnf->status || __entry->ack_failures)
- __entry->ack_failures += 1;
-
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- if (rates[0].flags & IEEE80211_TX_RC_MCS)
- __entry->rate[i] = rates[i].idx;
- else
- __entry->rate[i] = hw_rate[rates[i].idx];
- __entry->tx_count[i] = rates[i].count;
- }
- __entry->flags = 0;
- if (rates[0].flags & IEEE80211_TX_RC_MCS)
- __entry->flags |= 0x01;
- if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
- __entry->flags |= 0x02;
- if (rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)
- __entry->flags |= 0x04;
- if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
- __entry->flags |= 0x08;
- if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)
- __entry->flags |= 0x10;
- if (tx_cnf->status)
- __entry->flags |= 0x20;
- if (tx_cnf->status == HIF_STATUS_TX_FAIL_REQUEUE)
- __entry->flags |= 0x40;
- ),
- TP_printk("packet ID: %08x, rate policy: %s %d|%d %d|%d %d|%d %d|%d -> %d attempt, Delays media/queue/total: %4dus/%4dus/%4dus",
- __entry->pkt_id,
- __print_flags(__entry->flags, NULL,
- { 0x01, "M" }, { 0x02, "S" }, { 0x04, "G" },
- { 0x08, "R" }, { 0x10, "D" }, { 0x20, "F" },
- { 0x40, "Q" }),
- __entry->rate[0],
- __entry->tx_count[0],
- __entry->rate[1],
- __entry->tx_count[1],
- __entry->rate[2],
- __entry->tx_count[2],
- __entry->rate[3],
- __entry->tx_count[3],
- __entry->ack_failures,
- __entry->delay_media,
- __entry->delay_queue,
- __entry->delay_fw
- )
-);
-#define _trace_tx_stats(tx_cnf, skb, delay) trace_tx_stats(tx_cnf, skb, delay)
-
-TRACE_EVENT(queues_stats,
- TP_PROTO(struct wfx_dev *wdev, const struct wfx_queue *elected_queue),
- TP_ARGS(wdev, elected_queue),
- TP_STRUCT__entry(
- __field(int, vif_id)
- __field(int, queue_id)
- __array(int, hw, IEEE80211_NUM_ACS * 2)
- __array(int, drv, IEEE80211_NUM_ACS * 2)
- __array(int, cab, IEEE80211_NUM_ACS * 2)
- ),
- TP_fast_assign(
- const struct wfx_queue *queue;
- struct wfx_vif *wvif;
- int i, j;
-
- for (j = 0; j < IEEE80211_NUM_ACS * 2; j++) {
- __entry->hw[j] = -1;
- __entry->drv[j] = -1;
- __entry->cab[j] = -1;
- }
- __entry->vif_id = -1;
- __entry->queue_id = -1;
- wvif = NULL;
- while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- j = wvif->id * IEEE80211_NUM_ACS + i;
- WARN_ON(j >= IEEE80211_NUM_ACS * 2);
- queue = &wvif->tx_queue[i];
- __entry->hw[j] = atomic_read(&queue->pending_frames);
- __entry->drv[j] = skb_queue_len(&queue->normal);
- __entry->cab[j] = skb_queue_len(&queue->cab);
- if (queue == elected_queue) {
- __entry->vif_id = wvif->id;
- __entry->queue_id = i;
- }
- }
- }
- ),
- TP_printk("got skb from %d/%d, pend. hw/norm/cab: [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ] [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ]",
- __entry->vif_id, __entry->queue_id,
- __entry->hw[0], __entry->drv[0], __entry->cab[0],
- __entry->hw[1], __entry->drv[1], __entry->cab[1],
- __entry->hw[2], __entry->drv[2], __entry->cab[2],
- __entry->hw[3], __entry->drv[3], __entry->cab[3],
- __entry->hw[4], __entry->drv[4], __entry->cab[4],
- __entry->hw[5], __entry->drv[5], __entry->cab[5],
- __entry->hw[6], __entry->drv[6], __entry->cab[6],
- __entry->hw[7], __entry->drv[7], __entry->cab[7]
- )
-);
-
-#endif
-
-/* This part must be outside protection */
-#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_FILE traces
-
-#include <trace/define_trace.h>
diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
deleted file mode 100644
index 94898680ccde..000000000000
--- a/drivers/staging/wfx/wfx.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Common private data for Silicon Labs WFx chips.
- *
- * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
- * Copyright (c) 2010, ST-Ericsson
- * Copyright (c) 2006, Michael Wu <[email protected]>
- * Copyright 2004-2006 Jean-Baptiste Note <[email protected]>, et al.
- */
-#ifndef WFX_H
-#define WFX_H
-
-#include <linux/completion.h>
-#include <linux/workqueue.h>
-#include <linux/mutex.h>
-#include <linux/nospec.h>
-#include <net/mac80211.h>
-
-#include "bh.h"
-#include "data_tx.h"
-#include "main.h"
-#include "queue.h"
-#include "hif_tx.h"
-
-#define USEC_PER_TXOP 32 // see struct ieee80211_tx_queue_params
-#define USEC_PER_TU 1024
-
-struct hwbus_ops;
-
-struct wfx_dev {
- struct wfx_platform_data pdata;
- struct device *dev;
- struct ieee80211_hw *hw;
- struct ieee80211_vif *vif[2];
- 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;
- struct delayed_work cooling_timeout_work;
- bool poll_irq;
- bool chip_frozen;
- struct mutex conf_mutex;
-
- struct wfx_hif_cmd hif_cmd;
- struct sk_buff_head tx_pending;
- wait_queue_head_t tx_dequeue;
- atomic_t tx_lock;
-
- atomic_t packet_id;
- u32 key_map;
-
- struct hif_rx_stats rx_stats;
- struct mutex rx_stats_lock;
- struct hif_tx_power_loop_info tx_power_loop_info;
- struct mutex tx_power_loop_info_lock;
- int force_ps_timeout;
-};
-
-struct wfx_vif {
- struct wfx_dev *wdev;
- struct ieee80211_vif *vif;
- struct ieee80211_channel *channel;
- int id;
-
- u32 link_id_map;
-
- bool after_dtim_tx_allowed;
- bool join_in_progress;
-
- struct delayed_work beacon_loss_work;
-
- struct wfx_queue tx_queue[4];
- struct tx_policy_cache tx_policy_cache;
- struct work_struct tx_policy_upload_work;
-
- struct work_struct update_tim_work;
-
- unsigned long uapsd_mask;
-
- /* avoid some operations in parallel with scan */
- struct mutex scan_lock;
- struct work_struct scan_work;
- struct completion scan_complete;
- bool scan_abort;
- struct ieee80211_scan_request *scan_req;
-
- struct completion set_pm_mode_complete;
-};
-
-static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id)
-{
- if (vif_id >= ARRAY_SIZE(wdev->vif)) {
- dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id);
- return NULL;
- }
- vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif));
- if (!wdev->vif[vif_id]) {
- dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n",
- vif_id);
- return NULL;
- }
- return (struct wfx_vif *) wdev->vif[vif_id]->drv_priv;
-}
-
-static inline struct wfx_vif *wvif_iterate(struct wfx_dev *wdev,
- struct wfx_vif *cur)
-{
- int i;
- int mark = 0;
- struct wfx_vif *tmp;
-
- if (!cur)
- mark = 1;
- for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) {
- tmp = wdev_to_wvif(wdev, i);
- if (mark && tmp)
- return tmp;
- if (tmp == cur)
- mark = 1;
- }
- return NULL;
-}
-
-static inline int wvif_count(struct wfx_dev *wdev)
-{
- int i;
- int ret = 0;
- struct wfx_vif *wvif;
-
- for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) {
- wvif = wdev_to_wvif(wdev, i);
- if (wvif)
- ret++;
- }
- return ret;
-}
-
-static inline void memreverse(u8 *src, u8 length)
-{
- u8 *lo = src;
- u8 *hi = src + length - 1;
- u8 swap;
-
- while (lo < hi) {
- swap = *lo;
- *lo++ = *hi;
- *hi-- = swap;
- }
-}
-
-static inline int memzcmp(void *src, unsigned int size)
-{
- u8 *buf = src;
-
- if (!size)
- return 0;
- if (*buf)
- return 1;
- return memcmp(buf, buf + 1, size - 1);
-}
-
-#endif /* WFX_H */
--
2.29.2

2020-12-23 15:45:19

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 15/24] wfx: add hif_rx.c/hif_rx.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/hif_rx.c | 416 +++++++++++++++++++++++
drivers/net/wireless/silabs/wfx/hif_rx.h | 18 +
2 files changed, 434 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/hif_rx.c
create mode 100644 drivers/net/wireless/silabs/wfx/hif_rx.h

diff --git a/drivers/net/wireless/silabs/wfx/hif_rx.c b/drivers/net/wireless/silabs/wfx/hif_rx.c
new file mode 100644
index 000000000000..2a9c09c5ee1f
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_rx.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
+ * (WSM) API.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+
+#include "hif_rx.h"
+#include "wfx.h"
+#include "scan.h"
+#include "bh.h"
+#include "sta.h"
+#include "data_rx.h"
+#include "hif_api_cmd.h"
+
+static int hif_generic_confirm(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf)
+{
+ /* All confirm messages start with status */
+ int status = le32_to_cpup((__le32 *)buf);
+ int cmd = hif->id;
+ int len = le16_to_cpu(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 && len > 0)
+ memcpy(wdev->hif_cmd.buf_recv, buf, len);
+ else
+ status = -EIO;
+ }
+ wdev->hif_cmd.ret = status;
+
+ complete(&wdev->hif_cmd.done);
+ return status;
+}
+
+static int hif_tx_confirm(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf)
+{
+ const struct hif_cnf_tx *body = buf;
+
+ wfx_tx_confirm_cb(wdev, body);
+ return 0;
+}
+
+static int hif_multi_tx_confirm(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf)
+{
+ const struct hif_cnf_multi_transmit *body = buf;
+ int i;
+
+ WARN(body->num_tx_confs <= 0, "corrupted message");
+ for (i = 0; i < body->num_tx_confs; i++)
+ wfx_tx_confirm_cb(wdev, &body->tx_conf_payload[i]);
+ return 0;
+}
+
+static int hif_startup_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf)
+{
+ const 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));
+ le16_to_cpus((__le16 *)&wdev->hw_caps.hardware_id);
+ le16_to_cpus((__le16 *)&wdev->hw_caps.num_inp_ch_bufs);
+ le16_to_cpus((__le16 *)&wdev->hw_caps.size_inp_ch_buf);
+ le32_to_cpus((__le32 *)&wdev->hw_caps.supported_rate_mask);
+
+ complete(&wdev->firmware_ready);
+ return 0;
+}
+
+static int hif_wakeup_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf)
+{
+ if (!wdev->pdata.gpio_wakeup ||
+ gpiod_get_value(wdev->pdata.gpio_wakeup) == 0) {
+ dev_warn(wdev->dev, "unexpected wake-up indication\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int hif_receive_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif,
+ const void *buf, struct sk_buff *skb)
+{
+ struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+ const struct hif_ind_rx *body = buf;
+
+ if (!wvif) {
+ dev_warn(wdev->dev, "%s: ignore rx data for non-existent vif %d\n",
+ __func__, hif->interface);
+ return -EIO;
+ }
+ skb_pull(skb, sizeof(struct hif_msg) + sizeof(struct hif_ind_rx));
+ wfx_rx_cb(wvif, body, skb);
+
+ return 0;
+}
+
+static int hif_event_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf)
+{
+ struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+ const struct hif_ind_event *body = buf;
+ int type = le32_to_cpu(body->event_id);
+
+ if (!wvif) {
+ dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
+ return -EIO;
+ }
+
+ switch (type) {
+ case HIF_EVENT_IND_RCPI_RSSI:
+ wfx_event_report_rssi(wvif, body->event_data.rcpi_rssi);
+ break;
+ case HIF_EVENT_IND_BSSLOST:
+ schedule_delayed_work(&wvif->beacon_loss_work, 0);
+ break;
+ case HIF_EVENT_IND_BSSREGAINED:
+ cancel_delayed_work(&wvif->beacon_loss_work);
+ dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n");
+ break;
+ case HIF_EVENT_IND_PS_MODE_ERROR:
+ dev_warn(wdev->dev, "error while processing power save request: %d\n",
+ le32_to_cpu(body->event_data.ps_mode_error));
+ break;
+ default:
+ dev_warn(wdev->dev, "unhandled event indication: %.2x\n",
+ type);
+ break;
+ }
+ return 0;
+}
+
+static int hif_pm_mode_complete_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif,
+ const void *buf)
+{
+ struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+
+ if (!wvif) {
+ dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
+ return -EIO;
+ }
+ complete(&wvif->set_pm_mode_complete);
+
+ return 0;
+}
+
+static int hif_scan_complete_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif,
+ const void *buf)
+{
+ struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+
+ if (!wvif) {
+ dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
+ return -EIO;
+ }
+
+ wfx_scan_complete(wvif);
+
+ return 0;
+}
+
+static int hif_join_complete_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif,
+ const void *buf)
+{
+ struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+
+ if (!wvif) {
+ dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
+ return -EIO;
+ }
+ dev_warn(wdev->dev, "unattended JoinCompleteInd\n");
+
+ return 0;
+}
+
+static int hif_suspend_resume_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif,
+ const void *buf)
+{
+ const struct hif_ind_suspend_resume_tx *body = buf;
+ struct wfx_vif *wvif;
+
+ if (body->bc_mc_only) {
+ wvif = wdev_to_wvif(wdev, hif->interface);
+ if (!wvif) {
+ dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
+ return -EIO;
+ }
+ if (body->resume)
+ wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE);
+ else
+ wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP);
+ } else {
+ WARN(body->peer_sta_set, "misunderstood indication");
+ WARN(hif->interface != 2, "misunderstood indication");
+ if (body->resume)
+ wfx_suspend_hot_dev(wdev, STA_NOTIFY_AWAKE);
+ else
+ wfx_suspend_hot_dev(wdev, STA_NOTIFY_SLEEP);
+ }
+
+ return 0;
+}
+
+static int hif_generic_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf)
+{
+ const struct hif_ind_generic *body = buf;
+ int type = le32_to_cpu(body->type);
+
+ switch (type) {
+ case HIF_GENERIC_INDICATION_TYPE_RAW:
+ return 0;
+ case HIF_GENERIC_INDICATION_TYPE_STRING:
+ dev_info(wdev->dev, "firmware says: %s\n", (char *)&body->data);
+ return 0;
+ case HIF_GENERIC_INDICATION_TYPE_RX_STATS:
+ mutex_lock(&wdev->rx_stats_lock);
+ /* Older firmware send a generic indication beside RxStats */
+ if (!wfx_api_older_than(wdev, 1, 4))
+ dev_info(wdev->dev, "Rx test ongoing. Temperature: %d degrees C\n",
+ body->data.rx_stats.current_temp);
+ memcpy(&wdev->rx_stats, &body->data.rx_stats,
+ sizeof(wdev->rx_stats));
+ mutex_unlock(&wdev->rx_stats_lock);
+ return 0;
+ case HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO:
+ mutex_lock(&wdev->tx_power_loop_info_lock);
+ memcpy(&wdev->tx_power_loop_info,
+ &body->data.tx_power_loop_info,
+ sizeof(wdev->tx_power_loop_info));
+ mutex_unlock(&wdev->tx_power_loop_info_lock);
+ return 0;
+ default:
+ dev_err(wdev->dev, "generic_indication: unknown indication type: %#.8x\n",
+ type);
+ return -EIO;
+ }
+}
+
+static const struct {
+ int val;
+ const char *str;
+ bool has_param;
+} hif_errors[] = {
+ { HIF_ERROR_FIRMWARE_ROLLBACK,
+ "rollback status" },
+ { HIF_ERROR_FIRMWARE_DEBUG_ENABLED,
+ "debug feature enabled" },
+ { HIF_ERROR_PDS_PAYLOAD,
+ "PDS version is not supported" },
+ { HIF_ERROR_PDS_TESTFEATURE,
+ "PDS ask for an unknown test mode" },
+ { HIF_ERROR_OOR_VOLTAGE,
+ "out-of-range power supply voltage", true },
+ { HIF_ERROR_OOR_TEMPERATURE,
+ "out-of-range temperature", true },
+ { HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE,
+ "secure link does not expect request during key exchange" },
+ { HIF_ERROR_SLK_SESSION_KEY,
+ "secure link session key is invalid" },
+ { HIF_ERROR_SLK_OVERFLOW,
+ "secure link overflow" },
+ { HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE,
+ "secure link messages list does not match message encryption" },
+ { HIF_ERROR_SLK_UNCONFIGURED,
+ "secure link not yet configured" },
+ { HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW,
+ "bus clock is too slow (<1kHz)" },
+ { HIF_ERROR_HIF_RX_DATA_TOO_LARGE,
+ "HIF message too large" },
+ /* Following errors only exists in old firmware versions: */
+ { HIF_ERROR_HIF_TX_QUEUE_FULL,
+ "HIF messages queue is full" },
+ { HIF_ERROR_HIF_BUS,
+ "HIF bus" },
+ { HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED,
+ "secure link does not support multi-tx confirmations" },
+ { HIF_ERROR_SLK_OUTDATED_SESSION_KEY,
+ "secure link session key is outdated" },
+ { HIF_ERROR_SLK_DECRYPTION,
+ "secure link params (nonce or tag) mismatch" },
+};
+
+static int hif_error_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf)
+{
+ const struct hif_ind_error *body = buf;
+ int type = le32_to_cpu(body->type);
+ int param = (s8)body->data[0];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hif_errors); i++)
+ if (type == hif_errors[i].val)
+ break;
+ if (i < ARRAY_SIZE(hif_errors))
+ if (hif_errors[i].has_param)
+ dev_err(wdev->dev, "asynchronous error: %s: %d\n",
+ hif_errors[i].str, param);
+ else
+ dev_err(wdev->dev, "asynchronous error: %s\n",
+ hif_errors[i].str);
+ else
+ dev_err(wdev->dev, "asynchronous error: unknown: %08x\n", type);
+ print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET,
+ 16, 1, hif, le16_to_cpu(hif->len), false);
+ wdev->chip_frozen = true;
+
+ return 0;
+};
+
+static int hif_exception_indication(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf)
+{
+ const struct hif_ind_exception *body = buf;
+ int type = le32_to_cpu(body->type);
+
+ if (type == 4)
+ dev_err(wdev->dev, "firmware assert %d\n",
+ le32_to_cpup((__le32 *)body->data));
+ else
+ dev_err(wdev->dev, "firmware exception\n");
+ print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET,
+ 16, 1, hif, le16_to_cpu(hif->len), false);
+ wdev->chip_frozen = true;
+
+ return -1;
+}
+
+static const struct {
+ int msg_id;
+ int (*handler)(struct wfx_dev *wdev,
+ const struct hif_msg *hif, const void *buf);
+} hif_handlers[] = {
+ /* Confirmations */
+ { HIF_CNF_ID_TX, hif_tx_confirm },
+ { HIF_CNF_ID_MULTI_TRANSMIT, hif_multi_tx_confirm },
+ /* Indications */
+ { HIF_IND_ID_STARTUP, hif_startup_indication },
+ { HIF_IND_ID_WAKEUP, hif_wakeup_indication },
+ { HIF_IND_ID_JOIN_COMPLETE, hif_join_complete_indication },
+ { HIF_IND_ID_SET_PM_MODE_CMPL, hif_pm_mode_complete_indication },
+ { HIF_IND_ID_SCAN_CMPL, hif_scan_complete_indication },
+ { HIF_IND_ID_SUSPEND_RESUME_TX, hif_suspend_resume_indication },
+ { HIF_IND_ID_EVENT, hif_event_indication },
+ { HIF_IND_ID_GENERIC, hif_generic_indication },
+ { HIF_IND_ID_ERROR, hif_error_indication },
+ { HIF_IND_ID_EXCEPTION, hif_exception_indication },
+ /* FIXME: allocate skb_p from hif_receive_indication and make it generic */
+ //{ HIF_IND_ID_RX, hif_receive_indication },
+};
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
+{
+ int i;
+ const struct hif_msg *hif = (const struct hif_msg *)skb->data;
+ int hif_id = hif->id;
+
+ if (hif_id == HIF_IND_ID_RX) {
+ /* hif_receive_indication take care of skb lifetime */
+ hif_receive_indication(wdev, hif, hif->body, skb);
+ return;
+ }
+ /* 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)
+ hif_handlers[i].handler(wdev, hif, hif->body);
+ goto free;
+ }
+ }
+ if (hif_id & 0x80)
+ dev_err(wdev->dev, "unsupported HIF indication: ID %02x\n",
+ hif_id);
+ else
+ dev_err(wdev->dev, "unexpected HIF confirmation: ID %02x\n",
+ hif_id);
+free:
+ dev_kfree_skb(skb);
+}
diff --git a/drivers/net/wireless/silabs/wfx/hif_rx.h b/drivers/net/wireless/silabs/wfx/hif_rx.h
new file mode 100644
index 000000000000..f07c10c8c6bd
--- /dev/null
+++ b/drivers/net/wireless/silabs/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
--
2.29.2

2020-12-23 15:45:26

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 24/24] wfx: get out from the staging area

From: Jérôme Pouiller <[email protected]>

The wfx driver is now mature enough to leave the staging area.

Signed-off-by: Jérôme Pouiller <[email protected]>
---
MAINTAINERS | 3 ++-
drivers/net/wireless/Kconfig | 1 +
drivers/net/wireless/Makefile | 1 +
drivers/net/wireless/silabs/Kconfig | 18 ++++++++++++++++++
drivers/net/wireless/silabs/Makefile | 3 +++
drivers/staging/Kconfig | 2 --
drivers/staging/Makefile | 1 -
drivers/staging/wfx/TODO | 6 ------
8 files changed, 25 insertions(+), 10 deletions(-)
create mode 100644 drivers/net/wireless/silabs/Kconfig
create mode 100644 drivers/net/wireless/silabs/Makefile
delete mode 100644 drivers/staging/wfx/TODO

diff --git a/MAINTAINERS b/MAINTAINERS
index 9d7784a5cb88..35810219bad0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16219,7 +16219,8 @@ F: drivers/platform/x86/touchscreen_dmi.c
SILICON LABS WIRELESS DRIVERS (for WFxxx series)
M: Jérôme Pouiller <[email protected]>
S: Supported
-F: drivers/staging/wfx/
+F: Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml
+F: drivers/net/wireless/silabs/wfx/

SILICON MOTION SM712 FRAME BUFFER DRIVER
M: Sudip Mukherjee <[email protected]>
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 7add2002ff4c..e78ff7af6517 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -31,6 +31,7 @@ source "drivers/net/wireless/microchip/Kconfig"
source "drivers/net/wireless/ralink/Kconfig"
source "drivers/net/wireless/realtek/Kconfig"
source "drivers/net/wireless/rsi/Kconfig"
+source "drivers/net/wireless/silabs/Kconfig"
source "drivers/net/wireless/st/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zydas/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 80b324499786..76885e5f0ea7 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_WLAN_VENDOR_MICROCHIP) += microchip/
obj-$(CONFIG_WLAN_VENDOR_RALINK) += ralink/
obj-$(CONFIG_WLAN_VENDOR_REALTEK) += realtek/
obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/
+obj-$(CONFIG_WLAN_VENDOR_SILABS) += silabs/
obj-$(CONFIG_WLAN_VENDOR_ST) += st/
obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
diff --git a/drivers/net/wireless/silabs/Kconfig b/drivers/net/wireless/silabs/Kconfig
new file mode 100644
index 000000000000..6262a799bf36
--- /dev/null
+++ b/drivers/net/wireless/silabs/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config WLAN_VENDOR_SILABS
+ bool "Silicon Laboratories devices"
+ default y
+ help
+ If you have a wireless card belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all the
+ questions about these cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if WLAN_VENDOR_SILABS
+
+source "drivers/net/wireless/silabs/wfx/Kconfig"
+
+endif # WLAN_VENDOR_SILABS
diff --git a/drivers/net/wireless/silabs/Makefile b/drivers/net/wireless/silabs/Makefile
new file mode 100644
index 000000000000..c2263ee21006
--- /dev/null
+++ b/drivers/net/wireless/silabs/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_WFX) += wfx/
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index b22f73d7bfc4..b07de39b9f0a 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,8 +110,6 @@ source "drivers/staging/qlge/Kconfig"

source "drivers/staging/wimax/Kconfig"

-source "drivers/staging/wfx/Kconfig"
-
source "drivers/staging/hikey9xx/Kconfig"

endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 2245059e69c7..c6a992d1edd5 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -45,5 +45,4 @@ obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
obj-$(CONFIG_KPC2000) += kpc2000/
obj-$(CONFIG_QLGE) += qlge/
obj-$(CONFIG_WIMAX) += wimax/
-obj-$(CONFIG_WFX) += wfx/
obj-y += hikey9xx/
diff --git a/drivers/staging/wfx/TODO b/drivers/staging/wfx/TODO
deleted file mode 100644
index 1b4bc2af94b6..000000000000
--- a/drivers/staging/wfx/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a list of things that need to be done to get this driver out of the
-staging directory.
-
- - As suggested by Felix, rate control could be improved following this idea:
- https://lore.kernel.org/lkml/3099559.gv3Q75KnN1@pc-42/
-
--
2.29.2

2020-12-23 15:45:28

by Jérôme Pouiller

[permalink] [raw]
Subject: [PATCH v4 13/24] wfx: add hif_tx*.c/hif_tx*.h

From: Jérôme Pouiller <[email protected]>

Signed-off-by: Jérôme Pouiller <[email protected]>
---
drivers/net/wireless/silabs/wfx/hif_tx.c | 527 +++++++++++++++++++
drivers/net/wireless/silabs/wfx/hif_tx.h | 60 +++
drivers/net/wireless/silabs/wfx/hif_tx_mib.c | 324 ++++++++++++
drivers/net/wireless/silabs/wfx/hif_tx_mib.h | 49 ++
4 files changed, 960 insertions(+)
create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx.c
create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx.h
create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx_mib.c
create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx_mib.h

diff --git a/drivers/net/wireless/silabs/wfx/hif_tx.c b/drivers/net/wireless/silabs/wfx/hif_tx.c
new file mode 100644
index 000000000000..626a6b5aee1e
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_tx.c
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx
+ * Split Mac (WSM) API.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include <linux/etherdevice.h>
+
+#include "hif_tx.h"
+#include "wfx.h"
+#include "bh.h"
+#include "hwio.h"
+#include "debug.h"
+#include "sta.h"
+
+void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
+{
+ init_completion(&hif_cmd->ready);
+ init_completion(&hif_cmd->done);
+ mutex_init(&hif_cmd->lock);
+}
+
+static void wfx_fill_header(struct hif_msg *hif, int if_id,
+ unsigned int cmd, size_t size)
+{
+ if (if_id == -1)
+ if_id = 2;
+
+ WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd);
+ WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size);
+ WARN(if_id > 0x3, "invalid interface ID %d", if_id);
+
+ hif->len = cpu_to_le16(size + 4);
+ hif->id = cmd;
+ hif->interface = if_id;
+}
+
+static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif)
+{
+ *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL);
+ if (*hif)
+ return (*hif)->body;
+ else
+ return NULL;
+}
+
+int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request,
+ void *reply, size_t reply_len, bool no_reply)
+{
+ const char *mib_name = "";
+ const char *mib_sep = "";
+ int cmd = request->id;
+ int vif = request->interface;
+ int ret;
+
+ /* Do not wait for any reply if chip is frozen */
+ if (wdev->chip_frozen)
+ return -ETIMEDOUT;
+
+ mutex_lock(&wdev->hif_cmd.lock);
+ WARN(wdev->hif_cmd.buf_send, "data locking error");
+
+ /* Note: call to complete() below has an implicit memory barrier that
+ * hopefully protect buf_send
+ */
+ wdev->hif_cmd.buf_send = request;
+ wdev->hif_cmd.buf_recv = reply;
+ wdev->hif_cmd.len_recv = reply_len;
+ complete(&wdev->hif_cmd.ready);
+
+ wfx_bh_request_tx(wdev);
+
+ if (no_reply) {
+ /* Chip won't reply. Give enough time to the wq to send the
+ * buffer.
+ */
+ msleep(100);
+ wdev->hif_cmd.buf_send = NULL;
+ mutex_unlock(&wdev->hif_cmd.lock);
+ return 0;
+ }
+
+ if (wdev->poll_irq)
+ wfx_bh_poll_irq(wdev);
+
+ ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ);
+ if (!ret) {
+ dev_err(wdev->dev, "chip is abnormally long to answer\n");
+ reinit_completion(&wdev->hif_cmd.ready);
+ ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ);
+ }
+ if (!ret) {
+ dev_err(wdev->dev, "chip did not answer\n");
+ wfx_pending_dump_old_frames(wdev, 3000);
+ wdev->chip_frozen = true;
+ reinit_completion(&wdev->hif_cmd.done);
+ ret = -ETIMEDOUT;
+ } else {
+ ret = wdev->hif_cmd.ret;
+ }
+
+ wdev->hif_cmd.buf_send = NULL;
+ mutex_unlock(&wdev->hif_cmd.lock);
+
+ if (ret &&
+ (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) {
+ mib_name = get_mib_name(((u16 *)request)[2]);
+ mib_sep = "/";
+ }
+ if (ret < 0)
+ dev_err(wdev->dev,
+ "WSM request %s%s%s (%#.2x) on vif %d returned error %d\n",
+ get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
+ if (ret > 0)
+ dev_warn(wdev->dev,
+ "WSM request %s%s%s (%#.2x) on vif %d returned status %d\n",
+ get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
+
+ return ret;
+}
+
+/* This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any
+ * request anymore. Obviously, only call this function during device unregister.
+ */
+int hif_shutdown(struct wfx_dev *wdev)
+{
+ int ret;
+ struct hif_msg *hif;
+
+ wfx_alloc_hif(0, &hif);
+ if (!hif)
+ return -ENOMEM;
+ wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0);
+ ret = wfx_cmd_send(wdev, hif, NULL, 0, true);
+ if (wdev->pdata.gpio_wakeup)
+ gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
+ else
+ control_reg_write(wdev, 0);
+ kfree(hif);
+ return ret;
+}
+
+int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
+{
+ int ret;
+ size_t buf_len = sizeof(struct hif_req_configuration) + len;
+ struct hif_msg *hif;
+ struct hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ body->length = cpu_to_le16(len);
+ memcpy(body->pds_data, conf, len);
+ wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len);
+ ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_reset(struct wfx_vif *wvif, bool reset_stat)
+{
+ int ret;
+ struct hif_msg *hif;
+ struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ body->reset_stat = reset_stat;
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body));
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
+ void *val, size_t val_len)
+{
+ int ret;
+ struct hif_msg *hif;
+ int buf_len = sizeof(struct hif_cnf_read_mib) + val_len;
+ struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif);
+ struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
+
+ if (!body || !reply) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ body->mib_id = cpu_to_le16(mib_id);
+ wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body));
+ ret = wfx_cmd_send(wdev, hif, reply, buf_len, false);
+
+ if (!ret && mib_id != le16_to_cpu(reply->mib_id)) {
+ dev_warn(wdev->dev, "%s: confirmation mismatch request\n",
+ __func__);
+ ret = -EIO;
+ }
+ if (ret == -ENOMEM)
+ dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n",
+ get_mib_name(mib_id), val_len,
+ le16_to_cpu(reply->length));
+ if (!ret)
+ memcpy(val, &reply->mib_data, le16_to_cpu(reply->length));
+ else
+ memset(val, 0xFF, val_len);
+out:
+ kfree(hif);
+ kfree(reply);
+ return ret;
+}
+
+int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
+ void *val, size_t val_len)
+{
+ int ret;
+ struct hif_msg *hif;
+ int buf_len = sizeof(struct hif_req_write_mib) + val_len;
+ struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ body->mib_id = cpu_to_le16(mib_id);
+ body->length = cpu_to_le16(val_len);
+ memcpy(&body->mib_data, val, val_len);
+ wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len);
+ ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req,
+ int chan_start_idx, int chan_num, int *timeout)
+{
+ int ret, i;
+ struct hif_msg *hif;
+ size_t buf_len =
+ sizeof(struct hif_req_start_scan_alt) + chan_num * sizeof(u8);
+ struct hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif);
+ int tmo_chan_fg, tmo_chan_bg, tmo;
+
+ WARN(chan_num > HIF_API_MAX_NB_CHANNELS, "invalid params");
+ WARN(req->n_ssids > HIF_API_MAX_NB_SSIDS, "invalid params");
+
+ if (!hif)
+ return -ENOMEM;
+ for (i = 0; i < req->n_ssids; i++) {
+ memcpy(body->ssid_def[i].ssid, req->ssids[i].ssid,
+ IEEE80211_MAX_SSID_LEN);
+ body->ssid_def[i].ssid_length =
+ cpu_to_le32(req->ssids[i].ssid_len);
+ }
+ body->num_of_ssids = HIF_API_MAX_NB_SSIDS;
+ body->maintain_current_bss = 1;
+ body->disallow_ps = 1;
+ body->tx_power_level =
+ cpu_to_le32(req->channels[chan_start_idx]->max_power);
+ body->num_of_channels = chan_num;
+ for (i = 0; i < chan_num; i++)
+ body->channel_list[i] =
+ req->channels[i + chan_start_idx]->hw_value;
+ if (req->no_cck)
+ body->max_transmit_rate = API_RATE_INDEX_G_6MBPS;
+ else
+ body->max_transmit_rate = API_RATE_INDEX_B_1MBPS;
+ if (req->channels[chan_start_idx]->flags & IEEE80211_CHAN_NO_IR) {
+ body->min_channel_time = cpu_to_le32(50);
+ body->max_channel_time = cpu_to_le32(150);
+ } else {
+ body->min_channel_time = cpu_to_le32(10);
+ body->max_channel_time = cpu_to_le32(50);
+ body->num_of_probe_requests = 2;
+ body->probe_delay = 100;
+ }
+ tmo_chan_bg = le32_to_cpu(body->max_channel_time) * USEC_PER_TU;
+ tmo_chan_fg = 512 * USEC_PER_TU + body->probe_delay;
+ tmo_chan_fg *= body->num_of_probe_requests;
+ tmo = chan_num * max(tmo_chan_bg, tmo_chan_fg) + 512 * USEC_PER_TU;
+ if (timeout)
+ *timeout = usecs_to_jiffies(tmo);
+
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len);
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_stop_scan(struct wfx_vif *wvif)
+{
+ int ret;
+ struct hif_msg *hif;
+ /* body associated to HIF_REQ_ID_STOP_SCAN is empty */
+ wfx_alloc_hif(0, &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0);
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+ struct ieee80211_channel *channel, const u8 *ssid, int ssidlen)
+{
+ int ret;
+ struct hif_msg *hif;
+ struct hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+ WARN_ON(!conf->beacon_int);
+ WARN_ON(!conf->basic_rates);
+ WARN_ON(sizeof(body->ssid) < ssidlen);
+ WARN(!conf->ibss_joined && !ssidlen, "joining an unknown BSS");
+ if (WARN_ON(!channel))
+ return -EINVAL;
+ if (!hif)
+ return -ENOMEM;
+ body->infrastructure_bss_mode = !conf->ibss_joined;
+ body->short_preamble = conf->use_short_preamble;
+ if (channel->flags & IEEE80211_CHAN_NO_IR)
+ body->probe_for_join = 0;
+ else
+ body->probe_for_join = 1;
+ body->channel_number = channel->hw_value;
+ body->beacon_interval = cpu_to_le32(conf->beacon_int);
+ body->basic_rate_set =
+ cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
+ memcpy(body->bssid, conf->bssid, sizeof(body->bssid));
+ if (ssid) {
+ body->ssid_length = cpu_to_le32(ssidlen);
+ memcpy(body->ssid, ssid, ssidlen);
+ }
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body));
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count)
+{
+ int ret;
+ struct hif_msg *hif;
+ struct hif_req_set_bss_params *body =
+ wfx_alloc_hif(sizeof(*body), &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ body->aid = cpu_to_le16(aid);
+ body->beacon_lost_count = beacon_lost_count;
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS,
+ sizeof(*body));
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg)
+{
+ int ret;
+ struct hif_msg *hif;
+ /* FIXME: only send necessary bits */
+ struct hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ /* FIXME: swap bytes as necessary in body */
+ memcpy(body, arg, sizeof(*body));
+ if (wfx_api_older_than(wdev, 1, 5))
+ /* Legacy firmwares expect that add_key to be sent on right
+ * interface.
+ */
+ wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY,
+ sizeof(*body));
+ else
+ wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body));
+ ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_remove_key(struct wfx_dev *wdev, int idx)
+{
+ int ret;
+ struct hif_msg *hif;
+ struct hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ body->entry_index = idx;
+ wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body));
+ ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
+ const struct ieee80211_tx_queue_params *arg)
+{
+ int ret;
+ struct hif_msg *hif;
+ struct hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body),
+ &hif);
+
+ if (!body)
+ return -ENOMEM;
+
+ WARN_ON(arg->aifs > 255);
+ if (!hif)
+ return -ENOMEM;
+ body->aifsn = arg->aifs;
+ body->cw_min = cpu_to_le16(arg->cw_min);
+ body->cw_max = cpu_to_le16(arg->cw_max);
+ body->tx_op_limit = cpu_to_le16(arg->txop * USEC_PER_TXOP);
+ body->queue_id = 3 - queue;
+ /* API 2.0 has changed queue IDs values */
+ if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BE)
+ body->queue_id = HIF_QUEUE_ID_BACKGROUND;
+ if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BK)
+ body->queue_id = HIF_QUEUE_ID_BESTEFFORT;
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS,
+ sizeof(*body));
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout)
+{
+ int ret;
+ struct hif_msg *hif;
+ struct hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+ if (!body)
+ return -ENOMEM;
+
+ if (!hif)
+ return -ENOMEM;
+ if (ps) {
+ body->enter_psm = 1;
+ /* Firmware does not support more than 128ms */
+ body->fast_psm_idle_period = min(dynamic_ps_timeout * 2, 255);
+ if (body->fast_psm_idle_period)
+ body->fast_psm = 1;
+ }
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body));
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+ const struct ieee80211_channel *channel)
+{
+ int ret;
+ struct hif_msg *hif;
+ struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+ WARN_ON(!conf->beacon_int);
+ if (!hif)
+ return -ENOMEM;
+ body->dtim_period = conf->dtim_period;
+ body->short_preamble = conf->use_short_preamble;
+ body->channel_number = channel->hw_value;
+ body->beacon_interval = cpu_to_le32(conf->beacon_int);
+ body->basic_rate_set =
+ cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
+ body->ssid_length = conf->ssid_len;
+ memcpy(body->ssid, conf->ssid, conf->ssid_len);
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body));
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_beacon_transmit(struct wfx_vif *wvif, bool enable)
+{
+ int ret;
+ struct hif_msg *hif;
+ struct hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body),
+ &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ body->enable_beaconing = enable ? 1 : 0;
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT,
+ sizeof(*body));
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp)
+{
+ int ret;
+ struct hif_msg *hif;
+ struct hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ if (mac_addr)
+ ether_addr_copy(body->mac_addr, mac_addr);
+ body->mfpc = mfp ? 1 : 0;
+ body->unmap = unmap ? 1 : 0;
+ body->peer_sta_id = sta_id;
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body));
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
+
+int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
+{
+ int ret;
+ struct hif_msg *hif;
+ int buf_len = sizeof(struct hif_req_update_ie) + ies_len;
+ struct hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif);
+
+ if (!hif)
+ return -ENOMEM;
+ body->beacon = 1;
+ body->num_ies = cpu_to_le16(1);
+ memcpy(body->ie, ies, ies_len);
+ wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len);
+ ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+ kfree(hif);
+ return ret;
+}
diff --git a/drivers/net/wireless/silabs/wfx/hif_tx.h b/drivers/net/wireless/silabs/wfx/hif_tx.h
new file mode 100644
index 000000000000..3521c545ae6b
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_tx.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx
+ * Split Mac (WSM) API.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ * Copyright (C) 2010, ST-Ericsson SA
+ */
+#ifndef WFX_HIF_TX_H
+#define WFX_HIF_TX_H
+
+struct ieee80211_channel;
+struct ieee80211_bss_conf;
+struct ieee80211_tx_queue_params;
+struct cfg80211_scan_request;
+struct hif_req_add_key;
+struct wfx_dev;
+struct wfx_vif;
+
+struct wfx_hif_cmd {
+ struct mutex lock;
+ struct completion ready;
+ struct completion done;
+ struct hif_msg *buf_send;
+ void *buf_recv;
+ size_t len_recv;
+ int ret;
+};
+
+void wfx_init_hif_cmd(struct wfx_hif_cmd *wfx_hif_cmd);
+int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request,
+ void *reply, size_t reply_len, bool async);
+
+int hif_shutdown(struct wfx_dev *wdev);
+int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len);
+int hif_reset(struct wfx_vif *wvif, bool reset_stat);
+int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
+ void *buf, size_t buf_size);
+int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
+ void *buf, size_t buf_size);
+int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211,
+ int chan_start, int chan_num, int *timeout);
+int hif_stop_scan(struct wfx_vif *wvif);
+int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+ struct ieee80211_channel *channel, const u8 *ssid, int ssidlen);
+int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout);
+int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count);
+int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg);
+int hif_remove_key(struct wfx_dev *wdev, int idx);
+int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
+ const struct ieee80211_tx_queue_params *arg);
+int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+ const struct ieee80211_channel *channel);
+int hif_beacon_transmit(struct wfx_vif *wvif, bool enable);
+int hif_map_link(struct wfx_vif *wvif,
+ bool unmap, u8 *mac_addr, int sta_id, bool mfp);
+int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len);
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/hif_tx_mib.c b/drivers/net/wireless/silabs/wfx/hif_tx_mib.c
new file mode 100644
index 000000000000..0ad661bf724b
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_tx_mib.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ * Copyright (C) 2010, ST-Ericsson SA
+ */
+
+#include <linux/etherdevice.h>
+
+#include "wfx.h"
+#include "hif_tx.h"
+#include "hif_tx_mib.h"
+#include "hif_api_mib.h"
+
+int hif_set_output_power(struct wfx_vif *wvif, int val)
+{
+ struct hif_mib_current_tx_power_level arg = {
+ .power_level = cpu_to_le32(val * 10),
+ };
+
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_CURRENT_TX_POWER_LEVEL,
+ &arg, sizeof(arg));
+}
+
+int hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
+ unsigned int dtim_interval,
+ unsigned int listen_interval)
+{
+ struct hif_mib_beacon_wake_up_period arg = {
+ .wakeup_period_min = dtim_interval,
+ .receive_dtim = 0,
+ .wakeup_period_max = listen_interval,
+ };
+
+ if (dtim_interval > 0xFF || listen_interval > 0xFFFF)
+ return -EINVAL;
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_BEACON_WAKEUP_PERIOD,
+ &arg, sizeof(arg));
+}
+
+int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif,
+ int rssi_thold, int rssi_hyst)
+{
+ struct hif_mib_rcpi_rssi_threshold arg = {
+ .rolling_average_count = 8,
+ .detection = 1,
+ };
+
+ if (!rssi_thold && !rssi_hyst) {
+ arg.upperthresh = 1;
+ arg.lowerthresh = 1;
+ } else {
+ arg.upper_threshold = rssi_thold + rssi_hyst;
+ arg.upper_threshold = (arg.upper_threshold + 110) * 2;
+ arg.lower_threshold = rssi_thold;
+ arg.lower_threshold = (arg.lower_threshold + 110) * 2;
+ }
+
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_RCPI_RSSI_THRESHOLD, &arg, sizeof(arg));
+}
+
+int hif_get_counters_table(struct wfx_dev *wdev, int vif_id,
+ struct hif_mib_extended_count_table *arg)
+{
+ if (wfx_api_older_than(wdev, 1, 3)) {
+ /* extended_count_table is wider than count_table */
+ memset(arg, 0xFF, sizeof(*arg));
+ return hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE,
+ arg, sizeof(struct hif_mib_count_table));
+ } else {
+ return hif_read_mib(wdev, vif_id,
+ HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, arg,
+ sizeof(struct hif_mib_extended_count_table));
+ }
+}
+
+int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac)
+{
+ struct hif_mib_mac_address msg = { };
+
+ if (mac)
+ ether_addr_copy(msg.mac_addr, mac);
+ return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS,
+ &msg, sizeof(msg));
+}
+
+int hif_set_rx_filter(struct wfx_vif *wvif,
+ bool filter_bssid, bool filter_prbreq)
+{
+ struct hif_mib_rx_filter arg = { };
+
+ if (filter_bssid)
+ arg.bssid_filter = 1;
+ if (!filter_prbreq)
+ arg.fwd_probe_req = 1;
+ return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER,
+ &arg, sizeof(arg));
+}
+
+int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len,
+ const struct hif_ie_table_entry *tbl)
+{
+ int ret;
+ struct hif_mib_bcn_filter_table *arg;
+ int buf_len = struct_size(arg, ie_table, tbl_len);
+
+ arg = kzalloc(buf_len, GFP_KERNEL);
+ if (!arg)
+ return -ENOMEM;
+ arg->num_of_info_elmts = cpu_to_le32(tbl_len);
+ memcpy(arg->ie_table, tbl, flex_array_size(arg, ie_table, tbl_len));
+ ret = hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_BEACON_FILTER_TABLE, arg, buf_len);
+ kfree(arg);
+ return ret;
+}
+
+int hif_beacon_filter_control(struct wfx_vif *wvif,
+ int enable, int beacon_count)
+{
+ struct hif_mib_bcn_filter_enable arg = {
+ .enable = cpu_to_le32(enable),
+ .bcn_count = cpu_to_le32(beacon_count),
+ };
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_BEACON_FILTER_ENABLE,
+ &arg, sizeof(arg));
+}
+
+int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode)
+{
+ struct hif_mib_gl_operational_power_mode arg = {
+ .power_mode = mode,
+ .wup_ind_activation = 1,
+ };
+
+ return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE,
+ &arg, sizeof(arg));
+}
+
+int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb,
+ u8 frame_type, int init_rate)
+{
+ struct hif_mib_template_frame *arg;
+
+ WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big");
+ skb_push(skb, 4);
+ arg = (struct hif_mib_template_frame *)skb->data;
+ skb_pull(skb, 4);
+ arg->init_rate = init_rate;
+ arg->frame_type = frame_type;
+ arg->frame_length = cpu_to_le16(skb->len);
+ return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME,
+ arg, sizeof(*arg) + skb->len);
+}
+
+int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required)
+{
+ struct hif_mib_protected_mgmt_policy arg = { };
+
+ WARN(required && !capable, "incoherent arguments");
+ if (capable) {
+ arg.pmf_enable = 1;
+ arg.host_enc_auth_frames = 1;
+ }
+ if (!required)
+ arg.unpmf_allowed = 1;
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_PROTECTED_MGMT_POLICY,
+ &arg, sizeof(arg));
+}
+
+int hif_set_block_ack_policy(struct wfx_vif *wvif,
+ u8 tx_tid_policy, u8 rx_tid_policy)
+{
+ struct hif_mib_block_ack_policy arg = {
+ .block_ack_tx_tid_policy = tx_tid_policy,
+ .block_ack_rx_tid_policy = rx_tid_policy,
+ };
+
+ return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY,
+ &arg, sizeof(arg));
+}
+
+int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density,
+ bool greenfield, bool short_preamble)
+{
+ struct hif_mib_set_association_mode arg = {
+ .preambtype_use = 1,
+ .mode = 1,
+ .spacing = 1,
+ .short_preamble = short_preamble,
+ .greenfield = greenfield,
+ .mpdu_start_spacing = ampdu_density,
+ };
+
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_SET_ASSOCIATION_MODE, &arg, sizeof(arg));
+}
+
+int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif,
+ int policy_index, u8 *rates)
+{
+ struct hif_mib_set_tx_rate_retry_policy *arg;
+ size_t size = struct_size(arg, tx_rate_retry_policy, 1);
+ int ret;
+
+ arg = kzalloc(size, GFP_KERNEL);
+ if (!arg)
+ return -ENOMEM;
+ arg->num_tx_rate_policies = 1;
+ arg->tx_rate_retry_policy[0].policy_index = policy_index;
+ arg->tx_rate_retry_policy[0].short_retry_count = 255;
+ arg->tx_rate_retry_policy[0].long_retry_count = 255;
+ arg->tx_rate_retry_policy[0].first_rate_sel = 1;
+ arg->tx_rate_retry_policy[0].terminate = 1;
+ arg->tx_rate_retry_policy[0].count_init = 1;
+ memcpy(&arg->tx_rate_retry_policy[0].rates, rates,
+ sizeof(arg->tx_rate_retry_policy[0].rates));
+ ret = hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size);
+ kfree(arg);
+ return ret;
+}
+
+int hif_keep_alive_period(struct wfx_vif *wvif, int period)
+{
+ struct hif_mib_keep_alive_period arg = {
+ .keep_alive_period = cpu_to_le16(period),
+ };
+
+ return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD,
+ &arg, sizeof(arg));
+};
+
+int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr)
+{
+ struct hif_mib_arp_ip_addr_table arg = {
+ .condition_idx = idx,
+ .arp_enable = HIF_ARP_NS_FILTERING_DISABLE,
+ };
+
+ if (addr) {
+ /* Caution: type of addr is __be32 */
+ memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address));
+ arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE;
+ }
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE,
+ &arg, sizeof(arg));
+}
+
+int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable)
+{
+ struct hif_mib_gl_set_multi_msg arg = {
+ .enable_multi_tx_conf = enable,
+ };
+
+ return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG,
+ &arg, sizeof(arg));
+}
+
+int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val)
+{
+ struct hif_mib_set_uapsd_information arg = { };
+
+ if (val & BIT(IEEE80211_AC_VO))
+ arg.trig_voice = 1;
+ if (val & BIT(IEEE80211_AC_VI))
+ arg.trig_video = 1;
+ if (val & BIT(IEEE80211_AC_BE))
+ arg.trig_be = 1;
+ if (val & BIT(IEEE80211_AC_BK))
+ arg.trig_bckgrnd = 1;
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_SET_UAPSD_INFORMATION,
+ &arg, sizeof(arg));
+}
+
+int hif_erp_use_protection(struct wfx_vif *wvif, bool enable)
+{
+ struct hif_mib_non_erp_protection arg = {
+ .use_cts_to_self = enable,
+ };
+
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg));
+}
+
+int hif_slot_time(struct wfx_vif *wvif, int val)
+{
+ struct hif_mib_slot_time arg = {
+ .slot_time = cpu_to_le32(val),
+ };
+
+ return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME,
+ &arg, sizeof(arg));
+}
+
+int hif_wep_default_key_id(struct wfx_vif *wvif, int val)
+{
+ struct hif_mib_wep_default_key_id arg = {
+ .wep_default_key_id = val,
+ };
+
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID,
+ &arg, sizeof(arg));
+}
+
+int hif_rts_threshold(struct wfx_vif *wvif, int val)
+{
+ struct hif_mib_dot11_rts_threshold arg = {
+ .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF),
+ };
+
+ return hif_write_mib(wvif->wdev, wvif->id,
+ HIF_MIB_ID_DOT11_RTS_THRESHOLD, &arg, sizeof(arg));
+}
diff --git a/drivers/net/wireless/silabs/wfx/hif_tx_mib.h b/drivers/net/wireless/silabs/wfx/hif_tx_mib.h
new file mode 100644
index 000000000000..812b3ba0f00e
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_tx_mib.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API.
+ *
+ * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ * Copyright (C) 2010, ST-Ericsson SA
+ */
+#ifndef WFX_HIF_TX_MIB_H
+#define WFX_HIF_TX_MIB_H
+
+struct wfx_vif;
+struct sk_buff;
+
+int hif_set_output_power(struct wfx_vif *wvif, int val);
+int hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
+ unsigned int dtim_interval,
+ unsigned int listen_interval);
+int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif,
+ int rssi_thold, int rssi_hyst);
+int hif_get_counters_table(struct wfx_dev *wdev, int vif_id,
+ struct hif_mib_extended_count_table *arg);
+int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac);
+int hif_set_rx_filter(struct wfx_vif *wvif,
+ bool filter_bssid, bool fwd_probe_req);
+int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len,
+ const struct hif_ie_table_entry *tbl);
+int hif_beacon_filter_control(struct wfx_vif *wvif,
+ int enable, int beacon_count);
+int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode);
+int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb,
+ u8 frame_type, int init_rate);
+int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required);
+int hif_set_block_ack_policy(struct wfx_vif *wvif,
+ u8 tx_tid_policy, u8 rx_tid_policy);
+int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density,
+ bool greenfield, bool short_preamble);
+int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif,
+ int policy_index, u8 *rates);
+int hif_keep_alive_period(struct wfx_vif *wvif, int period);
+int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr);
+int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable);
+int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val);
+int hif_erp_use_protection(struct wfx_vif *wvif, bool enable);
+int hif_slot_time(struct wfx_vif *wvif, int val);
+int hif_wep_default_key_id(struct wfx_vif *wvif, int val);
+int hif_rts_threshold(struct wfx_vif *wvif, int val);
+
+#endif
--
2.29.2