DriverDev-Devel Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 00/23] wfx: get out from the staging area
@ 2020-10-12 10:46 Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml Jerome Pouiller
                   ` (22 more replies)
  0 siblings, 23 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

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

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

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/:
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)


[1] https://lore.kernel.org/lkml/87ft6p2n0h.fsf@codeaurora.org/

*** BLURB HERE ***

Jérôme Pouiller (23):
  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      |  0
 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               |  0
 .../wireless/silabs}/wfx/Makefile              |  0
 .../{staging => net/wireless/silabs}/wfx/bh.c  |  0
 .../{staging => net/wireless/silabs}/wfx/bh.h  |  0
 .../{staging => net/wireless/silabs}/wfx/bus.h |  0
 .../wireless/silabs}/wfx/bus_sdio.c            |  0
 .../wireless/silabs}/wfx/bus_spi.c             |  0
 .../wireless/silabs}/wfx/data_rx.c             |  0
 .../wireless/silabs}/wfx/data_rx.h             |  0
 .../wireless/silabs}/wfx/data_tx.c             |  2 +-
 .../wireless/silabs}/wfx/data_tx.h             |  0
 .../wireless/silabs}/wfx/debug.c               |  0
 .../wireless/silabs}/wfx/debug.h               |  0
 .../wireless/silabs}/wfx/fwio.c                |  0
 .../wireless/silabs}/wfx/fwio.h                |  0
 .../wireless/silabs}/wfx/hif_api_cmd.h         |  0
 .../wireless/silabs}/wfx/hif_api_general.h     |  0
 .../wireless/silabs}/wfx/hif_api_mib.h         |  0
 .../wireless/silabs}/wfx/hif_rx.c              |  0
 .../wireless/silabs}/wfx/hif_rx.h              |  0
 .../wireless/silabs}/wfx/hif_tx.c              |  0
 .../wireless/silabs}/wfx/hif_tx.h              |  0
 .../wireless/silabs}/wfx/hif_tx_mib.c          |  0
 .../wireless/silabs}/wfx/hif_tx_mib.h          |  0
 .../wireless/silabs}/wfx/hwio.c                |  0
 .../wireless/silabs}/wfx/hwio.h                |  0
 .../{staging => net/wireless/silabs}/wfx/key.c |  0
 .../{staging => net/wireless/silabs}/wfx/key.h |  0
 .../wireless/silabs}/wfx/main.c                |  7 +++----
 .../wireless/silabs}/wfx/main.h                |  0
 .../wireless/silabs}/wfx/queue.c               |  0
 .../wireless/silabs}/wfx/queue.h               |  0
 .../wireless/silabs}/wfx/scan.c                |  0
 .../wireless/silabs}/wfx/scan.h                |  0
 .../{staging => net/wireless/silabs}/wfx/sta.c |  0
 .../{staging => net/wireless/silabs}/wfx/sta.h |  0
 .../wireless/silabs}/wfx/traces.h              |  0
 .../{staging => net/wireless/silabs}/wfx/wfx.h |  0
 drivers/staging/Kconfig                        |  2 --
 drivers/staging/Makefile                       |  1 -
 drivers/staging/wfx/TODO                       |  6 ------
 47 files changed, 29 insertions(+), 15 deletions(-)
 rename {drivers/staging/wfx/Documentation => Documentation}/devicetree/bindings/net/wireless/silabs,wfx.yaml (100%)
 create mode 100644 drivers/net/wireless/silabs/Kconfig
 create mode 100644 drivers/net/wireless/silabs/Makefile
 rename drivers/{staging => net/wireless/silabs}/wfx/Kconfig (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/Makefile (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bh.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bh.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bus.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bus_sdio.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/bus_spi.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/data_rx.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/data_rx.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/data_tx.c (99%)
 rename drivers/{staging => net/wireless/silabs}/wfx/data_tx.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/debug.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/debug.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/fwio.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/fwio.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_cmd.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_general.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_mib.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_rx.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_rx.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx_mib.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx_mib.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hwio.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/hwio.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/key.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/key.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/main.c (99%)
 rename drivers/{staging => net/wireless/silabs}/wfx/main.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/queue.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/queue.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/scan.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/scan.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/sta.c (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/sta.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/traces.h (100%)
 rename drivers/{staging => net/wireless/silabs}/wfx/wfx.h (100%)
 delete mode 100644 drivers/staging/wfx/TODO

-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-13 16:49   ` Rob Herring
  2020-10-12 10:46 ` [PATCH 02/23] wfx: add Makefile/Kconfig Jerome Pouiller
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 .../bindings/net/wireless/silabs,wfx.yaml     | 125 ++++++++++++++++++
 1 file changed, 125 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..43b5630c0407
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml
@@ -0,0 +1,125 @@
+# 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 <jerome.pouiller@silabs.com>
+
+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.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.
+
+  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>;
+        };
+    };
+...
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 02/23] wfx: add Makefile/Kconfig
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 03/23] wfx: add wfx.h Jerome Pouiller
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/Kconfig  |  8 ++++++++
 drivers/net/wireless/silabs/wfx/Makefile | 25 ++++++++++++++++++++++++
 2 files changed, 33 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..83ee4d0ca8c6
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/Kconfig
@@ -0,0 +1,8 @@
+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/net/wireless/silabs/wfx/Makefile b/drivers/net/wireless/silabs/wfx/Makefile
new file mode 100644
index 000000000000..0e0cc982ceab
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/Makefile
@@ -0,0 +1,25 @@
+# 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
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 03/23] wfx: add wfx.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 02/23] wfx: add Makefile/Kconfig Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 04/23] wfx: add main.c/main.h Jerome Pouiller
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 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..94898680ccde
--- /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 <flamingice@sourmilk.net>
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, 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.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 04/23] wfx: add main.c/main.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (2 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 03/23] wfx: add wfx.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 05/23] wfx: add bus.h Jerome Pouiller
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/main.c | 489 +++++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/main.h |  44 +++
 2 files changed, 533 insertions(+)
 create mode 100644 drivers/net/wireless/silabs/wfx/main.c
 create mode 100644 drivers/net/wireless/silabs/wfx/main.h

diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c
new file mode 100644
index 000000000000..bfff4c8f5677
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/main.c
@@ -0,0 +1,489 @@
+// 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 <johannes@sipsolutions.net>
+ * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, 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 <jerome.pouiller@silabs.com>");
+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);
+		return ret;
+	}
+	tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL);
+	if (!tmp_buf) {
+		ret = -ENOMEM;
+		goto release_fw;
+	}
+	ret = wfx_send_pds(wdev, tmp_buf, pds->size);
+	kfree(tmp_buf);
+release_fw:
+	release_firmware(pds);
+	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/net/wireless/silabs/wfx/main.h b/drivers/net/wireless/silabs/wfx/main.h
new file mode 100644
index 000000000000..a0db322383a3
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/main.h
@@ -0,0 +1,44 @@
+/* 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 <flamingice@sourmilk.net>
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, 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
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 05/23] wfx: add bus.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (3 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 04/23] wfx: add main.c/main.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 06/23] wfx: add bus_spi.c Jerome Pouiller
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 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.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 06/23] wfx: add bus_spi.c
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (4 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 05/23] wfx: add bus.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 07/23] wfx: add bus_sdio.c Jerome Pouiller
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 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..a99125d1a30d
--- /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.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 07/23] wfx: add bus_sdio.c
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (5 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 06/23] wfx: add bus_spi.c Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-13 20:11   ` Pali Rohár
  2020-10-16 11:30   ` Ulf Hansson
  2020-10-12 10:46 ` [PATCH 08/23] wfx: add hwio.c/hwio.h Jerome Pouiller
                   ` (15 subsequent siblings)
  22 siblings, 2 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/bus_sdio.c | 269 +++++++++++++++++++++
 1 file changed, 269 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..e06d7e1ebe9c
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/bus_sdio.c
@@ -0,0 +1,269 @@
+// 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,
+	}
+};
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 08/23] wfx: add hwio.c/hwio.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (6 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 07/23] wfx: add bus_sdio.c Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 09/23] wfx: add fwio.c/fwio.h Jerome Pouiller
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/hwio.c | 352 +++++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/hwio.h |  75 ++++++
 2 files changed, 427 insertions(+)
 create mode 100644 drivers/net/wireless/silabs/wfx/hwio.c
 create mode 100644 drivers/net/wireless/silabs/wfx/hwio.h

diff --git a/drivers/net/wireless/silabs/wfx/hwio.c b/drivers/net/wireless/silabs/wfx/hwio.c
new file mode 100644
index 000000000000..36fbc5b5d64c
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hwio.c
@@ -0,0 +1,352 @@
+// 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/net/wireless/silabs/wfx/hwio.h b/drivers/net/wireless/silabs/wfx/hwio.h
new file mode 100644
index 000000000000..0b8e4f7157df
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hwio.h
@@ -0,0 +1,75 @@
+/* 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 */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 09/23] wfx: add fwio.c/fwio.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (7 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 08/23] wfx: add hwio.c/hwio.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 10/23] wfx: add bh.c/bh.h Jerome Pouiller
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 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..1b8aec02d169
--- /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..6028f92503fe
--- /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 /* WFX_FWIO_H */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 10/23] wfx: add bh.c/bh.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (8 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 09/23] wfx: add fwio.c/fwio.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 11/23] wfx: add hif_api_*.h Jerome Pouiller
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/bh.c | 333 +++++++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/bh.h |  33 +++
 2 files changed, 366 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..2ffa587aefaa
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/bh.c
@@ -0,0 +1,333 @@
+// 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..78c49329e22a
--- /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 /* WFX_BH_H */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 11/23] wfx: add hif_api_*.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (9 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 10/23] wfx: add bh.c/bh.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 12/23] wfx: add hif_tx*.c/hif_tx*.h Jerome Pouiller
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/hif_api_cmd.h | 553 ++++++++++++++++++
 .../net/wireless/silabs/wfx/hif_api_general.h | 267 +++++++++
 drivers/net/wireless/silabs/wfx/hif_api_mib.h | 343 +++++++++++
 3 files changed, 1163 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..11bc1a58edae
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_api_cmd.h
@@ -0,0 +1,553 @@
+/* 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..24188945718d
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_api_general.h
@@ -0,0 +1,267 @@
+/* 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/net/wireless/silabs/wfx/hif_api_mib.h b/drivers/net/wireless/silabs/wfx/hif_api_mib.h
new file mode 100644
index 000000000000..ace924720ce6
--- /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.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 12/23] wfx: add hif_tx*.c/hif_tx*.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (10 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 11/23] wfx: add hif_api_*.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 13/23] wfx: add key.c/key.h Jerome Pouiller
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/hif_tx.c     | 523 +++++++++++++++++++
 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, 956 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..63b437261eb7
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_tx.c
@@ -0,0 +1,523 @@
+// 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..1926cf1b62be
--- /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.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 13/23] wfx: add key.c/key.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (11 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 12/23] wfx: add hif_tx*.c/hif_tx*.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 14/23] wfx: add hif_rx.c/hif_rx.h Jerome Pouiller
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 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..2ab82bed4c1b
--- /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..70a44d0ca35e
--- /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 /* WFX_STA_H */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 14/23] wfx: add hif_rx.c/hif_rx.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (12 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 13/23] wfx: add key.c/key.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 15/23] wfx: add data_rx.c/data_rx.h Jerome Pouiller
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/hif_rx.c | 415 +++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/hif_rx.h |  18 +
 2 files changed, 433 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..56a5f891447b
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/hif_rx.c
@@ -0,0 +1,415 @@
+// 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.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 15/23] wfx: add data_rx.c/data_rx.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (13 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 14/23] wfx: add hif_rx.c/hif_rx.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 16/23] wfx: add queue.c/queue.h Jerome Pouiller
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/data_rx.c | 93 +++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/data_rx.h | 18 +++++
 2 files changed, 111 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..385f2d42a0e2
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/data_rx.c
@@ -0,0 +1,93 @@
+// 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..4c0da37f2084
--- /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 /* WFX_DATA_RX_H */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 16/23] wfx: add queue.c/queue.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (14 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 15/23] wfx: add data_rx.c/data_rx.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 17/23] wfx: add data_tx.c/data_tx.h Jerome Pouiller
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/queue.c | 304 ++++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/queue.h |  45 ++++
 2 files changed, 349 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..31c37f69c295
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/queue.c
@@ -0,0 +1,304 @@
+// 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..80ba19455ef3
--- /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 /* WFX_QUEUE_H */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 17/23] wfx: add data_tx.c/data_tx.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (15 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 16/23] wfx: add queue.c/queue.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 18/23] wfx: add sta.c/sta.h Jerome Pouiller
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/data_tx.c | 585 ++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/data_tx.h |  67 +++
 2 files changed, 652 insertions(+)
 create mode 100644 drivers/net/wireless/silabs/wfx/data_tx.c
 create mode 100644 drivers/net/wireless/silabs/wfx/data_tx.h

diff --git a/drivers/net/wireless/silabs/wfx/data_tx.c b/drivers/net/wireless/silabs/wfx/data_tx.c
new file mode 100644
index 000000000000..a254a1ea7bbd
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/data_tx.c
@@ -0,0 +1,585 @@
+// 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;
+	}
+	if (rate->idx >= band->n_bitrates) {
+		WARN(1, "wrong rate->idx value: %d", rate->idx);
+		return -1;
+	}
+	// WFx only support 2GHz, else band information should be retrieved
+	// from ieee80211_tx_info
+	band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ];
+	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("vif associated with the skb does not exist anymore\n");
+		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/net/wireless/silabs/wfx/data_tx.h b/drivers/net/wireless/silabs/wfx/data_tx.h
new file mode 100644
index 000000000000..46c9fff7a870
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/data_tx.h
@@ -0,0 +1,67 @@
+/* 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 */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 18/23] wfx: add sta.c/sta.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (16 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 17/23] wfx: add data_tx.c/data_tx.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 19/23] wfx: add scan.c/scan.h Jerome Pouiller
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/sta.c | 807 ++++++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/sta.h |  73 +++
 2 files changed, 880 insertions(+)
 create mode 100644 drivers/net/wireless/silabs/wfx/sta.c
 create mode 100644 drivers/net/wireless/silabs/wfx/sta.h

diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c
new file mode 100644
index 000000000000..2320a81eae0b
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/sta.c
@@ -0,0 +1,807 @@
+// 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)
+{
+	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/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h
new file mode 100644
index 000000000000..d7b5df5ea4e6
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/sta.h
@@ -0,0 +1,73 @@
+/* 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 */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 19/23] wfx: add scan.c/scan.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (17 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 18/23] wfx: add sta.c/sta.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 20/23] wfx: add debug.c/debug.h Jerome Pouiller
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/scan.c | 132 +++++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/scan.h |  22 +++++
 2 files changed, 154 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..fb47c7cddf2f
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/scan.c
@@ -0,0 +1,132 @@
+// 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..c7496a766478
--- /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 /* WFX_SCAN_H */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 20/23] wfx: add debug.c/debug.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (18 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 19/23] wfx: add scan.c/scan.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 21/23] wfx: add traces.h Jerome Pouiller
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/net/wireless/silabs/wfx/debug.c | 359 ++++++++++++++++++++++++
 drivers/net/wireless/silabs/wfx/debug.h |  19 ++
 2 files changed, 378 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..eedada78c25f
--- /dev/null
+++ b/drivers/net/wireless/silabs/wfx/debug.c
@@ -0,0 +1,359 @@
+// 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..6f2f84d64c9e
--- /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 /* WFX_DEBUG_H */
-- 
2.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 21/23] wfx: add traces.h
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (19 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 20/23] wfx: add debug.c/debug.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 22/23] wfx: remove from the staging area Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 23/23] wfx: get out " Jerome Pouiller
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 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..e34c7a538c65
--- /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.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 22/23] wfx: remove from the staging area
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (20 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 21/23] wfx: add traces.h Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  2020-10-12 10:46 ` [PATCH 23/23] wfx: get out " Jerome Pouiller
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 .../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 43b5630c0407..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 <jerome.pouiller@silabs.com>
-
-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.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.
-
-  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 2ffa587aefaa..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 41f6a604a697..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;
-	}
-	if (rate->idx >= band->n_bitrates) {
-		WARN(1, "wrong rate->idx value: %d", rate->idx);
-		return -1;
-	}
-	// WFx only support 2GHz, else band information should be retrieved
-	// from ieee80211_tx_info
-	band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ];
-	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 <johannes@sipsolutions.net>
- * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, 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 <jerome.pouiller@silabs.com>");
-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 <flamingice@sourmilk.net>
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, 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 2320a81eae0b..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)
-{
-	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 <flamingice@sourmilk.net>
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, 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.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 23/23] wfx: get out from the staging area
  2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
                   ` (21 preceding siblings ...)
  2020-10-12 10:46 ` [PATCH 22/23] wfx: remove from the staging area Jerome Pouiller
