wfx: get out from the staging area
authorJérôme Pouiller <jerome.pouiller@silabs.com>
Sat, 26 Feb 2022 09:21:42 +0000 (10:21 +0100)
committerKalle Valo <kvalo@kernel.org>
Wed, 6 Apr 2022 06:52:14 +0000 (09:52 +0300)
The wfx driver is now mature enough to leave the staging area.

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
86 files changed:
Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/staging/net/wireless/silabs,wfx.yaml [deleted file]
MAINTAINERS
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/silabs/Kconfig [new file with mode: 0644]
drivers/net/wireless/silabs/Makefile [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/Kconfig [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/Makefile [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/bh.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/bh.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/bus.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/bus_sdio.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/bus_spi.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/data_rx.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/data_rx.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/data_tx.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/data_tx.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/debug.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/debug.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/fwio.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/fwio.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hif_api_cmd.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hif_api_general.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hif_api_mib.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hif_rx.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hif_rx.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hif_tx.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hif_tx.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hif_tx_mib.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hif_tx_mib.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hwio.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/hwio.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/key.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/key.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/main.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/main.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/queue.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/queue.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/scan.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/scan.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/sta.c [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/sta.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/traces.h [new file with mode: 0644]
drivers/net/wireless/silabs/wfx/wfx.h [new file with mode: 0644]
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/wfx/Kconfig [deleted file]
drivers/staging/wfx/Makefile [deleted file]
drivers/staging/wfx/TODO [deleted file]
drivers/staging/wfx/bh.c [deleted file]
drivers/staging/wfx/bh.h [deleted file]
drivers/staging/wfx/bus.h [deleted file]
drivers/staging/wfx/bus_sdio.c [deleted file]
drivers/staging/wfx/bus_spi.c [deleted file]
drivers/staging/wfx/data_rx.c [deleted file]
drivers/staging/wfx/data_rx.h [deleted file]
drivers/staging/wfx/data_tx.c [deleted file]
drivers/staging/wfx/data_tx.h [deleted file]
drivers/staging/wfx/debug.c [deleted file]
drivers/staging/wfx/debug.h [deleted file]
drivers/staging/wfx/fwio.c [deleted file]
drivers/staging/wfx/fwio.h [deleted file]
drivers/staging/wfx/hif_api_cmd.h [deleted file]
drivers/staging/wfx/hif_api_general.h [deleted file]
drivers/staging/wfx/hif_api_mib.h [deleted file]
drivers/staging/wfx/hif_rx.c [deleted file]
drivers/staging/wfx/hif_rx.h [deleted file]
drivers/staging/wfx/hif_tx.c [deleted file]
drivers/staging/wfx/hif_tx.h [deleted file]
drivers/staging/wfx/hif_tx_mib.c [deleted file]
drivers/staging/wfx/hif_tx_mib.h [deleted file]
drivers/staging/wfx/hwio.c [deleted file]
drivers/staging/wfx/hwio.h [deleted file]
drivers/staging/wfx/key.c [deleted file]
drivers/staging/wfx/key.h [deleted file]
drivers/staging/wfx/main.c [deleted file]
drivers/staging/wfx/main.h [deleted file]
drivers/staging/wfx/queue.c [deleted file]
drivers/staging/wfx/queue.h [deleted file]
drivers/staging/wfx/scan.c [deleted file]
drivers/staging/wfx/scan.h [deleted file]
drivers/staging/wfx/sta.c [deleted file]
drivers/staging/wfx/sta.h [deleted file]
drivers/staging/wfx/traces.h [deleted file]
drivers/staging/wfx/wfx.h [deleted file]

diff --git a/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml b/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml
new file mode 100644 (file)
index 0000000..f5a5317
--- /dev/null
@@ -0,0 +1,137 @@
+# 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: >
+  Support for the Wifi chip WFxxx from Silicon Labs. Currently, the only device
+  from the WFxxx series is the WF200 described here:
+     https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf
+
+  The WF200 can be connected via SPI or via SDIO.
+
+  For SDIO:
+
+    Declaring the WFxxx chip in device tree is mandatory (usually, the VID/PID is
+    sufficient for the SDIO devices).
+
+    It is recommended to declare a mmc-pwrseq on SDIO host above WFx. Without
+    it, you may encounter issues during reboot. The mmc-pwrseq should be
+    compatible with mmc-pwrseq-simple. Please consult
+    Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.yaml for more
+    information.
+
+  For SPI:
+
+    In add of the properties below, please consult
+    Documentation/devicetree/bindings/spi/spi-controller.yaml for optional SPI
+    related properties.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - silabs,brd4001a # WGM160P Evaluation Board
+          - silabs,brd8022a # WF200 Evaluation Board
+          - silabs,brd8023a # WFM200 Evaluation Board
+      - const: silabs,wf200 # Chip alone without antenna
+
+  reg:
+    description:
+      When used on SDIO bus, <reg> must be set to 1. When used on SPI bus, it is
+      the chip select address of the device as defined in the SPI devices
+      bindings.
+    maxItems: 1
+
+  spi-max-frequency: true
+
+  interrupts:
+    description: The interrupt line. Should be IRQ_TYPE_EDGE_RISING. 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 SDIO, the reset gpio should declared using a mmc-pwrseq.
+    maxItems: 1
+
+  wakeup-gpios:
+    description: Phandle of gpio that will be used to wake-up chip. Without this
+      property, driver will disable most of power saving features.
+    maxItems: 1
+
+  silabs,antenna-config-file:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: Use an alternative file for antenna configuration (aka
+      "Platform Data Set" in Silabs jargon). Default depends of "compatible"
+      string. For "silabs,wf200", the default is 'wf200.pds'.
+
+  local-mac-address: true
+
+  mac-address: true
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        wifi@0 {
+            compatible = "silabs,brd8022a", "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>;
+    };
+
+    mmc {
+        mmc-pwrseq = <&wfx_pwrseq>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        wifi@1 {
+            compatible = "silabs,brd8022a", "silabs,wf200";
+            pinctrl-names = "default";
+            pinctrl-0 = <&wfx_wakeup>;
+            reg = <1>;
+            wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/staging/net/wireless/silabs,wfx.yaml b/Documentation/devicetree/bindings/staging/net/wireless/silabs,wfx.yaml
deleted file mode 100644 (file)
index 105725a..0000000
+++ /dev/null
@@ -1,137 +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/staging/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: >
-  Support for the Wifi chip WFxxx from Silicon Labs. Currently, the only device
-  from the WFxxx series is the WF200 described here:
-     https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf
-
-  The WF200 can be connected via SPI or via SDIO.
-
-  For SDIO:
-
-    Declaring the WFxxx chip in device tree is mandatory (usually, the VID/PID is
-    sufficient for the SDIO devices).
-
-    It is recommended to declare a mmc-pwrseq on SDIO host above WFx. Without
-    it, you may encounter issues during reboot. The mmc-pwrseq should be
-    compatible with mmc-pwrseq-simple. Please consult
-    Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.yaml for more
-    information.
-
-  For SPI:
-
-    In add of the properties below, please consult
-    Documentation/devicetree/bindings/spi/spi-controller.yaml for optional SPI
-    related properties.
-
-properties:
-  compatible:
-    items:
-      - enum:
-          - silabs,brd4001a # WGM160P Evaluation Board
-          - silabs,brd8022a # WF200 Evaluation Board
-          - silabs,brd8023a # WFM200 Evaluation Board
-      - const: silabs,wf200 # Chip alone without antenna
-
-  reg:
-    description:
-      When used on SDIO bus, <reg> must be set to 1. When used on SPI bus, it is
-      the chip select address of the device as defined in the SPI devices
-      bindings.
-    maxItems: 1
-
-  spi-max-frequency: true
-
-  interrupts:
-    description: The interrupt line. Should be IRQ_TYPE_EDGE_RISING. 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 SDIO, the reset gpio should declared using a mmc-pwrseq.
-    maxItems: 1
-
-  wakeup-gpios:
-    description: Phandle of gpio that will be used to wake-up chip. Without this
-      property, driver will disable most of power saving features.
-    maxItems: 1
-
-  silabs,antenna-config-file:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: Use an alternative file for antenna configuration (aka
-      "Platform Data Set" in Silabs jargon). Default depends of "compatible"
-      string. For "silabs,wf200", the default is 'wf200.pds'.
-
-  local-mac-address: true
-
-  mac-address: true
-
-additionalProperties: false
-
-required:
-  - compatible
-  - reg
-
-examples:
-  - |
-    #include <dt-bindings/gpio/gpio.h>
-    #include <dt-bindings/interrupt-controller/irq.h>
-
-    spi {
-        #address-cells = <1>;
-        #size-cells = <0>;
-
-        wifi@0 {
-            compatible = "silabs,brd8022a", "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>;
-    };
-
-    mmc {
-        mmc-pwrseq = <&wfx_pwrseq>;
-        #address-cells = <1>;
-        #size-cells = <0>;
-
-        wifi@1 {
-            compatible = "silabs,brd8022a", "silabs,wf200";
-            pinctrl-names = "default";
-            pinctrl-0 = <&wfx_wakeup>;
-            reg = <1>;
-            wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>;
-        };
-    };
-...
index fd768d4..ba405f6 100644 (file)
@@ -17982,8 +17982,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:     Documentation/devicetree/bindings/staging/net/wireless/silabs,wfx.yaml
-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>
index 7add200..e78ff7a 100644 (file)
@@ -31,6 +31,7 @@ source "drivers/net/wireless/microchip/Kconfig"
 source "drivers/net/wireless/ralink/Kconfig"
 source "drivers/net/wireless/realtek/Kconfig"
 source "drivers/net/wireless/rsi/Kconfig"
+source "drivers/net/wireless/silabs/Kconfig"
 source "drivers/net/wireless/st/Kconfig"
 source "drivers/net/wireless/ti/Kconfig"
 source "drivers/net/wireless/zydas/Kconfig"
index 80b3244..76885e5 100644 (file)
@@ -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 (file)
index 0000000..6262a79
--- /dev/null
@@ -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 (file)
index 0000000..c2263ee
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_WFX)      += wfx/
diff --git a/drivers/net/wireless/silabs/wfx/Kconfig b/drivers/net/wireless/silabs/wfx/Kconfig
new file mode 100644 (file)
index 0000000..835a855
--- /dev/null
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config WFX
+       tristate "Silicon Labs wireless chips WF200 and further"
+       depends on MAC80211
+       depends on MMC || !MMC # do not allow WFX=y if MMC=m
+       depends on (SPI || MMC)
+       help
+         This is a driver for Silicons Labs WFxxx series (WF200 and further)
+         chipsets. This chip can be found on SPI or SDIO buses.
+
+         Silabs does not use a reliable SDIO vendor ID. So, to avoid conflicts,
+         the driver won't probe the device if it is not also declared in the
+         Device Tree.
diff --git a/drivers/net/wireless/silabs/wfx/Makefile b/drivers/net/wireless/silabs/wfx/Makefile
new file mode 100644 (file)
index 0000000..c8b356f
--- /dev/null
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# 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 \
+       debug.o
+wfx-$(CONFIG_SPI) += bus_spi.o
+# When CONFIG_MMC == m, append to 'wfx-y' (and not to 'wfx-m')
+wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
+
+obj-$(CONFIG_WFX) += wfx.o
diff --git a/drivers/net/wireless/silabs/wfx/bh.c b/drivers/net/wireless/silabs/wfx/bh.c
new file mode 100644 (file)
index 0000000..bcea9d5
--- /dev/null
@@ -0,0 +1,324 @@
+// 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 wfx_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), "request exceed the chip capability");
+
+       /* 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 wfx_hif_msg *)skb->data;
+       WARN(hif->encrypted & 0x3, "encryption is unsupported");
+       if (WARN(read_len < sizeof(struct wfx_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 wfx_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 wfx_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 > le16_to_cpu(wdev->hw_caps.size_inp_ch_buf),
+            "request exceed the chip capability: %zu > %d\n",
+            len, le16_to_cpu(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 wfx_hif_msg *hif;
+       int i;
+
+       for (i = 0; i < max_msg; i++) {
+               hif = NULL;
+               if (wdev->hif.tx_buffers_used < le16_to_cpu(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;
+
+       wfx_config_reg_read(wdev, &cfg_reg);
+       if (cfg_reg & 0xFF) {
+               dev_warn(wdev->dev, "chip reports errors: %02x\n", cfg_reg & 0xFF);
+               wfx_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;
+
+       wfx_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");
+       flush_workqueue(system_highpri_wq);
+       start = ktime_get();
+       for (;;) {
+               wfx_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 (file)
index 0000000..a44c8b4
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Interrupt bottom half (BH).
+ *
+ * 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/completion.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
diff --git a/drivers/net/wireless/silabs/wfx/bus.h b/drivers/net/wireless/silabs/wfx/bus.h
new file mode 100644 (file)
index 0000000..ccadfdd
--- /dev/null
@@ -0,0 +1,36 @@
+/* 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 wfx_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/net/wireless/silabs/wfx/bus_sdio.c b/drivers/net/wireless/silabs/wfx/bus_sdio.c
new file mode 100644 (file)
index 0000000..51a0d58
--- /dev/null
@@ -0,0 +1,273 @@
+// 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_device.h>
+#include <linux/of_irq.h>
+#include <linux/irq.h>
+#include <linux/align.h>
+
+#include "bus.h"
+#include "wfx.h"
+#include "hwio.h"
+#include "main.h"
+#include "bh.h"
+
+static const struct wfx_platform_data pdata_wf200 = {
+       .file_fw = "wfx/wfm_wf200",
+       .file_pds = "wfx/wf200.pds",
+};
+
+static const struct wfx_platform_data pdata_brd4001a = {
+       .file_fw = "wfx/wfm_wf200",
+       .file_pds = "wfx/brd4001a.pds",
+};
+
+static const struct wfx_platform_data pdata_brd8022a = {
+       .file_fw = "wfx/wfm_wf200",
+       .file_pds = "wfx/brd8022a.pds",
+};
+
+static const struct wfx_platform_data pdata_brd8023a = {
+       .file_fw = "wfx/wfm_wf200",
+       .file_pds = "wfx/brd8023a.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(!IS_ALIGNED((uintptr_t)dst, 4), "unaligned buffer address");
+       WARN(!IS_ALIGNED(count, 4), "unaligned buffer size");
+
+       /* 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(!IS_ALIGNED((uintptr_t)src, 4), "unaligned buffer address");
+       WARN(!IS_ALIGNED(count, 4), "unaligned buffer size");
+
+       /* 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;
+       }
+
+       flags = irq_get_trigger_type(bus->of_irq);
+       if (!flags)
+               flags = IRQF_TRIGGER_HIGH;
+       flags |= IRQF_ONESHOT;
+       ret = devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL,
+                                       wfx_sdio_irq_handler_ext, flags, "wfx", bus);
+       if (ret)
+               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);
+       return 0;
+}
+
+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 wfx_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,wf200",    .data = &pdata_wf200 },
+       { .compatible = "silabs,brd4001a", .data = &pdata_brd4001a },
+       { .compatible = "silabs,brd8022a", .data = &pdata_brd8022a },
+       { .compatible = "silabs,brd8023a", .data = &pdata_brd8023a },
+       { },
+};
+MODULE_DEVICE_TABLE(of, wfx_sdio_of_match);
+
+static int wfx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+       const struct wfx_platform_data *pdata = of_device_get_match_data(&func->dev);
+       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;
+       }
+
+       if (!pdata) {
+               dev_warn(&func->dev, "no compatible device found in DT\n");
+               return -ENODEV;
+       }
+
+       bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL);
+       if (!bus)
+               return -ENOMEM;
+
+       bus->func = func;
+       bus->of_irq = irq_of_parse_and_map(np, 0);
+       sdio_set_drvdata(func, bus);
+
+       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)
+               return ret;
+
+       bus->core = wfx_init_common(&func->dev, pdata, &wfx_sdio_hwbus_ops, bus);
+       if (!bus->core) {
+               ret = -EIO;
+               goto sdio_release;
+       }
+
+       ret = wfx_probe(bus->core);
+       if (ret)
+               goto sdio_release;
+
+       return 0;
+
+sdio_release:
+       sdio_claim_host(func);
+       sdio_disable_func(func);
+       sdio_release_host(func);
+       return ret;
+}
+
+static void wfx_sdio_remove(struct sdio_func *func)
+{
+       struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
+
+       wfx_release(bus->core);
+       sdio_claim_host(func);
+       sdio_disable_func(func);
+       sdio_release_host(func);
+}
+
+static const struct sdio_device_id wfx_sdio_ids[] = {
+       /* WF200 does not have official VID/PID */
+       { SDIO_DEVICE(0x0000, 0x1000) },
+       { },
+};
+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/net/wireless/silabs/wfx/bus_spi.c b/drivers/net/wireless/silabs/wfx/bus_spi.c
new file mode 100644 (file)
index 0000000..7fb1afb
--- /dev/null
@@ -0,0 +1,284 @@
+// 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 */
+
+static const struct wfx_platform_data pdata_wf200 = {
+       .file_fw = "wfx/wfm_wf200",
+       .file_pds = "wfx/wf200.pds",
+       .use_rising_clk = true,
+};
+
+static const struct wfx_platform_data pdata_brd4001a = {
+       .file_fw = "wfx/wfm_wf200",
+       .file_pds = "wfx/brd4001a.pds",
+       .use_rising_clk = true,
+};
+
+static const struct wfx_platform_data pdata_brd8022a = {
+       .file_fw = "wfx/wfm_wf200",
+       .file_pds = "wfx/brd8022a.pds",
+       .use_rising_clk = true,
+};
+
+static const struct wfx_platform_data pdata_brd8023a = {
+       .file_fw = "wfx/wfm_wf200",
+       .file_pds = "wfx/brd8023a.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;
+};
+
+/* The chip reads 16bits of data at time and place them directly into (little endian) CPU register.
+ * So, the chip expects bytes order to be "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, flags, "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 wfx_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_platform_data *pdata;
+       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;
+       pdata = (struct wfx_platform_data *)spi_get_device_id(func)->driver_data;
+       if (!pdata) {
+               dev_err(&func->dev, "unable to retrieve driver data (please report)\n");
+               return -ENODEV;
+       }
+
+       /* 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");
+               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, pdata, &wfx_spi_hwbus_ops, bus);
+       if (!bus->core)
+               return -EIO;
+
+       return wfx_probe(bus->core);
+}
+
+static void wfx_spi_remove(struct spi_device *func)
+{
+       struct wfx_spi_priv *bus = spi_get_drvdata(func);
+
+       wfx_release(bus->core);
+}
+
+/* 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[] = {
+       { "wf200",    (kernel_ulong_t)&pdata_wf200 },
+       { "brd4001a", (kernel_ulong_t)&pdata_brd4001a },
+       { "brd8022a", (kernel_ulong_t)&pdata_brd8022a },
+       { "brd8023a", (kernel_ulong_t)&pdata_brd8023a },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, wfx_spi_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id wfx_spi_of_match[] = {
+       { .compatible = "silabs,wf200" },
+       { .compatible = "silabs,brd4001a" },
+       { .compatible = "silabs,brd8022a" },
+       { .compatible = "silabs,brd8023a" },
+       { },
+};
+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/net/wireless/silabs/wfx/data_rx.c b/drivers/net/wireless/silabs/wfx/data_rx.c
new file mode 100644 (file)
index 0000000..a4b5ffe
--- /dev/null
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Data receiving 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 wfx_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 (file)
index 0000000..cf708f1
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Data receiving 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 wfx_hif_ind_rx;
+
+void wfx_rx_cb(struct wfx_vif *wvif, const struct wfx_hif_ind_rx *arg, struct sk_buff *skb);
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/data_tx.c b/drivers/net/wireless/silabs/wfx/data_tx.c
new file mode 100644 (file)
index 0000000..e07381b
--- /dev/null
@@ -0,0 +1,568 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Data transmitting 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;
+       }
+       /* The device only support 2GHz, else band information should be retrieved from
+        * ieee80211_tx_info
+        */
+       band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ];
+       if (rate->idx >= band->n_bitrates) {
+               WARN(1, "wrong rate->idx value: %d", rate->idx);
+               return -1;
+       }
+       return band->bitrates[rate->idx].hw_value;
+}
+
+/* TX policy cache implementation */
+
+static void wfx_tx_policy_build(struct wfx_vif *wvif, struct wfx_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 wfx_tx_policy_is_equal(const struct wfx_tx_policy *a, const struct wfx_tx_policy *b)
+{
+       return !memcmp(a->rates, b->rates, sizeof(a->rates));
+}
+
+static int wfx_tx_policy_find(struct wfx_tx_policy_cache *cache, struct wfx_tx_policy *wanted)
+{
+       struct wfx_tx_policy *it;
+
+       list_for_each_entry(it, &cache->used, link)
+               if (wfx_tx_policy_is_equal(wanted, it))
+                       return it - cache->cache;
+       list_for_each_entry(it, &cache->free, link)
+               if (wfx_tx_policy_is_equal(wanted, it))
+                       return it - cache->cache;
+       return -1;
+}
+
+static void wfx_tx_policy_use(struct wfx_tx_policy_cache *cache, struct wfx_tx_policy *entry)
+{
+       ++entry->usage_count;
+       list_move(&entry->link, &cache->used);
+}
+
+static int wfx_tx_policy_release(struct wfx_tx_policy_cache *cache, struct wfx_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 wfx_tx_policy_cache *cache = &wvif->tx_policy_cache;
+       struct wfx_tx_policy wanted;
+       struct wfx_tx_policy *entry;
+
+       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 {
+               /* If policy is not found create a new one using the oldest entry in "free" list */
+               *renew = true;
+               entry = list_entry(cache->free.prev, struct wfx_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 wfx_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 wfx_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);
+                       wfx_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 wfx_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 wfx_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_retry_policy_id(struct wfx_vif *wvif, struct ieee80211_tx_info *tx_info)
+{
+       bool tx_policy_renew = false;
+       u8 ret;
+
+       ret = wfx_tx_policy_get(wvif, tx_info->driver_rates, &tx_policy_renew);
+       if (ret == 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 ret;
+}
+
+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 wfx_hif_msg *hif_msg;
+       struct wfx_hif_req_tx *req;
+       struct wfx_tx_priv *tx_priv;
+       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 wfx_hif_msg) + sizeof(struct wfx_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 tx_priv */
+       tx_priv = (struct wfx_tx_priv *)tx_info->rate_driver_data;
+       tx_priv->icv_size = wfx_tx_get_icv_len(hw_key);
+
+       /* 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, tx_priv->icv_size);
+       skb_push(skb, wmsg_len);
+       memset(skb->data, 0, wmsg_len);
+       hif_msg = (struct wfx_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 > le16_to_cpu(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, le16_to_cpu(wvif->wdev->hw_caps.size_inp_ch_buf));
+               skb_pull(skb, wmsg_len);
+               return -EIO;
+       }
+
+       /* Fill tx request */
+       req = (struct wfx_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 take 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;
+       /* Queue index are inverted between firmware and Linux */
+       req->queue_id = 3 - queue_id;
+       req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr);
+       req->retry_policy_index = wfx_tx_get_retry_policy_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;
+       if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)
+               req->after_dtim = 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);
+
+       BUILD_BUG_ON_MSG(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 (wfx_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 wfx_hif_msg *hif = (struct wfx_hif_msg *)skb->data;
+       struct wfx_hif_req_tx *req = (struct wfx_hif_req_tx *)hif->body;
+       unsigned int offset = sizeof(struct wfx_hif_msg) + sizeof(struct wfx_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 wfx_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 wfx_hif_cnf_tx *arg)
+{
+       const struct wfx_tx_priv *tx_priv;
+       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);
+       tx_priv = wfx_skb_tx_priv(skb);
+       wvif = wdev_to_wvif(wdev, ((struct wfx_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);
+       skb_trim(skb, skb->len - tx_priv->icv_size);
+
+       /* 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 wfx_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 wfx_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 (file)
index 0000000..9834707
--- /dev/null
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Data transmitting 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 wfx_tx_policy {
+       struct list_head link;
+       int usage_count;
+       u8 rates[12];
+       bool uploaded;
+};
+
+struct wfx_tx_policy_cache {
+       struct wfx_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;
+       unsigned char icv_size;
+};
+
+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 wfx_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 wfx_hif_req_tx *wfx_skb_txreq(struct sk_buff *skb)
+{
+       struct wfx_hif_msg *hif = (struct wfx_hif_msg *)skb->data;
+       struct wfx_hif_req_tx *req = (struct wfx_hif_req_tx *)hif->body;
+
+       return req;
+}
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/debug.c b/drivers/net/wireless/silabs/wfx/debug.c
new file mode 100644 (file)
index 0000000..e826520
--- /dev/null
@@ -0,0 +1,331 @@
+// 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 *wfx_get_hif_name(unsigned long id)
+{
+       return get_symbol(id, hif_msg_print_map);
+}
+
+const char *wfx_get_mib_name(unsigned long id)
+{
+       return get_symbol(id, hif_mib_print_map);
+}
+
+const char *wfx_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 wfx_hif_mib_extended_count_table counters[3];
+
+       for (i = 0; i < ARRAY_SIZE(counters); i++) {
+               ret = wfx_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_frames);
+       PUT_COUNTER(tx_frames_multicast);
+       PUT_COUNTER(tx_frames_success);
+       PUT_COUNTER(tx_frames_retried);
+       PUT_COUNTER(tx_frames_multi_retried);
+       PUT_COUNTER(tx_frames_failed);
+
+       PUT_COUNTER(ack_failed);
+       PUT_COUNTER(rts_success);
+       PUT_COUNTER(rts_failed);
+
+       PUT_COUNTER(rx_frames);
+       PUT_COUNTER(rx_frames_multicast);
+       PUT_COUNTER(rx_frames_success);
+       PUT_COUNTER(rx_frames_failed);
+       PUT_COUNTER(drop_plcp);
+       PUT_COUNTER(drop_fcs);
+       PUT_COUNTER(drop_no_key);
+       PUT_COUNTER(drop_decryption);
+       PUT_COUNTER(drop_tkip_mic);
+       PUT_COUNTER(drop_bip_mic);
+       PUT_COUNTER(drop_cmac_icv);
+       PUT_COUNTER(drop_cmac_replay);
+       PUT_COUNTER(drop_ccmp_replay);
+       PUT_COUNTER(drop_duplicate);
+
+       PUT_COUNTER(rx_bcn_miss);
+       PUT_COUNTER(rx_bcn_success);
+       PUT_COUNTER(rx_bcn_dtim);
+       PUT_COUNTER(rx_bcn_dtim_aid0_clr);
+       PUT_COUNTER(rx_bcn_dtim_aid0_set);
+
+#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 wfx_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 wfx_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 wfx_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 wfx_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,
+};
+
+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);
+
+       return 0;
+}
diff --git a/drivers/net/wireless/silabs/wfx/debug.h b/drivers/net/wireless/silabs/wfx/debug.h
new file mode 100644 (file)
index 0000000..3840575
--- /dev/null
@@ -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 *wfx_get_hif_name(unsigned long id);
+const char *wfx_get_mib_name(unsigned long id);
+const char *wfx_get_reg_name(unsigned long id);
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/fwio.c b/drivers/net/wireless/silabs/wfx/fwio.c
new file mode 100644 (file)
index 0000000..3d1b8a1
--- /dev/null
@@ -0,0 +1,389 @@
+// 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 wfx_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 = wfx_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 = wfx_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 = wfx_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 = wfx_sram_write_dma_safe(wdev, WFX_DNLD_FIFO + (offs % DNLD_FIFO_SIZE),
+                                             data + offs, DNLD_BLOCK_SIZE);
+               if (ret < 0)
+                       return ret;
+
+               /* The device seems to not support writing 0 in this register during first loop */
+               offs += DNLD_BLOCK_SIZE;
+               ret = wfx_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;
+
+       wfx_sram_reg_read(wdev, WFX_STATUS_INFO, &reg);
+       if (reg == 0x12345678)
+               return;
+       wfx_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;
+
+       wfx_sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_READY);
+       ret = wait_ncp_status(wdev, NCP_INFO_READY);
+       if (ret)
+               goto error;
+
+       wfx_sram_buf_read(wdev, WFX_BOOTLOADER_LABEL, buf, BOOTLOADER_LABEL_SIZE);
+       buf[BOOTLOADER_LABEL_SIZE] = 0;
+       dev_dbg(wdev->dev, "bootloader: \"%s\"\n", buf);
+
+       wfx_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;
+
+       wfx_sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_INFO_READ);
+       ret = wait_ncp_status(wdev, NCP_READY);
+       if (ret)
+               goto error;
+
+       wfx_sram_reg_write(wdev, WFX_DNLD_FIFO, 0xFFFFFFFF); /* Fifo init */
+       wfx_sram_write_dma_safe(wdev, WFX_DCA_FW_VERSION, "\x01\x00\x00\x00", FW_VERSION_SIZE);
+       wfx_sram_write_dma_safe(wdev, WFX_DCA_FW_SIGNATURE, fw->data + fw_offset,
+                               FW_SIGNATURE_SIZE);
+       wfx_sram_write_dma_safe(wdev, WFX_DCA_FW_HASH, fw->data + fw_offset + FW_SIGNATURE_SIZE,
+                               FW_HASH_SIZE);
+       wfx_sram_reg_write(wdev, WFX_DCA_IMAGE_SIZE, fw->size - header_size);
+       wfx_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));
+
+       wfx_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;
+       wfx_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 = wfx_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 = wfx_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 = wfx_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 = wfx_control_reg_write(wdev, CTRL_WLAN_WAKEUP);
+       if (ret < 0)
+               return -EIO;
+       start = ktime_get();
+       for (;;) {
+               ret = wfx_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 = wfx_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 wfx_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 (file)
index 0000000..eeea612
--- /dev/null
@@ -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
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 (file)
index 0000000..8b91b1d
--- /dev/null
@@ -0,0 +1,553 @@
+/* SPDX-License-Identifier: GPL-2.0-only or Apache-2.0 */
+/*
+ * WF200 hardware interface definitions
+ *
+ * Copyright (c) 2018-2020, Silicon Laboratories Inc.
+ */
+
+#ifndef WFX_HIF_API_CMD_H
+#define WFX_HIF_API_CMD_H
+
+#include "hif_api_general.h"
+
+enum wfx_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 wfx_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 wfx_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 wfx_hif_req_reset {
+       u8     reset_stat:1;
+       u8     reset_all_int:1;
+       u8     reserved1:6;
+       u8     reserved2[3];
+} __packed;
+
+struct wfx_hif_cnf_reset {
+       __le32 status;
+} __packed;
+
+struct wfx_hif_req_read_mib {
+       __le16 mib_id;
+       __le16 reserved;
+} __packed;
+
+struct wfx_hif_cnf_read_mib {
+       __le32 status;
+       __le16 mib_id;
+       __le16 length;
+       u8     mib_data[];
+} __packed;
+
+struct wfx_hif_req_write_mib {
+       __le16 mib_id;
+       __le16 length;
+       u8     mib_data[];
+} __packed;
+
+struct wfx_hif_cnf_write_mib {
+       __le32 status;
+} __packed;
+
+struct wfx_hif_req_update_ie {
+       u8     beacon:1;
+       u8     probe_resp:1;
+       u8     probe_req:1;
+       u8     reserved1:5;
+       u8     reserved2;
+       __le16 num_ies;
+       u8     ie[];
+} __packed;
+
+struct wfx_hif_cnf_update_ie {
+       __le32 status;
+} __packed;
+
+struct wfx_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 wfx_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 wfx_hif_ssid_def ssid_def[HIF_API_MAX_NB_SSIDS];
+       u8     channel_list[];
+} __packed;
+
+struct wfx_hif_cnf_start_scan {
+       __le32 status;
+} __packed;
+
+struct wfx_hif_cnf_stop_scan {
+       __le32 status;
+} __packed;
+
+enum wfx_hif_pm_mode_status {
+       HIF_PM_MODE_ACTIVE                         = 0x0,
+       HIF_PM_MODE_PS                             = 0x1,
+       HIF_PM_MODE_UNDETERMINED                   = 0x2
+};
+
+struct wfx_hif_ind_scan_cmpl {
+       __le32 status;
+       u8     pm_mode;
+       u8     num_channels_completed;
+       __le16 reserved;
+} __packed;
+
+enum wfx_hif_queue_id {
+       HIF_QUEUE_ID_BACKGROUND                    = 0x0,
+       HIF_QUEUE_ID_BESTEFFORT                    = 0x1,
+       HIF_QUEUE_ID_VIDEO                         = 0x2,
+       HIF_QUEUE_ID_VOICE                         = 0x3
+};
+
+enum wfx_hif_frame_format {
+       HIF_FRAME_FORMAT_NON_HT                    = 0x0,
+       HIF_FRAME_FORMAT_MIXED_FORMAT_HT           = 0x1,
+       HIF_FRAME_FORMAT_GF_HT_11N                 = 0x2
+};
+
+struct wfx_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 wfx_hif_qos_ackplcy {
+       HIF_QOS_ACKPLCY_NORMAL                         = 0x0,
+       HIF_QOS_ACKPLCY_TXNOACK                        = 0x1,
+       HIF_QOS_ACKPLCY_NOEXPACK                       = 0x2,
+       HIF_QOS_ACKPLCY_BLCKACK                        = 0x3
+};
+
+struct wfx_hif_cnf_tx {
+       __le32 status;
+       /* packet_id is copied from struct wfx_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 wfx_hif_cnf_multi_transmit {
+       u8     num_tx_confs;
+       u8     reserved[3];
+       struct wfx_hif_cnf_tx tx_conf_payload[];
+} __packed;
+
+enum wfx_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 wfx_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 wfx_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 wfx_hif_cnf_edca_queue_params {
+       __le32 status;
+} __packed;
+
+struct wfx_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 wfx_hif_cnf_join {
+       __le32 status;
+} __packed;
+
+struct wfx_hif_ind_join_complete {
+       __le32 status;
+} __packed;
+
+struct wfx_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 wfx_hif_cnf_set_bss_params {
+       __le32 status;
+} __packed;
+
+struct wfx_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 wfx_hif_cnf_set_pm_mode {
+       __le32 status;
+} __packed;
+
+struct wfx_hif_ind_set_pm_mode_cmpl {
+       __le32 status;
+       u8     pm_mode;
+       u8     reserved[3];
+} __packed;
+
+struct wfx_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 wfx_hif_cnf_start {
+       __le32 status;
+} __packed;
+
+struct wfx_hif_req_beacon_transmit {
+       u8     enable_beaconing;
+       u8     reserved[3];
+} __packed;
+
+struct wfx_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 wfx_hif_req_map_link {
+       u8     mac_addr[ETH_ALEN];
+       u8     unmap:1;
+       u8     mfpc:1;
+       u8     reserved:6;
+       u8     peer_sta_id;
+} __packed;
+
+struct wfx_hif_cnf_map_link {
+       __le32 status;
+} __packed;
+
+struct wfx_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 wfx_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 wfx_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 wfx_hif_wep_group_key {
+       u8     key_id;
+       u8     key_length;
+       u8     reserved[2];
+       u8     key_data[HIF_API_WEP_KEY_DATA_SIZE];
+} __packed;
+
+struct wfx_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 wfx_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 wfx_hif_aes_pairwise_key {
+       u8     peer_address[ETH_ALEN];
+       u8     reserved[2];
+       u8     aes_key_data[HIF_API_AES_KEY_DATA_SIZE];
+} __packed;
+
+struct wfx_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 wfx_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 wfx_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 wfx_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 wfx_hif_req_add_key {
+       u8     type;
+       u8     entry_index;
+       u8     int_id:2;
+       u8     reserved1:6;
+       u8     reserved2;
+       union {
+               struct wfx_hif_wep_pairwise_key  wep_pairwise_key;
+               struct wfx_hif_wep_group_key     wep_group_key;
+               struct wfx_hif_tkip_pairwise_key tkip_pairwise_key;
+               struct wfx_hif_tkip_group_key    tkip_group_key;
+               struct wfx_hif_aes_pairwise_key  aes_pairwise_key;
+               struct wfx_hif_aes_group_key     aes_group_key;
+               struct wfx_hif_wapi_pairwise_key wapi_pairwise_key;
+               struct wfx_hif_wapi_group_key    wapi_group_key;
+               struct wfx_hif_igtk_group_key    igtk_group_key;
+       } key;
+} __packed;
+
+struct wfx_hif_cnf_add_key {
+       __le32 status;
+} __packed;
+
+struct wfx_hif_req_remove_key {
+       u8     entry_index;
+       u8     reserved[3];
+} __packed;
+
+struct wfx_hif_cnf_remove_key {
+       __le32 status;
+} __packed;
+
+enum wfx_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 wfx_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 wfx_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 (file)
index 0000000..4d400fd
--- /dev/null
@@ -0,0 +1,252 @@
+/* SPDX-License-Identifier: GPL-2.0-only or Apache-2.0 */
+/*
+ * WF200 hardware interface definitions
+ *
+ * Copyright (c) 2018-2020, Silicon Laboratories Inc.
+ */
+
+#ifndef WFX_HIF_API_GENERAL_H
+#define WFX_HIF_API_GENERAL_H
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+
+#define HIF_ID_IS_INDICATION      0x80
+#define HIF_COUNTER_MAX           7
+
+struct wfx_hif_msg {
+       __le16 len;
+       u8     id;
+       u8     reserved:1;
+       u8     interface:2;
+       u8     seqnum:3;
+       u8     encrypted:2;
+       u8     body[];
+} __packed;
+
+enum wfx_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 wfx_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 wfx_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 wfx_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
+};
+
+struct wfx_hif_ind_startup {
+       __le32 status;
+       __le16 hardware_id;
+       u8     opn[14];
+       u8     uid[8];
+       __le16 num_inp_ch_bufs;
+       __le16 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;
+       __le32 supported_rate_mask;
+       u8     firmware_label[128];
+} __packed;
+
+struct wfx_hif_ind_wakeup {
+} __packed;
+
+struct wfx_hif_req_configuration {
+       __le16 length;
+       u8     pds_data[];
+} __packed;
+
+struct wfx_hif_cnf_configuration {
+       __le32 status;
+} __packed;
+
+enum wfx_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 wfx_hif_req_control_gpio {
+       u8     gpio_label;
+       u8     gpio_mode;
+} __packed;
+
+struct wfx_hif_cnf_control_gpio {
+       __le32 status;
+       __le32 value;
+} __packed;
+
+enum wfx_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 wfx_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 wfx_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 wfx_hif_ind_generic {
+       __le32 type;
+       union {
+               struct wfx_hif_rx_stats rx_stats;
+               struct wfx_hif_tx_power_loop_info tx_power_loop_info;
+       } data;
+} __packed;
+
+enum wfx_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 wfx_hif_ind_error {
+       __le32 type;
+       u8     data[];
+} __packed;
+
+struct wfx_hif_ind_exception {
+       __le32 type;
+       u8     data[];
+} __packed;
+
+enum wfx_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 (file)
index 0000000..7b68b83
--- /dev/null
@@ -0,0 +1,346 @@
+/* SPDX-License-Identifier: GPL-2.0-only or Apache-2.0 */
+/*
+ * WF200 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 wfx_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 wfx_hif_op_power_mode {
+       HIF_OP_POWER_MODE_ACTIVE    = 0x0,
+       HIF_OP_POWER_MODE_DOZE      = 0x1,
+       HIF_OP_POWER_MODE_QUIESCENT = 0x2
+};
+
+struct wfx_hif_mib_gl_operational_power_mode {
+       u8     power_mode:4;
+       u8     reserved1:3;
+       u8     wup_ind_activation:1;
+       u8     reserved2[3];
+} __packed;
+
+struct wfx_hif_mib_gl_set_multi_msg {
+       u8     enable_multi_tx_conf:1;
+       u8     reserved1:7;
+       u8     reserved2[3];
+} __packed;
+
+enum wfx_hif_arp_ns_frame_treatment {
+       HIF_ARP_NS_FILTERING_DISABLE = 0x0,
+       HIF_ARP_NS_FILTERING_ENABLE  = 0x1,
+       HIF_ARP_NS_REPLY_ENABLE      = 0x2
+};
+
+struct wfx_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 wfx_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 wfx_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 wfx_hif_mib_bcn_filter_table {
+       __le32 num_of_info_elmts;
+       struct wfx_hif_ie_table_entry ie_table[];
+} __packed;
+
+enum wfx_hif_beacon_filter {
+       HIF_BEACON_FILTER_DISABLE  = 0x0,
+       HIF_BEACON_FILTER_ENABLE   = 0x1,
+       HIF_BEACON_FILTER_AUTO_ERP = 0x2
+};
+
+struct wfx_hif_mib_bcn_filter_enable {
+       __le32 enable;
+       __le32 bcn_count;
+} __packed;
+
+struct wfx_hif_mib_extended_count_table {
+       __le32 count_drop_plcp;
+       __le32 count_drop_fcs;
+       __le32 count_tx_frames;
+       __le32 count_rx_frames;
+       __le32 count_rx_frames_failed;
+       __le32 count_drop_decryption;
+       __le32 count_drop_tkip_mic;
+       __le32 count_drop_no_key;
+       __le32 count_tx_frames_multicast;
+       __le32 count_tx_frames_success;
+       __le32 count_tx_frames_failed;
+       __le32 count_tx_frames_retried;
+       __le32 count_tx_frames_multi_retried;
+       __le32 count_drop_duplicate;
+       __le32 count_rts_success;
+       __le32 count_rts_failed;
+       __le32 count_ack_failed;
+       __le32 count_rx_frames_multicast;
+       __le32 count_rx_frames_success;
+       __le32 count_drop_cmac_icv;
+       __le32 count_drop_cmac_replay;
+       __le32 count_drop_ccmp_replay;
+       __le32 count_drop_bip_mic;
+       __le32 count_rx_bcn_success;
+       __le32 count_rx_bcn_miss;
+       __le32 count_rx_bcn_dtim;
+       __le32 count_rx_bcn_dtim_aid0_clr;
+       __le32 count_rx_bcn_dtim_aid0_set;
+       __le32 reserved[12];
+} __packed;
+
+struct wfx_hif_mib_count_table {
+       __le32 count_drop_plcp;
+       __le32 count_drop_fcs;
+       __le32 count_tx_frames;
+       __le32 count_rx_frames;
+       __le32 count_rx_frames_failed;
+       __le32 count_drop_decryption;
+       __le32 count_drop_tkip_mic;
+       __le32 count_drop_no_key;
+       __le32 count_tx_frames_multicast;
+       __le32 count_tx_frames_success;
+       __le32 count_tx_frames_failed;
+       __le32 count_tx_frames_retried;
+       __le32 count_tx_frames_multi_retried;
+       __le32 count_drop_duplicate;
+       __le32 count_rts_success;
+       __le32 count_rts_failed;
+       __le32 count_ack_failed;
+       __le32 count_rx_frames_multicast;
+       __le32 count_rx_frames_success;
+       __le32 count_drop_cmac_icv;
+       __le32 count_drop_cmac_replay;
+       __le32 count_drop_ccmp_replay;
+       __le32 count_drop_bip_mic;
+} __packed;
+
+struct wfx_hif_mib_mac_address {
+       u8     mac_addr[ETH_ALEN];
+       __le16 reserved;
+} __packed;
+
+struct wfx_hif_mib_wep_default_key_id {
+       u8     wep_default_key_id;
+       u8     reserved[3];
+} __packed;
+
+struct wfx_hif_mib_dot11_rts_threshold {
+       __le32 threshold;
+} __packed;
+
+struct wfx_hif_mib_slot_time {
+       __le32 slot_time;
+} __packed;
+
+struct wfx_hif_mib_current_tx_power_level {
+       __le32 power_level; /* signed value */
+} __packed;
+
+struct wfx_hif_mib_non_erp_protection {
+       u8     use_cts_to_self:1;
+       u8     reserved1:7;
+       u8     reserved2[3];
+} __packed;
+
+enum wfx_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 wfx_hif_mib_template_frame {
+       u8     frame_type;
+       u8     init_rate:7;
+       u8     mode:1;
+       __le16 frame_length;
+       u8     frame[];
+} __packed;
+
+struct wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_hif_mib_set_tx_rate_retry_policy {
+       u8     num_tx_rate_policies;
+       u8     reserved[3];
+       struct wfx_hif_tx_rate_retry_policy tx_rate_retry_policy[];
+} __packed;
+
+struct wfx_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 wfx_hif_mib_keep_alive_period {
+       __le16 keep_alive_period;
+       u8     reserved[2];
+} __packed;
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/hif_rx.c b/drivers/net/wireless/silabs/wfx/hif_rx.c
new file mode 100644 (file)
index 0000000..64ca8ac
--- /dev/null
@@ -0,0 +1,391 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Handling of the chip-to-host events (aka indications) of the hardware 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 wfx_hif_generic_confirm(struct wfx_dev *wdev,
+                                  const struct wfx_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 wfx_hif_tx_confirm(struct wfx_dev *wdev,
+                             const struct wfx_hif_msg *hif, const void *buf)
+{
+       const struct wfx_hif_cnf_tx *body = buf;
+
+       wfx_tx_confirm_cb(wdev, body);
+       return 0;
+}
+
+static int wfx_hif_multi_tx_confirm(struct wfx_dev *wdev,
+                                   const struct wfx_hif_msg *hif, const void *buf)
+{
+       const struct wfx_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 wfx_hif_startup_indication(struct wfx_dev *wdev,
+                                     const struct wfx_hif_msg *hif, const void *buf)
+{
+       const struct wfx_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 wfx_hif_ind_startup));
+       complete(&wdev->firmware_ready);
+       return 0;
+}
+
+static int wfx_hif_wakeup_indication(struct wfx_dev *wdev,
+                                    const struct wfx_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 wfx_hif_receive_indication(struct wfx_dev *wdev, const struct wfx_hif_msg *hif,
+                                     const void *buf, struct sk_buff *skb)
+{
+       struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+       const struct wfx_hif_ind_rx *body = buf;
+
+       if (!wvif) {
+               dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
+               return -EIO;
+       }
+       skb_pull(skb, sizeof(struct wfx_hif_msg) + sizeof(struct wfx_hif_ind_rx));
+       wfx_rx_cb(wvif, body, skb);
+
+       return 0;
+}
+
+static int wfx_hif_event_indication(struct wfx_dev *wdev,
+                                   const struct wfx_hif_msg *hif, const void *buf)
+{
+       struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+       const struct wfx_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 wfx_hif_pm_mode_complete_indication(struct wfx_dev *wdev,
+                                              const struct wfx_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 wfx_hif_scan_complete_indication(struct wfx_dev *wdev,
+                                           const struct wfx_hif_msg *hif, const void *buf)
+{
+       struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+       const struct wfx_hif_ind_scan_cmpl *body = buf;
+
+       if (!wvif) {
+               dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
+               return -EIO;
+       }
+
+       wfx_scan_complete(wvif, body->num_channels_completed);
+
+       return 0;
+}
+
+static int wfx_hif_join_complete_indication(struct wfx_dev *wdev,
+                                           const struct wfx_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 wfx_hif_suspend_resume_indication(struct wfx_dev *wdev,
+                                            const struct wfx_hif_msg *hif, const void *buf)
+{
+       const struct wfx_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 wfx_hif_generic_indication(struct wfx_dev *wdev,
+                                     const struct wfx_hif_msg *hif, const void *buf)
+{
+       const struct wfx_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 wfx_hif_error_indication(struct wfx_dev *wdev,
+                                   const struct wfx_hif_msg *hif, const void *buf)
+{
+       const struct wfx_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 wfx_hif_exception_indication(struct wfx_dev *wdev,
+                                       const struct wfx_hif_msg *hif, const void *buf)
+{
+       const struct wfx_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 wfx_hif_msg *hif, const void *buf);
+} hif_handlers[] = {
+       /* Confirmations */
+       { HIF_CNF_ID_TX,                wfx_hif_tx_confirm },
+       { HIF_CNF_ID_MULTI_TRANSMIT,    wfx_hif_multi_tx_confirm },
+       /* Indications */
+       { HIF_IND_ID_STARTUP,           wfx_hif_startup_indication },
+       { HIF_IND_ID_WAKEUP,            wfx_hif_wakeup_indication },
+       { HIF_IND_ID_JOIN_COMPLETE,     wfx_hif_join_complete_indication },
+       { HIF_IND_ID_SET_PM_MODE_CMPL,  wfx_hif_pm_mode_complete_indication },
+       { HIF_IND_ID_SCAN_CMPL,         wfx_hif_scan_complete_indication },
+       { HIF_IND_ID_SUSPEND_RESUME_TX, wfx_hif_suspend_resume_indication },
+       { HIF_IND_ID_EVENT,             wfx_hif_event_indication },
+       { HIF_IND_ID_GENERIC,           wfx_hif_generic_indication },
+       { HIF_IND_ID_ERROR,             wfx_hif_error_indication },
+       { HIF_IND_ID_EXCEPTION,         wfx_hif_exception_indication },
+       /* FIXME: allocate skb_p from wfx_hif_receive_indication and make it generic */
+       //{ HIF_IND_ID_RX,              wfx_hif_receive_indication },
+};
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
+{
+       int i;
+       const struct wfx_hif_msg *hif = (const struct wfx_hif_msg *)skb->data;
+       int hif_id = hif->id;
+
+       if (hif_id == HIF_IND_ID_RX) {
+               /* wfx_hif_receive_indication take care of skb lifetime */
+               wfx_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) {
+               wfx_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 & HIF_ID_IS_INDICATION)
+               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 (file)
index 0000000..96543b8
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Handling of the chip-to-host events (aka indications) of the hardware 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/net/wireless/silabs/wfx/hif_tx.c b/drivers/net/wireless/silabs/wfx/hif_tx.c
new file mode 100644 (file)
index 0000000..ae3cc59
--- /dev/null
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of the host-to-chip commands (aka request/confirmation) of the
+ * hardware 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 wfx_hif_msg *hif, int if_id, unsigned int cmd, size_t size)
+{
+       if (if_id == -1)
+               if_id = 2;
+
+       WARN(cmd > 0x3f, "invalid hardware 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 wfx_hif_msg **hif)
+{
+       *hif = kzalloc(sizeof(struct wfx_hif_msg) + body_len, GFP_KERNEL);
+       if (*hif)
+               return (*hif)->body;
+       else
+               return NULL;
+}
+
+int wfx_cmd_send(struct wfx_dev *wdev, struct wfx_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. Ensure the wq has send the buffer before to continue. */
+               flush_workqueue(system_highpri_wq);
+               ret = 0;
+               goto end;
+       }
+
+       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;
+       }
+
+end:
+       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 = wfx_get_mib_name(((u16 *)request)[2]);
+               mib_sep = "/";
+       }
+       if (ret < 0)
+               dev_err(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned error %d\n",
+                       wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
+       if (ret > 0)
+               dev_warn(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned status %d\n",
+                        wfx_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 wfx_hif_shutdown(struct wfx_dev *wdev)
+{
+       int ret;
+       struct wfx_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
+               wfx_control_reg_write(wdev, 0);
+       kfree(hif);
+       return ret;
+}
+
+int wfx_hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
+{
+       int ret;
+       size_t buf_len = sizeof(struct wfx_hif_req_configuration) + len;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 wfx_hif_reset(struct wfx_vif *wvif, bool reset_stat)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 wfx_hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       int buf_len = sizeof(struct wfx_hif_cnf_read_mib) + val_len;
+       struct wfx_hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif);
+       struct wfx_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",
+                       wfx_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 wfx_hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       int buf_len = sizeof(struct wfx_hif_req_write_mib) + val_len;
+       struct wfx_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 wfx_hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req,
+                int chan_start_idx, int chan_num)
+{
+       int ret, i;
+       struct wfx_hif_msg *hif;
+       size_t buf_len = sizeof(struct wfx_hif_req_start_scan_alt) + chan_num * sizeof(u8);
+       struct wfx_hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif);
+
+       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;
+       }
+
+       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 wfx_hif_stop_scan(struct wfx_vif *wvif)
+{
+       int ret;
+       struct wfx_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 wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+                struct ieee80211_channel *channel, const u8 *ssid, int ssidlen)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 (!hif)
+               return -ENOMEM;
+       body->infrastructure_bss_mode = !conf->ibss_joined;
+       body->short_preamble = conf->use_short_preamble;
+       body->probe_for_join = !(channel->flags & IEEE80211_CHAN_NO_IR);
+       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 wfx_hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 wfx_hif_add_key(struct wfx_dev *wdev, const struct wfx_hif_req_add_key *arg)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       /* FIXME: only send necessary bits */
+       struct wfx_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 wfx_hif_remove_key(struct wfx_dev *wdev, int idx)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 wfx_hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
+                                 const struct ieee80211_tx_queue_params *arg)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+                 const struct ieee80211_channel *channel)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 wfx_hif_beacon_transmit(struct wfx_vif *wvif, bool enable)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 wfx_hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       struct wfx_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 wfx_hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
+{
+       int ret;
+       struct wfx_hif_msg *hif;
+       int buf_len = sizeof(struct wfx_hif_req_update_ie) + ies_len;
+       struct wfx_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 (file)
index 0000000..71817a6
--- /dev/null
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Implementation of the host-to-chip commands (aka request/confirmation) of the
+ * hardware 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
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+
+struct ieee80211_channel;
+struct ieee80211_bss_conf;
+struct ieee80211_tx_queue_params;
+struct cfg80211_scan_request;
+struct wfx_hif_req_add_key;
+struct wfx_dev;
+struct wfx_vif;
+
+struct wfx_hif_cmd {
+       struct mutex       lock;
+       struct completion  ready;
+       struct completion  done;
+       struct wfx_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 wfx_hif_msg *request,
+                void *reply, size_t reply_len, bool async);
+
+int wfx_hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *buf, size_t buf_size);
+int wfx_hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *buf, size_t buf_size);
+int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+                 const struct ieee80211_channel *channel);
+int wfx_hif_reset(struct wfx_vif *wvif, bool reset_stat);
+int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
+                struct ieee80211_channel *channel, const u8 *ssid, int ssidlen);
+int wfx_hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp);
+int wfx_hif_add_key(struct wfx_dev *wdev, const struct wfx_hif_req_add_key *arg);
+int wfx_hif_remove_key(struct wfx_dev *wdev, int idx);
+int wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout);
+int wfx_hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count);
+int wfx_hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
+                                 const struct ieee80211_tx_queue_params *arg);
+int wfx_hif_beacon_transmit(struct wfx_vif *wvif, bool enable);
+int wfx_hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len);
+int wfx_hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211,
+                int chan_start, int chan_num);
+int wfx_hif_stop_scan(struct wfx_vif *wvif);
+int wfx_hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len);
+int wfx_hif_shutdown(struct wfx_dev *wdev);
+
+#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 (file)
index 0000000..df1bcb1
--- /dev/null
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of the host-to-chip MIBs of the hardware 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 wfx_hif_set_output_power(struct wfx_vif *wvif, int val)
+{
+       struct wfx_hif_mib_current_tx_power_level arg = {
+               .power_level = cpu_to_le32(val * 10),
+       };
+
+       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_CURRENT_TX_POWER_LEVEL,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
+                                    unsigned int dtim_interval, unsigned int listen_interval)
+{
+       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_WAKEUP_PERIOD,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, int rssi_thold, int rssi_hyst)
+{
+       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RCPI_RSSI_THRESHOLD,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_get_counters_table(struct wfx_dev *wdev, int vif_id,
+                              struct wfx_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 wfx_hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE,
+                                   arg, sizeof(struct wfx_hif_mib_count_table));
+       } else {
+               return wfx_hif_read_mib(wdev, vif_id, HIF_MIB_ID_EXTENDED_COUNTERS_TABLE,
+                                       arg, sizeof(struct wfx_hif_mib_extended_count_table));
+       }
+}
+
+int wfx_hif_set_macaddr(struct wfx_vif *wvif, u8 *mac)
+{
+       struct wfx_hif_mib_mac_address arg = { };
+
+       if (mac)
+               ether_addr_copy(arg.mac_addr, mac);
+       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_set_rx_filter(struct wfx_vif *wvif, bool filter_bssid, bool filter_prbreq)
+{
+       struct wfx_hif_mib_rx_filter arg = { };
+
+       if (filter_bssid)
+               arg.bssid_filter = 1;
+       if (!filter_prbreq)
+               arg.fwd_probe_req = 1;
+       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, &arg, sizeof(arg));
+}
+
+int wfx_hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len,
+                                   const struct wfx_hif_ie_table_entry *tbl)
+{
+       int ret;
+       struct wfx_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 = wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_FILTER_TABLE,
+                               arg, buf_len);
+       kfree(arg);
+       return ret;
+}
+
+int wfx_hif_beacon_filter_control(struct wfx_vif *wvif, int enable, int beacon_count)
+{
+       struct wfx_hif_mib_bcn_filter_enable arg = {
+               .enable = cpu_to_le32(enable),
+               .bcn_count = cpu_to_le32(beacon_count),
+       };
+       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_FILTER_ENABLE,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_set_operational_mode(struct wfx_dev *wdev, enum wfx_hif_op_power_mode mode)
+{
+       struct wfx_hif_mib_gl_operational_power_mode arg = {
+               .power_mode = mode,
+               .wup_ind_activation = 1,
+       };
+
+       return wfx_hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb,
+                              u8 frame_type, int init_rate)
+{
+       struct wfx_hif_mib_template_frame *arg;
+
+       WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big");
+       skb_push(skb, 4);
+       arg = (struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME,
+                                arg, sizeof(*arg) + skb->len);
+}
+
+int wfx_hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required)
+{
+       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_PROTECTED_MGMT_POLICY,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_set_block_ack_policy(struct wfx_vif *wvif, u8 tx_tid_policy, u8 rx_tid_policy)
+{
+       struct wfx_hif_mib_block_ack_policy arg = {
+               .block_ack_tx_tid_policy = tx_tid_policy,
+               .block_ack_rx_tid_policy = rx_tid_policy,
+       };
+
+       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density,
+                                bool greenfield, bool short_preamble)
+{
+       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_ASSOCIATION_MODE,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, int policy_index, u8 *rates)
+{
+       struct wfx_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 = wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY,
+                               arg, size);
+       kfree(arg);
+       return ret;
+}
+
+int wfx_hif_keep_alive_period(struct wfx_vif *wvif, int period)
+{
+       struct wfx_hif_mib_keep_alive_period arg = {
+               .keep_alive_period = cpu_to_le16(period),
+       };
+
+       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD,
+                                &arg, sizeof(arg));
+};
+
+int wfx_hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr)
+{
+       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable)
+{
+       struct wfx_hif_mib_gl_set_multi_msg arg = {
+               .enable_multi_tx_conf = enable,
+       };
+
+       return wfx_hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, &arg, sizeof(arg));
+}
+
+int wfx_hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val)
+{
+       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_UAPSD_INFORMATION,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_erp_use_protection(struct wfx_vif *wvif, bool enable)
+{
+       struct wfx_hif_mib_non_erp_protection arg = {
+               .use_cts_to_self = enable,
+       };
+
+       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_NON_ERP_PROTECTION,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_slot_time(struct wfx_vif *wvif, int val)
+{
+       struct wfx_hif_mib_slot_time arg = {
+               .slot_time = cpu_to_le32(val),
+       };
+
+       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, &arg, sizeof(arg));
+}
+
+int wfx_hif_wep_default_key_id(struct wfx_vif *wvif, int val)
+{
+       struct wfx_hif_mib_wep_default_key_id arg = {
+               .wep_default_key_id = val,
+       };
+
+       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID,
+                                &arg, sizeof(arg));
+}
+
+int wfx_hif_rts_threshold(struct wfx_vif *wvif, int val)
+{
+       struct wfx_hif_mib_dot11_rts_threshold arg = {
+               .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF),
+       };
+
+       return wfx_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 (file)
index 0000000..bcd4ef6
--- /dev/null
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Implementation of the host-to-chip MIBs of the hardware 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
+
+#include <linux/types.h>
+
+struct sk_buff;
+struct wfx_vif;
+struct wfx_dev;
+struct wfx_hif_ie_table_entry;
+struct wfx_hif_mib_extended_count_table;
+
+int wfx_hif_set_output_power(struct wfx_vif *wvif, int val);
+int wfx_hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
+                                    unsigned int dtim_interval, unsigned int listen_interval);
+int wfx_hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, int rssi_thold, int rssi_hyst);
+int wfx_hif_get_counters_table(struct wfx_dev *wdev, int vif_id,
+                              struct wfx_hif_mib_extended_count_table *arg);
+int wfx_hif_set_macaddr(struct wfx_vif *wvif, u8 *mac);
+int wfx_hif_set_rx_filter(struct wfx_vif *wvif, bool filter_bssid, bool fwd_probe_req);
+int wfx_hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len,
+                                   const struct wfx_hif_ie_table_entry *tbl);
+int wfx_hif_beacon_filter_control(struct wfx_vif *wvif, int enable, int beacon_count);
+int wfx_hif_set_operational_mode(struct wfx_dev *wdev, enum wfx_hif_op_power_mode mode);
+int wfx_hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb,
+                              u8 frame_type, int init_rate);
+int wfx_hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required);
+int wfx_hif_set_block_ack_policy(struct wfx_vif *wvif, u8 tx_tid_policy, u8 rx_tid_policy);
+int wfx_hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density,
+                                bool greenfield, bool short_preamble);
+int wfx_hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, int policy_index, u8 *rates);
+int wfx_hif_keep_alive_period(struct wfx_vif *wvif, int period);
+int wfx_hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr);
+int wfx_hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable);
+int wfx_hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val);
+int wfx_hif_erp_use_protection(struct wfx_vif *wvif, bool enable);
+int wfx_hif_slot_time(struct wfx_vif *wvif, int val);
+int wfx_hif_wep_default_key_id(struct wfx_vif *wvif, int val);
+int wfx_hif_rts_threshold(struct wfx_vif *wvif, int val);
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/hwio.c b/drivers/net/wireless/silabs/wfx/hwio.c
new file mode 100644 (file)
index 0000000..3f9750b
--- /dev/null
@@ -0,0 +1,332 @@
+// 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 <linux/align.h>
+
+#include "hwio.h"
+#include "wfx.h"
+#include "bus.h"
+#include "traces.h"
+
+#define WFX_HIF_BUFFER_SIZE 0x2000
+
+static int wfx_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 wfx_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 wfx_read32_locked(struct wfx_dev *wdev, int reg, u32 *val)
+{
+       int ret;
+
+       wdev->hwbus_ops->lock(wdev->hwbus_priv);
+       ret = wfx_read32(wdev, reg, val);
+       _trace_io_read32(reg, *val);
+       wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+       return ret;
+}
+
+static int wfx_write32_locked(struct wfx_dev *wdev, int reg, u32 val)
+{
+       int ret;
+
+       wdev->hwbus_ops->lock(wdev->hwbus_priv);
+       ret = wfx_write32(wdev, reg, val);
+       _trace_io_write32(reg, val);
+       wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+       return ret;
+}
+
+static int wfx_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 = wfx_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 = wfx_write32(wdev, reg, val_w);
+               _trace_io_write32(reg, val_w);
+       }
+err:
+       wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+       return ret;
+}
+
+static int wfx_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 >= WFX_HIF_BUFFER_SIZE);
+       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 = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr);
+       if (ret < 0)
+               goto err;
+
+       ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg);
+       if (ret < 0)
+               goto err;
+
+       ret = wfx_write32(wdev, WFX_REG_CONFIG, cfg | prefetch);
+       if (ret < 0)
+               goto err;
+
+       for (i = 0; i < 20; i++) {
+               ret = wfx_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 wfx_indirect_write(struct wfx_dev *wdev, int reg, u32 addr,
+                             const void *buf, size_t len)
+{
+       int ret;
+
+       WARN_ON(len >= WFX_HIF_BUFFER_SIZE);
+       WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
+       ret = wfx_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 wfx_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 = wfx_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 wfx_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 = wfx_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 wfx_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 = wfx_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 wfx_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 = wfx_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(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer");
+       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(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer");
+       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 wfx_sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
+{
+       return wfx_indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
+}
+
+int wfx_ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
+{
+       return wfx_indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
+}
+
+int wfx_sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
+{
+       return wfx_indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
+}
+
+int wfx_ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
+{
+       return wfx_indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
+}
+
+int wfx_sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
+{
+       return wfx_indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
+}
+
+int wfx_ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
+{
+       return wfx_indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
+}
+
+int wfx_sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
+{
+       return wfx_indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
+}
+
+int wfx_ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
+{
+       return wfx_indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
+}
+
+int wfx_config_reg_read(struct wfx_dev *wdev, u32 *val)
+{
+       return wfx_read32_locked(wdev, WFX_REG_CONFIG, val);
+}
+
+int wfx_config_reg_write(struct wfx_dev *wdev, u32 val)
+{
+       return wfx_write32_locked(wdev, WFX_REG_CONFIG, val);
+}
+
+int wfx_config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
+{
+       return wfx_write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val);
+}
+
+int wfx_control_reg_read(struct wfx_dev *wdev, u32 *val)
+{
+       return wfx_read32_locked(wdev, WFX_REG_CONTROL, val);
+}
+
+int wfx_control_reg_write(struct wfx_dev *wdev, u32 val)
+{
+       return wfx_write32_locked(wdev, WFX_REG_CONTROL, val);
+}
+
+int wfx_control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
+{
+       return wfx_write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val);
+}
+
+int wfx_igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val)
+{
+       int ret;
+
+       *val = ~0; /* Never return undefined value */
+       ret = wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24);
+       if (ret)
+               return ret;
+       ret = wfx_read32_locked(wdev, WFX_REG_SET_GEN_R_W, val);
+       if (ret)
+               return ret;
+       *val &= IGPR_VALUE;
+       return ret;
+}
+
+int wfx_igpr_reg_write(struct wfx_dev *wdev, int index, u32 val)
+{
+       return wfx_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 (file)
index 0000000..c6e7b06
--- /dev/null
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Low-level I/O functions.
+ *
+ * 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;
+
+/* Caution: in the functions below, 'buf' will used with a DMA. So, it must be kmalloc'd (do not use
+ * stack allocated buffers). In doubt, enable CONFIG_DEBUG_SG to detect badly located buffer.
+ */
+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 wfx_sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len);
+int wfx_sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len);
+
+int wfx_ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len);
+int wfx_ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len);
+
+int wfx_sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val);
+int wfx_sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val);
+
+int wfx_ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val);
+int wfx_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 wfx_config_reg_read(struct wfx_dev *wdev, u32 *val);
+int wfx_config_reg_write(struct wfx_dev *wdev, u32 val);
+int wfx_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 wfx_control_reg_read(struct wfx_dev *wdev, u32 *val);
+int wfx_control_reg_write(struct wfx_dev *wdev, u32 val);
+int wfx_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 wfx_igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val);
+int wfx_igpr_reg_write(struct wfx_dev *wdev, int index, u32 val);
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/key.c b/drivers/net/wireless/silabs/wfx/key.c
new file mode 100644 (file)
index 0000000..8f23e8d
--- /dev/null
@@ -0,0 +1,227 @@
+// 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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 = wfx_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 wfx_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 (file)
index 0000000..2234e36
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Key management related functions.
+ *
+ * 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
diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c
new file mode 100644 (file)
index 0000000..b93b16b
--- /dev/null
@@ -0,0 +1,491 @@
+// 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_TLV_TYPE 0x4450 // "PD" (Platform Data) in ascii little-endian
+#define WFX_PDS_MAX_CHUNK_SIZE 1500
+
+MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WF200");
+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;
+}
+
+/* The device needs data about the antenna configuration. This information in provided by PDS
+ * (Platform Data Set, this is the wording used in WF200 documentation) files. For hardware
+ * integrators, the full process to create PDS files is described here:
+ *   https://github.com/SiliconLabs/wfx-firmware/blob/master/PDS/README.md
+ *
+ * The PDS file is an array of Time-Length-Value structs.
+ */
+ int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len)
+{
+       int ret, chunk_type, chunk_len, chunk_num = 0;
+
+       if (*buf == '{') {
+               dev_err(wdev->dev, "PDS: malformed file (legacy format?)\n");
+               return -EINVAL;
+       }
+       while (len > 0) {
+               chunk_type = get_unaligned_le16(buf + 0);
+               chunk_len = get_unaligned_le16(buf + 2);
+               if (chunk_len > len) {
+                       dev_err(wdev->dev, "PDS:%d: corrupted file\n", chunk_num);
+                       return -EINVAL;
+               }
+               if (chunk_type != WFX_PDS_TLV_TYPE) {
+                       dev_info(wdev->dev, "PDS:%d: skip unknown data\n", chunk_num);
+                       goto next;
+               }
+               if (chunk_len > WFX_PDS_MAX_CHUNK_SIZE)
+                       dev_warn(wdev->dev, "PDS:%d: unexpectedly large chunk\n", chunk_num);
+               if (buf[4] != '{' || buf[chunk_len - 1] != '}')
+                       dev_warn(wdev->dev, "PDS:%d: unexpected content\n", chunk_num);
+
+               ret = wfx_hif_configuration(wdev, buf + 4, chunk_len - 4);
+               if (ret > 0) {
+                       dev_err(wdev->dev, "PDS:%d: invalid data (unsupported options?)\n", chunk_num);
+                       return -EINVAL;
+               }
+               if (ret == -ETIMEDOUT) {
+                       dev_err(wdev->dev, "PDS:%d: chip didn't reply (corrupted file?)\n", chunk_num);
+                       return ret;
+               }
+               if (ret) {
+                       dev_err(wdev->dev, "PDS:%d: chip returned an unknown error\n", chunk_num);
+                       return -EIO;
+               }
+next:
+               chunk_num++;
+               len -= chunk_len;
+               buf += chunk_len;
+       }
+       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 antenna parameters (PDS file %s). The device may be unstable.\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 wfx_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 wfx_hif_msg) + sizeof(struct wfx_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);
+       if (!hw->wiphy->bands[NL80211_BAND_2GHZ])
+               goto err;
+
+       /* 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, "silabs,antenna-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))
+               goto err;
+
+       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);
+
+       if (devm_add_action_or_reset(dev, wfx_free_common, wdev))
+               return NULL;
+
+       return wdev;
+
+err:
+       ieee80211_free_hw(hw);
+       return NULL;
+}
+
+int wfx_probe(struct wfx_dev *wdev)
+{
+       int i;
+       int err;
+       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 bh_unregister;
+
+       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 bh_unregister;
+       }
+
+       /* 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 = -EOPNOTSUPP;
+               goto bh_unregister;
+       }
+
+       if (wdev->hw_caps.link_mode == SEC_LINK_ENFORCED) {
+               dev_err(wdev->dev, "chip require secure_link, but can't negotiate it\n");
+               goto bh_unregister;
+       }
+
+       if (wdev->hw_caps.region_sel_mode) {
+               wdev->hw->wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
+               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 && err != -ENOENT)
+               goto bh_unregister;
+
+       wdev->poll_irq = false;
+       err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv);
+       if (err)
+               goto bh_unregister;
+
+       err = wfx_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);
+               wfx_control_reg_write(wdev, 0);
+               wfx_hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT);
+       } else {
+               wfx_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);
+               err = of_get_mac_address(wdev->dev->of_node, wdev->addresses[i].addr);
+               if (!err)
+                       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;
+
+       if (!wfx_api_older_than(wdev, 3, 8))
+               wdev->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
+       err = ieee80211_register_hw(wdev->hw);
+       if (err)
+               goto irq_unsubscribe;
+
+       err = wfx_debug_init(wdev);
+       if (err)
+               goto ieee80211_unregister;
+
+       return 0;
+
+ieee80211_unregister:
+       ieee80211_unregister_hw(wdev->hw);
+irq_unsubscribe:
+       wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv);
+bh_unregister:
+       wfx_bh_unregister(wdev);
+       return err;
+}
+
+void wfx_release(struct wfx_dev *wdev)
+{
+       ieee80211_unregister_hw(wdev->hw);
+       wfx_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 (file)
index 0000000..68c6653
--- /dev/null
@@ -0,0 +1,41 @@
+/* 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 wfx_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 wfx_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/net/wireless/silabs/wfx/queue.c b/drivers/net/wireless/silabs/wfx/queue.c
new file mode 100644 (file)
index 0000000..7298252
--- /dev/null
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Queue between the tx operation and the bh workqueue.
+ *
+ * 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];
+       }
+}
+
+bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue)
+{
+       return skb_queue_empty_lockless(&queue->normal) && skb_queue_empty_lockless(&queue->cab);
+}
+
+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(!wfx_tx_queue_empty(wvif, &wvif->tx_queue[i]));
+       }
+}
+
+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 wfx_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 wfx_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 wfx_hif_req_tx *req;
+       struct wfx_vif *wvif;
+       struct wfx_hif_msg *hif;
+       struct sk_buff *skb;
+
+       spin_lock_bh(&wdev->tx_pending.lock);
+       skb_queue_walk(&wdev->tx_pending, skb) {
+               hif = (struct wfx_hif_msg *)skb->data;
+               req = (struct wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 (file)
index 0000000..4731deb
--- /dev/null
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Queue between the tx operation and the bh workqueue.
+ *
+ * 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 wfx_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
diff --git a/drivers/net/wireless/silabs/wfx/scan.c b/drivers/net/wireless/silabs/wfx/scan.c
new file mode 100644 (file)
index 0000000..7f34f0d
--- /dev/null
@@ -0,0 +1,144 @@
+// 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 wfx_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);
+       wfx_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;
+       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 = wfx_hif_scan(wvif, req, start_idx, i - start_idx);
+       if (ret) {
+               wfx_tx_unlock(wvif->wdev);
+               return -EIO;
+       }
+       ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
+       if (!ret) {
+               wfx_hif_stop_scan(wvif);
+               ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
+               dev_dbg(wvif->wdev->dev, "scan timeout (%d channels done)\n",
+                       wvif->scan_nb_chan_done);
+       }
+       if (!ret) {
+               dev_err(wvif->wdev->dev, "scan didn't stop\n");
+               ret = -ETIMEDOUT;
+       } else if (wvif->scan_abort) {
+               dev_notice(wvif->wdev->dev, "scan abort\n");
+               ret = -ECONNABORTED;
+       } else if (wvif->scan_nb_chan_done > i - start_idx) {
+               ret = -EIO;
+       } else {
+               ret = wvif->scan_nb_chan_done;
+       }
+       if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower)
+               wfx_hif_set_output_power(wvif, wvif->vif->bss_conf.txpower);
+       wfx_tx_unlock(wvif->wdev);
+       return ret;
+}
+
+/* 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, err;
+
+       mutex_lock(&wvif->wdev->conf_mutex);
+       mutex_lock(&wvif->scan_lock);
+       if (wvif->join_in_progress) {
+               dev_info(wvif->wdev->dev, "abort in-progress REQ_JOIN");
+               wfx_reset(wvif);
+       }
+       update_probe_tmpl(wvif, &hw_req->req);
+       chan_cur = 0;
+       err = 0;
+       do {
+               ret = send_scan_req(wvif, &hw_req->req, chan_cur);
+               if (ret > 0) {
+                       chan_cur += ret;
+                       err = 0;
+               }
+               if (!ret)
+                       err++;
+               if (err > 2) {
+                       dev_err(wvif->wdev->dev, "scan has not been able to start\n");
+                       ret = -ETIMEDOUT;
+               }
+       } while (ret >= 0 && chan_cur < hw_req->req.n_channels);
+       mutex_unlock(&wvif->scan_lock);
+       mutex_unlock(&wvif->wdev->conf_mutex);
+       wfx_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;
+       wfx_hif_stop_scan(wvif);
+}
+
+void wfx_scan_complete(struct wfx_vif *wvif, int nb_chan_done)
+{
+       wvif->scan_nb_chan_done = nb_chan_done;
+       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 (file)
index 0000000..78e3b98
--- /dev/null
@@ -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, int nb_chan_done);
+
+#endif
diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c
new file mode 100644 (file)
index 0000000..b1e9fb1
--- /dev/null
@@ -0,0 +1,794 @@
+// 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;
+       /* The device only supports 2GHz */
+       struct ieee80211_supported_band *sband = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ];
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if (rates & BIT(i)) {
+                       if (i >= sband->n_bitrates)
+                               dev_warn(wdev->dev, "unsupported basic rate\n");
+                       else
+                               ret |= BIT(sband->bitrates[i].hw_value);
+               }
+       }
+       return ret;
+}
+
+void wfx_cooling_timeout_work(struct work_struct *work)
+{
+       struct wfx_dev *wdev = container_of(to_delayed_work(work), struct wfx_dev,
+                                           cooling_timeout_work);
+
+       wdev->chip_frozen = true;
+       wfx_tx_unlock(wdev);
+}
+
+void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd)
+{
+       if (cmd == STA_NOTIFY_AWAKE) {
+               /* Device recover normal temperature */
+               if (cancel_delayed_work(&wdev->cooling_timeout_work))
+                       wfx_tx_unlock(wdev);
+       } else {
+               /* Device is too hot */
+               schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ);
+               wfx_tx_lock(wdev);
+       }
+}
+
+static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon)
+{
+       static const struct wfx_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,
+               }, {
+                       .ie_id        = WLAN_EID_CHANNEL_SWITCH,
+                       .has_changed  = 1,
+                       .no_longer    = 1,
+                       .has_appeared = 1,
+               }
+       };
+
+       if (!filter_beacon) {
+               wfx_hif_beacon_filter_control(wvif, 0, 1);
+       } else {
+               wfx_hif_set_beacon_filter_table(wvif, ARRAY_SIZE(filter_ies), filter_ies);
+               wfx_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;
+               wfx_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 && wvif->vif->type != NL80211_IFTYPE_AP) {
+               if (chan0->hw_value == chan1->hw_value) {
+                       /* It is useless to enable PS if channels are the same. */
+                       if (enable_ps)
+                               *enable_ps = false;
+                       if (wvif->vif->bss_conf.assoc && wvif->vif->bss_conf.ps)
+                               dev_info(wvif->wdev->dev, "ignoring requested PS mode");
+                       return -1;
+               }
+               /* It is necessary to enable PS if channels are different. */
+               if (enable_ps)
+                       *enable_ps = true;
+               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->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 wfx_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);
+       wfx_hif_set_edca_queue_params(wvif, queue, params);
+       if (wvif->vif->type == NL80211_IFTYPE_STATION && old_uapsd != wvif->uapsd_mask) {
+               wfx_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)
+               wfx_hif_rts_threshold(wvif, value);
+       return 0;
+}
+
+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;
+
+       wfx_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);
+       wfx_hif_reset(wvif, false);
+       wfx_tx_policy_init(wvif);
+       if (wvif_count(wdev) <= 1)
+               wfx_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)
+               wfx_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);
+       wfx_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? */
+       wfx_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;
+       wfx_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;
+       wfx_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;
+               wfx_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 = wfx_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 = wfx_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;
+       wfx_hif_set_association_mode(wvif, ampdu_density, greenfield, info->use_short_preamble);
+       wfx_hif_keep_alive_period(wvif, 0);
+       /* beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use the same value. */
+       wfx_hif_set_bss_params(wvif, info->aid, 7);
+       wfx_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);
+       }
+       wfx_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, "misunderstood change: ASSOC\n");
+       }
+
+       if (changed & BSS_CHANGED_BEACON_INFO) {
+               if (vif->type != NL80211_IFTYPE_STATION)
+                       dev_warn(wdev->dev, "misunderstood change: BEACON_INFO\n");
+               wfx_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;
+                       wfx_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)
+               wfx_hif_keep_alive_period(wvif,
+                                         info->max_idle_period * USEC_PER_TU / USEC_PER_MSEC);
+
+       if (changed & BSS_CHANGED_ERP_CTS_PROT)
+               wfx_hif_erp_use_protection(wvif, info->use_cts_prot);
+
+       if (changed & BSS_CHANGED_ERP_SLOT)
+               wfx_hif_slot_time(wvif, info->use_short_slot ? 9 : 20);
+
+       if (changed & BSS_CHANGED_CQM)
+               wfx_hif_set_rcpi_rssi_threshold(wvif, info->cqm_rssi_thold, info->cqm_rssi_hyst);
+
+       if (changed & BSS_CHANGED_TXPOWER)
+               wfx_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) {
+               /* Firmware handles DTIM counter 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;
+       }
+
+       wfx_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)
+{
+       struct wfx_vif *wvif_it;
+
+       if (notify_cmd != STA_NOTIFY_AWAKE)
+               return;
+
+       /* Device won't be able to honor CAB if a scan is in progress on any interface. Prefer to
+        * skip this DTIM and wait for the next one.
+        */
+       wvif_it = NULL;
+       while ((wvif_it = wvif_iterate(wvif->wdev, wvif_it)) != NULL)
+               if (mutex_is_locked(&wvif_it->scan_lock))
+                       return;
+
+       if (!wfx_tx_queues_has_cab(wvif) || wvif->after_dtim_tx_allowed)
+               dev_warn(wvif->wdev->dev, "incorrect sequence (%d CAB in queue)",
+                        wfx_tx_queues_has_cab(wvif));
+       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 -EOPNOTSUPP;
+       }
+}
+
+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;
+       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");
+
+       wfx_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)
+                       wfx_hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
+               else
+                       wfx_hif_set_block_ack_policy(wvif, 0x00, 0x00);
+       }
+       return 0;
+}
+
+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");
+
+       wfx_hif_reset(wvif, false);
+       wfx_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)
+                       wfx_hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
+               else
+                       wfx_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 (file)
index 0000000..c69b222
--- /dev/null
@@ -0,0 +1,66 @@
+/* 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);
+
+/* Hardware API 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
diff --git a/drivers/net/wireless/silabs/wfx/traces.h b/drivers/net/wireless/silabs/wfx/traces.h
new file mode 100644 (file)
index 0000000..e011e8a
--- /dev/null
@@ -0,0 +1,496 @@
+/* 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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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/net/wireless/silabs/wfx/wfx.h b/drivers/net/wireless/silabs/wfx/wfx.h
new file mode 100644 (file)
index 0000000..6594cc6
--- /dev/null
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Common private data.
+ *
+ * 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 wfx_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 wfx_hwbus_ops *hwbus_ops;
+       void                       *hwbus_priv;
+
+       u8                         keyset;
+       struct completion          firmware_ready;
+       struct wfx_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 wfx_hif_rx_stats    rx_stats;
+       struct mutex               rx_stats_lock;
+       struct wfx_hif_tx_power_loop_info tx_power_loop_info;
+       struct mutex               tx_power_loop_info_lock;
+};
+
+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 wfx_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;
+       int                        scan_nb_chan_done;
+       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])
+               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
index 932acb4..fc27473 100644 (file)
@@ -86,6 +86,5 @@ source "drivers/staging/fieldbus/Kconfig"
 
 source "drivers/staging/qlge/Kconfig"
 
-source "drivers/staging/wfx/Kconfig"
 
 endif # STAGING
index 3ffb35c..65e3179 100644 (file)
@@ -33,4 +33,3 @@ obj-$(CONFIG_PI433)           += pi433/
 obj-$(CONFIG_XIL_AXIS_FIFO)    += axis-fifo/
 obj-$(CONFIG_FIELDBUS_DEV)     += fieldbus/
 obj-$(CONFIG_QLGE)             += qlge/
-obj-$(CONFIG_WFX)              += wfx/
diff --git a/drivers/staging/wfx/Kconfig b/drivers/staging/wfx/Kconfig
deleted file mode 100644 (file)
index 835a855..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config WFX
-       tristate "Silicon Labs wireless chips WF200 and further"
-       depends on MAC80211
-       depends on MMC || !MMC # do not allow WFX=y if MMC=m
-       depends on (SPI || MMC)
-       help
-         This is a driver for Silicons Labs WFxxx series (WF200 and further)
-         chipsets. This chip can be found on SPI or SDIO buses.
-
-         Silabs does not use a reliable SDIO vendor ID. So, to avoid conflicts,
-         the driver won't probe the device if it is not also declared in the
-         Device Tree.
diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
deleted file mode 100644 (file)
index c8b356f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-
-# 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 \
-       debug.o
-wfx-$(CONFIG_SPI) += bus_spi.o
-# When CONFIG_MMC == m, append to 'wfx-y' (and not to 'wfx-m')
-wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
-
-obj-$(CONFIG_WFX) += wfx.o
diff --git a/drivers/staging/wfx/TODO b/drivers/staging/wfx/TODO
deleted file mode 100644 (file)
index 1b4bc2a..0000000
+++ /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/
-
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
deleted file mode 100644 (file)
index bcea9d5..0000000
+++ /dev/null
@@ -1,324 +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 wfx_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), "request exceed the chip capability");
-
-       /* 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 wfx_hif_msg *)skb->data;
-       WARN(hif->encrypted & 0x3, "encryption is unsupported");
-       if (WARN(read_len < sizeof(struct wfx_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 wfx_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 wfx_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 > le16_to_cpu(wdev->hw_caps.size_inp_ch_buf),
-            "request exceed the chip capability: %zu > %d\n",
-            len, le16_to_cpu(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 wfx_hif_msg *hif;
-       int i;
-
-       for (i = 0; i < max_msg; i++) {
-               hif = NULL;
-               if (wdev->hif.tx_buffers_used < le16_to_cpu(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;
-
-       wfx_config_reg_read(wdev, &cfg_reg);
-       if (cfg_reg & 0xFF) {
-               dev_warn(wdev->dev, "chip reports errors: %02x\n", cfg_reg & 0xFF);
-               wfx_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;
-
-       wfx_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");
-       flush_workqueue(system_highpri_wq);
-       start = ktime_get();
-       for (;;) {
-               wfx_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 (file)
index a44c8b4..0000000
+++ /dev/null
@@ -1,34 +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
- */
-#ifndef WFX_BH_H
-#define WFX_BH_H
-
-#include <linux/atomic.h>
-#include <linux/wait.h>
-#include <linux/completion.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
diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h
deleted file mode 100644 (file)
index ccadfdd..0000000
+++ /dev/null
@@ -1,36 +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 wfx_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 (file)
index 51a0d58..0000000
+++ /dev/null
@@ -1,273 +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_device.h>
-#include <linux/of_irq.h>
-#include <linux/irq.h>
-#include <linux/align.h>
-
-#include "bus.h"
-#include "wfx.h"
-#include "hwio.h"
-#include "main.h"
-#include "bh.h"
-
-static const struct wfx_platform_data pdata_wf200 = {
-       .file_fw = "wfx/wfm_wf200",
-       .file_pds = "wfx/wf200.pds",
-};
-
-static const struct wfx_platform_data pdata_brd4001a = {
-       .file_fw = "wfx/wfm_wf200",
-       .file_pds = "wfx/brd4001a.pds",
-};
-
-static const struct wfx_platform_data pdata_brd8022a = {
-       .file_fw = "wfx/wfm_wf200",
-       .file_pds = "wfx/brd8022a.pds",
-};
-
-static const struct wfx_platform_data pdata_brd8023a = {
-       .file_fw = "wfx/wfm_wf200",
-       .file_pds = "wfx/brd8023a.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(!IS_ALIGNED((uintptr_t)dst, 4), "unaligned buffer address");
-       WARN(!IS_ALIGNED(count, 4), "unaligned buffer size");
-
-       /* 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(!IS_ALIGNED((uintptr_t)src, 4), "unaligned buffer address");
-       WARN(!IS_ALIGNED(count, 4), "unaligned buffer size");
-
-       /* 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;
-       }
-
-       flags = irq_get_trigger_type(bus->of_irq);
-       if (!flags)
-               flags = IRQF_TRIGGER_HIGH;
-       flags |= IRQF_ONESHOT;
-       ret = devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL,
-                                       wfx_sdio_irq_handler_ext, flags, "wfx", bus);
-       if (ret)
-               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);
-       return 0;
-}
-
-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 wfx_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,wf200",    .data = &pdata_wf200 },
-       { .compatible = "silabs,brd4001a", .data = &pdata_brd4001a },
-       { .compatible = "silabs,brd8022a", .data = &pdata_brd8022a },
-       { .compatible = "silabs,brd8023a", .data = &pdata_brd8023a },
-       { },
-};
-MODULE_DEVICE_TABLE(of, wfx_sdio_of_match);
-
-static int wfx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
-{
-       const struct wfx_platform_data *pdata = of_device_get_match_data(&func->dev);
-       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;
-       }
-
-       if (!pdata) {
-               dev_warn(&func->dev, "no compatible device found in DT\n");
-               return -ENODEV;
-       }
-
-       bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL);
-       if (!bus)
-               return -ENOMEM;
-
-       bus->func = func;
-       bus->of_irq = irq_of_parse_and_map(np, 0);
-       sdio_set_drvdata(func, bus);
-
-       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)
-               return ret;
-
-       bus->core = wfx_init_common(&func->dev, pdata, &wfx_sdio_hwbus_ops, bus);
-       if (!bus->core) {
-               ret = -EIO;
-               goto sdio_release;
-       }
-
-       ret = wfx_probe(bus->core);
-       if (ret)
-               goto sdio_release;
-
-       return 0;
-
-sdio_release:
-       sdio_claim_host(func);
-       sdio_disable_func(func);
-       sdio_release_host(func);
-       return ret;
-}
-
-static void wfx_sdio_remove(struct sdio_func *func)
-{
-       struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
-
-       wfx_release(bus->core);
-       sdio_claim_host(func);
-       sdio_disable_func(func);
-       sdio_release_host(func);
-}
-
-static const struct sdio_device_id wfx_sdio_ids[] = {
-       /* WF200 does not have official VID/PID */
-       { SDIO_DEVICE(0x0000, 0x1000) },
-       { },
-};
-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 (file)
index 7fb1afb..0000000
+++ /dev/null
@@ -1,284 +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 */
-
-static const struct wfx_platform_data pdata_wf200 = {
-       .file_fw = "wfx/wfm_wf200",
-       .file_pds = "wfx/wf200.pds",
-       .use_rising_clk = true,
-};
-
-static const struct wfx_platform_data pdata_brd4001a = {
-       .file_fw = "wfx/wfm_wf200",
-       .file_pds = "wfx/brd4001a.pds",
-       .use_rising_clk = true,
-};
-
-static const struct wfx_platform_data pdata_brd8022a = {
-       .file_fw = "wfx/wfm_wf200",
-       .file_pds = "wfx/brd8022a.pds",
-       .use_rising_clk = true,
-};
-
-static const struct wfx_platform_data pdata_brd8023a = {
-       .file_fw = "wfx/wfm_wf200",
-       .file_pds = "wfx/brd8023a.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;
-};
-
-/* The chip reads 16bits of data at time and place them directly into (little endian) CPU register.
- * So, the chip expects bytes order to be "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, flags, "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 wfx_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_platform_data *pdata;
-       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;
-       pdata = (struct wfx_platform_data *)spi_get_device_id(func)->driver_data;
-       if (!pdata) {
-               dev_err(&func->dev, "unable to retrieve driver data (please report)\n");
-               return -ENODEV;
-       }
-
-       /* 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");
-               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, pdata, &wfx_spi_hwbus_ops, bus);
-       if (!bus->core)
-               return -EIO;
-
-       return wfx_probe(bus->core);
-}
-
-static void wfx_spi_remove(struct spi_device *func)
-{
-       struct wfx_spi_priv *bus = spi_get_drvdata(func);
-
-       wfx_release(bus->core);
-}
-
-/* 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[] = {
-       { "wf200",    (kernel_ulong_t)&pdata_wf200 },
-       { "brd4001a", (kernel_ulong_t)&pdata_brd4001a },
-       { "brd8022a", (kernel_ulong_t)&pdata_brd8022a },
-       { "brd8023a", (kernel_ulong_t)&pdata_brd8023a },
-       { },
-};
-MODULE_DEVICE_TABLE(spi, wfx_spi_id);
-
-#ifdef CONFIG_OF
-static const struct of_device_id wfx_spi_of_match[] = {
-       { .compatible = "silabs,wf200" },
-       { .compatible = "silabs,brd4001a" },
-       { .compatible = "silabs,brd8022a" },
-       { .compatible = "silabs,brd8023a" },
-       { },
-};
-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 (file)
index a4b5ffe..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Data receiving 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 wfx_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 (file)
index cf708f1..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Data receiving 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 wfx_hif_ind_rx;
-
-void wfx_rx_cb(struct wfx_vif *wvif, const struct wfx_hif_ind_rx *arg, struct sk_buff *skb);
-
-#endif
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
deleted file mode 100644 (file)
index e07381b..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Data transmitting 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;
-       }
-       /* The device only support 2GHz, else band information should be retrieved from
-        * ieee80211_tx_info
-        */
-       band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ];
-       if (rate->idx >= band->n_bitrates) {
-               WARN(1, "wrong rate->idx value: %d", rate->idx);
-               return -1;
-       }
-       return band->bitrates[rate->idx].hw_value;
-}
-
-/* TX policy cache implementation */
-
-static void wfx_tx_policy_build(struct wfx_vif *wvif, struct wfx_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 wfx_tx_policy_is_equal(const struct wfx_tx_policy *a, const struct wfx_tx_policy *b)
-{
-       return !memcmp(a->rates, b->rates, sizeof(a->rates));
-}
-
-static int wfx_tx_policy_find(struct wfx_tx_policy_cache *cache, struct wfx_tx_policy *wanted)
-{
-       struct wfx_tx_policy *it;
-
-       list_for_each_entry(it, &cache->used, link)
-               if (wfx_tx_policy_is_equal(wanted, it))
-                       return it - cache->cache;
-       list_for_each_entry(it, &cache->free, link)
-               if (wfx_tx_policy_is_equal(wanted, it))
-                       return it - cache->cache;
-       return -1;
-}
-
-static void wfx_tx_policy_use(struct wfx_tx_policy_cache *cache, struct wfx_tx_policy *entry)
-{
-       ++entry->usage_count;
-       list_move(&entry->link, &cache->used);
-}
-
-static int wfx_tx_policy_release(struct wfx_tx_policy_cache *cache, struct wfx_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 wfx_tx_policy_cache *cache = &wvif->tx_policy_cache;
-       struct wfx_tx_policy wanted;
-       struct wfx_tx_policy *entry;
-
-       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 {
-               /* If policy is not found create a new one using the oldest entry in "free" list */
-               *renew = true;
-               entry = list_entry(cache->free.prev, struct wfx_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 wfx_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 wfx_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);
-                       wfx_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 wfx_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 wfx_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_retry_policy_id(struct wfx_vif *wvif, struct ieee80211_tx_info *tx_info)
-{
-       bool tx_policy_renew = false;
-       u8 ret;
-
-       ret = wfx_tx_policy_get(wvif, tx_info->driver_rates, &tx_policy_renew);
-       if (ret == 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 ret;
-}
-
-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 wfx_hif_msg *hif_msg;
-       struct wfx_hif_req_tx *req;
-       struct wfx_tx_priv *tx_priv;
-       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 wfx_hif_msg) + sizeof(struct wfx_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 tx_priv */
-       tx_priv = (struct wfx_tx_priv *)tx_info->rate_driver_data;
-       tx_priv->icv_size = wfx_tx_get_icv_len(hw_key);
-
-       /* 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, tx_priv->icv_size);
-       skb_push(skb, wmsg_len);
-       memset(skb->data, 0, wmsg_len);
-       hif_msg = (struct wfx_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 > le16_to_cpu(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, le16_to_cpu(wvif->wdev->hw_caps.size_inp_ch_buf));
-               skb_pull(skb, wmsg_len);
-               return -EIO;
-       }
-
-       /* Fill tx request */
-       req = (struct wfx_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 take 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;
-       /* Queue index are inverted between firmware and Linux */
-       req->queue_id = 3 - queue_id;
-       req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr);
-       req->retry_policy_index = wfx_tx_get_retry_policy_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;
-       if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)
-               req->after_dtim = 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);
-
-       BUILD_BUG_ON_MSG(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 (wfx_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 wfx_hif_msg *hif = (struct wfx_hif_msg *)skb->data;
-       struct wfx_hif_req_tx *req = (struct wfx_hif_req_tx *)hif->body;
-       unsigned int offset = sizeof(struct wfx_hif_msg) + sizeof(struct wfx_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 wfx_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 wfx_hif_cnf_tx *arg)
-{
-       const struct wfx_tx_priv *tx_priv;
-       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);
-       tx_priv = wfx_skb_tx_priv(skb);
-       wvif = wdev_to_wvif(wdev, ((struct wfx_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);
-       skb_trim(skb, skb->len - tx_priv->icv_size);
-
-       /* 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 wfx_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 wfx_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 (file)
index 9834707..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Data transmitting 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 wfx_tx_policy {
-       struct list_head link;
-       int usage_count;
-       u8 rates[12];
-       bool uploaded;
-};
-
-struct wfx_tx_policy_cache {
-       struct wfx_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;
-       unsigned char icv_size;
-};
-
-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 wfx_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 wfx_hif_req_tx *wfx_skb_txreq(struct sk_buff *skb)
-{
-       struct wfx_hif_msg *hif = (struct wfx_hif_msg *)skb->data;
-       struct wfx_hif_req_tx *req = (struct wfx_hif_req_tx *)hif->body;
-
-       return req;
-}
-
-#endif
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
deleted file mode 100644 (file)
index e826520..0000000
+++ /dev/null
@@ -1,331 +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 *wfx_get_hif_name(unsigned long id)
-{
-       return get_symbol(id, hif_msg_print_map);
-}
-
-const char *wfx_get_mib_name(unsigned long id)
-{
-       return get_symbol(id, hif_mib_print_map);
-}
-
-const char *wfx_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 wfx_hif_mib_extended_count_table counters[3];
-
-       for (i = 0; i < ARRAY_SIZE(counters); i++) {
-               ret = wfx_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_frames);
-       PUT_COUNTER(tx_frames_multicast);
-       PUT_COUNTER(tx_frames_success);
-       PUT_COUNTER(tx_frames_retried);
-       PUT_COUNTER(tx_frames_multi_retried);
-       PUT_COUNTER(tx_frames_failed);
-
-       PUT_COUNTER(ack_failed);
-       PUT_COUNTER(rts_success);
-       PUT_COUNTER(rts_failed);
-
-       PUT_COUNTER(rx_frames);
-       PUT_COUNTER(rx_frames_multicast);
-       PUT_COUNTER(rx_frames_success);
-       PUT_COUNTER(rx_frames_failed);
-       PUT_COUNTER(drop_plcp);
-       PUT_COUNTER(drop_fcs);
-       PUT_COUNTER(drop_no_key);
-       PUT_COUNTER(drop_decryption);
-       PUT_COUNTER(drop_tkip_mic);
-       PUT_COUNTER(drop_bip_mic);
-       PUT_COUNTER(drop_cmac_icv);
-       PUT_COUNTER(drop_cmac_replay);
-       PUT_COUNTER(drop_ccmp_replay);
-       PUT_COUNTER(drop_duplicate);
-
-       PUT_COUNTER(rx_bcn_miss);
-       PUT_COUNTER(rx_bcn_success);
-       PUT_COUNTER(rx_bcn_dtim);
-       PUT_COUNTER(rx_bcn_dtim_aid0_clr);
-       PUT_COUNTER(rx_bcn_dtim_aid0_set);
-
-#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 wfx_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 wfx_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 wfx_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 wfx_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,
-};
-
-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);
-
-       return 0;
-}
diff --git a/drivers/staging/wfx/debug.h b/drivers/staging/wfx/debug.h
deleted file mode 100644 (file)
index 3840575..0000000
+++ /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 *wfx_get_hif_name(unsigned long id);
-const char *wfx_get_mib_name(unsigned long id);
-const char *wfx_get_reg_name(unsigned long id);
-
-#endif
diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c
deleted file mode 100644 (file)
index 3d1b8a1..0000000
+++ /dev/null
@@ -1,389 +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 wfx_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 = wfx_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 = wfx_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 = wfx_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 = wfx_sram_write_dma_safe(wdev, WFX_DNLD_FIFO + (offs % DNLD_FIFO_SIZE),
-                                             data + offs, DNLD_BLOCK_SIZE);
-               if (ret < 0)
-                       return ret;
-
-               /* The device seems to not support writing 0 in this register during first loop */
-               offs += DNLD_BLOCK_SIZE;
-               ret = wfx_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;
-
-       wfx_sram_reg_read(wdev, WFX_STATUS_INFO, &reg);
-       if (reg == 0x12345678)
-               return;
-       wfx_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;
-
-       wfx_sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_READY);
-       ret = wait_ncp_status(wdev, NCP_INFO_READY);
-       if (ret)
-               goto error;
-
-       wfx_sram_buf_read(wdev, WFX_BOOTLOADER_LABEL, buf, BOOTLOADER_LABEL_SIZE);
-       buf[BOOTLOADER_LABEL_SIZE] = 0;
-       dev_dbg(wdev->dev, "bootloader: \"%s\"\n", buf);
-
-       wfx_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;
-
-       wfx_sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_INFO_READ);
-       ret = wait_ncp_status(wdev, NCP_READY);
-       if (ret)
-               goto error;
-
-       wfx_sram_reg_write(wdev, WFX_DNLD_FIFO, 0xFFFFFFFF); /* Fifo init */
-       wfx_sram_write_dma_safe(wdev, WFX_DCA_FW_VERSION, "\x01\x00\x00\x00", FW_VERSION_SIZE);
-       wfx_sram_write_dma_safe(wdev, WFX_DCA_FW_SIGNATURE, fw->data + fw_offset,
-                               FW_SIGNATURE_SIZE);
-       wfx_sram_write_dma_safe(wdev, WFX_DCA_FW_HASH, fw->data + fw_offset + FW_SIGNATURE_SIZE,
-                               FW_HASH_SIZE);
-       wfx_sram_reg_write(wdev, WFX_DCA_IMAGE_SIZE, fw->size - header_size);
-       wfx_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));
-
-       wfx_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;
-       wfx_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 = wfx_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 = wfx_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 = wfx_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 = wfx_control_reg_write(wdev, CTRL_WLAN_WAKEUP);
-       if (ret < 0)
-               return -EIO;
-       start = ktime_get();
-       for (;;) {
-               ret = wfx_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 = wfx_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 wfx_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 (file)
index eeea612..0000000
+++ /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
diff --git a/drivers/staging/wfx/hif_api_cmd.h b/drivers/staging/wfx/hif_api_cmd.h
deleted file mode 100644 (file)
index 8b91b1d..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only or Apache-2.0 */
-/*
- * WF200 hardware interface definitions
- *
- * Copyright (c) 2018-2020, Silicon Laboratories Inc.
- */
-
-#ifndef WFX_HIF_API_CMD_H
-#define WFX_HIF_API_CMD_H
-
-#include "hif_api_general.h"
-
-enum wfx_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 wfx_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 wfx_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 wfx_hif_req_reset {
-       u8     reset_stat:1;
-       u8     reset_all_int:1;
-       u8     reserved1:6;
-       u8     reserved2[3];
-} __packed;
-
-struct wfx_hif_cnf_reset {
-       __le32 status;
-} __packed;
-
-struct wfx_hif_req_read_mib {
-       __le16 mib_id;
-       __le16 reserved;
-} __packed;
-
-struct wfx_hif_cnf_read_mib {
-       __le32 status;
-       __le16 mib_id;
-       __le16 length;
-       u8     mib_data[];
-} __packed;
-
-struct wfx_hif_req_write_mib {
-       __le16 mib_id;
-       __le16 length;
-       u8     mib_data[];
-} __packed;
-
-struct wfx_hif_cnf_write_mib {
-       __le32 status;
-} __packed;
-
-struct wfx_hif_req_update_ie {
-       u8     beacon:1;
-       u8     probe_resp:1;
-       u8     probe_req:1;
-       u8     reserved1:5;
-       u8     reserved2;
-       __le16 num_ies;
-       u8     ie[];
-} __packed;
-
-struct wfx_hif_cnf_update_ie {
-       __le32 status;
-} __packed;
-
-struct wfx_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 wfx_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 wfx_hif_ssid_def ssid_def[HIF_API_MAX_NB_SSIDS];
-       u8     channel_list[];
-} __packed;
-
-struct wfx_hif_cnf_start_scan {
-       __le32 status;
-} __packed;
-
-struct wfx_hif_cnf_stop_scan {
-       __le32 status;
-} __packed;
-
-enum wfx_hif_pm_mode_status {
-       HIF_PM_MODE_ACTIVE                         = 0x0,
-       HIF_PM_MODE_PS                             = 0x1,
-       HIF_PM_MODE_UNDETERMINED                   = 0x2
-};
-
-struct wfx_hif_ind_scan_cmpl {
-       __le32 status;
-       u8     pm_mode;
-       u8     num_channels_completed;
-       __le16 reserved;
-} __packed;
-
-enum wfx_hif_queue_id {
-       HIF_QUEUE_ID_BACKGROUND                    = 0x0,
-       HIF_QUEUE_ID_BESTEFFORT                    = 0x1,
-       HIF_QUEUE_ID_VIDEO                         = 0x2,
-       HIF_QUEUE_ID_VOICE                         = 0x3
-};
-
-enum wfx_hif_frame_format {
-       HIF_FRAME_FORMAT_NON_HT                    = 0x0,
-       HIF_FRAME_FORMAT_MIXED_FORMAT_HT           = 0x1,
-       HIF_FRAME_FORMAT_GF_HT_11N                 = 0x2
-};
-
-struct wfx_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 wfx_hif_qos_ackplcy {
-       HIF_QOS_ACKPLCY_NORMAL                         = 0x0,
-       HIF_QOS_ACKPLCY_TXNOACK                        = 0x1,
-       HIF_QOS_ACKPLCY_NOEXPACK                       = 0x2,
-       HIF_QOS_ACKPLCY_BLCKACK                        = 0x3
-};
-
-struct wfx_hif_cnf_tx {
-       __le32 status;
-       /* packet_id is copied from struct wfx_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 wfx_hif_cnf_multi_transmit {
-       u8     num_tx_confs;
-       u8     reserved[3];
-       struct wfx_hif_cnf_tx tx_conf_payload[];
-} __packed;
-
-enum wfx_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 wfx_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 wfx_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 wfx_hif_cnf_edca_queue_params {
-       __le32 status;
-} __packed;
-
-struct wfx_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 wfx_hif_cnf_join {
-       __le32 status;
-} __packed;
-
-struct wfx_hif_ind_join_complete {
-       __le32 status;
-} __packed;
-
-struct wfx_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 wfx_hif_cnf_set_bss_params {
-       __le32 status;
-} __packed;
-
-struct wfx_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 wfx_hif_cnf_set_pm_mode {
-       __le32 status;
-} __packed;
-
-struct wfx_hif_ind_set_pm_mode_cmpl {
-       __le32 status;
-       u8     pm_mode;
-       u8     reserved[3];
-} __packed;
-
-struct wfx_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 wfx_hif_cnf_start {
-       __le32 status;
-} __packed;
-
-struct wfx_hif_req_beacon_transmit {
-       u8     enable_beaconing;
-       u8     reserved[3];
-} __packed;
-
-struct wfx_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 wfx_hif_req_map_link {
-       u8     mac_addr[ETH_ALEN];
-       u8     unmap:1;
-       u8     mfpc:1;
-       u8     reserved:6;
-       u8     peer_sta_id;
-} __packed;
-
-struct wfx_hif_cnf_map_link {
-       __le32 status;
-} __packed;
-
-struct wfx_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 wfx_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 wfx_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 wfx_hif_wep_group_key {
-       u8     key_id;
-       u8     key_length;
-       u8     reserved[2];
-       u8     key_data[HIF_API_WEP_KEY_DATA_SIZE];
-} __packed;
-
-struct wfx_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 wfx_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 wfx_hif_aes_pairwise_key {
-       u8     peer_address[ETH_ALEN];
-       u8     reserved[2];
-       u8     aes_key_data[HIF_API_AES_KEY_DATA_SIZE];
-} __packed;
-
-struct wfx_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 wfx_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 wfx_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 wfx_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 wfx_hif_req_add_key {
-       u8     type;
-       u8     entry_index;
-       u8     int_id:2;
-       u8     reserved1:6;
-       u8     reserved2;
-       union {
-               struct wfx_hif_wep_pairwise_key  wep_pairwise_key;
-               struct wfx_hif_wep_group_key     wep_group_key;
-               struct wfx_hif_tkip_pairwise_key tkip_pairwise_key;
-               struct wfx_hif_tkip_group_key    tkip_group_key;
-               struct wfx_hif_aes_pairwise_key  aes_pairwise_key;
-               struct wfx_hif_aes_group_key     aes_group_key;
-               struct wfx_hif_wapi_pairwise_key wapi_pairwise_key;
-               struct wfx_hif_wapi_group_key    wapi_group_key;
-               struct wfx_hif_igtk_group_key    igtk_group_key;
-       } key;
-} __packed;
-
-struct wfx_hif_cnf_add_key {
-       __le32 status;
-} __packed;
-
-struct wfx_hif_req_remove_key {
-       u8     entry_index;
-       u8     reserved[3];
-} __packed;
-
-struct wfx_hif_cnf_remove_key {
-       __le32 status;
-} __packed;
-
-enum wfx_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 wfx_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 wfx_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 (file)
index 4d400fd..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only or Apache-2.0 */
-/*
- * WF200 hardware interface definitions
- *
- * Copyright (c) 2018-2020, Silicon Laboratories Inc.
- */
-
-#ifndef WFX_HIF_API_GENERAL_H
-#define WFX_HIF_API_GENERAL_H
-
-#include <linux/types.h>
-#include <linux/if_ether.h>
-
-#define HIF_ID_IS_INDICATION      0x80
-#define HIF_COUNTER_MAX           7
-
-struct wfx_hif_msg {
-       __le16 len;
-       u8     id;
-       u8     reserved:1;
-       u8     interface:2;
-       u8     seqnum:3;
-       u8     encrypted:2;
-       u8     body[];
-} __packed;
-
-enum wfx_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 wfx_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 wfx_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 wfx_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
-};
-
-struct wfx_hif_ind_startup {
-       __le32 status;
-       __le16 hardware_id;
-       u8     opn[14];
-       u8     uid[8];
-       __le16 num_inp_ch_bufs;
-       __le16 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;
-       __le32 supported_rate_mask;
-       u8     firmware_label[128];
-} __packed;
-
-struct wfx_hif_ind_wakeup {
-} __packed;
-
-struct wfx_hif_req_configuration {
-       __le16 length;
-       u8     pds_data[];
-} __packed;
-
-struct wfx_hif_cnf_configuration {
-       __le32 status;
-} __packed;
-
-enum wfx_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 wfx_hif_req_control_gpio {
-       u8     gpio_label;
-       u8     gpio_mode;
-} __packed;
-
-struct wfx_hif_cnf_control_gpio {
-       __le32 status;
-       __le32 value;
-} __packed;
-
-enum wfx_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 wfx_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 wfx_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 wfx_hif_ind_generic {
-       __le32 type;
-       union {
-               struct wfx_hif_rx_stats rx_stats;
-               struct wfx_hif_tx_power_loop_info tx_power_loop_info;
-       } data;
-} __packed;
-
-enum wfx_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 wfx_hif_ind_error {
-       __le32 type;
-       u8     data[];
-} __packed;
-
-struct wfx_hif_ind_exception {
-       __le32 type;
-       u8     data[];
-} __packed;
-
-enum wfx_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 (file)
index 7b68b83..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only or Apache-2.0 */
-/*
- * WF200 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 wfx_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 wfx_hif_op_power_mode {
-       HIF_OP_POWER_MODE_ACTIVE    = 0x0,
-       HIF_OP_POWER_MODE_DOZE      = 0x1,
-       HIF_OP_POWER_MODE_QUIESCENT = 0x2
-};
-
-struct wfx_hif_mib_gl_operational_power_mode {
-       u8     power_mode:4;
-       u8     reserved1:3;
-       u8     wup_ind_activation:1;
-       u8     reserved2[3];
-} __packed;
-
-struct wfx_hif_mib_gl_set_multi_msg {
-       u8     enable_multi_tx_conf:1;
-       u8     reserved1:7;
-       u8     reserved2[3];
-} __packed;
-
-enum wfx_hif_arp_ns_frame_treatment {
-       HIF_ARP_NS_FILTERING_DISABLE = 0x0,
-       HIF_ARP_NS_FILTERING_ENABLE  = 0x1,
-       HIF_ARP_NS_REPLY_ENABLE      = 0x2
-};
-
-struct wfx_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 wfx_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 wfx_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 wfx_hif_mib_bcn_filter_table {
-       __le32 num_of_info_elmts;
-       struct wfx_hif_ie_table_entry ie_table[];
-} __packed;
-
-enum wfx_hif_beacon_filter {
-       HIF_BEACON_FILTER_DISABLE  = 0x0,
-       HIF_BEACON_FILTER_ENABLE   = 0x1,
-       HIF_BEACON_FILTER_AUTO_ERP = 0x2
-};
-
-struct wfx_hif_mib_bcn_filter_enable {
-       __le32 enable;
-       __le32 bcn_count;
-} __packed;
-
-struct wfx_hif_mib_extended_count_table {
-       __le32 count_drop_plcp;
-       __le32 count_drop_fcs;
-       __le32 count_tx_frames;
-       __le32 count_rx_frames;
-       __le32 count_rx_frames_failed;
-       __le32 count_drop_decryption;
-       __le32 count_drop_tkip_mic;
-       __le32 count_drop_no_key;
-       __le32 count_tx_frames_multicast;
-       __le32 count_tx_frames_success;
-       __le32 count_tx_frames_failed;
-       __le32 count_tx_frames_retried;
-       __le32 count_tx_frames_multi_retried;
-       __le32 count_drop_duplicate;
-       __le32 count_rts_success;
-       __le32 count_rts_failed;
-       __le32 count_ack_failed;
-       __le32 count_rx_frames_multicast;
-       __le32 count_rx_frames_success;
-       __le32 count_drop_cmac_icv;
-       __le32 count_drop_cmac_replay;
-       __le32 count_drop_ccmp_replay;
-       __le32 count_drop_bip_mic;
-       __le32 count_rx_bcn_success;
-       __le32 count_rx_bcn_miss;
-       __le32 count_rx_bcn_dtim;
-       __le32 count_rx_bcn_dtim_aid0_clr;
-       __le32 count_rx_bcn_dtim_aid0_set;
-       __le32 reserved[12];
-} __packed;
-
-struct wfx_hif_mib_count_table {
-       __le32 count_drop_plcp;
-       __le32 count_drop_fcs;
-       __le32 count_tx_frames;
-       __le32 count_rx_frames;
-       __le32 count_rx_frames_failed;
-       __le32 count_drop_decryption;
-       __le32 count_drop_tkip_mic;
-       __le32 count_drop_no_key;
-       __le32 count_tx_frames_multicast;
-       __le32 count_tx_frames_success;
-       __le32 count_tx_frames_failed;
-       __le32 count_tx_frames_retried;
-       __le32 count_tx_frames_multi_retried;
-       __le32 count_drop_duplicate;
-       __le32 count_rts_success;
-       __le32 count_rts_failed;
-       __le32 count_ack_failed;
-       __le32 count_rx_frames_multicast;
-       __le32 count_rx_frames_success;
-       __le32 count_drop_cmac_icv;
-       __le32 count_drop_cmac_replay;
-       __le32 count_drop_ccmp_replay;
-       __le32 count_drop_bip_mic;
-} __packed;
-
-struct wfx_hif_mib_mac_address {
-       u8     mac_addr[ETH_ALEN];
-       __le16 reserved;
-} __packed;
-
-struct wfx_hif_mib_wep_default_key_id {
-       u8     wep_default_key_id;
-       u8     reserved[3];
-} __packed;
-
-struct wfx_hif_mib_dot11_rts_threshold {
-       __le32 threshold;
-} __packed;
-
-struct wfx_hif_mib_slot_time {
-       __le32 slot_time;
-} __packed;
-
-struct wfx_hif_mib_current_tx_power_level {
-       __le32 power_level; /* signed value */
-} __packed;
-
-struct wfx_hif_mib_non_erp_protection {
-       u8     use_cts_to_self:1;
-       u8     reserved1:7;
-       u8     reserved2[3];
-} __packed;
-
-enum wfx_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 wfx_hif_mib_template_frame {
-       u8     frame_type;
-       u8     init_rate:7;
-       u8     mode:1;
-       __le16 frame_length;
-       u8     frame[];
-} __packed;
-
-struct wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_hif_mib_set_tx_rate_retry_policy {
-       u8     num_tx_rate_policies;
-       u8     reserved[3];
-       struct wfx_hif_tx_rate_retry_policy tx_rate_retry_policy[];
-} __packed;
-
-struct wfx_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 wfx_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 (file)
index 64ca8ac..0000000
+++ /dev/null
@@ -1,391 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Handling of the chip-to-host events (aka indications) of the hardware 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 wfx_hif_generic_confirm(struct wfx_dev *wdev,
-                                  const struct wfx_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 wfx_hif_tx_confirm(struct wfx_dev *wdev,
-                             const struct wfx_hif_msg *hif, const void *buf)
-{
-       const struct wfx_hif_cnf_tx *body = buf;
-
-       wfx_tx_confirm_cb(wdev, body);
-       return 0;
-}
-
-static int wfx_hif_multi_tx_confirm(struct wfx_dev *wdev,
-                                   const struct wfx_hif_msg *hif, const void *buf)
-{
-       const struct wfx_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 wfx_hif_startup_indication(struct wfx_dev *wdev,
-                                     const struct wfx_hif_msg *hif, const void *buf)
-{
-       const struct wfx_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 wfx_hif_ind_startup));
-       complete(&wdev->firmware_ready);
-       return 0;
-}
-
-static int wfx_hif_wakeup_indication(struct wfx_dev *wdev,
-                                    const struct wfx_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 wfx_hif_receive_indication(struct wfx_dev *wdev, const struct wfx_hif_msg *hif,
-                                     const void *buf, struct sk_buff *skb)
-{
-       struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
-       const struct wfx_hif_ind_rx *body = buf;
-
-       if (!wvif) {
-               dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
-               return -EIO;
-       }
-       skb_pull(skb, sizeof(struct wfx_hif_msg) + sizeof(struct wfx_hif_ind_rx));
-       wfx_rx_cb(wvif, body, skb);
-
-       return 0;
-}
-
-static int wfx_hif_event_indication(struct wfx_dev *wdev,
-                                   const struct wfx_hif_msg *hif, const void *buf)
-{
-       struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
-       const struct wfx_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 wfx_hif_pm_mode_complete_indication(struct wfx_dev *wdev,
-                                              const struct wfx_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 wfx_hif_scan_complete_indication(struct wfx_dev *wdev,
-                                           const struct wfx_hif_msg *hif, const void *buf)
-{
-       struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
-       const struct wfx_hif_ind_scan_cmpl *body = buf;
-
-       if (!wvif) {
-               dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
-               return -EIO;
-       }
-
-       wfx_scan_complete(wvif, body->num_channels_completed);
-
-       return 0;
-}
-
-static int wfx_hif_join_complete_indication(struct wfx_dev *wdev,
-                                           const struct wfx_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 wfx_hif_suspend_resume_indication(struct wfx_dev *wdev,
-                                            const struct wfx_hif_msg *hif, const void *buf)
-{
-       const struct wfx_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 wfx_hif_generic_indication(struct wfx_dev *wdev,
-                                     const struct wfx_hif_msg *hif, const void *buf)
-{
-       const struct wfx_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 wfx_hif_error_indication(struct wfx_dev *wdev,
-                                   const struct wfx_hif_msg *hif, const void *buf)
-{
-       const struct wfx_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 wfx_hif_exception_indication(struct wfx_dev *wdev,
-                                       const struct wfx_hif_msg *hif, const void *buf)
-{
-       const struct wfx_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 wfx_hif_msg *hif, const void *buf);
-} hif_handlers[] = {
-       /* Confirmations */
-       { HIF_CNF_ID_TX,                wfx_hif_tx_confirm },
-       { HIF_CNF_ID_MULTI_TRANSMIT,    wfx_hif_multi_tx_confirm },
-       /* Indications */
-       { HIF_IND_ID_STARTUP,           wfx_hif_startup_indication },
-       { HIF_IND_ID_WAKEUP,            wfx_hif_wakeup_indication },
-       { HIF_IND_ID_JOIN_COMPLETE,     wfx_hif_join_complete_indication },
-       { HIF_IND_ID_SET_PM_MODE_CMPL,  wfx_hif_pm_mode_complete_indication },
-       { HIF_IND_ID_SCAN_CMPL,         wfx_hif_scan_complete_indication },
-       { HIF_IND_ID_SUSPEND_RESUME_TX, wfx_hif_suspend_resume_indication },
-       { HIF_IND_ID_EVENT,             wfx_hif_event_indication },
-       { HIF_IND_ID_GENERIC,           wfx_hif_generic_indication },
-       { HIF_IND_ID_ERROR,             wfx_hif_error_indication },
-       { HIF_IND_ID_EXCEPTION,         wfx_hif_exception_indication },
-       /* FIXME: allocate skb_p from wfx_hif_receive_indication and make it generic */
-       //{ HIF_IND_ID_RX,              wfx_hif_receive_indication },
-};
-
-void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
-{
-       int i;
-       const struct wfx_hif_msg *hif = (const struct wfx_hif_msg *)skb->data;
-       int hif_id = hif->id;
-
-       if (hif_id == HIF_IND_ID_RX) {
-               /* wfx_hif_receive_indication take care of skb lifetime */
-               wfx_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) {
-               wfx_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 & HIF_ID_IS_INDICATION)
-               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 (file)
index 96543b8..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Handling of the chip-to-host events (aka indications) of the hardware 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 (file)
index ae3cc59..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Implementation of the host-to-chip commands (aka request/confirmation) of the
- * hardware 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 wfx_hif_msg *hif, int if_id, unsigned int cmd, size_t size)
-{
-       if (if_id == -1)
-               if_id = 2;
-
-       WARN(cmd > 0x3f, "invalid hardware 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 wfx_hif_msg **hif)
-{
-       *hif = kzalloc(sizeof(struct wfx_hif_msg) + body_len, GFP_KERNEL);
-       if (*hif)
-               return (*hif)->body;
-       else
-               return NULL;
-}
-
-int wfx_cmd_send(struct wfx_dev *wdev, struct wfx_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. Ensure the wq has send the buffer before to continue. */
-               flush_workqueue(system_highpri_wq);
-               ret = 0;
-               goto end;
-       }
-
-       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;
-       }
-
-end:
-       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 = wfx_get_mib_name(((u16 *)request)[2]);
-               mib_sep = "/";
-       }
-       if (ret < 0)
-               dev_err(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned error %d\n",
-                       wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
-       if (ret > 0)
-               dev_warn(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned status %d\n",
-                        wfx_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 wfx_hif_shutdown(struct wfx_dev *wdev)
-{
-       int ret;
-       struct wfx_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
-               wfx_control_reg_write(wdev, 0);
-       kfree(hif);
-       return ret;
-}
-
-int wfx_hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
-{
-       int ret;
-       size_t buf_len = sizeof(struct wfx_hif_req_configuration) + len;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 wfx_hif_reset(struct wfx_vif *wvif, bool reset_stat)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 wfx_hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       int buf_len = sizeof(struct wfx_hif_cnf_read_mib) + val_len;
-       struct wfx_hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif);
-       struct wfx_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",
-                       wfx_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 wfx_hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       int buf_len = sizeof(struct wfx_hif_req_write_mib) + val_len;
-       struct wfx_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 wfx_hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req,
-                int chan_start_idx, int chan_num)
-{
-       int ret, i;
-       struct wfx_hif_msg *hif;
-       size_t buf_len = sizeof(struct wfx_hif_req_start_scan_alt) + chan_num * sizeof(u8);
-       struct wfx_hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif);
-
-       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;
-       }
-
-       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 wfx_hif_stop_scan(struct wfx_vif *wvif)
-{
-       int ret;
-       struct wfx_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 wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
-                struct ieee80211_channel *channel, const u8 *ssid, int ssidlen)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 (!hif)
-               return -ENOMEM;
-       body->infrastructure_bss_mode = !conf->ibss_joined;
-       body->short_preamble = conf->use_short_preamble;
-       body->probe_for_join = !(channel->flags & IEEE80211_CHAN_NO_IR);
-       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 wfx_hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 wfx_hif_add_key(struct wfx_dev *wdev, const struct wfx_hif_req_add_key *arg)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       /* FIXME: only send necessary bits */
-       struct wfx_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 wfx_hif_remove_key(struct wfx_dev *wdev, int idx)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 wfx_hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
-                                 const struct ieee80211_tx_queue_params *arg)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
-                 const struct ieee80211_channel *channel)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 wfx_hif_beacon_transmit(struct wfx_vif *wvif, bool enable)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 wfx_hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       struct wfx_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 wfx_hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
-{
-       int ret;
-       struct wfx_hif_msg *hif;
-       int buf_len = sizeof(struct wfx_hif_req_update_ie) + ies_len;
-       struct wfx_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 (file)
index 71817a6..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Implementation of the host-to-chip commands (aka request/confirmation) of the
- * hardware 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
-
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/completion.h>
-
-struct ieee80211_channel;
-struct ieee80211_bss_conf;
-struct ieee80211_tx_queue_params;
-struct cfg80211_scan_request;
-struct wfx_hif_req_add_key;
-struct wfx_dev;
-struct wfx_vif;
-
-struct wfx_hif_cmd {
-       struct mutex       lock;
-       struct completion  ready;
-       struct completion  done;
-       struct wfx_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 wfx_hif_msg *request,
-                void *reply, size_t reply_len, bool async);
-
-int wfx_hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *buf, size_t buf_size);
-int wfx_hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *buf, size_t buf_size);
-int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
-                 const struct ieee80211_channel *channel);
-int wfx_hif_reset(struct wfx_vif *wvif, bool reset_stat);
-int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
-                struct ieee80211_channel *channel, const u8 *ssid, int ssidlen);
-int wfx_hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp);
-int wfx_hif_add_key(struct wfx_dev *wdev, const struct wfx_hif_req_add_key *arg);
-int wfx_hif_remove_key(struct wfx_dev *wdev, int idx);
-int wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout);
-int wfx_hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count);
-int wfx_hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
-                                 const struct ieee80211_tx_queue_params *arg);
-int wfx_hif_beacon_transmit(struct wfx_vif *wvif, bool enable);
-int wfx_hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len);
-int wfx_hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211,
-                int chan_start, int chan_num);
-int wfx_hif_stop_scan(struct wfx_vif *wvif);
-int wfx_hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len);
-int wfx_hif_shutdown(struct wfx_dev *wdev);
-
-#endif
diff --git a/drivers/staging/wfx/hif_tx_mib.c b/drivers/staging/wfx/hif_tx_mib.c
deleted file mode 100644 (file)
index df1bcb1..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Implementation of the host-to-chip MIBs of the hardware 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 wfx_hif_set_output_power(struct wfx_vif *wvif, int val)
-{
-       struct wfx_hif_mib_current_tx_power_level arg = {
-               .power_level = cpu_to_le32(val * 10),
-       };
-
-       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_CURRENT_TX_POWER_LEVEL,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
-                                    unsigned int dtim_interval, unsigned int listen_interval)
-{
-       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_WAKEUP_PERIOD,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, int rssi_thold, int rssi_hyst)
-{
-       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RCPI_RSSI_THRESHOLD,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_get_counters_table(struct wfx_dev *wdev, int vif_id,
-                              struct wfx_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 wfx_hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE,
-                                   arg, sizeof(struct wfx_hif_mib_count_table));
-       } else {
-               return wfx_hif_read_mib(wdev, vif_id, HIF_MIB_ID_EXTENDED_COUNTERS_TABLE,
-                                       arg, sizeof(struct wfx_hif_mib_extended_count_table));
-       }
-}
-
-int wfx_hif_set_macaddr(struct wfx_vif *wvif, u8 *mac)
-{
-       struct wfx_hif_mib_mac_address arg = { };
-
-       if (mac)
-               ether_addr_copy(arg.mac_addr, mac);
-       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_set_rx_filter(struct wfx_vif *wvif, bool filter_bssid, bool filter_prbreq)
-{
-       struct wfx_hif_mib_rx_filter arg = { };
-
-       if (filter_bssid)
-               arg.bssid_filter = 1;
-       if (!filter_prbreq)
-               arg.fwd_probe_req = 1;
-       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, &arg, sizeof(arg));
-}
-
-int wfx_hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len,
-                                   const struct wfx_hif_ie_table_entry *tbl)
-{
-       int ret;
-       struct wfx_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 = wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_FILTER_TABLE,
-                               arg, buf_len);
-       kfree(arg);
-       return ret;
-}
-
-int wfx_hif_beacon_filter_control(struct wfx_vif *wvif, int enable, int beacon_count)
-{
-       struct wfx_hif_mib_bcn_filter_enable arg = {
-               .enable = cpu_to_le32(enable),
-               .bcn_count = cpu_to_le32(beacon_count),
-       };
-       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_FILTER_ENABLE,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_set_operational_mode(struct wfx_dev *wdev, enum wfx_hif_op_power_mode mode)
-{
-       struct wfx_hif_mib_gl_operational_power_mode arg = {
-               .power_mode = mode,
-               .wup_ind_activation = 1,
-       };
-
-       return wfx_hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb,
-                              u8 frame_type, int init_rate)
-{
-       struct wfx_hif_mib_template_frame *arg;
-
-       WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big");
-       skb_push(skb, 4);
-       arg = (struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME,
-                                arg, sizeof(*arg) + skb->len);
-}
-
-int wfx_hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required)
-{
-       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_PROTECTED_MGMT_POLICY,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_set_block_ack_policy(struct wfx_vif *wvif, u8 tx_tid_policy, u8 rx_tid_policy)
-{
-       struct wfx_hif_mib_block_ack_policy arg = {
-               .block_ack_tx_tid_policy = tx_tid_policy,
-               .block_ack_rx_tid_policy = rx_tid_policy,
-       };
-
-       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density,
-                                bool greenfield, bool short_preamble)
-{
-       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_ASSOCIATION_MODE,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, int policy_index, u8 *rates)
-{
-       struct wfx_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 = wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY,
-                               arg, size);
-       kfree(arg);
-       return ret;
-}
-
-int wfx_hif_keep_alive_period(struct wfx_vif *wvif, int period)
-{
-       struct wfx_hif_mib_keep_alive_period arg = {
-               .keep_alive_period = cpu_to_le16(period),
-       };
-
-       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD,
-                                &arg, sizeof(arg));
-};
-
-int wfx_hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr)
-{
-       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable)
-{
-       struct wfx_hif_mib_gl_set_multi_msg arg = {
-               .enable_multi_tx_conf = enable,
-       };
-
-       return wfx_hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, &arg, sizeof(arg));
-}
-
-int wfx_hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val)
-{
-       struct wfx_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 wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_UAPSD_INFORMATION,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_erp_use_protection(struct wfx_vif *wvif, bool enable)
-{
-       struct wfx_hif_mib_non_erp_protection arg = {
-               .use_cts_to_self = enable,
-       };
-
-       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_NON_ERP_PROTECTION,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_slot_time(struct wfx_vif *wvif, int val)
-{
-       struct wfx_hif_mib_slot_time arg = {
-               .slot_time = cpu_to_le32(val),
-       };
-
-       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, &arg, sizeof(arg));
-}
-
-int wfx_hif_wep_default_key_id(struct wfx_vif *wvif, int val)
-{
-       struct wfx_hif_mib_wep_default_key_id arg = {
-               .wep_default_key_id = val,
-       };
-
-       return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID,
-                                &arg, sizeof(arg));
-}
-
-int wfx_hif_rts_threshold(struct wfx_vif *wvif, int val)
-{
-       struct wfx_hif_mib_dot11_rts_threshold arg = {
-               .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF),
-       };
-
-       return wfx_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 (file)
index bcd4ef6..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Implementation of the host-to-chip MIBs of the hardware 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
-
-#include <linux/types.h>
-
-struct sk_buff;
-struct wfx_vif;
-struct wfx_dev;
-struct wfx_hif_ie_table_entry;
-struct wfx_hif_mib_extended_count_table;
-
-int wfx_hif_set_output_power(struct wfx_vif *wvif, int val);
-int wfx_hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
-                                    unsigned int dtim_interval, unsigned int listen_interval);
-int wfx_hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, int rssi_thold, int rssi_hyst);
-int wfx_hif_get_counters_table(struct wfx_dev *wdev, int vif_id,
-                              struct wfx_hif_mib_extended_count_table *arg);
-int wfx_hif_set_macaddr(struct wfx_vif *wvif, u8 *mac);
-int wfx_hif_set_rx_filter(struct wfx_vif *wvif, bool filter_bssid, bool fwd_probe_req);
-int wfx_hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len,
-                                   const struct wfx_hif_ie_table_entry *tbl);
-int wfx_hif_beacon_filter_control(struct wfx_vif *wvif, int enable, int beacon_count);
-int wfx_hif_set_operational_mode(struct wfx_dev *wdev, enum wfx_hif_op_power_mode mode);
-int wfx_hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb,
-                              u8 frame_type, int init_rate);
-int wfx_hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required);
-int wfx_hif_set_block_ack_policy(struct wfx_vif *wvif, u8 tx_tid_policy, u8 rx_tid_policy);
-int wfx_hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density,
-                                bool greenfield, bool short_preamble);
-int wfx_hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, int policy_index, u8 *rates);
-int wfx_hif_keep_alive_period(struct wfx_vif *wvif, int period);
-int wfx_hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr);
-int wfx_hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable);
-int wfx_hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val);
-int wfx_hif_erp_use_protection(struct wfx_vif *wvif, bool enable);
-int wfx_hif_slot_time(struct wfx_vif *wvif, int val);
-int wfx_hif_wep_default_key_id(struct wfx_vif *wvif, int val);
-int wfx_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 (file)
index 3f9750b..0000000
+++ /dev/null
@@ -1,332 +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 <linux/align.h>
-
-#include "hwio.h"
-#include "wfx.h"
-#include "bus.h"
-#include "traces.h"
-
-#define WFX_HIF_BUFFER_SIZE 0x2000
-
-static int wfx_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 wfx_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 wfx_read32_locked(struct wfx_dev *wdev, int reg, u32 *val)
-{
-       int ret;
-
-       wdev->hwbus_ops->lock(wdev->hwbus_priv);
-       ret = wfx_read32(wdev, reg, val);
-       _trace_io_read32(reg, *val);
-       wdev->hwbus_ops->unlock(wdev->hwbus_priv);
-       return ret;
-}
-
-static int wfx_write32_locked(struct wfx_dev *wdev, int reg, u32 val)
-{
-       int ret;
-
-       wdev->hwbus_ops->lock(wdev->hwbus_priv);
-       ret = wfx_write32(wdev, reg, val);
-       _trace_io_write32(reg, val);
-       wdev->hwbus_ops->unlock(wdev->hwbus_priv);
-       return ret;
-}
-
-static int wfx_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 = wfx_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 = wfx_write32(wdev, reg, val_w);
-               _trace_io_write32(reg, val_w);
-       }
-err:
-       wdev->hwbus_ops->unlock(wdev->hwbus_priv);
-       return ret;
-}
-
-static int wfx_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 >= WFX_HIF_BUFFER_SIZE);
-       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 = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr);
-       if (ret < 0)
-               goto err;
-
-       ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg);
-       if (ret < 0)
-               goto err;
-
-       ret = wfx_write32(wdev, WFX_REG_CONFIG, cfg | prefetch);
-       if (ret < 0)
-               goto err;
-
-       for (i = 0; i < 20; i++) {
-               ret = wfx_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 wfx_indirect_write(struct wfx_dev *wdev, int reg, u32 addr,
-                             const void *buf, size_t len)
-{
-       int ret;
-
-       WARN_ON(len >= WFX_HIF_BUFFER_SIZE);
-       WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
-       ret = wfx_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 wfx_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 = wfx_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 wfx_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 = wfx_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 wfx_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 = wfx_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 wfx_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 = wfx_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(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer");
-       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(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer");
-       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 wfx_sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
-{
-       return wfx_indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
-}
-
-int wfx_ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
-{
-       return wfx_indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
-}
-
-int wfx_sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
-{
-       return wfx_indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
-}
-
-int wfx_ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
-{
-       return wfx_indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
-}
-
-int wfx_sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
-{
-       return wfx_indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
-}
-
-int wfx_ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
-{
-       return wfx_indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
-}
-
-int wfx_sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
-{
-       return wfx_indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
-}
-
-int wfx_ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
-{
-       return wfx_indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
-}
-
-int wfx_config_reg_read(struct wfx_dev *wdev, u32 *val)
-{
-       return wfx_read32_locked(wdev, WFX_REG_CONFIG, val);
-}
-
-int wfx_config_reg_write(struct wfx_dev *wdev, u32 val)
-{
-       return wfx_write32_locked(wdev, WFX_REG_CONFIG, val);
-}
-
-int wfx_config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
-{
-       return wfx_write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val);
-}
-
-int wfx_control_reg_read(struct wfx_dev *wdev, u32 *val)
-{
-       return wfx_read32_locked(wdev, WFX_REG_CONTROL, val);
-}
-
-int wfx_control_reg_write(struct wfx_dev *wdev, u32 val)
-{
-       return wfx_write32_locked(wdev, WFX_REG_CONTROL, val);
-}
-
-int wfx_control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
-{
-       return wfx_write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val);
-}
-
-int wfx_igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val)
-{
-       int ret;
-
-       *val = ~0; /* Never return undefined value */
-       ret = wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24);
-       if (ret)
-               return ret;
-       ret = wfx_read32_locked(wdev, WFX_REG_SET_GEN_R_W, val);
-       if (ret)
-               return ret;
-       *val &= IGPR_VALUE;
-       return ret;
-}
-
-int wfx_igpr_reg_write(struct wfx_dev *wdev, int index, u32 val)
-{
-       return wfx_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 (file)
index c6e7b06..0000000
+++ /dev/null
@@ -1,78 +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
- */
-#ifndef WFX_HWIO_H
-#define WFX_HWIO_H
-
-#include <linux/types.h>
-
-struct wfx_dev;
-
-/* Caution: in the functions below, 'buf' will used with a DMA. So, it must be kmalloc'd (do not use
- * stack allocated buffers). In doubt, enable CONFIG_DEBUG_SG to detect badly located buffer.
- */
-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 wfx_sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len);
-int wfx_sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len);
-
-int wfx_ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len);
-int wfx_ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len);
-
-int wfx_sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val);
-int wfx_sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val);
-
-int wfx_ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val);
-int wfx_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 wfx_config_reg_read(struct wfx_dev *wdev, u32 *val);
-int wfx_config_reg_write(struct wfx_dev *wdev, u32 val);
-int wfx_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 wfx_control_reg_read(struct wfx_dev *wdev, u32 *val);
-int wfx_control_reg_write(struct wfx_dev *wdev, u32 val);
-int wfx_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 wfx_igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val);
-int wfx_igpr_reg_write(struct wfx_dev *wdev, int index, u32 val);
-
-#endif
diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c
deleted file mode 100644 (file)
index 8f23e8d..0000000
+++ /dev/null
@@ -1,227 +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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 = wfx_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 wfx_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 (file)
index 2234e36..0000000
+++ /dev/null
@@ -1,19 +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
- */
-#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
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
deleted file mode 100644 (file)
index b93b16b..0000000
+++ /dev/null
@@ -1,491 +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_TLV_TYPE 0x4450 // "PD" (Platform Data) in ascii little-endian
-#define WFX_PDS_MAX_CHUNK_SIZE 1500
-
-MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WF200");
-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;
-}
-
-/* The device needs data about the antenna configuration. This information in provided by PDS
- * (Platform Data Set, this is the wording used in WF200 documentation) files. For hardware
- * integrators, the full process to create PDS files is described here:
- *   https://github.com/SiliconLabs/wfx-firmware/blob/master/PDS/README.md
- *
- * The PDS file is an array of Time-Length-Value structs.
- */
- int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len)
-{
-       int ret, chunk_type, chunk_len, chunk_num = 0;
-
-       if (*buf == '{') {
-               dev_err(wdev->dev, "PDS: malformed file (legacy format?)\n");
-               return -EINVAL;
-       }
-       while (len > 0) {
-               chunk_type = get_unaligned_le16(buf + 0);
-               chunk_len = get_unaligned_le16(buf + 2);
-               if (chunk_len > len) {
-                       dev_err(wdev->dev, "PDS:%d: corrupted file\n", chunk_num);
-                       return -EINVAL;
-               }
-               if (chunk_type != WFX_PDS_TLV_TYPE) {
-                       dev_info(wdev->dev, "PDS:%d: skip unknown data\n", chunk_num);
-                       goto next;
-               }
-               if (chunk_len > WFX_PDS_MAX_CHUNK_SIZE)
-                       dev_warn(wdev->dev, "PDS:%d: unexpectedly large chunk\n", chunk_num);
-               if (buf[4] != '{' || buf[chunk_len - 1] != '}')
-                       dev_warn(wdev->dev, "PDS:%d: unexpected content\n", chunk_num);
-
-               ret = wfx_hif_configuration(wdev, buf + 4, chunk_len - 4);
-               if (ret > 0) {
-                       dev_err(wdev->dev, "PDS:%d: invalid data (unsupported options?)\n", chunk_num);
-                       return -EINVAL;
-               }
-               if (ret == -ETIMEDOUT) {
-                       dev_err(wdev->dev, "PDS:%d: chip didn't reply (corrupted file?)\n", chunk_num);
-                       return ret;
-               }
-               if (ret) {
-                       dev_err(wdev->dev, "PDS:%d: chip returned an unknown error\n", chunk_num);
-                       return -EIO;
-               }
-next:
-               chunk_num++;
-               len -= chunk_len;
-               buf += chunk_len;
-       }
-       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 antenna parameters (PDS file %s). The device may be unstable.\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 wfx_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 wfx_hif_msg) + sizeof(struct wfx_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);
-       if (!hw->wiphy->bands[NL80211_BAND_2GHZ])
-               goto err;
-
-       /* 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, "silabs,antenna-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))
-               goto err;
-
-       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);
-
-       if (devm_add_action_or_reset(dev, wfx_free_common, wdev))
-               return NULL;
-
-       return wdev;
-
-err:
-       ieee80211_free_hw(hw);
-       return NULL;
-}
-
-int wfx_probe(struct wfx_dev *wdev)
-{
-       int i;
-       int err;
-       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 bh_unregister;
-
-       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 bh_unregister;
-       }
-
-       /* 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 = -EOPNOTSUPP;
-               goto bh_unregister;
-       }
-
-       if (wdev->hw_caps.link_mode == SEC_LINK_ENFORCED) {
-               dev_err(wdev->dev, "chip require secure_link, but can't negotiate it\n");
-               goto bh_unregister;
-       }
-
-       if (wdev->hw_caps.region_sel_mode) {
-               wdev->hw->wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
-               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 && err != -ENOENT)
-               goto bh_unregister;
-
-       wdev->poll_irq = false;
-       err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv);
-       if (err)
-               goto bh_unregister;
-
-       err = wfx_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);
-               wfx_control_reg_write(wdev, 0);
-               wfx_hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT);
-       } else {
-               wfx_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);
-               err = of_get_mac_address(wdev->dev->of_node, wdev->addresses[i].addr);
-               if (!err)
-                       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;
-
-       if (!wfx_api_older_than(wdev, 3, 8))
-               wdev->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
-
-       err = ieee80211_register_hw(wdev->hw);
-       if (err)
-               goto irq_unsubscribe;
-
-       err = wfx_debug_init(wdev);
-       if (err)
-               goto ieee80211_unregister;
-
-       return 0;
-
-ieee80211_unregister:
-       ieee80211_unregister_hw(wdev->hw);
-irq_unsubscribe:
-       wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv);
-bh_unregister:
-       wfx_bh_unregister(wdev);
-       return err;
-}
-
-void wfx_release(struct wfx_dev *wdev)
-{
-       ieee80211_unregister_hw(wdev->hw);
-       wfx_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 (file)
index 68c6653..0000000
+++ /dev/null
@@ -1,41 +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 wfx_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 wfx_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 (file)
index 7298252..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Queue between the tx operation and the bh workqueue.
- *
- * 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];
-       }
-}
-
-bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue)
-{
-       return skb_queue_empty_lockless(&queue->normal) && skb_queue_empty_lockless(&queue->cab);
-}
-
-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(!wfx_tx_queue_empty(wvif, &wvif->tx_queue[i]));
-       }
-}
-
-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 wfx_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 wfx_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 wfx_hif_req_tx *req;
-       struct wfx_vif *wvif;
-       struct wfx_hif_msg *hif;
-       struct sk_buff *skb;
-
-       spin_lock_bh(&wdev->tx_pending.lock);
-       skb_queue_walk(&wdev->tx_pending, skb) {
-               hif = (struct wfx_hif_msg *)skb->data;
-               req = (struct wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_hif_msg *)skb->data;
-}
diff --git a/drivers/staging/wfx/queue.h b/drivers/staging/wfx/queue.h
deleted file mode 100644 (file)
index 4731deb..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Queue between the tx operation and the bh workqueue.
- *
- * 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 wfx_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
diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c
deleted file mode 100644 (file)
index 7f34f0d..0000000
+++ /dev/null
@@ -1,144 +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 wfx_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);
-       wfx_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;
-       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 = wfx_hif_scan(wvif, req, start_idx, i - start_idx);
-       if (ret) {
-               wfx_tx_unlock(wvif->wdev);
-               return -EIO;
-       }
-       ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
-       if (!ret) {
-               wfx_hif_stop_scan(wvif);
-               ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
-               dev_dbg(wvif->wdev->dev, "scan timeout (%d channels done)\n",
-                       wvif->scan_nb_chan_done);
-       }
-       if (!ret) {
-               dev_err(wvif->wdev->dev, "scan didn't stop\n");
-               ret = -ETIMEDOUT;
-       } else if (wvif->scan_abort) {
-               dev_notice(wvif->wdev->dev, "scan abort\n");
-               ret = -ECONNABORTED;
-       } else if (wvif->scan_nb_chan_done > i - start_idx) {
-               ret = -EIO;
-       } else {
-               ret = wvif->scan_nb_chan_done;
-       }
-       if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower)
-               wfx_hif_set_output_power(wvif, wvif->vif->bss_conf.txpower);
-       wfx_tx_unlock(wvif->wdev);
-       return ret;
-}
-
-/* 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, err;
-
-       mutex_lock(&wvif->wdev->conf_mutex);
-       mutex_lock(&wvif->scan_lock);
-       if (wvif->join_in_progress) {
-               dev_info(wvif->wdev->dev, "abort in-progress REQ_JOIN");
-               wfx_reset(wvif);
-       }
-       update_probe_tmpl(wvif, &hw_req->req);
-       chan_cur = 0;
-       err = 0;
-       do {
-               ret = send_scan_req(wvif, &hw_req->req, chan_cur);
-               if (ret > 0) {
-                       chan_cur += ret;
-                       err = 0;
-               }
-               if (!ret)
-                       err++;
-               if (err > 2) {
-                       dev_err(wvif->wdev->dev, "scan has not been able to start\n");
-                       ret = -ETIMEDOUT;
-               }
-       } while (ret >= 0 && chan_cur < hw_req->req.n_channels);
-       mutex_unlock(&wvif->scan_lock);
-       mutex_unlock(&wvif->wdev->conf_mutex);
-       wfx_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;
-       wfx_hif_stop_scan(wvif);
-}
-
-void wfx_scan_complete(struct wfx_vif *wvif, int nb_chan_done)
-{
-       wvif->scan_nb_chan_done = nb_chan_done;
-       complete(&wvif->scan_complete);
-}
diff --git a/drivers/staging/wfx/scan.h b/drivers/staging/wfx/scan.h
deleted file mode 100644 (file)
index 78e3b98..0000000
+++ /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, int nb_chan_done);
-
-#endif
diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c
deleted file mode 100644 (file)
index b1e9fb1..0000000
+++ /dev/null
@@ -1,794 +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;
-       /* The device only supports 2GHz */
-       struct ieee80211_supported_band *sband = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ];
-
-       for (i = 0; i < sband->n_bitrates; i++) {
-               if (rates & BIT(i)) {
-                       if (i >= sband->n_bitrates)
-                               dev_warn(wdev->dev, "unsupported basic rate\n");
-                       else
-                               ret |= BIT(sband->bitrates[i].hw_value);
-               }
-       }
-       return ret;
-}
-
-void wfx_cooling_timeout_work(struct work_struct *work)
-{
-       struct wfx_dev *wdev = container_of(to_delayed_work(work), struct wfx_dev,
-                                           cooling_timeout_work);
-
-       wdev->chip_frozen = true;
-       wfx_tx_unlock(wdev);
-}
-
-void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd)
-{
-       if (cmd == STA_NOTIFY_AWAKE) {
-               /* Device recover normal temperature */
-               if (cancel_delayed_work(&wdev->cooling_timeout_work))
-                       wfx_tx_unlock(wdev);
-       } else {
-               /* Device is too hot */
-               schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ);
-               wfx_tx_lock(wdev);
-       }
-}
-
-static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon)
-{
-       static const struct wfx_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,
-               }, {
-                       .ie_id        = WLAN_EID_CHANNEL_SWITCH,
-                       .has_changed  = 1,
-                       .no_longer    = 1,
-                       .has_appeared = 1,
-               }
-       };
-
-       if (!filter_beacon) {
-               wfx_hif_beacon_filter_control(wvif, 0, 1);
-       } else {
-               wfx_hif_set_beacon_filter_table(wvif, ARRAY_SIZE(filter_ies), filter_ies);
-               wfx_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;
-               wfx_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 && wvif->vif->type != NL80211_IFTYPE_AP) {
-               if (chan0->hw_value == chan1->hw_value) {
-                       /* It is useless to enable PS if channels are the same. */
-                       if (enable_ps)
-                               *enable_ps = false;
-                       if (wvif->vif->bss_conf.assoc && wvif->vif->bss_conf.ps)
-                               dev_info(wvif->wdev->dev, "ignoring requested PS mode");
-                       return -1;
-               }
-               /* It is necessary to enable PS if channels are different. */
-               if (enable_ps)
-                       *enable_ps = true;
-               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->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 wfx_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);
-       wfx_hif_set_edca_queue_params(wvif, queue, params);
-       if (wvif->vif->type == NL80211_IFTYPE_STATION && old_uapsd != wvif->uapsd_mask) {
-               wfx_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)
-               wfx_hif_rts_threshold(wvif, value);
-       return 0;
-}
-
-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;
-
-       wfx_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);
-       wfx_hif_reset(wvif, false);
-       wfx_tx_policy_init(wvif);
-       if (wvif_count(wdev) <= 1)
-               wfx_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)
-               wfx_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);
-       wfx_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? */
-       wfx_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;
-       wfx_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;
-       wfx_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;
-               wfx_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 = wfx_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 = wfx_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;
-       wfx_hif_set_association_mode(wvif, ampdu_density, greenfield, info->use_short_preamble);
-       wfx_hif_keep_alive_period(wvif, 0);
-       /* beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use the same value. */
-       wfx_hif_set_bss_params(wvif, info->aid, 7);
-       wfx_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);
-       }
-       wfx_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, "misunderstood change: ASSOC\n");
-       }
-
-       if (changed & BSS_CHANGED_BEACON_INFO) {
-               if (vif->type != NL80211_IFTYPE_STATION)
-                       dev_warn(wdev->dev, "misunderstood change: BEACON_INFO\n");
-               wfx_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;
-                       wfx_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)
-               wfx_hif_keep_alive_period(wvif,
-                                         info->max_idle_period * USEC_PER_TU / USEC_PER_MSEC);
-
-       if (changed & BSS_CHANGED_ERP_CTS_PROT)
-               wfx_hif_erp_use_protection(wvif, info->use_cts_prot);
-
-       if (changed & BSS_CHANGED_ERP_SLOT)
-               wfx_hif_slot_time(wvif, info->use_short_slot ? 9 : 20);
-
-       if (changed & BSS_CHANGED_CQM)
-               wfx_hif_set_rcpi_rssi_threshold(wvif, info->cqm_rssi_thold, info->cqm_rssi_hyst);
-
-       if (changed & BSS_CHANGED_TXPOWER)
-               wfx_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) {
-               /* Firmware handles DTIM counter 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;
-       }
-
-       wfx_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)
-{
-       struct wfx_vif *wvif_it;
-
-       if (notify_cmd != STA_NOTIFY_AWAKE)
-               return;
-
-       /* Device won't be able to honor CAB if a scan is in progress on any interface. Prefer to
-        * skip this DTIM and wait for the next one.
-        */
-       wvif_it = NULL;
-       while ((wvif_it = wvif_iterate(wvif->wdev, wvif_it)) != NULL)
-               if (mutex_is_locked(&wvif_it->scan_lock))
-                       return;
-
-       if (!wfx_tx_queues_has_cab(wvif) || wvif->after_dtim_tx_allowed)
-               dev_warn(wvif->wdev->dev, "incorrect sequence (%d CAB in queue)",
-                        wfx_tx_queues_has_cab(wvif));
-       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 -EOPNOTSUPP;
-       }
-}
-
-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;
-       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");
-
-       wfx_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)
-                       wfx_hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
-               else
-                       wfx_hif_set_block_ack_policy(wvif, 0x00, 0x00);
-       }
-       return 0;
-}
-
-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");
-
-       wfx_hif_reset(wvif, false);
-       wfx_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)
-                       wfx_hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
-               else
-                       wfx_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 (file)
index c69b222..0000000
+++ /dev/null
@@ -1,66 +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);
-
-/* Hardware API 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
diff --git a/drivers/staging/wfx/traces.h b/drivers/staging/wfx/traces.h
deleted file mode 100644 (file)
index e011e8a..0000000
+++ /dev/null
@@ -1,496 +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 wfx_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 wfx_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 wfx_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 wfx_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 wfx_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 (file)
index 6594cc6..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Common private data.
- *
- * 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 wfx_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 wfx_hwbus_ops *hwbus_ops;
-       void                       *hwbus_priv;
-
-       u8                         keyset;
-       struct completion          firmware_ready;
-       struct wfx_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 wfx_hif_rx_stats    rx_stats;
-       struct mutex               rx_stats_lock;
-       struct wfx_hif_tx_power_loop_info tx_power_loop_info;
-       struct mutex               tx_power_loop_info_lock;
-};
-
-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 wfx_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;
-       int                        scan_nb_chan_done;
-       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])
-               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