@ 2020-10-12 10:46 ` Jerome Pouiller
  22 siblings, 0 replies; 35+ messages in thread
From: Jerome Pouiller @ 2020-10-12 10:46 UTC (permalink / raw)
  To: linux-wireless, netdev
  Cc: devel, devicetree, Greg Kroah-Hartman, linux-kernel, Rob Herring,
	David S . Miller, Kalle Valo

From: Jérôme Pouiller <jerome.pouiller@silabs.com>

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

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 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 5e10735be654..d1671c54b967 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15799,7 +15799,8 @@ F:	drivers/platform/x86/touchscreen_dmi.c
 SILICON LABS WIRELESS DRIVERS (for WFxxx series)
 M:	Jérôme Pouiller <jerome.pouiller@silabs.com>
 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 <sudipm.mukherjee@gmail.com>
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 170a64e67709..69ea83279907 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -44,6 +44,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 2d0310448eba..2d326b16272e 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -114,8 +114,6 @@ source "drivers/staging/kpc2000/Kconfig"
 
 source "drivers/staging/qlge/Kconfig"
 
-source "drivers/staging/wfx/Kconfig"
-
 source "drivers/staging/hikey9xx/Kconfig"
 
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 757a892ab5b9..9de260802db5 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -47,5 +47,4 @@ obj-$(CONFIG_XIL_AXIS_FIFO)	+= axis-fifo/
 obj-$(CONFIG_FIELDBUS_DEV)     += fieldbus/
 obj-$(CONFIG_KPC2000)		+= kpc2000/
 obj-$(CONFIG_QLGE)		+= qlge/
-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.28.0

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml
  2020-10-12 10:46 ` [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml Jerome Pouiller
@ 2020-10-13 16:49   ` Rob Herring
  2020-10-14 13:49     ` Jérôme Pouiller
  0 siblings, 1 reply; 35+ messages in thread
From: Rob Herring @ 2020-10-13 16:49 UTC (permalink / raw)
  To: Jerome Pouiller
  Cc: devel, devicetree, netdev, linux-wireless, linux-kernel,
	Greg Kroah-Hartman, David S . Miller, Kalle Valo

On Mon, Oct 12, 2020 at 12:46:26PM +0200, Jerome Pouiller wrote:
> From: Jérôme Pouiller <jerome.pouiller@silabs.com>
> 
> Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
> ---
>  .../bindings/net/wireless/silabs,wfx.yaml     | 125 ++++++++++++++++++
>  1 file changed, 125 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..43b5630c0407
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml
> @@ -0,0 +1,125 @@
> +# 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 <jerome.pouiller@silabs.com>
> +
> +description:
> +  The WFxxx chip series can be connected via SPI or via SDIO.

What does this chip do? WiFi or some other wireless?

> +
> +  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.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.
> +
> +  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

Note what ethernet.txt contains... This should have a $ref to 
ethernet-controller.yaml to express the above.

You can add 'mac-address: true' if you want to be explicit about what 
properties are used.

> +
> +properties:
> +  compatible:
> +    const: silabs,wf200

blank line between each DT property.

> +  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.

No need to redefine a common property.

> +    maxItems: 1

Not an array. Just need:

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
> +  config-file:
> +    description: Use an alternative file as PDS. Default is `wf200.pds`. Only
> +      necessary for development/debug purpose.

'firmware-name' is typically what we'd use here. Though if just for 
debug/dev, perhaps do a debugfs interface for this instead. As DT should 
come from the firmware/bootloader, requiring changing the DT for 
dev/debug is not the easiest workflow compared to doing something from 
userspace.

> +    maxItems: 1

Looks like a string, not an array.

> +
> +required:
> +  - compatible
> +  - reg

Will need additionalProperties or unevaluatedProperties depending on 
whether you list out properties from ethernet-controller.yaml or not.

Rob
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 07/23] wfx: add bus_sdio.c
  2020-10-12 10:46 ` [PATCH 07/23] wfx: add bus_sdio.c Jerome Pouiller
@ 2020-10-13 20:11   ` Pali Rohár
  2020-10-14 11:52     ` Jérôme Pouiller
  2020-10-16 11:30   ` Ulf Hansson
  1 sibling, 1 reply; 35+ messages in thread
From: Pali Rohár @ 2020-10-13 20:11 UTC (permalink / raw)
  To: Jerome Pouiller
  Cc: devel, devicetree, netdev, linux-wireless, linux-kernel,
	Rob Herring, Greg Kroah-Hartman, David S . Miller, Kalle Valo

Hello!

On Monday 12 October 2020 12:46:32 Jerome Pouiller wrote:
> +#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) },

Please move ids into common include file include/linux/mmc/sdio_ids.h
where are all SDIO ids. Now all drivers have ids defined in that file.

> +	// FIXME: ignore VID/PID and only rely on device tree
> +	// { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) },

What is the reason for ignoring vendor and device ids?

> +	{ },
> +};
> +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.28.0
> 
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 07/23] wfx: add bus_sdio.c
  2020-10-13 20:11   ` Pali Rohár
@ 2020-10-14 11:52     ` Jérôme Pouiller
  2020-10-14 12:43       ` Pali Rohár
  0 siblings, 1 reply; 35+ messages in thread
From: Jérôme Pouiller @ 2020-10-14 11:52 UTC (permalink / raw)
  To: Pali Rohár
  Cc: devel, devicetree, netdev, linux-wireless, linux-kernel,
	Rob Herring, Greg Kroah-Hartman, David S . Miller, Kalle Valo

Hello Pali,

On Tuesday 13 October 2020 22:11:56 CEST Pali Rohár wrote:
> Hello!
> 
> On Monday 12 October 2020 12:46:32 Jerome Pouiller wrote:
> > +#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) },
> 
> Please move ids into common include file include/linux/mmc/sdio_ids.h
> where are all SDIO ids. Now all drivers have ids defined in that file.
> 
> > +     // FIXME: ignore VID/PID and only rely on device tree
> > +     // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) },
> 
> What is the reason for ignoring vendor and device ids?

The device has a particularity, its VID/PID is 0000:1000 (as you can see
above). This value is weird. The risk of collision with another device is
high.

So, maybe the device should be probed only if it appears in the DT. Since
WF200 targets embedded platforms, I don't think it is a problem to rely on
DT. You will find another FIXME further in the code about that:

+               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;

However, it wouldn't be usual way to manage SDIO devices (and it is the
reason why the code is commented out).

Anyway, if we choose to rely on the DT, should we also check the VID/PID?

Personally, I am in favor to probe the device only if VID/PID match and if
a DT node is found, even if it is not the usual way.

-- 
Jérôme Pouiller


_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 07/23] wfx: add bus_sdio.c
  2020-10-14 11:52     ` Jérôme Pouiller
@ 2020-10-14 12:43       ` Pali Rohár
  2020-10-15 14:03         ` Jérôme Pouiller
  0 siblings, 1 reply; 35+ messages in thread
From: Pali Rohár @ 2020-10-14 12:43 UTC (permalink / raw)
  To: Jérôme Pouiller, Ulf Hansson
  Cc: devel, devicetree, netdev, linux-wireless, linux-kernel,
	Rob Herring, Greg Kroah-Hartman, linux-mmc, David S . Miller,
	Kalle Valo

On Wednesday 14 October 2020 13:52:15 Jérôme Pouiller wrote:
> Hello Pali,
> 
> On Tuesday 13 October 2020 22:11:56 CEST Pali Rohár wrote:
> > Hello!
> > 
> > On Monday 12 October 2020 12:46:32 Jerome Pouiller wrote:
> > > +#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) },
> > 
> > Please move ids into common include file include/linux/mmc/sdio_ids.h
> > where are all SDIO ids. Now all drivers have ids defined in that file.
> > 
> > > +     // FIXME: ignore VID/PID and only rely on device tree
> > > +     // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) },
> > 
> > What is the reason for ignoring vendor and device ids?
> 
> The device has a particularity, its VID/PID is 0000:1000 (as you can see
> above). This value is weird. The risk of collision with another device is
> high.

Those ids looks strange. You are from Silabs, can you check internally
in Silabs if ids are really correct? And which sdio vendor id you in
Silabs got assigned for your products?

I know that sdio devices with multiple functions may have different sdio
vendor/device id particular function and in common CIS (function 0).

Could not be a problem that on one place is vendor/device id correct and
on other place is that strange value?

I have sent following patch (now part of upstream kernel) which exports
these ids to userspace:
https://lore.kernel.org/linux-mmc/20200527110858.17504-2-pali@kernel.org/T/#u

Also for debugging ids and information about sdio cards, I sent another
patch which export additional data:
https://lore.kernel.org/linux-mmc/20200727133837.19086-1-pali@kernel.org/T/#u

Could you try them and look at /sys/class/mmc_host/ attribute outputs?

> So, maybe the device should be probed only if it appears in the DT. Since
> WF200 targets embedded platforms, I don't think it is a problem to rely on
> DT. You will find another FIXME further in the code about that:
> 
> +               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;
> 
> However, it wouldn't be usual way to manage SDIO devices (and it is the
> reason why the code is commented out).
> 
> Anyway, if we choose to rely on the DT, should we also check the VID/PID?
> 
> Personally, I am in favor to probe the device only if VID/PID match and if
> a DT node is found, even if it is not the usual way.

Normally all sdio devices are hotplugged in linux kernel based on sdio
device and vendor ids. And these ids are unique identifiers of sdio
devices. So should be enough for detection.

Months ago I have checked it and moved all SDIO device and vendor ids
into common include/linux/mmc/sdio_ids.h file. I would like to not have
this "mess" again, which was basically fully cleaned.

I'm adding linux-mmc mailing list and Ulf Hansson to loop.

Ulf, can you look at this "problem"? What do you think about those
"strange" sdio ids?
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml
  2020-10-13 16:49   ` Rob Herring
@ 2020-10-14 13:49     ` Jérôme Pouiller
  2020-11-02 15:58       ` Kalle Valo
  0 siblings, 1 reply; 35+ messages in thread
From: Jérôme Pouiller @ 2020-10-14 13:49 UTC (permalink / raw)
  To: Rob Herring
  Cc: devel, devicetree, netdev, linux-wireless, linux-kernel,
	Greg Kroah-Hartman, David S . Miller, Kalle Valo

On Tuesday 13 October 2020 18:49:35 CEST Rob Herring wrote:
> On Mon, Oct 12, 2020 at 12:46:26PM +0200, Jerome Pouiller wrote:
> > From: Jérôme Pouiller <jerome.pouiller@silabs.com>
[...]
> > +  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
> 
> Note what ethernet.txt contains... This should have a $ref to
> ethernet-controller.yaml to express the above.
> 
> You can add 'mac-address: true' if you want to be explicit about what
> properties are used.

Here, only mac-address and local-mac-address are supported. So, would the
code below do the job?

  local-mac-address:
    $ref: ethernet-controller.yaml#/properties/local-mac-address

  mac-address:
    $ref: ethernet-controller.yaml#/properties/mac-address


[...]
> > +  spi-max-frequency:
> > +    description: (SPI only) Maximum SPI clocking speed of device in Hz.
> 
> No need to redefine a common property.

When a property is specific to a bus, I would have like to explicitly
say it. That's why I redefined the description.


[...]
> > +  config-file:
> > +    description: Use an alternative file as PDS. Default is `wf200.pds`. Only
> > +      necessary for development/debug purpose.
> 
> 'firmware-name' is typically what we'd use here. Though if just for
> debug/dev, perhaps do a debugfs interface for this instead. As DT should
> come from the firmware/bootloader, requiring changing the DT for
> dev/debug is not the easiest workflow compared to doing something from
> userspace.

This file is not a firmware. It mainly contains data related to the
antenna. At the beginning, this property has been added for
development. With the time, I think it can be used to  have one disk
image for several devices that differ only in antenna.

I am going to remove the part about development/debug purpose.


[...]
> Will need additionalProperties or unevaluatedProperties depending on
> whether you list out properties from ethernet-controller.yaml or not.

I think I need to specify "additionalProperties: true" since the user can
also use properties defined for the SPI devices.

In fact, I would like to write something like:

    allOf:
        $ref: spi-controller.yaml#/patternProperties/^.*@[0-9a-f]+$/properties



-- 
Jérôme Pouiller


_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 07/23] wfx: add bus_sdio.c
  2020-10-14 12:43       ` Pali Rohár
@ 2020-10-15 14:03         ` Jérôme Pouiller
  2020-10-16 11:54           ` Ulf Hansson
  0 siblings, 1 reply; 35+ messages in thread
From: Jérôme Pouiller @ 2020-10-15 14:03 UTC (permalink / raw)
  To: Ulf Hansson, Pali Rohár
  Cc: devel, devicetree, netdev, linux-wireless, linux-kernel,
	Rob Herring, Greg Kroah-Hartman, linux-mmc, David S . Miller,
	Kalle Valo

On Wednesday 14 October 2020 14:43:34 CEST Pali Rohár wrote:
> On Wednesday 14 October 2020 13:52:15 Jérôme Pouiller wrote:
> > On Tuesday 13 October 2020 22:11:56 CEST Pali Rohár wrote:
> > > On Monday 12 October 2020 12:46:32 Jerome Pouiller wrote:
> > > > +#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) },
> > >
> > > Please move ids into common include file include/linux/mmc/sdio_ids.h
> > > where are all SDIO ids. Now all drivers have ids defined in that file.
> > >
> > > > +     // FIXME: ignore VID/PID and only rely on device tree
> > > > +     // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) },
> > >
> > > What is the reason for ignoring vendor and device ids?
> >
> > The device has a particularity, its VID/PID is 0000:1000 (as you can see
> > above). This value is weird. The risk of collision with another device is
> > high.
> 
> Those ids looks strange. You are from Silabs, can you check internally
> in Silabs if ids are really correct? And which sdio vendor id you in
> Silabs got assigned for your products?

I confirm these ids are the ones burned in the WF200. We have to deal with
that :( .


> I know that sdio devices with multiple functions may have different sdio
> vendor/device id particular function and in common CIS (function 0).
> 
> Could not be a problem that on one place is vendor/device id correct and
> on other place is that strange value?
> 
> I have sent following patch (now part of upstream kernel) which exports
> these ids to userspace:
> https://lore.kernel.org/linux-mmc/20200527110858.17504-2-pali@kernel.org/T/#u
> 
> Also for debugging ids and information about sdio cards, I sent another
> patch which export additional data:
> https://lore.kernel.org/linux-mmc/20200727133837.19086-1-pali@kernel.org/T/#u
> 
> Could you try them and look at /sys/class/mmc_host/ attribute outputs?

Here is:

    # cd /sys/class/mmc_host/ && grep -r . mmc1/
    mmc1/power/runtime_suspended_time:0
    grep: mmc1/power/autosuspend_delay_ms: Input/output error
    mmc1/power/runtime_active_time:0
    mmc1/power/control:auto
    mmc1/power/runtime_status:unsupported
    mmc1/mmc1:0001/vendor:0x0000
    mmc1/mmc1:0001/rca:0x0001
    mmc1/mmc1:0001/device:0x1000
    mmc1/mmc1:0001/mmc1:0001:1/vendor:0x0000
    mmc1/mmc1:0001/mmc1:0001:1/device:0x1000
    grep: mmc1/mmc1:0001/mmc1:0001:1/info4: No data available
    mmc1/mmc1:0001/mmc1:0001:1/power/runtime_suspended_time:0
    grep: mmc1/mmc1:0001/mmc1:0001:1/power/autosuspend_delay_ms: Input/output error
    mmc1/mmc1:0001/mmc1:0001:1/power/runtime_active_time:0
    mmc1/mmc1:0001/mmc1:0001:1/power/control:auto
    mmc1/mmc1:0001/mmc1:0001:1/power/runtime_status:unsupported
    mmc1/mmc1:0001/mmc1:0001:1/class:0x00
    grep: mmc1/mmc1:0001/mmc1:0001:1/info2: No data available
    mmc1/mmc1:0001/mmc1:0001:1/modalias:sdio:c00v0000d1000
    mmc1/mmc1:0001/mmc1:0001:1/revision:0.0
    mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_NAME=mmc
    mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_FULLNAME=/soc/sdhci@7e300000/mmc@1
    mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_COMPATIBLE_0=silabs,wfx-sdio
    mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_COMPATIBLE_N=1
    mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_CLASS=00
    mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_ID=0000:1000
    mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_REVISION=0.0
    mmc1/mmc1:0001/mmc1:0001:1/uevent:MODALIAS=sdio:c00v0000d1000
    grep: mmc1/mmc1:0001/mmc1:0001:1/info3: No data available
    grep: mmc1/mmc1:0001/mmc1:0001:1/info1: No data available
    mmc1/mmc1:0001/ocr:0x00200000
    grep: mmc1/mmc1:0001/info4: No data available
    mmc1/mmc1:0001/power/runtime_suspended_time:0
    grep: mmc1/mmc1:0001/power/autosuspend_delay_ms: Input/output error
    mmc1/mmc1:0001/power/runtime_active_time:0
    mmc1/mmc1:0001/power/control:auto
    mmc1/mmc1:0001/power/runtime_status:unsupported
    grep: mmc1/mmc1:0001/info2: No data available
    mmc1/mmc1:0001/type:SDIO
    mmc1/mmc1:0001/revision:0.0
    mmc1/mmc1:0001/uevent:MMC_TYPE=SDIO
    mmc1/mmc1:0001/uevent:SDIO_ID=0000:1000
    mmc1/mmc1:0001/uevent:SDIO_REVISION=0.0
    grep: mmc1/mmc1:0001/info3: No data available
    grep: mmc1/mmc1:0001/info1: No data available



-- 
Jérôme Pouiller


_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 07/23] wfx: add bus_sdio.c
  2020-10-12 10:46 ` [PATCH 07/23] wfx: add bus_sdio.c Jerome Pouiller
  2020-10-13 20:11   ` Pali Rohár
@ 2020-10-16 11:30   ` Ulf Hansson
  2020-10-16 12:16     ` Jérôme Pouiller
  1 sibling, 1 reply; 35+ messages in thread
From: Ulf Hansson @ 2020-10-16 11:30 UTC (permalink / raw)
  To: Jerome Pouiller
  Cc: driverdevel, DTML, netdev, linux-wireless,
	Linux Kernel Mailing List, Rob Herring, Greg Kroah-Hartman,
	David S . Miller, Kalle Valo

On Mon, 12 Oct 2020 at 12:47, Jerome Pouiller
<Jerome.Pouiller@silabs.com> wrote:
>
> From: Jérôme Pouiller <jerome.pouiller@silabs.com>

Please fill out this commit message to explain a bit more about the
patch and the HW it enables support for.

>
> Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
> ---
>  drivers/net/wireless/silabs/wfx/bus_sdio.c | 269 +++++++++++++++++++++
>  1 file changed, 269 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..e06d7e1ebe9c

[...]

> +
> +static int wfx_sdio_irq_subscribe(void *priv)
> +{
> +       struct wfx_sdio_priv *bus = priv;
> +       u32 flags;
> +       int ret;
> +       u8 cccr;
> +

I would appreciate a comment about an out-of-band IRQ line. If it's
supported, that is the preferred option to use, else the SDIO IRQs.

> +       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);
> +}
> +

[...]

> +
> +#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);

I will comment about the sdio IDs separately, replying to the other
thread between you and Pali.

> +
> +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,
> +       }
> +};

I couldn't find where you call sdio_register|unregister_driver(), but
maybe that's done from another patch in series?

Kind regards
Uffe
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 07/23] wfx: add bus_sdio.c
  2020-10-15 14:03         ` Jérôme Pouiller
@ 2020-10-16 11:54           ` Ulf Hansson
  2020-11-02 16:02             ` Kalle Valo
  0 siblings, 1 reply; 35+ messages in thread
From: Ulf Hansson @ 2020-10-16 11:54 UTC (permalink / raw)
  To: Jérôme Pouiller
  Cc: driverdevel, DTML, Greg Kroah-Hartman, linux-wireless,
	Linux Kernel Mailing List, Rob Herring, netdev, linux-mmc,
	Pali Rohár, David S . Miller, Kalle Valo

On Thu, 15 Oct 2020 at 16:03, Jérôme Pouiller
<jerome.pouiller@silabs.com> wrote:
>
> On Wednesday 14 October 2020 14:43:34 CEST Pali Rohár wrote:
> > On Wednesday 14 October 2020 13:52:15 Jérôme Pouiller wrote:
> > > On Tuesday 13 October 2020 22:11:56 CEST Pali Rohár wrote:
> > > > On Monday 12 October 2020 12:46:32 Jerome Pouiller wrote:
> > > > > +#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) },
> > > >
> > > > Please move ids into common include file include/linux/mmc/sdio_ids.h
> > > > where are all SDIO ids. Now all drivers have ids defined in that file.
> > > >
> > > > > +     // FIXME: ignore VID/PID and only rely on device tree
> > > > > +     // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) },
> > > >
> > > > What is the reason for ignoring vendor and device ids?
> > >
> > > The device has a particularity, its VID/PID is 0000:1000 (as you can see
> > > above). This value is weird. The risk of collision with another device is
> > > high.
> >
> > Those ids looks strange. You are from Silabs, can you check internally
> > in Silabs if ids are really correct? And which sdio vendor id you in
> > Silabs got assigned for your products?
>
> I confirm these ids are the ones burned in the WF200. We have to deal with
> that :( .

Yep. Unfortunately this isn't so uncommon when targeting the embedded
types of devices.

The good thing is, that we already have bindings allowing us to specify this.

>
>
> > I know that sdio devices with multiple functions may have different sdio
> > vendor/device id particular function and in common CIS (function 0).
> >
> > Could not be a problem that on one place is vendor/device id correct and
> > on other place is that strange value?
> >
> > I have sent following patch (now part of upstream kernel) which exports
> > these ids to userspace:
> > https://lore.kernel.org/linux-mmc/20200527110858.17504-2-pali@kernel.org/T/#u
> >
> > Also for debugging ids and information about sdio cards, I sent another
> > patch which export additional data:
> > https://lore.kernel.org/linux-mmc/20200727133837.19086-1-pali@kernel.org/T/#u
> >
> > Could you try them and look at /sys/class/mmc_host/ attribute outputs?
>
> Here is:
>
>     # cd /sys/class/mmc_host/ && grep -r . mmc1/
>     mmc1/power/runtime_suspended_time:0
>     grep: mmc1/power/autosuspend_delay_ms: Input/output error
>     mmc1/power/runtime_active_time:0
>     mmc1/power/control:auto
>     mmc1/power/runtime_status:unsupported
>     mmc1/mmc1:0001/vendor:0x0000
>     mmc1/mmc1:0001/rca:0x0001
>     mmc1/mmc1:0001/device:0x1000
>     mmc1/mmc1:0001/mmc1:0001:1/vendor:0x0000
>     mmc1/mmc1:0001/mmc1:0001:1/device:0x1000
>     grep: mmc1/mmc1:0001/mmc1:0001:1/info4: No data available
>     mmc1/mmc1:0001/mmc1:0001:1/power/runtime_suspended_time:0
>     grep: mmc1/mmc1:0001/mmc1:0001:1/power/autosuspend_delay_ms: Input/output error
>     mmc1/mmc1:0001/mmc1:0001:1/power/runtime_active_time:0
>     mmc1/mmc1:0001/mmc1:0001:1/power/control:auto
>     mmc1/mmc1:0001/mmc1:0001:1/power/runtime_status:unsupported
>     mmc1/mmc1:0001/mmc1:0001:1/class:0x00
>     grep: mmc1/mmc1:0001/mmc1:0001:1/info2: No data available
>     mmc1/mmc1:0001/mmc1:0001:1/modalias:sdio:c00v0000d1000
>     mmc1/mmc1:0001/mmc1:0001:1/revision:0.0
>     mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_NAME=mmc
>     mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_FULLNAME=/soc/sdhci@7e300000/mmc@1
>     mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_COMPATIBLE_0=silabs,wfx-sdio
>     mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_COMPATIBLE_N=1
>     mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_CLASS=00
>     mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_ID=0000:1000
>     mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_REVISION=0.0
>     mmc1/mmc1:0001/mmc1:0001:1/uevent:MODALIAS=sdio:c00v0000d1000
>     grep: mmc1/mmc1:0001/mmc1:0001:1/info3: No data available
>     grep: mmc1/mmc1:0001/mmc1:0001:1/info1: No data available
>     mmc1/mmc1:0001/ocr:0x00200000
>     grep: mmc1/mmc1:0001/info4: No data available
>     mmc1/mmc1:0001/power/runtime_suspended_time:0
>     grep: mmc1/mmc1:0001/power/autosuspend_delay_ms: Input/output error
>     mmc1/mmc1:0001/power/runtime_active_time:0
>     mmc1/mmc1:0001/power/control:auto
>     mmc1/mmc1:0001/power/runtime_status:unsupported
>     grep: mmc1/mmc1:0001/info2: No data available
>     mmc1/mmc1:0001/type:SDIO
>     mmc1/mmc1:0001/revision:0.0
>     mmc1/mmc1:0001/uevent:MMC_TYPE=SDIO
>     mmc1/mmc1:0001/uevent:SDIO_ID=0000:1000
>     mmc1/mmc1:0001/uevent:SDIO_REVISION=0.0
>     grep: mmc1/mmc1:0001/info3: No data available
>     grep: mmc1/mmc1:0001/info1: No data available
>
>

Please have a look at the
Documentation/devicetree/bindings/mmc/mmc-controller.yaml, there you
find that from a child node of the mmc host's node, we can specify an
embedded SDIO functional device.

In sdio_add_func(), which calls sdio_set_of_node() - we assign the
func->dev.of_node its corresponding child node for the SDIO func.
Allowing the sdio functional driver to be matched with the SDIO func
device.

Perhaps what is missing, is that we may want to avoid probing an
in-correct sdio driver, based upon buggy SDIO ids. I don't think we
take some actions in the mmc core to prevent this, but maybe it's not
a big problem anyway.

When it comes to documenting the buggy SDIO ids, please add some
information about this in the common SDIO headers. It's nice to have a
that information, if any issue comes up later on.

Kind regards
Uffe
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 07/23] wfx: add bus_sdio.c
  2020-10-16 11:30   ` Ulf Hansson
@ 2020-10-16 12:16     ` Jérôme Pouiller
  0 siblings, 0 replies; 35+ messages in thread
From: Jérôme Pouiller @ 2020-10-16 12:16 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: driverdevel, DTML, netdev, linux-wireless,
	Linux Kernel Mailing List, Rob Herring, Greg Kroah-Hartman,
	David S . Miller, Kalle Valo

Hello Ulf,

On Friday 16 October 2020 13:30:30 CEST Ulf Hansson wrote:
> On Mon, 12 Oct 2020 at 12:47, Jerome Pouiller
> <Jerome.Pouiller@silabs.com> wrote:
> >
> > From: Jérôme Pouiller <jerome.pouiller@silabs.com>
> 
> Please fill out this commit message to explain a bit more about the
> patch and the HW it enables support for.

This patch belongs to a series[1] that will squashed before to be
committed (Kalle Valo prefer to process like that for this review). So,
I didn't bother to write real commit messages. For the v2, I will take
care to add linux-mmc in copy of the whole series.

[1] https://lore.kernel.org/lkml/20201012104648.985256-1-Jerome.Pouiller@silabs.com/


> > Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
> > ---
> >  drivers/net/wireless/silabs/wfx/bus_sdio.c | 269 +++++++++++++++++++++
> >  1 file changed, 269 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..e06d7e1ebe9c
[...]
> > +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,
> > +       }
> > +};
> 
> I couldn't find where you call sdio_register|unregister_driver(), but
> maybe that's done from another patch in series?

Indeed, it is here[2].

[2] https://lore.kernel.org/lkml/20201012104648.985256-5-Jerome.Pouiller@silabs.com/


-- 
Jérôme Pouiller


_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml
  2020-10-14 13:49     ` Jérôme Pouiller
@ 2020-11-02 15:58       ` Kalle Valo
  0 siblings, 0 replies; 35+ messages in thread
From: Kalle Valo @ 2020-11-02 15:58 UTC (permalink / raw)
  To: Jérôme Pouiller
  Cc: devel, Rob Herring, devicetree, Greg Kroah-Hartman,
	linux-wireless, linux-kernel, netdev, David S . Miller

Jérôme Pouiller <jerome.pouiller@silabs.com> writes:

> On Tuesday 13 October 2020 18:49:35 CEST Rob Herring wrote:
>> On Mon, Oct 12, 2020 at 12:46:26PM +0200, Jerome Pouiller wrote:
>> > From: Jérôme Pouiller <jerome.pouiller@silabs.com>
> [...]
>> > +  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
>> 
>> Note what ethernet.txt contains... This should have a $ref to
>> ethernet-controller.yaml to express the above.
>> 
>> You can add 'mac-address: true' if you want to be explicit about what
>> properties are used.
>
> Here, only mac-address and local-mac-address are supported. So, would the
> code below do the job?
>
>   local-mac-address:
>     $ref: ethernet-controller.yaml#/properties/local-mac-address
>
>   mac-address:
>     $ref: ethernet-controller.yaml#/properties/mac-address
>
>
> [...]
>> > +  spi-max-frequency:
>> > +    description: (SPI only) Maximum SPI clocking speed of device in Hz.
>> 
>> No need to redefine a common property.
>
> When a property is specific to a bus, I would have like to explicitly
> say it. That's why I redefined the description.
>
>
> [...]
>> > +  config-file:
>> > +    description: Use an alternative file as PDS. Default is `wf200.pds`. Only
>> > +      necessary for development/debug purpose.
>> 
>> 'firmware-name' is typically what we'd use here. Though if just for
>> debug/dev, perhaps do a debugfs interface for this instead. As DT should
>> come from the firmware/bootloader, requiring changing the DT for
>> dev/debug is not the easiest workflow compared to doing something from
>> userspace.
>
> This file is not a firmware. It mainly contains data related to the
> antenna. At the beginning, this property has been added for
> development. With the time, I think it can be used to  have one disk
> image for several devices that differ only in antenna.
>
> I am going to remove the part about development/debug purpose.

config-file doesn't sound right either. So what kind of data is this,
calibration data or what?

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 07/23] wfx: add bus_sdio.c
  2020-10-16 11:54           ` Ulf Hansson
@ 2020-11-02 16:02             ` Kalle Valo
  0 siblings, 0 replies; 35+ messages in thread
From: Kalle Valo @ 2020-11-02 16:02 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: driverdevel, DTML, netdev, linux-wireless,
	Linux Kernel Mailing List, Rob Herring, Greg Kroah-Hartman,
	linux-mmc, Pali Rohár, David S . Miller

Ulf Hansson <ulf.hansson@linaro.org> writes:

> On Thu, 15 Oct 2020 at 16:03, Jérôme Pouiller
> <jerome.pouiller@silabs.com> wrote:
>>
>> On Wednesday 14 October 2020 14:43:34 CEST Pali Rohár wrote:
>> > On Wednesday 14 October 2020 13:52:15 Jérôme Pouiller wrote:
>> > > On Tuesday 13 October 2020 22:11:56 CEST Pali Rohár wrote:
>> > > > On Monday 12 October 2020 12:46:32 Jerome Pouiller wrote:
>> > > > > +#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) },
>> > > >
>> > > > Please move ids into common include file include/linux/mmc/sdio_ids.h
>> > > > where are all SDIO ids. Now all drivers have ids defined in that file.
>> > > >
>> > > > > +     // FIXME: ignore VID/PID and only rely on device tree
>> > > > > +     // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) },
>> > > >
>> > > > What is the reason for ignoring vendor and device ids?
>> > >
>> > > The device has a particularity, its VID/PID is 0000:1000 (as you can see
>> > > above). This value is weird. The risk of collision with another device is
>> > > high.
>> >
>> > Those ids looks strange. You are from Silabs, can you check internally
>> > in Silabs if ids are really correct? And which sdio vendor id you in
>> > Silabs got assigned for your products?
>>
>> I confirm these ids are the ones burned in the WF200. We have to deal with
>> that :( .
>
> Yep. Unfortunately this isn't so uncommon when targeting the embedded
> types of devices.
>
> The good thing is, that we already have bindings allowing us to specify this.
>
>>
>>
>> > I know that sdio devices with multiple functions may have different sdio
>> > vendor/device id particular function and in common CIS (function 0).
>> >
>> > Could not be a problem that on one place is vendor/device id correct and
>> > on other place is that strange value?
>> >
>> > I have sent following patch (now part of upstream kernel) which exports
>> > these ids to userspace:
>> > https://lore.kernel.org/linux-mmc/20200527110858.17504-2-pali@kernel.org/T/#u
>> >
>> > Also for debugging ids and information about sdio cards, I sent another
>> > patch which export additional data:
>> > https://lore.kernel.org/linux-mmc/20200727133837.19086-1-pali@kernel.org/T/#u
>> >
>> > Could you try them and look at /sys/class/mmc_host/ attribute outputs?
>>
>> Here is:
>>
>>     # cd /sys/class/mmc_host/ && grep -r . mmc1/
>>     mmc1/power/runtime_suspended_time:0
>>     grep: mmc1/power/autosuspend_delay_ms: Input/output error
>>     mmc1/power/runtime_active_time:0
>>     mmc1/power/control:auto
>>     mmc1/power/runtime_status:unsupported
>>     mmc1/mmc1:0001/vendor:0x0000
>>     mmc1/mmc1:0001/rca:0x0001
>>     mmc1/mmc1:0001/device:0x1000
>>     mmc1/mmc1:0001/mmc1:0001:1/vendor:0x0000
>>     mmc1/mmc1:0001/mmc1:0001:1/device:0x1000
>>     grep: mmc1/mmc1:0001/mmc1:0001:1/info4: No data available
>>     mmc1/mmc1:0001/mmc1:0001:1/power/runtime_suspended_time:0
>>     grep: mmc1/mmc1:0001/mmc1:0001:1/power/autosuspend_delay_ms: Input/output error
>>     mmc1/mmc1:0001/mmc1:0001:1/power/runtime_active_time:0
>>     mmc1/mmc1:0001/mmc1:0001:1/power/control:auto
>>     mmc1/mmc1:0001/mmc1:0001:1/power/runtime_status:unsupported
>>     mmc1/mmc1:0001/mmc1:0001:1/class:0x00
>>     grep: mmc1/mmc1:0001/mmc1:0001:1/info2: No data available
>>     mmc1/mmc1:0001/mmc1:0001:1/modalias:sdio:c00v0000d1000
>>     mmc1/mmc1:0001/mmc1:0001:1/revision:0.0
>>     mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_NAME=mmc
>>     mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_FULLNAME=/soc/sdhci@7e300000/mmc@1
>>     mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_COMPATIBLE_0=silabs,wfx-sdio
>>     mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_COMPATIBLE_N=1
>>     mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_CLASS=00
>>     mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_ID=0000:1000
>>     mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_REVISION=0.0
>>     mmc1/mmc1:0001/mmc1:0001:1/uevent:MODALIAS=sdio:c00v0000d1000
>>     grep: mmc1/mmc1:0001/mmc1:0001:1/info3: No data available
>>     grep: mmc1/mmc1:0001/mmc1:0001:1/info1: No data available
>>     mmc1/mmc1:0001/ocr:0x00200000
>>     grep: mmc1/mmc1:0001/info4: No data available
>>     mmc1/mmc1:0001/power/runtime_suspended_time:0
>>     grep: mmc1/mmc1:0001/power/autosuspend_delay_ms: Input/output error
>>     mmc1/mmc1:0001/power/runtime_active_time:0
>>     mmc1/mmc1:0001/power/control:auto
>>     mmc1/mmc1:0001/power/runtime_status:unsupported
>>     grep: mmc1/mmc1:0001/info2: No data available
>>     mmc1/mmc1:0001/type:SDIO
>>     mmc1/mmc1:0001/revision:0.0
>>     mmc1/mmc1:0001/uevent:MMC_TYPE=SDIO
>>     mmc1/mmc1:0001/uevent:SDIO_ID=0000:1000
>>     mmc1/mmc1:0001/uevent:SDIO_REVISION=0.0
>>     grep: mmc1/mmc1:0001/info3: No data available
>>     grep: mmc1/mmc1:0001/info1: No data available
>>
>>
>
> Please have a look at the
> Documentation/devicetree/bindings/mmc/mmc-controller.yaml, there you
> find that from a child node of the mmc host's node, we can specify an
> embedded SDIO functional device.
>
> In sdio_add_func(), which calls sdio_set_of_node() - we assign the
> func->dev.of_node its corresponding child node for the SDIO func.
> Allowing the sdio functional driver to be matched with the SDIO func
> device.
>
> Perhaps what is missing, is that we may want to avoid probing an
> in-correct sdio driver, based upon buggy SDIO ids. I don't think we
> take some actions in the mmc core to prevent this, but maybe it's not
> a big problem anyway.
>
> When it comes to documenting the buggy SDIO ids, please add some
> information about this in the common SDIO headers. It's nice to have a
> that information, if any issue comes up later on.

And if there's some special setup (DT etc) needed to get the wireless
driver working that should be documented in the driver side as well. The
expectation is that an upstream driver is just plug and play, and if
it's not there should be clear documentation how to enable the driver.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, back to index

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-12 10:46 [PATCH 00/23] wfx: get out from the staging area Jerome Pouiller
2020-10-12 10:46 ` [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml Jerome Pouiller
2020-10-13 16:49   ` Rob Herring
2020-10-14 13:49     ` Jérôme Pouiller
2020-11-02 15:58       ` Kalle Valo
2020-10-12 10:46 ` [PATCH 02/23] wfx: add Makefile/Kconfig Jerome Pouiller
2020-10-12 10:46 ` [PATCH 03/23] wfx: add wfx.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 04/23] wfx: add main.c/main.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 05/23] wfx: add bus.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 06/23] wfx: add bus_spi.c Jerome Pouiller
2020-10-12 10:46 ` [PATCH 07/23] wfx: add bus_sdio.c Jerome Pouiller
2020-10-13 20:11   ` Pali Rohár
2020-10-14 11:52     ` Jérôme Pouiller
2020-10-14 12:43       ` Pali Rohár
2020-10-15 14:03         ` Jérôme Pouiller
2020-10-16 11:54           ` Ulf Hansson
2020-11-02 16:02             ` Kalle Valo
2020-10-16 11:30   ` Ulf Hansson
2020-10-16 12:16     ` Jérôme Pouiller
2020-10-12 10:46 ` [PATCH 08/23] wfx: add hwio.c/hwio.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 09/23] wfx: add fwio.c/fwio.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 10/23] wfx: add bh.c/bh.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 11/23] wfx: add hif_api_*.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 12/23] wfx: add hif_tx*.c/hif_tx*.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 13/23] wfx: add key.c/key.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 14/23] wfx: add hif_rx.c/hif_rx.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 15/23] wfx: add data_rx.c/data_rx.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 16/23] wfx: add queue.c/queue.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 17/23] wfx: add data_tx.c/data_tx.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 18/23] wfx: add sta.c/sta.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 19/23] wfx: add scan.c/scan.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 20/23] wfx: add debug.c/debug.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 21/23] wfx: add traces.h Jerome Pouiller
2020-10-12 10:46 ` [PATCH 22/23] wfx: remove from the staging area Jerome Pouiller
2020-10-12 10:46 ` [PATCH 23/23] wfx: get out " Jerome Pouiller

DriverDev-Devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/driverdev-devel/0 driverdev-devel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 driverdev-devel driverdev-devel/ https://lore.kernel.org/driverdev-devel \
		driverdev-devel@linuxdriverproject.org devel@driverdev.osuosl.org
	public-inbox-index driverdev-devel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.linuxdriverproject.driverdev-devel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git