[PATCH 16/20] staging: wfx: allow to send 802.11 frames

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Three things make this task more complex than it should:
  - Chip necessitate to associate a link-id to each station. It is same
thing than association ID but, using 8 bits only.
  - Rate policy is sent separately from Tx frames
  - Driver try to handle itself power saving of stations and multicast
data

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile  |   3 +
 drivers/staging/wfx/bh.c  |   2 +
 drivers/staging/wfx/data_tx.c | 783 ++
 drivers/staging/wfx/data_tx.h |  93 
 drivers/staging/wfx/hif_rx.c  |  37 ++
 drivers/staging/wfx/hif_tx.c  |   1 +
 drivers/staging/wfx/main.c|   4 +
 drivers/staging/wfx/queue.c   | 526 +++
 drivers/staging/wfx/queue.h   |  59 +++
 drivers/staging/wfx/sta.c | 145 +++
 drivers/staging/wfx/sta.h |   8 +
 drivers/staging/wfx/traces.h  |  74 
 drivers/staging/wfx/wfx.h |  73 
 13 files changed, 1808 insertions(+)
 create mode 100644 drivers/staging/wfx/data_tx.c
 create mode 100644 drivers/staging/wfx/data_tx.h
 create mode 100644 drivers/staging/wfx/queue.c
 create mode 100644 drivers/staging/wfx/queue.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index e158589468a3..d5ac9fafd1f1 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -9,6 +9,9 @@ wfx-y := \
fwio.o \
hif_tx.o \
hif_rx.o \
+   queue.o \
+   data_tx.o \
+   sta.o \
main.o \
sta.o \
debug.o
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index d321fd312d55..ed81c3924d98 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -220,6 +220,8 @@ static int bh_work_tx(struct wfx_dev *wdev, int max_msg)
if (try_wait_for_completion(>hif_cmd.ready)) {
WARN(!mutex_is_locked(>hif_cmd.lock), 
"data locking error");
hif = wdev->hif_cmd.buf_send;
+   } else {
+   hif = wfx_tx_queues_get(wdev);
}
}
if (!hif)
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
new file mode 100644
index ..217d3c270706
--- /dev/null
+++ b/drivers/staging/wfx/data_tx.c
@@ -0,0 +1,783 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Datapath implementation.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+
+#include "data_tx.h"
+#include "wfx.h"
+#include "bh.h"
+#include "queue.h"
+#include "debug.h"
+#include "traces.h"
+#include "hif_tx_mib.h"
+
+#define WFX_INVALID_RATE_ID (0xFF)
+#define WFX_LINK_ID_GC_TIMEOUT ((unsigned long)(10 * HZ))
+
+static int wfx_get_hw_rate(struct wfx_dev *wdev, const struct 
ieee80211_tx_rate *rate)
+{
+   if (rate->idx < 0)
+   return -1;
+   if (rate->flags & IEEE80211_TX_RC_MCS) {
+   if (rate->idx > 7) {
+   WARN(1, "wrong rate->idx value: %d", rate->idx);
+   return -1;
+   }
+   return rate->idx + 14;
+   }
+   // WFx only support 2GHz, else band information should be retreived
+   // from ieee80211_tx_info
+   return 
wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->bitrates[rate->idx].hw_value;
+}
+
+/* TX policy cache implementation */
+
+static void tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy,
+   struct ieee80211_tx_rate *rates)
+{
+   int i;
+   size_t count;
+   struct wfx_dev *wdev = wvif->wdev;
+
+   BUG_ON(rates[0].idx < 0);
+   memset(policy, 0, sizeof(*policy));
+   for (i = 1; i < IEEE80211_TX_MAX_RATES; i++)
+   if (rates[i].idx < 0)
+   break;
+   count = i;
+
+   /* HACK!!! Device has problems (at least) switching from
+* 54Mbps CTS to 1Mbps. This switch takes enormous amount
+* of time (100-200 ms), leading to valuable throughput drop.
+* As a workaround, additional g-rates are injected to the
+* policy.
+*/
+   if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) &&
+   rates[0].idx > 4 && rates[0].count > 2 &&
+   rates[1].idx < 2) {
+   int mid_rate = (rates[0].idx + 4) >> 1;
+
+   /* Decrease number of retries for the initial rate */
+   rates[0].count -= 2;
+
+   if (mid_rate != 4) {
+   /* Keep fallback rate at 1Mbps. */
+   rates[3] = rates[1];
+
+   /* Inject 1 transmission on lowest g-rate */
+   rates[2].idx = 4;
+   rates[2].count = 1;
+   rates[2].flags = rates[1].flags;
+
+   /* Inject 1 transmission on mid-rate */
+   rates[1].idx = 

[PATCH 13/20] staging: wfx: introduce "secure link"

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Chip support encryption of the link between host and chip. This feature
is called "secure link". Driver code on github[1] support it. However,
it relies on mbedtls for cryptographic functions. So, I decided to not
import this feature in current patch. However, in order to keep code
synchronized between github and kernel, I imported all code related to
this feature, even if most of it is just no-op.

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

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bh.c  | 31 +++--
 drivers/staging/wfx/debug.c   | 17 
 drivers/staging/wfx/hif_rx.c  | 17 
 drivers/staging/wfx/hif_tx.c  |  6 
 drivers/staging/wfx/hif_tx.h  |  1 +
 drivers/staging/wfx/main.c| 36 
 drivers/staging/wfx/main.h|  2 ++
 drivers/staging/wfx/secure_link.h | 46 +++
 drivers/staging/wfx/wfx.h |  2 ++
 9 files changed, 156 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/secure_link.h

diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index c94c9c401a69..d321fd312d55 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -12,6 +12,7 @@
 #include "wfx.h"
 #include "hwio.h"
 #include "traces.h"
+#include "secure_link.h"
 #include "hif_rx.h"
 #include "hif_api_cmd.h"
 
@@ -74,7 +75,18 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
hif = (struct hif_msg *) skb->data;
WARN(hif->encrypted & 0x1, "unsupported encryption type");
if (hif->encrypted == 0x2) {
-   BUG(); // Not yet implemented
+   if (wfx_sl_decode(wdev, (void *) hif)) {
+   dev_kfree_skb(skb);
+   // If frame was a confirmation, expect trouble in next
+   // exchange. However, it is harmless to fail to decode
+   // an indication frame, so try to continue. Anyway,
+   // piggyback is probably correct.
+   return piggyback;
+   }
+   le16_to_cpus(hif->len);
+   computed_len = round_up(hif->len - sizeof(hif->len), 16)
+  + sizeof(struct hif_sl_msg)
+  + sizeof(struct hif_sl_tag);
} else {
le16_to_cpus(hif->len);
computed_len = round_up(hif->len, 2);
@@ -166,7 +178,22 @@ static void tx_helper(struct wfx_dev *wdev, struct hif_msg 
*hif)
hif->seqnum = wdev->hif.tx_seqnum;
wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1);
 
-   data = hif;
+   if (wfx_is_secure_command(wdev, hif->id)) {
+   len = round_up(len - sizeof(hif->len), 16) + sizeof(hif->len)
+ + sizeof(struct hif_sl_msg_hdr) + sizeof(struct 
hif_sl_tag);
+   // AES support encryption in-place. However, mac80211 access to
+   // 802.11 header after frame was sent (to get MAC addresses).
+   // So, keep origin buffer clear.
+   data = kmalloc(len, GFP_KERNEL);
+   if (!data)
+   goto end;
+   is_encrypted = true;
+   ret = wfx_sl_encode(wdev, hif, data);
+   if (ret)
+   goto end;
+   } else {
+   data = hif;
+   }
WARN(len > wdev->hw_caps.size_inp_ch_buf,
 "%s: request exceed WFx capability: %zu > %d\n", __func__,
 len, wdev->hw_caps.size_inp_ch_buf);
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 0a328c96eaa0..f79693a4be7f 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -6,6 +6,7 @@
  * Copyright (c) 2010, ST-Ericsson
  */
 #include 
+#include 
 
 #include "debug.h"
 #include "wfx.h"
@@ -53,6 +54,21 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map);
 }
 
+static ssize_t wfx_burn_slk_key_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+   struct wfx_dev *wdev = file->private_data;
+
+   dev_info(wdev->dev, "this driver does not support secure link\n");
+   return -EINVAL;
+}
+
+static const struct file_operations wfx_burn_slk_key_fops = {
+   .open = simple_open,
+   .write = wfx_burn_slk_key_write,
+};
+
 struct dbgfs_hif_msg {
struct wfx_dev *wdev;
struct completion complete;
@@ -146,6 +162,7 @@ int wfx_debug_init(struct wfx_dev *wdev)
struct dentry *d;
 
d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+   debugfs_create_file("burn_slk_key", 0200, d, wdev, 
_burn_slk_key_fops);
debugfs_create_file("send_hif_msg", 0600, d, wdev, 
_send_hif_msg_fops);
 
return 0;
diff --git 

[PATCH 02/20] staging: wfx: add support for I/O access

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Introduce bus level communication layer. At this level, 7 registers can
be addressed.

Notice that SPI driver is able to manage chip reset. SDIO mode relies
on an external driver (`mmc-pwrseq`) to reset chip.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bus.h  |  17 +++
 drivers/staging/wfx/bus_sdio.c | 189 ++-
 drivers/staging/wfx/bus_spi.c  | 271 -
 drivers/staging/wfx/hwio.h |  48 ++
 drivers/staging/wfx/main.c |  53 +++
 drivers/staging/wfx/main.h |  32 
 drivers/staging/wfx/wfx.h  |  24 +++
 7 files changed, 632 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/hwio.h
 create mode 100644 drivers/staging/wfx/main.h
 create mode 100644 drivers/staging/wfx/wfx.h

diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h
index 8ce871a8a9ff..eb77abc09ec2 100644
--- a/drivers/staging/wfx/bus.h
+++ b/drivers/staging/wfx/bus.h
@@ -11,6 +11,23 @@
 #include 
 #include 
 
+#define WFX_REG_CONFIG0x0
+#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_DPORT0x5
+#define WFX_REG_SET_GEN_R_W   0x6
+#define WFX_REG_FRAME_OUT 0x7
+
+struct hwbus_ops {
+   int (*copy_from_io)(void *bus_priv, unsigned int addr, void *dst, 
size_t count);
+   int (*copy_to_io)(void *bus_priv, unsigned int addr, const void *src, 
size_t count);
+   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;
 
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 4b26c994f43c..35bcca7ec5dc 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -8,36 +8,223 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "bus.h"
+#include "wfx.h"
+#include "hwio.h"
+#include "main.h"
+
+static const struct wfx_platform_data wfx_sdio_pdata = {
+};
+
+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;
+
+   BUG_ON(reg_id > 7);
+   WARN(((uintptr_t) dst) & 3, "unaligned buffer size");
+   WARN(count & 3, "unaligned buffer address");
+
+   /* Use queue mode buffers */
+   if (reg_id == WFX_REG_IN_OUT_QUEUE)
+   sdio_addr |= (bus->buf_id_rx + 1) << 7;
+   ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count);
+   if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
+   bus->buf_id_rx = (bus->buf_id_rx + 1) % 4;
+
+   return ret;
+}
+
+static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id,
+  const void *src, size_t count)
+{
+   struct wfx_sdio_priv *bus = priv;
+   unsigned int sdio_addr = reg_id << 2;
+   int ret;
+
+   BUG_ON(reg_id > 7);
+   WARN(((uintptr_t) src) & 3, "unaligned buffer size");
+   WARN(count & 3, "unaligned buffer address");
+
+   /* Use queue mode buffers */
+   if (reg_id == WFX_REG_IN_OUT_QUEUE)
+   sdio_addr |= bus->buf_id_tx << 7;
+   // FIXME: discards 'const' qualifier for src
+   ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *) src, count);
+   if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
+   bus->buf_id_tx = (bus->buf_id_tx + 1) % 32;
+
+   return ret;
+}
+
+static void wfx_sdio_lock(void *priv)
+{
+   struct wfx_sdio_priv *bus = priv;
+
+   sdio_claim_host(bus->func);
+}
+
+static void wfx_sdio_unlock(void *priv)
+{
+   struct wfx_sdio_priv *bus = priv;
+
+   sdio_release_host(bus->func);
+}
+
+static void wfx_sdio_irq_handler(struct sdio_func *func)
+{
+   struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
+
+   if (bus->core)
+   /* empty */;
+   else
+   WARN(!bus->core, "race condition in driver init/deinit");
+}
+
+static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv)
+{
+   struct wfx_sdio_priv *bus = priv;
+
+   if (!bus->core) {
+   WARN(!bus->core, "race condition in driver init/deinit");
+   return IRQ_NONE;
+   }
+   sdio_claim_host(bus->func);
+   sdio_release_host(bus->func);
+   return IRQ_HANDLED;
+}
+
+static int wfx_sdio_irq_subscribe(struct wfx_sdio_priv *bus)
+{
+   int ret;
+
+   if (bus->of_irq) {
+   ret = request_irq(bus->of_irq, wfx_sdio_irq_handler_ext,
+ IRQF_TRIGGER_RISING, "wfx", bus);
+   } else {
+   

[PATCH 01/20] staging: wfx: add infrastructure for new driver

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Instantiate build infrastructure WFx driver. This driver provides support
for Wifi chipset Silicon Labs WF200 and further:

   https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf

This chip support SPI and SDIO bus.

SDIO interface has two particularities:
1. Some parameters may be useful for end user (I will talk about
   gpio_wakeup later).
2. The SDIO VID and PID of WF200 are :0001 which are too much
   generic to rely on.

So, current code checks VID/PID and looks for a node in DT (since WF200
targets embedded platforms, I don't think it is a problem to rely on
DT). DT can also be used to define to parameters for driver. Currently,
if no node is found, a warning is emitted, but it could be changed in
error.

Signed-off-by: Jérôme Pouiller 
---
 MAINTAINERS   |  5 +
 drivers/staging/Kconfig   |  2 +
 drivers/staging/Makefile  |  1 +
 .../bindings/net/wireless/siliabs,wfx.txt | 97 +++
 drivers/staging/wfx/Kconfig   |  7 ++
 drivers/staging/wfx/Makefile  |  8 ++
 drivers/staging/wfx/bus.h | 17 
 drivers/staging/wfx/bus_sdio.c| 70 +
 drivers/staging/wfx/bus_spi.c | 53 ++
 drivers/staging/wfx/main.c| 47 +
 drivers/staging/wfx/wfx_version.h |  3 +
 11 files changed, 310 insertions(+)
 create mode 100644 
drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
 create mode 100644 drivers/staging/wfx/Kconfig
 create mode 100644 drivers/staging/wfx/Makefile
 create mode 100644 drivers/staging/wfx/bus.h
 create mode 100644 drivers/staging/wfx/bus_sdio.c
 create mode 100644 drivers/staging/wfx/bus_spi.c
 create mode 100644 drivers/staging/wfx/main.c
 create mode 100644 drivers/staging/wfx/wfx_version.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b2326dece28e..0ad6fbde3ac9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14755,6 +14755,11 @@ S: Maintained
 F: drivers/input/touchscreen/silead.c
 F: drivers/platform/x86/touchscreen_dmi.c
 
+SILICON LABS WIRELESS DRIVERS (for WFxxx series)
+M: Jérôme Pouiller 
+S: Supported
+F: drivers/staging/wfx/
+
 SILICON MOTION SM712 FRAME BUFFER DRIVER
 M: Sudip Mukherjee 
 M: Teddy Wang 
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 6f1fa4c849a1..a490141a0e88 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig"
 
 source "drivers/staging/qlge/Kconfig"
 
+source "drivers/staging/wfx/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index a90f9b308c8d..4cb548a0ff87 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_UWB) += uwb/
 obj-$(CONFIG_USB_WUSB) += wusbcore/
 obj-$(CONFIG_EXFAT_FS) += exfat/
 obj-$(CONFIG_QLGE) += qlge/
+obj-$(CONFIG_WFX)  += wfx/
diff --git 
a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
 
b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
new file mode 100644
index ..15965c9b4180
--- /dev/null
+++ 
b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
@@ -0,0 +1,97 @@
+The WFxxx chip series can be connected via SPI or via SDIO.
+
+SPI
+---
+
+You have to declare the WFxxx chip in your device tree.
+
+Required properties:
+ - compatible: Should be "silabs,wfx-spi"
+ - reg: Chip select address of device
+ - spi-max-frequency: Maximum SPI clocking speed of device in Hz
+ - interrupts-extended: Should contain interrupt line (interrupt-parent +
+   interrupt can also been used). Trigger should be `IRQ_TYPE_EDGE_RISING`.
+
+Optional properties:
+ - reset-gpios: phandle of gpio that will be used to reset chip during probe.
+   Without this property, you may encounter issues with warm boot.
+
+Please consult Documentation/devicetree/bindings/spi/spi-bus.txt for optional
+SPI connection related properties,
+
+Example:
+
+ {
+   wfx {
+   compatible = "silabs,wfx-spi";
+   pinctrl-names = "default";
+   pinctrl-0 = <_irq _gpios>;
+   interrupts-extended = < 16 IRQ_TYPE_EDGE_RISING>;
+   wakeup-gpios = < 12 GPIO_ACTIVE_HIGH>;
+   reset-gpios = < 13 GPIO_ACTIVE_HIGH>;
+   reg = <0>;
+   spi-max-frequency = <4200>;
+   };
+};
+
+
+SDIO
+
+
+The driver is able to detect a WFxxx chip on SDIO bus by matching its Vendor ID
+and Product ID. However, driver will only provide limited features in this
+case. Thus declaring WFxxx chip in device tree is strongly recommended (and may
+become mandatory in the future).
+
+Required properties:
+ - compatible: Should 

[PATCH 00/20] Add support for Silicon Labs WiFi chip WF200 and further

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Hello all,

This series add support for Silicon Labs WiFi chip WF200 and further:

   https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf

This driver is an export from:

   https://github.com/SiliconLabs/wfx-linux-driver/
   
I squashed all commits from github (it definitely does not make sense to
import history). Then I split it in comprehensible (at least try to be)
commits. I hope it will help readers to understand driver architecture.
IMHO, firsts commits are clean enough to be reviewed. Things get more
difficult when I introduce mac8011 API. I tried to extract important
parts like Rx/Tx process but, big and complex patches seem unavoidable
in this part.

Architecture itself is described in commit messages.

The series below is aligned on version 2.3.1 on github. If compare this
series with github, you will find traditional differences between
external and a in-tree driver: Documentation, build infrastructure,
etc... In add, I dropped all code in CONFIG_WFX_SECURE_LINK. Indeed,
"Secure Link" feature depends on mbedtls and I don't think to pull
mbedtls in kernel is an option (see "To be done" below).


What need to be done in this driver  to leave staging area?

  - I kept wfx_version.h in order to ensure synchronization with github
waiting for development goes entirely in kernel
  - I also kept compatibility code for earlier Linux kernel version. I
may drop it in future. Maybe I will maintain compatibility with
older kernels in a external set of patches.
  - I have to make decision about secure link support. I can:
  - drop completely
  - keep it in an external patch (my preferred option)
  - replace call to mbedtls with kernel crypto API (necessitate a
bunch of work)
  - pull mbedtls in kernel (non-realistic)
  - mac80211 interface does not (yet) have expected quality to be placed
outside of staging:
  - Some processings are redundant with mac80211 ones
  - Many members from wfx_dev/wfx_vif can be retrieved from mac80211
structures
  - Some functions are too complex
  - ...

Jérôme Pouiller (20):
  staging: wfx: add infrastructure for new driver
  staging: wfx: add support for I/O access
  staging: wfx: add I/O API
  staging: wfx: add tracepoints for I/O access
  staging: wfx: load firmware
  staging: wfx: import HIF API headers
  staging: wfx: add IRQ handling
  staging: wfx: add tracepoints for HIF
  staging: wfx: add support for start-up indication
  staging: wfx: instantiate mac80211 data
  staging: wfx: allow to send commands to chip
  staging: wfx: add HIF commands helpers
  staging: wfx: introduce "secure link"
  staging: wfx: setup initial chip configuration
  staging: wfx: add debug files and trace debug events
  staging: wfx: allow to send 802.11 frames
  staging: wfx: allow to receive 802.11 frames
  staging: wfx: allow to scan networks
  staging: wfx: implement 802.11 key handling
  staging: wfx: implement the rest of mac80211 API

 MAINTAINERS   |5 +
 drivers/staging/Kconfig   |2 +
 drivers/staging/Makefile  |1 +
 .../bindings/net/wireless/siliabs,wfx.txt |   97 +
 drivers/staging/wfx/Kconfig   |7 +
 drivers/staging/wfx/Makefile  |   24 +
 drivers/staging/wfx/bh.c  |  316 
 drivers/staging/wfx/bh.h  |   32 +
 drivers/staging/wfx/bus.h |   34 +
 drivers/staging/wfx/bus_sdio.c|  268 +++
 drivers/staging/wfx/bus_spi.c |  335 
 drivers/staging/wfx/data_rx.c |  213 +++
 drivers/staging/wfx/data_rx.h |   18 +
 drivers/staging/wfx/data_tx.c |  799 
 drivers/staging/wfx/data_tx.h |   93 +
 drivers/staging/wfx/debug.c   |  322 
 drivers/staging/wfx/debug.h   |   19 +
 drivers/staging/wfx/fwio.c|  397 
 drivers/staging/wfx/fwio.h|   15 +
 drivers/staging/wfx/hif_api_cmd.h |  681 +++
 drivers/staging/wfx/hif_api_general.h |  437 +
 drivers/staging/wfx/hif_api_mib.h |  558 ++
 drivers/staging/wfx/hif_rx.c  |  336 
 drivers/staging/wfx/hif_rx.h  |   18 +
 drivers/staging/wfx/hif_tx.c  |  470 +
 drivers/staging/wfx/hif_tx.h  |   67 +
 drivers/staging/wfx/hif_tx_mib.h  |  281 +++
 drivers/staging/wfx/hwio.c|  338 
 drivers/staging/wfx/hwio.h|   75 +
 drivers/staging/wfx/key.c |  272 +++
 drivers/staging/wfx/key.h |   22 +
 drivers/staging/wfx/main.c|  504 +
 drivers/staging/wfx/main.h|   48 +
 drivers/staging/wfx/queue.c   |  606 ++
 

[PATCH 15/20] staging: wfx: add debug files and trace debug events

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Add traces when debug events happen and allow to ask internal
information to chip.

These features work independently from mac80211.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/debug.c  | 122 +++
 drivers/staging/wfx/hif_rx.c |  80 +++
 drivers/staging/wfx/main.c   |   2 +
 drivers/staging/wfx/wfx.h|  16 +
 4 files changed, 220 insertions(+)

diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 0619c7d1cf79..4bd9a079cbd9 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -5,16 +5,35 @@
  * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include 
 #include 
+#include 
 #include 
 
 #include "debug.h"
 #include "wfx.h"
 #include "main.h"
+#include "hif_tx_mib.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
 
+#if (KERNEL_VERSION(4, 17, 0) > LINUX_VERSION_CODE)
+#define DEFINE_SHOW_ATTRIBUTE(__name)  \
+static int __name ## _open(struct inode *inode, struct file *file) \
+{  \
+   return single_open(file, __name ## _show, inode->i_private);\
+}  \
+   \
+static const struct file_operations __name ## _fops = {
\
+   .owner  = THIS_MODULE,  \
+   .open   = __name ## _open,  \
+   .read   = seq_read, \
+   .llseek = seq_lseek,\
+   .release= single_release,   \
+}
+#endif
+
 static const struct trace_print_flags hif_msg_print_map[] = {
hif_msg_list,
 };
@@ -55,6 +74,107 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map);
 }
 
+static int wfx_counters_show(struct seq_file *seq, void *v)
+{
+   int ret;
+   struct wfx_dev *wdev = seq->private;
+   struct hif_mib_extended_count_table counters;
+
+   ret = hif_get_counters_table(wdev, );
+   if (ret < 0)
+   return ret;
+   if (ret > 0)
+   return -EIO;
+
+#define PUT_COUNTER(name) \
+   seq_printf(seq, "%24s %d\n", #name ":", 
le32_to_cpu(counters.count_##name))
+
+   PUT_COUNTER(tx_packets);
+   PUT_COUNTER(tx_multicast_frames);
+   PUT_COUNTER(tx_frames_success);
+   PUT_COUNTER(tx_frame_failures);
+   PUT_COUNTER(tx_frames_retried);
+   PUT_COUNTER(tx_frames_multi_retried);
+
+   PUT_COUNTER(rts_success);
+   PUT_COUNTER(rts_failures);
+   PUT_COUNTER(ack_failures);
+
+   PUT_COUNTER(rx_packets);
+   PUT_COUNTER(rx_frames_success);
+   PUT_COUNTER(rx_packet_errors);
+   PUT_COUNTER(plcp_errors);
+   PUT_COUNTER(fcs_errors);
+   PUT_COUNTER(rx_decryption_failures);
+   PUT_COUNTER(rx_mic_failures);
+   PUT_COUNTER(rx_no_key_failures);
+   PUT_COUNTER(rx_frame_duplicates);
+   PUT_COUNTER(rx_multicast_frames);
+   PUT_COUNTER(rx_cmacicv_errors);
+   PUT_COUNTER(rx_cmac_replays);
+   PUT_COUNTER(rx_mgmt_ccmp_replays);
+
+   PUT_COUNTER(rx_beacon);
+   PUT_COUNTER(miss_beacon);
+
+#undef PUT_COUNTER
+
+   return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_counters);
+
+static const char * const channel_names[] = {
+   [0] = "1M",
+   [1] = "2M",
+   [2] = "5.5M",
+   [3] = "11M",
+   /* Entries 4 and 5 does not exist */
+   [6] = "6M",
+   [7] = "9M",
+   [8] = "12M",
+   [9] = "18M",
+   [10] = "24M",
+   [11] = "36M",
+   [12] = "48M",
+   [13] = "54M",
+   [14] = "MCS0",
+   [15] = "MCS1",
+   [16] = "MCS2",
+   [17] = "MCS3",
+   [18] = "MCS4",
+   [19] = "MCS5",
+   [20] = "MCS6",
+   [21] = "MCS7",
+};
+
+static int wfx_rx_stats_show(struct seq_file *seq, void *v)
+{
+   struct wfx_dev *wdev = seq->private;
+   struct hif_rx_stats *st = >rx_stats;
+   int i;
+
+   mutex_lock(>rx_stats_lock);
+   seq_printf(seq, "Timestamp: %dus\n", st->date);
+   seq_printf(seq, "Low power clock: frequency %uHz, external %s\n",
+   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",
+

[PATCH 18/20] staging: wfx: allow to scan networks

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/bh.c |   2 +-
 drivers/staging/wfx/hif_rx.c |  13 ++
 drivers/staging/wfx/main.c   |   5 +
 drivers/staging/wfx/scan.c   | 258 +++
 drivers/staging/wfx/scan.h   |  42 ++
 drivers/staging/wfx/sta.c|  23 +++-
 drivers/staging/wfx/sta.h|   4 +
 drivers/staging/wfx/wfx.h|  11 ++
 9 files changed, 357 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/scan.c
 create mode 100644 drivers/staging/wfx/scan.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index d9e21515d08e..2b8a5fa86fac 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -12,6 +12,7 @@ wfx-y := \
queue.o \
data_tx.o \
data_rx.o \
+   scan.o \
sta.o \
main.o \
sta.o \
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index ed81c3924d98..6000c03bb658 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -268,7 +268,7 @@ static void bh_work(struct work_struct *work)
 
if (last_op_is_rx)
ack_sdio_data(wdev);
-   if (!wdev->hif.tx_buffers_used && !work_pending(work)) {
+   if (!wdev->hif.tx_buffers_used && !work_pending(work) && 
!atomic_read(>scan_in_progress)) {
device_release(wdev);
release_chip = true;
}
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index c07984b0535d..d386fab0a90f 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -11,6 +11,7 @@
 
 #include "hif_rx.h"
 #include "wfx.h"
+#include "scan.h"
 #include "data_rx.h"
 #include "secure_link.h"
 #include "hif_api_cmd.h"
@@ -143,6 +144,17 @@ static int hif_receive_indication(struct wfx_dev *wdev, 
struct hif_msg *hif, voi
return 0;
 }
 
+static int hif_scan_complete_indication(struct wfx_dev *wdev, struct hif_msg 
*hif, void *buf)
+{
+   struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+   struct hif_ind_scan_cmpl *body = buf;
+
+   WARN_ON(!wvif);
+   wfx_scan_complete_cb(wvif, body);
+
+   return 0;
+}
+
 static int hif_join_complete_indication(struct wfx_dev *wdev, struct hif_msg 
*hif, void *buf)
 {
struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
@@ -230,6 +242,7 @@ static const struct {
{ HIF_IND_ID_STARTUP,  hif_startup_indication },
{ HIF_IND_ID_WAKEUP,   hif_wakeup_indication },
{ HIF_IND_ID_JOIN_COMPLETE,hif_join_complete_indication },
+   { HIF_IND_ID_SCAN_CMPL,hif_scan_complete_indication },
{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
{ HIF_IND_ID_GENERIC,  hif_generic_indication },
{ HIF_IND_ID_ERROR,hif_error_indication },
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index cce4e30dd94a..06220bac5b75 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -55,6 +55,7 @@ static const struct ieee80211_ops wfx_ops = {
.add_interface  = wfx_add_interface,
.remove_interface   = wfx_remove_interface,
.tx = wfx_tx,
+   .hw_scan= wfx_hw_scan,
 };
 
 bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor)
@@ -203,6 +204,8 @@ struct wfx_dev *wfx_init_common(struct device *dev,
hw->extra_tx_headroom = sizeof(struct hif_sl_msg_hdr) + sizeof(struct 
hif_msg)
+ sizeof(struct hif_req_tx)
+ 4 /* alignment */ + 8 /* TKIP IV */;
+   hw->wiphy->max_scan_ssids = 2;
+   hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
 
wdev = hw->priv;
wdev->hw = hw;
@@ -214,6 +217,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
wdev->pdata.gpio_wakeup = wfx_get_gpio(dev, gpio_wakeup, "wakeup");
wfx_fill_sl_key(dev, >pdata);
 
+   mutex_init(>conf_mutex);
mutex_init(>rx_stats_lock);
init_completion(>firmware_ready);
wfx_init_hif_cmd(>hif_cmd);
@@ -225,6 +229,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
 void wfx_free_common(struct wfx_dev *wdev)
 {
mutex_destroy(>rx_stats_lock);
+   mutex_destroy(>conf_mutex);
wfx_tx_queues_deinit(wdev);
ieee80211_free_hw(wdev->hw);
 }
diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c
new file mode 100644
index ..89af294cf23d
--- /dev/null
+++ b/drivers/staging/wfx/scan.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Scan related functions.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#include "scan.h"
+#include "wfx.h"
+#include "sta.h"
+#include "hif_tx_mib.h"
+
+static void 

[PATCH 11/20] staging: wfx: allow to send commands to chip

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Chip has multiple input buffers and can handle multiple 802.11 frames
in parallel. However, other HIF command must be sent sequentially.
wsm_send_cmd() handles these requests.

This commit also add send_hif_cmd in debugfs. This file allows to send
arbitrary commands to chip. It can be used for debug and testing.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/bh.c |   5 +-
 drivers/staging/wfx/debug.c  | 130 +++
 drivers/staging/wfx/debug.h  |   4 ++
 drivers/staging/wfx/hif_rx.c |  45 
 drivers/staging/wfx/hif_tx.c |  87 +++
 drivers/staging/wfx/hif_tx.h |  33 +
 drivers/staging/wfx/main.c   |   1 +
 drivers/staging/wfx/wfx.h|   4 ++
 9 files changed, 309 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/wfx/hif_tx.c
 create mode 100644 drivers/staging/wfx/hif_tx.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 2896a2127c88..e158589468a3 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -7,6 +7,7 @@ wfx-y := \
bh.o \
hwio.o \
fwio.o \
+   hif_tx.o \
hif_rx.o \
main.o \
sta.o \
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index c40da3f1f25d..c94c9c401a69 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -190,7 +190,10 @@ static int bh_work_tx(struct wfx_dev *wdev, int max_msg)
for (i = 0; i < max_msg; i++) {
hif = NULL;
if (wdev->hif.tx_buffers_used < wdev->hw_caps.num_inp_ch_bufs) {
-   /* FIXME: get queued data */
+   if (try_wait_for_completion(>hif_cmd.ready)) {
+   WARN(!mutex_is_locked(>hif_cmd.lock), 
"data locking error");
+   hif = wdev->hif_cmd.buf_send;
+   }
}
if (!hif)
return i;
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index f28c94d8de89..0a328c96eaa0 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -7,16 +7,146 @@
  */
 #include 
 
+#include "debug.h"
 #include "wfx.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
 
+static const struct trace_print_flags hif_msg_print_map[] = {
+   hif_msg_list,
+};
+
+static const struct trace_print_flags hif_mib_print_map[] = {
+   hif_mib_list,
+};
+
+static const struct trace_print_flags wfx_reg_print_map[] = {
+   wfx_reg_list,
+};
+
+static const char *get_symbol(unsigned long val,
+   const struct trace_print_flags *symbol_array)
+{
+   int i;
+
+   for (i = 0; symbol_array[i].mask != -1; i++) {
+   if (val == symbol_array[i].mask)
+   return symbol_array[i].name;
+   }
+
+   return "unknown";
+}
+
+const char *get_hif_name(unsigned long id)
+{
+   return get_symbol(id, hif_msg_print_map);
+}
+
+const char *get_mib_name(unsigned long id)
+{
+   return get_symbol(id, hif_mib_print_map);
+}
+
+const char *get_reg_name(unsigned long id)
+{
+   return get_symbol(id, wfx_reg_print_map);
+}
+
+struct dbgfs_hif_msg {
+   struct wfx_dev *wdev;
+   struct completion complete;
+   u8 reply[1024];
+   int ret;
+};
+
+static ssize_t wfx_send_hif_msg_write(struct file *file, const char __user 
*user_buf,
+ size_t count, loff_t *ppos)
+{
+   struct dbgfs_hif_msg *context = file->private_data;
+   struct wfx_dev *wdev = context->wdev;
+   struct hif_msg *request;
+
+   if (completion_done(>complete)) {
+   dev_dbg(wdev->dev, "read previous result before start a new 
one\n");
+   return -EBUSY;
+   }
+   if (count < sizeof(struct hif_msg))
+   return -EINVAL;
+
+   // wfx_cmd_send() chekc that reply buffer is wide enough, but do 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, sizeof(context->reply), 0xFF);
+   request = memdup_user(user_buf, count);
+   if (IS_ERR(request))
+   return PTR_ERR(request);
+   if (request->len != count) {
+   kfree(request);
+   return -EINVAL;
+   }
+   context->ret = wfx_cmd_send(wdev, request, context->reply, 
sizeof(context->reply), false);
+
+   kfree(request);
+   complete(>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 = 

[PATCH 06/20] staging: wfx: import HIF API headers

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

These files are shared with firmware sources. Only a subset of these
definitions are used by driver but, for now, it is easier to import all.

API defines 3 kinds of messages:
   - Requests (req) are sent from host to chip
   - Confirmations (cnf) are sent by chip and are always in reply to a
 request
   - Indications (ind) are spontaneous message from chip to host

One request normally generate one confirmation. There are a few
exceptions to this rule:
   - "shutdown" request is not acknowledged
   - multiple tx request can be acknowledged a unique "multi-tx"
 confirmation

In add, API defines MIB. They are sub-structures for write_mib and
read_mib API.

Note that all numbers in API have to be little endian when sent/received
from/to chip (I didn't declared them with __le32 because driver also use
them internally).

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/hif_api_cmd.h | 681 ++
 drivers/staging/wfx/hif_api_general.h | 437 +
 drivers/staging/wfx/hif_api_mib.h | 558 +
 3 files changed, 1676 insertions(+)
 create mode 100644 drivers/staging/wfx/hif_api_cmd.h
 create mode 100644 drivers/staging/wfx/hif_api_general.h
 create mode 100644 drivers/staging/wfx/hif_api_mib.h

diff --git a/drivers/staging/wfx/hif_api_cmd.h 
b/drivers/staging/wfx/hif_api_cmd.h
new file mode 100644
index ..7c5d1ea6098d
--- /dev/null
+++ b/drivers/staging/wfx/hif_api_cmd.h
@@ -0,0 +1,681 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * WFx hardware interface definitions
+ *
+ * Copyright (c) 2018-2019, Silicon Laboratories Inc.
+ */
+
+#ifndef WFX_HIF_API_CMD_H
+#define WFX_HIF_API_CMD_H
+
+#include "hif_api_general.h"
+
+#define HIF_NUM_AC 4
+
+#define HIF_API_SSID_SIZE  API_SSID_SIZE
+
+enum hif_requests_ids {
+   HIF_REQ_ID_RESET = 0x0a,
+   HIF_REQ_ID_READ_MIB  = 0x05,
+   HIF_REQ_ID_WRITE_MIB = 0x06,
+   HIF_REQ_ID_START_SCAN= 0x07,
+   HIF_REQ_ID_STOP_SCAN = 0x08,
+   HIF_REQ_ID_TX= 0x04,
+   HIF_REQ_ID_JOIN  = 0x0b,
+   HIF_REQ_ID_SET_PM_MODE   = 0x10,
+   HIF_REQ_ID_SET_BSS_PARAMS= 0x11,
+   HIF_REQ_ID_ADD_KEY   = 0x0c,
+   HIF_REQ_ID_REMOVE_KEY= 0x0d,
+   HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13,
+   HIF_REQ_ID_START = 0x17,
+   HIF_REQ_ID_BEACON_TRANSMIT   = 0x18,
+   HIF_REQ_ID_UPDATE_IE = 0x1b,
+   HIF_REQ_ID_MAP_LINK  = 0x1c,
+};
+
+enum hif_confirmations_ids {
+   HIF_CNF_ID_RESET = 0x0a,
+   HIF_CNF_ID_READ_MIB  = 0x05,
+   HIF_CNF_ID_WRITE_MIB = 0x06,
+   HIF_CNF_ID_START_SCAN= 0x07,
+   HIF_CNF_ID_STOP_SCAN = 0x08,
+   HIF_CNF_ID_TX= 0x04,
+   HIF_CNF_ID_MULTI_TRANSMIT= 0x1e,
+   HIF_CNF_ID_JOIN  = 0x0b,
+   HIF_CNF_ID_SET_PM_MODE   = 0x10,
+   HIF_CNF_ID_SET_BSS_PARAMS= 0x11,
+   HIF_CNF_ID_ADD_KEY   = 0x0c,
+   HIF_CNF_ID_REMOVE_KEY= 0x0d,
+   HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13,
+   HIF_CNF_ID_START = 0x17,
+   HIF_CNF_ID_BEACON_TRANSMIT   = 0x18,
+   HIF_CNF_ID_UPDATE_IE = 0x1b,
+   HIF_CNF_ID_MAP_LINK  = 0x1c,
+};
+
+enum hif_indications_ids {
+   HIF_IND_ID_RX= 0x84,
+   HIF_IND_ID_SCAN_CMPL = 0x86,
+   HIF_IND_ID_JOIN_COMPLETE = 0x8f,
+   HIF_IND_ID_SET_PM_MODE_CMPL  = 0x89,
+   HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c,
+   HIF_IND_ID_EVENT = 0x85
+};
+
+union hif_commands_ids {
+   enum hif_requests_ids request;
+   enum hif_confirmations_ids confirmation;
+   enum hif_indications_ids indication;
+};
+
+enum hif_status {
+   HIF_STATUS_SUCCESS = 0x0,
+   HIF_STATUS_FAILURE = 0x1,
+   HIF_INVALID_PARAMETER  = 0x2,
+   HIF_STATUS_WARNING = 0x3,
+   HIF_ERROR_UNSUPPORTED_MSG_ID   = 0x4,
+   HIF_STATUS_DECRYPTFAILURE  = 0x10,
+   HIF_STATUS_MICFAILURE  = 0x11,
+   HIF_STATUS_NO_KEY_FOUND= 0x12,

[PATCH 08/20] staging: wfx: add tracepoints for HIF

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

These tracepoints decode HIF headers and provide more human readable
results.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bh.c |   5 +
 drivers/staging/wfx/traces.h | 211 +++
 2 files changed, 216 insertions(+)

diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index 02a42e5c1e10..76afecdf579d 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -11,6 +11,7 @@
 #include "bh.h"
 #include "wfx.h"
 #include "hwio.h"
+#include "traces.h"
 #include "hif_api_cmd.h"
 
 static void device_wakeup(struct wfx_dev *wdev)
@@ -67,6 +68,7 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
goto err;
 
piggyback = le16_to_cpup((u16 *) (skb->data + alloc_len - 2));
+   _trace_piggyback(piggyback, false);
 
hif = (struct hif_msg *) skb->data;
WARN(hif->encrypted & 0x1, "unsupported encryption type");
@@ -95,6 +97,7 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
if (!wdev->hif.tx_buffers_used)
wake_up(>hif.tx_buffers_empty);
}
+   _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)
@@ -171,6 +174,7 @@ static void tx_helper(struct wfx_dev *wdev, struct hif_msg 
*hif)
goto end;
 
wdev->hif.tx_buffers_used++;
+   _trace_hif_send(hif, wdev->hif.tx_buffers_used);
 end:
if (is_encrypted)
kfree(data);
@@ -234,6 +238,7 @@ static void bh_work(struct work_struct *work)
device_release(wdev);
release_chip = true;
}
+   _trace_bh_stats(stats_ind, stats_req, stats_cnf, 
wdev->hif.tx_buffers_used, release_chip);
 }
 
 /*
diff --git a/drivers/staging/wfx/traces.h b/drivers/staging/wfx/traces.h
index ba97df821f1b..fd75c4c7e9c7 100644
--- a/drivers/staging/wfx/traces.h
+++ b/drivers/staging/wfx/traces.h
@@ -15,6 +15,8 @@
 #include 
 
 #include "bus.h"
+#include "hif_api_cmd.h"
+#include "hif_api_mib.h"
 
 #if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
 #define TRACE_DEFINE_ENUM(a)
@@ -50,6 +52,167 @@
  *  #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_WAKEUP_PERIOD)   \
+   hif_mib_name(BLOCK_ACK_POLICY)   \
+   hif_mib_name(CONFIG_DATA_FILTER) \
+   hif_mib_name(COUNTERS_TABLE) \
+   

[PATCH v2 11/20] staging: wfx: allow to send commands to chip

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Chip has multiple input buffers and can handle multiple 802.11 frames
in parallel. However, other HIF command must be sent sequentially.
wsm_send_cmd() handles these requests.

This commit also add send_hif_cmd in debugfs. This file allows to send
arbitrary commands to chip. It can be used for debug and testing.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/bh.c |   5 +-
 drivers/staging/wfx/debug.c  | 130 +++
 drivers/staging/wfx/debug.h  |   4 ++
 drivers/staging/wfx/hif_rx.c |  45 
 drivers/staging/wfx/hif_tx.c |  87 +++
 drivers/staging/wfx/hif_tx.h |  33 +
 drivers/staging/wfx/main.c   |   1 +
 drivers/staging/wfx/wfx.h|   4 ++
 9 files changed, 309 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/wfx/hif_tx.c
 create mode 100644 drivers/staging/wfx/hif_tx.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 2896a2127c88..e158589468a3 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -7,6 +7,7 @@ wfx-y := \
bh.o \
hwio.o \
fwio.o \
+   hif_tx.o \
hif_rx.o \
main.o \
sta.o \
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index c40da3f1f25d..c94c9c401a69 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -190,7 +190,10 @@ static int bh_work_tx(struct wfx_dev *wdev, int max_msg)
for (i = 0; i < max_msg; i++) {
hif = NULL;
if (wdev->hif.tx_buffers_used < wdev->hw_caps.num_inp_ch_bufs) {
-   /* FIXME: get queued data */
+   if (try_wait_for_completion(>hif_cmd.ready)) {
+   WARN(!mutex_is_locked(>hif_cmd.lock), 
"data locking error");
+   hif = wdev->hif_cmd.buf_send;
+   }
}
if (!hif)
return i;
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index f28c94d8de89..0a328c96eaa0 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -7,16 +7,146 @@
  */
 #include 
 
+#include "debug.h"
 #include "wfx.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
 
+static const struct trace_print_flags hif_msg_print_map[] = {
+   hif_msg_list,
+};
+
+static const struct trace_print_flags hif_mib_print_map[] = {
+   hif_mib_list,
+};
+
+static const struct trace_print_flags wfx_reg_print_map[] = {
+   wfx_reg_list,
+};
+
+static const char *get_symbol(unsigned long val,
+   const struct trace_print_flags *symbol_array)
+{
+   int i;
+
+   for (i = 0; symbol_array[i].mask != -1; i++) {
+   if (val == symbol_array[i].mask)
+   return symbol_array[i].name;
+   }
+
+   return "unknown";
+}
+
+const char *get_hif_name(unsigned long id)
+{
+   return get_symbol(id, hif_msg_print_map);
+}
+
+const char *get_mib_name(unsigned long id)
+{
+   return get_symbol(id, hif_mib_print_map);
+}
+
+const char *get_reg_name(unsigned long id)
+{
+   return get_symbol(id, wfx_reg_print_map);
+}
+
+struct dbgfs_hif_msg {
+   struct wfx_dev *wdev;
+   struct completion complete;
+   u8 reply[1024];
+   int ret;
+};
+
+static ssize_t wfx_send_hif_msg_write(struct file *file, const char __user 
*user_buf,
+ size_t count, loff_t *ppos)
+{
+   struct dbgfs_hif_msg *context = file->private_data;
+   struct wfx_dev *wdev = context->wdev;
+   struct hif_msg *request;
+
+   if (completion_done(>complete)) {
+   dev_dbg(wdev->dev, "read previous result before start a new 
one\n");
+   return -EBUSY;
+   }
+   if (count < sizeof(struct hif_msg))
+   return -EINVAL;
+
+   // wfx_cmd_send() chekc that reply buffer is wide enough, but do 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, sizeof(context->reply), 0xFF);
+   request = memdup_user(user_buf, count);
+   if (IS_ERR(request))
+   return PTR_ERR(request);
+   if (request->len != count) {
+   kfree(request);
+   return -EINVAL;
+   }
+   context->ret = wfx_cmd_send(wdev, request, context->reply, 
sizeof(context->reply), false);
+
+   kfree(request);
+   complete(>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 = 

[PATCH v2 04/20] staging: wfx: add tracepoints for I/O access

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Some tracepoints are useful for debugging.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   6 +-
 drivers/staging/wfx/debug.c  |  10 +++
 drivers/staging/wfx/hwio.c   |  11 +++
 drivers/staging/wfx/traces.h | 149 +++
 4 files changed, 175 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/wfx/debug.c
 create mode 100644 drivers/staging/wfx/traces.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index e860845186cf..330b7288ebb5 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -1,8 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0
 
+# Necessary for CREATE_TRACE_POINTS
+CFLAGS_debug.o = -I$(src)
+
 wfx-y := \
hwio.o \
-   main.o
+   main.o \
+   debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
 wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
 
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
new file mode 100644
index ..bf44c944640d
--- /dev/null
+++ b/drivers/staging/wfx/debug.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Debugfs interface.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+
+#define CREATE_TRACE_POINTS
+#include "traces.h"
diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c
index fa626a49dd8a..0cf52aee10e7 100644
--- a/drivers/staging/wfx/hwio.c
+++ b/drivers/staging/wfx/hwio.c
@@ -12,6 +12,7 @@
 #include "hwio.h"
 #include "wfx.h"
 #include "bus.h"
+#include "traces.h"
 
 /*
  * Internal helpers.
@@ -63,6 +64,7 @@ static int read32_locked(struct wfx_dev *wdev, int reg, u32 
*val)
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = read32(wdev, reg, val);
+   _trace_io_read32(reg, *val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -73,6 +75,7 @@ static int write32_locked(struct wfx_dev *wdev, int reg, u32 
val)
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = write32(wdev, reg, val);
+   _trace_io_write32(reg, val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -86,11 +89,13 @@ static int write32_bits_locked(struct wfx_dev *wdev, int 
reg, u32 mask, u32 val)
val &= mask;
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = read32(wdev, reg, _r);
+   _trace_io_read32(reg, val_r);
if (ret < 0)
goto err;
val_w = (val_r & ~mask) | val;
if (val_w != val_r) {
ret = write32(wdev, reg, val_w);
+   _trace_io_write32(reg, val_w);
}
 err:
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
@@ -166,6 +171,7 @@ static int indirect_read_locked(struct wfx_dev *wdev, int 
reg, u32 addr, void *b
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_read(wdev, reg, addr, buf, len);
+   _trace_io_ind_read(reg, addr, buf, len);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -176,6 +182,7 @@ static int indirect_write_locked(struct wfx_dev *wdev, int 
reg, u32 addr, const
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_write(wdev, reg, addr, buf, len);
+   _trace_io_ind_write(reg, addr, buf, len);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -190,6 +197,7 @@ static int indirect_read32_locked(struct wfx_dev *wdev, int 
reg, u32 addr, u32 *
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32));
*val = cpu_to_le32(*tmp);
+   _trace_io_ind_read32(reg, addr, *val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
kfree(tmp);
return ret;
@@ -205,6 +213,7 @@ static int indirect_write32_locked(struct wfx_dev *wdev, 
int reg, u32 addr, u32
*tmp = cpu_to_le32(val);
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32));
+   _trace_io_ind_write32(reg, addr, val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
kfree(tmp);
return ret;
@@ -217,6 +226,7 @@ int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t 
len)
WARN((long) buf & 3, "%s: unaligned buffer", __func__);
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, 
WFX_REG_IN_OUT_QUEUE, buf, len);
+   _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
if (ret)
dev_err(wdev->dev, "%s: bus communication error: %d\n", 
__func__, ret);
@@ -230,6 +240,7 @@ int wfx_data_write(struct wfx_dev *wdev, const void *buf, 
size_t len)
WARN((long) buf & 3, "%s: unaligned buffer", __func__);
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, 
WFX_REG_IN_OUT_QUEUE, buf, len);
+   _trace_io_write(WFX_REG_IN_OUT_QUEUE, 

[PATCH v2 19/20] staging: wfx: implement 802.11 key handling

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/key.c| 258 +++
 drivers/staging/wfx/key.h|  22 +++
 drivers/staging/wfx/main.c   |   2 +
 drivers/staging/wfx/sta.c|   4 +
 drivers/staging/wfx/wfx.h|  19 +++
 6 files changed, 306 insertions(+)
 create mode 100644 drivers/staging/wfx/key.c
 create mode 100644 drivers/staging/wfx/key.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 2b8a5fa86fac..0d9c1ed092f6 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -14,6 +14,7 @@ wfx-y := \
data_rx.o \
scan.o \
sta.o \
+   key.o \
main.o \
sta.o \
debug.o
diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c
new file mode 100644
index ..4e7d2b510a9c
--- /dev/null
+++ b/drivers/staging/wfx/key.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Key management related functions.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+
+#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);
+   wdev->keys[idx].entry_index = idx;
+   return idx;
+}
+
+static void wfx_free_key(struct wfx_dev *wdev, int idx)
+{
+   BUG_ON(!(wdev->key_map & BIT(idx)));
+   memset(>keys[idx], 0, sizeof(wdev->keys[idx]));
+   wdev->key_map &= ~BIT(idx);
+}
+
+static uint8_t fill_wep_pair(struct hif_wep_pairwise_key *msg,
+struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+   WARN_ON(key->keylen > sizeof(msg->key_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 uint8_t fill_wep_group(struct hif_wep_group_key *msg,
+ struct ieee80211_key_conf *key)
+{
+   WARN_ON(key->keylen > sizeof(msg->key_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 uint8_t fill_tkip_pair(struct hif_tkip_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+   uint8_t *keybuf = key->key;
+
+   WARN_ON(key->keylen != sizeof(msg->tkip_key_data)
+  + sizeof(msg->tx_mic_key)
+  + sizeof(msg->rx_mic_key));
+   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 uint8_t fill_tkip_group(struct hif_tkip_group_key *msg,
+  struct ieee80211_key_conf *key,
+  struct ieee80211_key_seq *seq,
+  enum nl80211_iftype iftype)
+{
+   uint8_t *keybuf = key->key;
+
+   WARN_ON(key->keylen != sizeof(msg->tkip_key_data)
+  + 2 * sizeof(msg->rx_mic_key));
+   msg->key_id = key->keyidx;
+   memcpy(msg->rx_sequence_counter, >tkip.iv16, 
sizeof(seq->tkip.iv16));
+   memcpy(msg->rx_sequence_counter + sizeof(uint16_t), >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 uint8_t fill_ccmp_pair(struct hif_aes_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+   WARN_ON(key->keylen != sizeof(msg->aes_key_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 uint8_t fill_ccmp_group(struct hif_aes_group_key *msg,
+  struct ieee80211_key_conf *key,
+  struct ieee80211_key_seq *seq)
+{
+   WARN_ON(key->keylen != sizeof(msg->aes_key_data));
+   memcpy(msg->aes_key_data, key->key, key->keylen);
+   memcpy(msg->rx_sequence_counter, 

[PATCH v2 08/20] staging: wfx: add tracepoints for HIF

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

These tracepoints decode HIF headers and provide more human readable
results.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bh.c |   5 +
 drivers/staging/wfx/traces.h | 211 +++
 2 files changed, 216 insertions(+)

diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index 02a42e5c1e10..76afecdf579d 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -11,6 +11,7 @@
 #include "bh.h"
 #include "wfx.h"
 #include "hwio.h"
+#include "traces.h"
 #include "hif_api_cmd.h"
 
 static void device_wakeup(struct wfx_dev *wdev)
@@ -67,6 +68,7 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
goto err;
 
piggyback = le16_to_cpup((u16 *) (skb->data + alloc_len - 2));
+   _trace_piggyback(piggyback, false);
 
hif = (struct hif_msg *) skb->data;
WARN(hif->encrypted & 0x1, "unsupported encryption type");
@@ -95,6 +97,7 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
if (!wdev->hif.tx_buffers_used)
wake_up(>hif.tx_buffers_empty);
}
+   _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)
@@ -171,6 +174,7 @@ static void tx_helper(struct wfx_dev *wdev, struct hif_msg 
*hif)
goto end;
 
wdev->hif.tx_buffers_used++;
+   _trace_hif_send(hif, wdev->hif.tx_buffers_used);
 end:
if (is_encrypted)
kfree(data);
@@ -234,6 +238,7 @@ static void bh_work(struct work_struct *work)
device_release(wdev);
release_chip = true;
}
+   _trace_bh_stats(stats_ind, stats_req, stats_cnf, 
wdev->hif.tx_buffers_used, release_chip);
 }
 
 /*
diff --git a/drivers/staging/wfx/traces.h b/drivers/staging/wfx/traces.h
index 34642f3451b5..e7b03b940535 100644
--- a/drivers/staging/wfx/traces.h
+++ b/drivers/staging/wfx/traces.h
@@ -14,6 +14,8 @@
 #include 
 
 #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.
@@ -45,6 +47,167 @@
  *  #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_WAKEUP_PERIOD)   \
+   hif_mib_name(BLOCK_ACK_POLICY)   \
+   hif_mib_name(CONFIG_DATA_FILTER) 

[PATCH v2 13/20] staging: wfx: introduce "secure link"

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Chip support encryption of the link between host and chip. This feature
is called "secure link". Driver code on github[1] support it. However,
it relies on mbedtls for cryptographic functions. So, I decided to not
import this feature in current patch. However, in order to keep code
synchronized between github and kernel, I imported all code related to
this feature, even if most of it is just no-op.

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

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bh.c  | 31 +++--
 drivers/staging/wfx/debug.c   | 17 
 drivers/staging/wfx/hif_rx.c  | 17 
 drivers/staging/wfx/hif_tx.c  |  6 
 drivers/staging/wfx/hif_tx.h  |  1 +
 drivers/staging/wfx/main.c| 36 
 drivers/staging/wfx/main.h|  2 ++
 drivers/staging/wfx/secure_link.h | 46 +++
 drivers/staging/wfx/wfx.h |  2 ++
 9 files changed, 156 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/secure_link.h

diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index c94c9c401a69..d321fd312d55 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -12,6 +12,7 @@
 #include "wfx.h"
 #include "hwio.h"
 #include "traces.h"
+#include "secure_link.h"
 #include "hif_rx.h"
 #include "hif_api_cmd.h"
 
@@ -74,7 +75,18 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
hif = (struct hif_msg *) skb->data;
WARN(hif->encrypted & 0x1, "unsupported encryption type");
if (hif->encrypted == 0x2) {
-   BUG(); // Not yet implemented
+   if (wfx_sl_decode(wdev, (void *) hif)) {
+   dev_kfree_skb(skb);
+   // If frame was a confirmation, expect trouble in next
+   // exchange. However, it is harmless to fail to decode
+   // an indication frame, so try to continue. Anyway,
+   // piggyback is probably correct.
+   return piggyback;
+   }
+   le16_to_cpus(hif->len);
+   computed_len = round_up(hif->len - sizeof(hif->len), 16)
+  + sizeof(struct hif_sl_msg)
+  + sizeof(struct hif_sl_tag);
} else {
le16_to_cpus(hif->len);
computed_len = round_up(hif->len, 2);
@@ -166,7 +178,22 @@ static void tx_helper(struct wfx_dev *wdev, struct hif_msg 
*hif)
hif->seqnum = wdev->hif.tx_seqnum;
wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1);
 
-   data = hif;
+   if (wfx_is_secure_command(wdev, hif->id)) {
+   len = round_up(len - sizeof(hif->len), 16) + sizeof(hif->len)
+ + sizeof(struct hif_sl_msg_hdr) + sizeof(struct 
hif_sl_tag);
+   // AES support encryption in-place. However, mac80211 access to
+   // 802.11 header after frame was sent (to get MAC addresses).
+   // So, keep origin buffer clear.
+   data = kmalloc(len, GFP_KERNEL);
+   if (!data)
+   goto end;
+   is_encrypted = true;
+   ret = wfx_sl_encode(wdev, hif, data);
+   if (ret)
+   goto end;
+   } else {
+   data = hif;
+   }
WARN(len > wdev->hw_caps.size_inp_ch_buf,
 "%s: request exceed WFx capability: %zu > %d\n", __func__,
 len, wdev->hw_caps.size_inp_ch_buf);
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 0a328c96eaa0..f79693a4be7f 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -6,6 +6,7 @@
  * Copyright (c) 2010, ST-Ericsson
  */
 #include 
+#include 
 
 #include "debug.h"
 #include "wfx.h"
@@ -53,6 +54,21 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map);
 }
 
+static ssize_t wfx_burn_slk_key_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+   struct wfx_dev *wdev = file->private_data;
+
+   dev_info(wdev->dev, "this driver does not support secure link\n");
+   return -EINVAL;
+}
+
+static const struct file_operations wfx_burn_slk_key_fops = {
+   .open = simple_open,
+   .write = wfx_burn_slk_key_write,
+};
+
 struct dbgfs_hif_msg {
struct wfx_dev *wdev;
struct completion complete;
@@ -146,6 +162,7 @@ int wfx_debug_init(struct wfx_dev *wdev)
struct dentry *d;
 
d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+   debugfs_create_file("burn_slk_key", 0200, d, wdev, 
_burn_slk_key_fops);
debugfs_create_file("send_hif_msg", 0600, d, wdev, 
_send_hif_msg_fops);
 
return 0;
diff --git 

[PATCH v2 17/20] staging: wfx: allow to receive 802.11 frames

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Again, this task is more complex than it should since driver try to
handle itself power saving of stations.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile  |   1 +
 drivers/staging/wfx/data_rx.c | 182 ++
 drivers/staging/wfx/data_rx.h |  18 
 drivers/staging/wfx/hif_rx.c  |  23 +
 4 files changed, 224 insertions(+)
 create mode 100644 drivers/staging/wfx/data_rx.c
 create mode 100644 drivers/staging/wfx/data_rx.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index d5ac9fafd1f1..d9e21515d08e 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -11,6 +11,7 @@ wfx-y := \
hif_rx.o \
queue.o \
data_tx.o \
+   data_rx.o \
sta.o \
main.o \
sta.o \
diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c
new file mode 100644
index ..3b3117b2edac
--- /dev/null
+++ b/drivers/staging/wfx/data_rx.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Datapath implementation.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#include "data_rx.h"
+#include "wfx.h"
+#include "bh.h"
+#include "sta.h"
+
+static int wfx_handle_pspoll(struct wfx_vif *wvif, struct sk_buff *skb)
+{
+   struct ieee80211_sta *sta;
+   struct ieee80211_pspoll *pspoll = (struct ieee80211_pspoll *)skb->data;
+   int link_id = 0;
+   u32 pspoll_mask = 0;
+   int i;
+
+   if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid))
+   return 1;
+
+   rcu_read_lock();
+   sta = ieee80211_find_sta(wvif->vif, pspoll->ta);
+   if (sta)
+   link_id = ((struct wfx_sta_priv *) >drv_priv)->link_id;
+   rcu_read_unlock();
+   if (link_id)
+   pspoll_mask = BIT(link_id);
+   else
+   return 1;
+
+   wvif->pspoll_mask |= pspoll_mask;
+   /* Do not report pspols if data for given link id is queued already. */
+   for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
+   if (wfx_tx_queue_get_num_queued(>wdev->tx_queue[i],
+   pspoll_mask)) {
+   wfx_bh_request_tx(wvif->wdev);
+   return 1;
+   }
+   }
+   return 0;
+}
+
+static int wfx_drop_encrypt_data(struct wfx_dev *wdev, struct hif_ind_rx *arg, 
struct sk_buff *skb)
+{
+   struct ieee80211_hdr *frame = (struct ieee80211_hdr *) skb->data;
+   size_t hdrlen = ieee80211_hdrlen(frame->frame_control);
+   size_t iv_len, icv_len;
+
+   /* Oops... There is no fast way to ask mac80211 about
+* IV/ICV lengths. Even defineas are not exposed.
+*/
+   switch (arg->rx_flags.encryp) {
+   case HIF_RI_FLAGS_WEP_ENCRYPTED:
+   iv_len = 4 /* WEP_IV_LEN */;
+   icv_len = 4 /* WEP_ICV_LEN */;
+   break;
+   case HIF_RI_FLAGS_TKIP_ENCRYPTED:
+   iv_len = 8 /* TKIP_IV_LEN */;
+   icv_len = 4 /* TKIP_ICV_LEN */
+   + 8 /*MICHAEL_MIC_LEN*/;
+   break;
+   case HIF_RI_FLAGS_AES_ENCRYPTED:
+   iv_len = 8 /* CCMP_HDR_LEN */;
+   icv_len = 8 /* CCMP_MIC_LEN */;
+   break;
+   case HIF_RI_FLAGS_WAPI_ENCRYPTED:
+   iv_len = 18 /* WAPI_HDR_LEN */;
+   icv_len = 16 /* WAPI_MIC_LEN */;
+   break;
+   default:
+   dev_err(wdev->dev, "unknown encryption type %d\n",
+arg->rx_flags.encryp);
+   return -EIO;
+   }
+
+   /* Firmware strips ICV in case of MIC failure. */
+   if (arg->status == HIF_STATUS_MICFAILURE)
+   icv_len = 0;
+
+   if (skb->len < hdrlen + iv_len + icv_len) {
+   dev_warn(wdev->dev, "malformed SDU received\n");
+   return -EIO;
+   }
+
+   /* Remove IV, ICV and MIC */
+   skb_trim(skb, skb->len - icv_len);
+   memmove(skb->data + iv_len, skb->data, hdrlen);
+   skb_pull(skb, iv_len);
+   return 0;
+
+}
+
+void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx *arg, struct sk_buff 
*skb)
+{
+   int link_id = arg->rx_flags.peer_sta_id;
+   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;
+   struct wfx_link_entry *entry = NULL;
+   bool early_data = false;
+
+   memset(hdr, 0, sizeof(*hdr));
+
+   // FIXME: Why do we drop these frames?
+   if (!arg->rcpi_rssi &&
+   (ieee80211_is_probe_resp(frame->frame_control) ||
+ieee80211_is_beacon(frame->frame_control)))
+   goto drop;
+
+   if (link_id && link_id <= WFX_MAX_STA_IN_AP_MODE) {
+   entry = 

[PATCH v2 12/20] staging: wfx: add HIF commands helpers

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Provide an abstraction for HIF commands.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/hif_tx.c | 375 +++
 drivers/staging/wfx/hif_tx.h |  33 +++
 drivers/staging/wfx/hif_tx_mib.h | 281 +++
 3 files changed, 689 insertions(+)
 create mode 100644 drivers/staging/wfx/hif_tx_mib.h

diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c
index f81a19089db4..781a6e28dbad 100644
--- a/drivers/staging/wfx/hif_tx.c
+++ b/drivers/staging/wfx/hif_tx.c
@@ -12,6 +12,7 @@
 #include "hif_tx.h"
 #include "wfx.h"
 #include "bh.h"
+#include "hwio.h"
 #include "debug.h"
 
 void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
@@ -21,6 +22,29 @@ void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
mutex_init(_cmd->lock);
 }
 
+static void wfx_fill_header(struct hif_msg *hif, int if_id, unsigned int cmd, 
size_t size)
+{
+   if (if_id == -1)
+   if_id = 2;
+
+   WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd);
+   WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size);
+   WARN(if_id > 0x3, "invalid interface ID %d", if_id);
+
+   hif->len = cpu_to_le16(size + 4);
+   hif->id = cmd;
+   hif->interface = if_id;
+}
+
+static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif)
+{
+   *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL);
+   if (*hif)
+   return (*hif)->body;
+   else
+   return NULL;
+}
+
 int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, 
size_t reply_len, bool async)
 {
const char *mib_name = "";
@@ -85,3 +109,354 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg 
*request, void *reply, siz
 
return ret;
 }
+
+// This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to 
any
+// request anymore. We need to slightly hack struct wfx_hif_cmd for that job. 
Be
+// carefull to only call this funcion during device unregister.
+int hif_shutdown(struct wfx_dev *wdev)
+{
+   int ret;
+   struct hif_msg *hif;
+
+   wfx_alloc_hif(0, );
+   wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0);
+   ret = wfx_cmd_send(wdev, hif, NULL, 0, true);
+   // After this command, chip won't reply. Be sure to give enough time to
+   // bh to send buffer:
+   msleep(100);
+   wdev->hif_cmd.buf_send = NULL;
+   if (wdev->pdata.gpio_wakeup)
+   gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
+   else
+   control_reg_write(wdev, 0);
+   mutex_unlock(>hif_cmd.lock);
+   kfree(hif);
+   return ret;
+}
+
+int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
+{
+   int ret;
+   size_t buf_len = sizeof(struct hif_req_configuration) + len;
+   struct hif_msg *hif;
+   struct hif_req_configuration *body = wfx_alloc_hif(buf_len, );
+
+   body->length = cpu_to_le16(len);
+   memcpy(body->pds_data, conf, len);
+   wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len);
+   ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+   kfree(hif);
+   return ret;
+}
+
+int hif_reset(struct wfx_vif *wvif, bool reset_stat)
+{
+   int ret;
+   struct hif_msg *hif;
+   struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), );
+
+   body->reset_flags.reset_stat = reset_stat;
+   wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body));
+   ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+   kfree(hif);
+   return ret;
+}
+
+int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, 
size_t val_len)
+{
+   int ret;
+   struct hif_msg *hif;
+   int buf_len = sizeof(struct hif_cnf_read_mib) + val_len;
+   struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), );
+   struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
+
+   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 != reply->mib_id) {
+   dev_warn(wdev->dev, "%s: confirmation mismatch request\n", 
__func__);
+   ret = -EIO;
+   }
+   if (ret == -ENOMEM)
+   dev_err(wdev->dev, "buffer is too small to receive %s (%zu < 
%d)\n",
+   get_mib_name(mib_id), val_len, reply->length);
+   if (!ret)
+   memcpy(val, >mib_data, reply->length);
+   else
+   memset(val, 0xFF, val_len);
+   kfree(hif);
+   kfree(reply);
+   return ret;
+}
+
+int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, 
size_t val_len)
+{
+   int ret;
+   struct hif_msg *hif;
+   int buf_len = sizeof(struct hif_req_write_mib) + val_len;
+   struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, );
+
+   body->mib_id = 

[PATCH v2 10/20] staging: wfx: instantiate mac80211 data

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Allocate a struct ieee80211_hw but do not yet register it.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |  1 +
 drivers/staging/wfx/debug.c  | 12 ++
 drivers/staging/wfx/debug.h  | 15 
 drivers/staging/wfx/main.c   | 41 ++--
 drivers/staging/wfx/sta.c| 46 
 drivers/staging/wfx/sta.h| 24 +++
 drivers/staging/wfx/wfx.h|  8 +++
 7 files changed, 145 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/debug.h
 create mode 100644 drivers/staging/wfx/sta.c
 create mode 100644 drivers/staging/wfx/sta.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 35670b86c64f..2896a2127c88 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -9,6 +9,7 @@ wfx-y := \
fwio.o \
hif_rx.o \
main.o \
+   sta.o \
debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
 wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index bf44c944640d..f28c94d8de89 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -5,6 +5,18 @@
  * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include 
+
+#include "wfx.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
+
+int wfx_debug_init(struct wfx_dev *wdev)
+{
+   struct dentry *d;
+
+   d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+
+   return 0;
+}
diff --git a/drivers/staging/wfx/debug.h b/drivers/staging/wfx/debug.h
new file mode 100644
index ..8bfba1a9fa20
--- /dev/null
+++ b/drivers/staging/wfx/debug.h
@@ -0,0 +1,15 @@
+/* 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);
+
+#endif /* WFX_DEBUG_H */
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 5e7e7225f068..ca0ca873bd7d 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -25,6 +25,9 @@
 #include "hwio.h"
 #include "bus.h"
 #include "bh.h"
+#include "sta.h"
+#include "debug.h"
+#include "hif_api_cmd.h"
 #include "wfx_version.h"
 
 MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx");
@@ -36,6 +39,13 @@ static int gpio_wakeup = -2;
 module_param(gpio_wakeup, int, 0644);
 MODULE_PARM_DESC(gpio_wakeup, "gpio number for wakeup. -1 for none.");
 
+static const struct ieee80211_ops wfx_ops = {
+   .start  = wfx_start,
+   .stop   = wfx_stop,
+   .add_interface  = wfx_add_interface,
+   .remove_interface   = wfx_remove_interface,
+};
+
 bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor)
 {
if (wdev->hw_caps.api_version_major < major)
@@ -79,11 +89,26 @@ struct wfx_dev *wfx_init_common(struct device *dev,
const struct hwbus_ops *hwbus_ops,
void *hwbus_priv)
 {
+   struct ieee80211_hw *hw;
struct wfx_dev *wdev;
 
-   wdev = devm_kmalloc(dev, sizeof(*wdev), GFP_KERNEL);
-   if (!wdev)
+   hw = ieee80211_alloc_hw(sizeof(struct wfx_dev), _ops);
+   if (!hw)
return NULL;
+
+   SET_IEEE80211_DEV(hw, dev);
+
+   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 = 15;
+   hw->extra_tx_headroom = sizeof(struct hif_sl_msg_hdr) + sizeof(struct 
hif_msg)
+   + sizeof(struct hif_req_tx)
+   + 4 /* alignment */ + 8 /* TKIP IV */;
+
+   wdev = hw->priv;
+   wdev->hw = hw;
wdev->dev = dev;
wdev->hwbus_ops = hwbus_ops;
wdev->hwbus_priv = hwbus_priv;
@@ -96,6 +121,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
 
 void wfx_free_common(struct wfx_dev *wdev)
 {
+   ieee80211_free_hw(wdev->hw);
 }
 
 int wfx_probe(struct wfx_dev *wdev)
@@ -127,6 +153,11 @@ int wfx_probe(struct wfx_dev *wdev)
 wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label,
 wdev->hw_caps.api_version_major, 
wdev->hw_caps.api_version_minor,
 wdev->keyset, *((u32 *) >hw_caps.capabilities));
+   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",
@@ -150,8 

[PATCH v2 03/20] staging: wfx: add I/O API

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

hwio.c provides an abstraction to access different types of register of
the chip.

Note that only data register (aka FRAME_OUT) and control register are
used normal communication. Other registers are only used during chip
start up.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/hwio.c   | 327 +++
 drivers/staging/wfx/hwio.h   |  27 +++
 3 files changed, 355 insertions(+)
 create mode 100644 drivers/staging/wfx/hwio.c

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 74939a5a0a1c..e860845186cf 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 wfx-y := \
+   hwio.o \
main.o
 wfx-$(CONFIG_SPI) += bus_spi.o
 wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c
new file mode 100644
index ..fa626a49dd8a
--- /dev/null
+++ b/drivers/staging/wfx/hwio.c
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Low-level I/O functions.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+#include 
+
+#include "hwio.h"
+#include "wfx.h"
+#include "bus.h"
+
+/*
+ * Internal helpers.
+ *
+ * About CONFIG_VMAP_STACK:
+ * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack
+ * allocated data. Functions below that work with registers (aka functions
+ * ending with "32") automatically reallocate buffers with kmalloc. However,
+ * functions that work with arbitrary length buffers let's caller to handle
+ * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located
+ * buffer.
+ */
+
+static int read32(struct wfx_dev *wdev, int reg, u32 *val)
+{
+   int ret;
+   __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
+
+   *val = ~0; // Never return undefined value
+   if (!tmp)
+   return -ENOMEM;
+   ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, 
sizeof(u32));
+   if (ret >= 0)
+   *val = le32_to_cpu(*tmp);
+   kfree(tmp);
+   if (ret)
+   dev_err(wdev->dev, "%s: bus communication error: %d\n", 
__func__, ret);
+   return ret;
+}
+
+static int write32(struct wfx_dev *wdev, int reg, u32 val)
+{
+   int ret;
+   __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
+
+   if (!tmp)
+   return -ENOMEM;
+   *tmp = cpu_to_le32(val);
+   ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, 
sizeof(u32));
+   kfree(tmp);
+   if (ret)
+   dev_err(wdev->dev, "%s: bus communication error: %d\n", 
__func__, ret);
+   return ret;
+}
+
+static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val)
+{
+   int ret;
+
+   wdev->hwbus_ops->lock(wdev->hwbus_priv);
+   ret = read32(wdev, reg, val);
+   wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+   return ret;
+}
+
+static int write32_locked(struct wfx_dev *wdev, int reg, u32 val)
+{
+   int ret;
+
+   wdev->hwbus_ops->lock(wdev->hwbus_priv);
+   ret = write32(wdev, reg, val);
+   wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+   return ret;
+}
+
+static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 
val)
+{
+   int ret;
+   u32 val_r, val_w;
+
+   WARN_ON(~mask & val);
+   val &= mask;
+   wdev->hwbus_ops->lock(wdev->hwbus_priv);
+   ret = read32(wdev, reg, _r);
+   if (ret < 0)
+   goto err;
+   val_w = (val_r & ~mask) | val;
+   if (val_w != val_r) {
+   ret = write32(wdev, reg, val_w);
+   }
+err:
+   wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+   return ret;
+}
+
+static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf, 
size_t len)
+{
+   int ret;
+   int i;
+   u32 cfg;
+   u32 prefetch;
+
+   WARN_ON(len >= 0x2000);
+   WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
+
+   if (reg == WFX_REG_AHB_DPORT)
+   prefetch = CFG_PREFETCH_AHB;
+   else if (reg == WFX_REG_SRAM_DPORT)
+   prefetch = CFG_PREFETCH_SRAM;
+   else
+   return -ENODEV;
+
+   ret = write32(wdev, WFX_REG_BASE_ADDR, addr);
+   if (ret < 0)
+   goto err;
+
+   ret = read32(wdev, WFX_REG_CONFIG, );
+   if (ret < 0)
+   goto err;
+
+   ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch);
+   if (ret < 0)
+   goto err;
+
+   for (i = 0; i < 20; i++) {
+   ret = read32(wdev, WFX_REG_CONFIG, );
+   if (ret < 0)
+   goto err;
+   if (!(cfg & prefetch))
+   break;
+   udelay(200);
+   }
+   if (i == 20) {
+   ret = -ETIMEDOUT;
+   goto err;
+   }
+
+  

[PATCH v2 01/20] staging: wfx: add infrastructure for new driver

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Instantiate build infrastructure WFx driver. This driver provides support
for Wifi chipset Silicon Labs WF200 and further:

   https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf

This chip support SPI and SDIO bus.

SDIO interface has two particularities:
1. Some parameters may be useful for end user (I will talk about
   gpio_wakeup later).
2. The SDIO VID and PID of WF200 are :0001 which are too much
   generic to rely on.

So, current code checks VID/PID and looks for a node in DT (since WF200
targets embedded platforms, I don't think it is a problem to rely on
DT). DT can also be used to define to parameters for driver. Currently,
if no node is found, a warning is emitted, but it could be changed in
error.

Signed-off-by: Jérôme Pouiller 
---
 MAINTAINERS   |  5 +
 drivers/staging/Kconfig   |  2 +
 drivers/staging/Makefile  |  1 +
 .../bindings/net/wireless/siliabs,wfx.txt | 97 +++
 drivers/staging/wfx/Kconfig   |  7 ++
 drivers/staging/wfx/Makefile  |  8 ++
 drivers/staging/wfx/TODO  | 20 
 drivers/staging/wfx/bus.h | 17 
 drivers/staging/wfx/bus_sdio.c| 70 +
 drivers/staging/wfx/bus_spi.c | 53 ++
 drivers/staging/wfx/main.c| 47 +
 drivers/staging/wfx/wfx_version.h |  3 +
 12 files changed, 330 insertions(+)
 create mode 100644 
drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
 create mode 100644 drivers/staging/wfx/Kconfig
 create mode 100644 drivers/staging/wfx/Makefile
 create mode 100644 drivers/staging/wfx/TODO
 create mode 100644 drivers/staging/wfx/bus.h
 create mode 100644 drivers/staging/wfx/bus_sdio.c
 create mode 100644 drivers/staging/wfx/bus_spi.c
 create mode 100644 drivers/staging/wfx/main.c
 create mode 100644 drivers/staging/wfx/wfx_version.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b2326dece28e..0ad6fbde3ac9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14755,6 +14755,11 @@ S: Maintained
 F: drivers/input/touchscreen/silead.c
 F: drivers/platform/x86/touchscreen_dmi.c
 
+SILICON LABS WIRELESS DRIVERS (for WFxxx series)
+M: Jérôme Pouiller 
+S: Supported
+F: drivers/staging/wfx/
+
 SILICON MOTION SM712 FRAME BUFFER DRIVER
 M: Sudip Mukherjee 
 M: Teddy Wang 
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 6f1fa4c849a1..a490141a0e88 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig"
 
 source "drivers/staging/qlge/Kconfig"
 
+source "drivers/staging/wfx/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index a90f9b308c8d..4cb548a0ff87 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_UWB) += uwb/
 obj-$(CONFIG_USB_WUSB) += wusbcore/
 obj-$(CONFIG_EXFAT_FS) += exfat/
 obj-$(CONFIG_QLGE) += qlge/
+obj-$(CONFIG_WFX)  += wfx/
diff --git 
a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
 
b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
new file mode 100644
index ..15965c9b4180
--- /dev/null
+++ 
b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
@@ -0,0 +1,97 @@
+The WFxxx chip series can be connected via SPI or via SDIO.
+
+SPI
+---
+
+You have to declare the WFxxx chip in your device tree.
+
+Required properties:
+ - compatible: Should be "silabs,wfx-spi"
+ - reg: Chip select address of device
+ - spi-max-frequency: Maximum SPI clocking speed of device in Hz
+ - interrupts-extended: Should contain interrupt line (interrupt-parent +
+   interrupt can also been used). Trigger should be `IRQ_TYPE_EDGE_RISING`.
+
+Optional properties:
+ - reset-gpios: phandle of gpio that will be used to reset chip during probe.
+   Without this property, you may encounter issues with warm boot.
+
+Please consult Documentation/devicetree/bindings/spi/spi-bus.txt for optional
+SPI connection related properties,
+
+Example:
+
+ {
+   wfx {
+   compatible = "silabs,wfx-spi";
+   pinctrl-names = "default";
+   pinctrl-0 = <_irq _gpios>;
+   interrupts-extended = < 16 IRQ_TYPE_EDGE_RISING>;
+   wakeup-gpios = < 12 GPIO_ACTIVE_HIGH>;
+   reset-gpios = < 13 GPIO_ACTIVE_HIGH>;
+   reg = <0>;
+   spi-max-frequency = <4200>;
+   };
+};
+
+
+SDIO
+
+
+The driver is able to detect a WFxxx chip on SDIO bus by matching its Vendor ID
+and Product ID. However, driver will only provide limited features in this
+case. Thus declaring WFxxx chip in device tree is strongly 

[PATCH v2 15/20] staging: wfx: add debug files and trace debug events

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Add traces when debug events happen and allow to ask internal
information to chip.

These features work independently from mac80211.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/debug.c  | 105 +++
 drivers/staging/wfx/hif_rx.c |  80 ++
 drivers/staging/wfx/main.c   |   2 +
 drivers/staging/wfx/wfx.h|  16 ++
 4 files changed, 203 insertions(+)

diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 0619c7d1cf79..1e23bb5bde3e 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -6,11 +6,13 @@
  * Copyright (c) 2010, ST-Ericsson
  */
 #include 
+#include 
 #include 
 
 #include "debug.h"
 #include "wfx.h"
 #include "main.h"
+#include "hif_tx_mib.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
@@ -55,6 +57,107 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map);
 }
 
+static int wfx_counters_show(struct seq_file *seq, void *v)
+{
+   int ret;
+   struct wfx_dev *wdev = seq->private;
+   struct hif_mib_extended_count_table counters;
+
+   ret = hif_get_counters_table(wdev, );
+   if (ret < 0)
+   return ret;
+   if (ret > 0)
+   return -EIO;
+
+#define PUT_COUNTER(name) \
+   seq_printf(seq, "%24s %d\n", #name ":", 
le32_to_cpu(counters.count_##name))
+
+   PUT_COUNTER(tx_packets);
+   PUT_COUNTER(tx_multicast_frames);
+   PUT_COUNTER(tx_frames_success);
+   PUT_COUNTER(tx_frame_failures);
+   PUT_COUNTER(tx_frames_retried);
+   PUT_COUNTER(tx_frames_multi_retried);
+
+   PUT_COUNTER(rts_success);
+   PUT_COUNTER(rts_failures);
+   PUT_COUNTER(ack_failures);
+
+   PUT_COUNTER(rx_packets);
+   PUT_COUNTER(rx_frames_success);
+   PUT_COUNTER(rx_packet_errors);
+   PUT_COUNTER(plcp_errors);
+   PUT_COUNTER(fcs_errors);
+   PUT_COUNTER(rx_decryption_failures);
+   PUT_COUNTER(rx_mic_failures);
+   PUT_COUNTER(rx_no_key_failures);
+   PUT_COUNTER(rx_frame_duplicates);
+   PUT_COUNTER(rx_multicast_frames);
+   PUT_COUNTER(rx_cmacicv_errors);
+   PUT_COUNTER(rx_cmac_replays);
+   PUT_COUNTER(rx_mgmt_ccmp_replays);
+
+   PUT_COUNTER(rx_beacon);
+   PUT_COUNTER(miss_beacon);
+
+#undef PUT_COUNTER
+
+   return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_counters);
+
+static const char * const channel_names[] = {
+   [0] = "1M",
+   [1] = "2M",
+   [2] = "5.5M",
+   [3] = "11M",
+   /* Entries 4 and 5 does not exist */
+   [6] = "6M",
+   [7] = "9M",
+   [8] = "12M",
+   [9] = "18M",
+   [10] = "24M",
+   [11] = "36M",
+   [12] = "48M",
+   [13] = "54M",
+   [14] = "MCS0",
+   [15] = "MCS1",
+   [16] = "MCS2",
+   [17] = "MCS3",
+   [18] = "MCS4",
+   [19] = "MCS5",
+   [20] = "MCS6",
+   [21] = "MCS7",
+};
+
+static int wfx_rx_stats_show(struct seq_file *seq, void *v)
+{
+   struct wfx_dev *wdev = seq->private;
+   struct hif_rx_stats *st = >rx_stats;
+   int i;
+
+   mutex_lock(>rx_stats_lock);
+   seq_printf(seq, "Timestamp: %dus\n", st->date);
+   seq_printf(seq, "Low power clock: frequency %uHz, external %s\n",
+   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], st->nb_rx_by_rate[i],
+  st->per[i], st->rssi[i] / 100,
+  st->snr[i] / 100, st->cfo[i]);
+   }
+   mutex_unlock(>rx_stats_lock);
+
+   return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats);
+
 static ssize_t wfx_send_pds_write(struct file *file, const char __user 
*user_buf,
 size_t count, loff_t *ppos)
 {
@@ -190,6 +293,8 @@ 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, _counters_fops);
+   debugfs_create_file("rx_stats", 0444, d, wdev, _rx_stats_fops);
debugfs_create_file("send_pds", 0200, d, wdev, _send_pds_fops);
debugfs_create_file("burn_slk_key", 0200, d, wdev, 
_burn_slk_key_fops);
debugfs_create_file("send_hif_msg", 0600, d, wdev, 
_send_hif_msg_fops);
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index 6b9683d69a3f..c93bae1b6acf 100644
--- 

[PATCH v2 06/20] staging: wfx: import HIF API headers

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

These files are shared with firmware sources. Only a subset of these
definitions are used by driver but, for now, it is easier to import all.

API defines 3 kinds of messages:
   - Requests (req) are sent from host to chip
   - Confirmations (cnf) are sent by chip and are always in reply to a
 request
   - Indications (ind) are spontaneous message from chip to host

One request normally generate one confirmation. There are a few
exceptions to this rule:
   - "shutdown" request is not acknowledged
   - multiple tx request can be acknowledged a unique "multi-tx"
 confirmation

In add, API defines MIB. They are sub-structures for write_mib and
read_mib API.

Note that all numbers in API have to be little endian when sent/received
from/to chip (I didn't declared them with __le32 because driver also use
them internally).

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/hif_api_cmd.h | 681 ++
 drivers/staging/wfx/hif_api_general.h | 437 +
 drivers/staging/wfx/hif_api_mib.h | 558 +
 3 files changed, 1676 insertions(+)
 create mode 100644 drivers/staging/wfx/hif_api_cmd.h
 create mode 100644 drivers/staging/wfx/hif_api_general.h
 create mode 100644 drivers/staging/wfx/hif_api_mib.h

diff --git a/drivers/staging/wfx/hif_api_cmd.h 
b/drivers/staging/wfx/hif_api_cmd.h
new file mode 100644
index ..7c5d1ea6098d
--- /dev/null
+++ b/drivers/staging/wfx/hif_api_cmd.h
@@ -0,0 +1,681 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * WFx hardware interface definitions
+ *
+ * Copyright (c) 2018-2019, Silicon Laboratories Inc.
+ */
+
+#ifndef WFX_HIF_API_CMD_H
+#define WFX_HIF_API_CMD_H
+
+#include "hif_api_general.h"
+
+#define HIF_NUM_AC 4
+
+#define HIF_API_SSID_SIZE  API_SSID_SIZE
+
+enum hif_requests_ids {
+   HIF_REQ_ID_RESET = 0x0a,
+   HIF_REQ_ID_READ_MIB  = 0x05,
+   HIF_REQ_ID_WRITE_MIB = 0x06,
+   HIF_REQ_ID_START_SCAN= 0x07,
+   HIF_REQ_ID_STOP_SCAN = 0x08,
+   HIF_REQ_ID_TX= 0x04,
+   HIF_REQ_ID_JOIN  = 0x0b,
+   HIF_REQ_ID_SET_PM_MODE   = 0x10,
+   HIF_REQ_ID_SET_BSS_PARAMS= 0x11,
+   HIF_REQ_ID_ADD_KEY   = 0x0c,
+   HIF_REQ_ID_REMOVE_KEY= 0x0d,
+   HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13,
+   HIF_REQ_ID_START = 0x17,
+   HIF_REQ_ID_BEACON_TRANSMIT   = 0x18,
+   HIF_REQ_ID_UPDATE_IE = 0x1b,
+   HIF_REQ_ID_MAP_LINK  = 0x1c,
+};
+
+enum hif_confirmations_ids {
+   HIF_CNF_ID_RESET = 0x0a,
+   HIF_CNF_ID_READ_MIB  = 0x05,
+   HIF_CNF_ID_WRITE_MIB = 0x06,
+   HIF_CNF_ID_START_SCAN= 0x07,
+   HIF_CNF_ID_STOP_SCAN = 0x08,
+   HIF_CNF_ID_TX= 0x04,
+   HIF_CNF_ID_MULTI_TRANSMIT= 0x1e,
+   HIF_CNF_ID_JOIN  = 0x0b,
+   HIF_CNF_ID_SET_PM_MODE   = 0x10,
+   HIF_CNF_ID_SET_BSS_PARAMS= 0x11,
+   HIF_CNF_ID_ADD_KEY   = 0x0c,
+   HIF_CNF_ID_REMOVE_KEY= 0x0d,
+   HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13,
+   HIF_CNF_ID_START = 0x17,
+   HIF_CNF_ID_BEACON_TRANSMIT   = 0x18,
+   HIF_CNF_ID_UPDATE_IE = 0x1b,
+   HIF_CNF_ID_MAP_LINK  = 0x1c,
+};
+
+enum hif_indications_ids {
+   HIF_IND_ID_RX= 0x84,
+   HIF_IND_ID_SCAN_CMPL = 0x86,
+   HIF_IND_ID_JOIN_COMPLETE = 0x8f,
+   HIF_IND_ID_SET_PM_MODE_CMPL  = 0x89,
+   HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c,
+   HIF_IND_ID_EVENT = 0x85
+};
+
+union hif_commands_ids {
+   enum hif_requests_ids request;
+   enum hif_confirmations_ids confirmation;
+   enum hif_indications_ids indication;
+};
+
+enum hif_status {
+   HIF_STATUS_SUCCESS = 0x0,
+   HIF_STATUS_FAILURE = 0x1,
+   HIF_INVALID_PARAMETER  = 0x2,
+   HIF_STATUS_WARNING = 0x3,
+   HIF_ERROR_UNSUPPORTED_MSG_ID   = 0x4,
+   HIF_STATUS_DECRYPTFAILURE  = 0x10,
+   HIF_STATUS_MICFAILURE  = 0x11,
+   HIF_STATUS_NO_KEY_FOUND= 0x12,

[PATCH v2 05/20] staging: wfx: load firmware

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

A firmware is necessary to run the chip. wfx_init_device() is in charge
of loading firmware on chip and doing low level initialization.

Firmwares for WF200 are available here:

  https://github.com/SiliconLabs/wfx-firmware/

Note that firmware are encrypted. Driver checks that key used to encrypt
firmware match with key burned into chip.

Currently, "C0" key is used for production chips.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile   |   1 +
 drivers/staging/wfx/bus_sdio.c |   8 +
 drivers/staging/wfx/bus_spi.c  |   7 +
 drivers/staging/wfx/fwio.c | 387 +
 drivers/staging/wfx/fwio.h |  15 ++
 drivers/staging/wfx/main.c |  20 ++
 drivers/staging/wfx/main.h |  10 +
 drivers/staging/wfx/wfx.h  |   2 +
 8 files changed, 450 insertions(+)
 create mode 100644 drivers/staging/wfx/fwio.c
 create mode 100644 drivers/staging/wfx/fwio.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 330b7288ebb5..e568d7a6fb06 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -5,6 +5,7 @@ CFLAGS_debug.o = -I$(src)
 
 wfx-y := \
hwio.o \
+   fwio.o \
main.o \
debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 35bcca7ec5dc..25c587fe2141 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -17,6 +17,7 @@
 #include "main.h"
 
 static const struct wfx_platform_data wfx_sdio_pdata = {
+   .file_fw = "wfm_wf200",
 };
 
 struct wfx_sdio_priv {
@@ -204,8 +205,14 @@ static int wfx_sdio_probe(struct sdio_func *func,
goto err2;
}
 
+   ret = wfx_probe(bus->core);
+   if (ret)
+   goto err3;
+
return 0;
 
+err3:
+   wfx_free_common(bus->core);
 err2:
wfx_sdio_irq_unsubscribe(bus);
 err1:
@@ -220,6 +227,7 @@ static void wfx_sdio_remove(struct sdio_func *func)
 {
struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
 
+   wfx_release(bus->core);
wfx_free_common(bus->core);
wfx_sdio_irq_unsubscribe(bus);
sdio_claim_host(func);
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index 5e8f84baf2ca..b73b9416273f 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -27,6 +27,8 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for 
none.");
 #define SET_READ 0x8000 /* usage: or operation */
 
 static const struct wfx_platform_data wfx_spi_pdata = {
+   .file_fw = "wfm_wf200",
+   .use_rising_clk = true,
 };
 
 struct wfx_spi_priv {
@@ -205,6 +207,10 @@ static int wfx_spi_probe(struct spi_device *func)
if (!bus->core)
return -EIO;
 
+   ret = wfx_probe(bus->core);
+   if (ret)
+   wfx_free_common(bus->core);
+
return ret;
 }
 
@@ -213,6 +219,7 @@ static int wfx_spi_disconnect(struct spi_device *func)
 {
struct wfx_spi_priv *bus = spi_get_drvdata(func);
 
+   wfx_release(bus->core);
wfx_free_common(bus->core);
// A few IRQ will be sent during device release. Hopefully, no IRQ
// should happen after wdev/wvif are released.
diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c
new file mode 100644
index ..8fb4a9f6d1a6
--- /dev/null
+++ b/drivers/staging/wfx/fwio.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Firmware loading.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+#include 
+#include 
+
+#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_SIZE0x8000 // (32 * DNLD_BLOCK_SIZE)
+// Download Control Area (DCA)
+#define WFX_DCA_IMAGE_SIZE0x0900C000
+#define WFX_DCA_PUT   0x0900C004
+#define WFX_DCA_GET   0x0900C008
+#define WFX_DCA_HOST_STATUS   0x0900C00C
+#define HOST_READY0x87654321
+#define HOST_INFO_READ0xA753BD99
+#define HOST_UPLOAD_PENDING   0xABCDDCBA
+#define HOST_UPLOAD_COMPLETE  0xD4C64A99
+#define HOST_OK_TO_JUMP   0x174FC882
+#define WFX_DCA_NCP_STATUS0x0900C010
+#define NCP_NOT_READY 0x12345678
+#define NCP_READY 0x87654321
+#define NCP_INFO_READY0xBD53EF99
+#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

[PATCH v2 07/20] staging: wfx: add IRQ handling

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

bh_work() is in charge to schedule all HIF message from/to chip.

On normal operation, when an IRQ is received, driver can get size of
next message in control register. In order to save control register
access, when chip send a message, it also appends a copy of control
register after the message (this register is not accounted in message
length declared in message header, but must accounted in bus request).
This copy of control register is called "piggyback".

It also handles a power saving mechanism specific to WFxxx series. This
mechanism is based on a GPIO called "wakeup" GPIO. Obviously, this gpio
is not part of SPI/SDIO standard buses and must be declared
independently (this is the main reason for why SDIO mode try to get
parameters from DT).

When wakeup is enabled, host can communicate with chip only if it is
awake. To wake up chip, there are two cases:
- host receive an IRQ from chip (chip initiate communication): host
  just have to set wakeup GPIO before reading data
- host want to send data to chip: host set wakeup GPIO, then wait
  for an IRQ (in fact, wait for an empty message) and finally send data

bh_work() is also in charge to track usage of chip buffers. Normally
each request expect a confirmation. However, you can notice that special
"multi tx" confirmation can acknowledge multiple requests at time.

Finally, note that wfx_bh_request_rx() is not atomic (because of
control_reg_read()). So, in SPI mode, hard-irq handler only postpone all
processing to wfx_spi_request_rx().

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile   |   1 +
 drivers/staging/wfx/bh.c   | 277 +
 drivers/staging/wfx/bh.h   |  32 
 drivers/staging/wfx/bus_sdio.c |   4 +-
 drivers/staging/wfx/bus_spi.c  |   5 +
 drivers/staging/wfx/main.c |  21 +++
 drivers/staging/wfx/main.h |   2 +
 drivers/staging/wfx/wfx.h  |   4 +
 8 files changed, 345 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/wfx/bh.c
 create mode 100644 drivers/staging/wfx/bh.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index e568d7a6fb06..1abd3115f11d 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -4,6 +4,7 @@
 CFLAGS_debug.o = -I$(src)
 
 wfx-y := \
+   bh.o \
hwio.o \
fwio.o \
main.o \
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
new file mode 100644
index ..02a42e5c1e10
--- /dev/null
+++ b/drivers/staging/wfx/bh.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Interrupt bottom half (BH).
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#include "bh.h"
+#include "wfx.h"
+#include "hwio.h"
+#include "hif_api_cmd.h"
+
+static void device_wakeup(struct wfx_dev *wdev)
+{
+   if (!wdev->pdata.gpio_wakeup)
+   return;
+   if (gpiod_get_value(wdev->pdata.gpio_wakeup))
+   return;
+
+   gpiod_set_value(wdev->pdata.gpio_wakeup, 1);
+   if (wfx_api_older_than(wdev, 1, 4)) {
+   if (!completion_done(>hif.ctrl_ready))
+   udelay(2000);
+   } else {
+   // 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(>hif.ctrl_ready, 
msecs_to_jiffies(2) + 1))
+   complete(>hif.ctrl_ready);
+   else
+   dev_err(wdev->dev, "timeout while wake up chip\n");
+   }
+}
+
+static void device_release(struct wfx_dev *wdev)
+{
+   if (!wdev->pdata.gpio_wakeup)
+   return;
+
+   gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
+}
+
+static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
+{
+   struct sk_buff *skb;
+   struct hif_msg *hif;
+   size_t alloc_len;
+   size_t computed_len;
+   int release_count;
+   int piggyback = 0;
+
+   WARN_ON(read_len < 4);
+   WARN(read_len > round_down(0xFFF, 2) * sizeof(u16),
+"%s: request exceed WFx capability", __func__);
+
+   // Add 2 to take into account piggyback size
+   alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2);
+   skb = dev_alloc_skb(alloc_len);
+   if (!skb)
+   return -ENOMEM;
+
+   if (wfx_data_read(wdev, skb->data, alloc_len))
+   goto err;
+
+   piggyback = le16_to_cpup((u16 *) (skb->data + alloc_len - 2));
+
+   hif = (struct hif_msg *) skb->data;
+   WARN(hif->encrypted & 0x1, "unsupported encryption type");
+   if (hif->encrypted == 0x2) {
+   BUG(); // Not yet implemented
+   } else {
+   le16_to_cpus(hif->len);
+   computed_len = 

[PATCH v2 00/20] Add support for Silicon Labs WiFi chip WF200 and further

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Hello all,

This series add support for Silicon Labs WiFi chip WF200 and further:

   https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf

This driver is an export from:

   https://github.com/SiliconLabs/wfx-linux-driver/
   
I squashed all commits from github (it definitely does not make sense to
import history). Then I split it in comprehensible (at least try to be)
commits. I hope it will help readers to understand driver architecture.
IMHO, firsts commits are clean enough to be reviewed. Things get more
difficult when I introduce mac8011 API. I tried to extract important
parts like Rx/Tx process but, big and complex patches seem unavoidable
in this part.

Architecture itself is described in commit messages.

The series below is aligned on version 2.3.1 on github. If compare this
series with github, you will find traditional differences between
external and a in-tree driver: Documentation, build infrastructure,
compatibility with older kernel revisions, etc... In add, I dropped all
code in CONFIG_WFX_SECURE_LINK. Indeed, "Secure Link" feature depends
on mbedtls and I don't think to pull mbedtls in kernel is an option
(see "TODO" file in first commit).


Changes in v2:
  - Add TODO file (and dropped todo list from cover letter)
  - Drop code relative to compatibility with older kernels
  
Jérôme Pouiller (20):
  staging: wfx: add infrastructure for new driver
  staging: wfx: add support for I/O access
  staging: wfx: add I/O API
  staging: wfx: add tracepoints for I/O access
  staging: wfx: load firmware
  staging: wfx: import HIF API headers
  staging: wfx: add IRQ handling
  staging: wfx: add tracepoints for HIF
  staging: wfx: add support for start-up indication
  staging: wfx: instantiate mac80211 data
  staging: wfx: allow to send commands to chip
  staging: wfx: add HIF commands helpers
  staging: wfx: introduce "secure link"
  staging: wfx: setup initial chip configuration
  staging: wfx: add debug files and trace debug events
  staging: wfx: allow to send 802.11 frames
  staging: wfx: allow to receive 802.11 frames
  staging: wfx: allow to scan networks
  staging: wfx: implement 802.11 key handling
  staging: wfx: implement the rest of mac80211 API

 MAINTAINERS   |5 +
 drivers/staging/Kconfig   |2 +
 drivers/staging/Makefile  |1 +
 .../bindings/net/wireless/siliabs,wfx.txt |   97 +
 drivers/staging/wfx/Kconfig   |7 +
 drivers/staging/wfx/Makefile  |   24 +
 drivers/staging/wfx/TODO  |   20 +
 drivers/staging/wfx/bh.c  |  316 
 drivers/staging/wfx/bh.h  |   32 +
 drivers/staging/wfx/bus.h |   34 +
 drivers/staging/wfx/bus_sdio.c|  268 +++
 drivers/staging/wfx/bus_spi.c |  264 +++
 drivers/staging/wfx/data_rx.c |  208 +++
 drivers/staging/wfx/data_rx.h |   18 +
 drivers/staging/wfx/data_tx.c |  799 
 drivers/staging/wfx/data_tx.h |   93 +
 drivers/staging/wfx/debug.c   |  305 +++
 drivers/staging/wfx/debug.h   |   19 +
 drivers/staging/wfx/fwio.c|  387 
 drivers/staging/wfx/fwio.h|   15 +
 drivers/staging/wfx/hif_api_cmd.h |  681 +++
 drivers/staging/wfx/hif_api_general.h |  437 +
 drivers/staging/wfx/hif_api_mib.h |  558 ++
 drivers/staging/wfx/hif_rx.c  |  336 
 drivers/staging/wfx/hif_rx.h  |   18 +
 drivers/staging/wfx/hif_tx.c  |  470 +
 drivers/staging/wfx/hif_tx.h  |   67 +
 drivers/staging/wfx/hif_tx_mib.h  |  281 +++
 drivers/staging/wfx/hwio.c|  338 
 drivers/staging/wfx/hwio.h|   75 +
 drivers/staging/wfx/key.c |  258 +++
 drivers/staging/wfx/key.h |   22 +
 drivers/staging/wfx/main.c|  500 +
 drivers/staging/wfx/main.h|   48 +
 drivers/staging/wfx/queue.c   |  606 ++
 drivers/staging/wfx/queue.h   |   59 +
 drivers/staging/wfx/scan.c|  289 +++
 drivers/staging/wfx/scan.h|   42 +
 drivers/staging/wfx/secure_link.h |   46 +
 drivers/staging/wfx/sta.c | 1643 +
 drivers/staging/wfx/sta.h |  101 +
 drivers/staging/wfx/traces.h  |  434 +
 drivers/staging/wfx/wfx.h |  204 ++
 drivers/staging/wfx/wfx_version.h |3 +
 44 files changed, 10430 insertions(+)
 create mode 100644 
drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
 create mode 100644 drivers/staging/wfx/Kconfig
 create mode 

[PATCH v2 02/20] staging: wfx: add support for I/O access

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Introduce bus level communication layer. At this level, 7 registers can
be addressed.

Notice that SPI driver is able to manage chip reset. SDIO mode relies
on an external driver (`mmc-pwrseq`) to reset chip.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bus.h  |  17 +++
 drivers/staging/wfx/bus_sdio.c | 189 ++-
 drivers/staging/wfx/bus_spi.c  | 200 -
 drivers/staging/wfx/hwio.h |  48 
 drivers/staging/wfx/main.c |  53 +
 drivers/staging/wfx/main.h |  32 ++
 drivers/staging/wfx/wfx.h  |  24 
 7 files changed, 561 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/hwio.h
 create mode 100644 drivers/staging/wfx/main.h
 create mode 100644 drivers/staging/wfx/wfx.h

diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h
index 8ce871a8a9ff..eb77abc09ec2 100644
--- a/drivers/staging/wfx/bus.h
+++ b/drivers/staging/wfx/bus.h
@@ -11,6 +11,23 @@
 #include 
 #include 
 
+#define WFX_REG_CONFIG0x0
+#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_DPORT0x5
+#define WFX_REG_SET_GEN_R_W   0x6
+#define WFX_REG_FRAME_OUT 0x7
+
+struct hwbus_ops {
+   int (*copy_from_io)(void *bus_priv, unsigned int addr, void *dst, 
size_t count);
+   int (*copy_to_io)(void *bus_priv, unsigned int addr, const void *src, 
size_t count);
+   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;
 
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 4b26c994f43c..35bcca7ec5dc 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -8,36 +8,223 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "bus.h"
+#include "wfx.h"
+#include "hwio.h"
+#include "main.h"
+
+static const struct wfx_platform_data wfx_sdio_pdata = {
+};
+
+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;
+
+   BUG_ON(reg_id > 7);
+   WARN(((uintptr_t) dst) & 3, "unaligned buffer size");
+   WARN(count & 3, "unaligned buffer address");
+
+   /* Use queue mode buffers */
+   if (reg_id == WFX_REG_IN_OUT_QUEUE)
+   sdio_addr |= (bus->buf_id_rx + 1) << 7;
+   ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count);
+   if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
+   bus->buf_id_rx = (bus->buf_id_rx + 1) % 4;
+
+   return ret;
+}
+
+static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id,
+  const void *src, size_t count)
+{
+   struct wfx_sdio_priv *bus = priv;
+   unsigned int sdio_addr = reg_id << 2;
+   int ret;
+
+   BUG_ON(reg_id > 7);
+   WARN(((uintptr_t) src) & 3, "unaligned buffer size");
+   WARN(count & 3, "unaligned buffer address");
+
+   /* Use queue mode buffers */
+   if (reg_id == WFX_REG_IN_OUT_QUEUE)
+   sdio_addr |= bus->buf_id_tx << 7;
+   // FIXME: discards 'const' qualifier for src
+   ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *) src, count);
+   if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
+   bus->buf_id_tx = (bus->buf_id_tx + 1) % 32;
+
+   return ret;
+}
+
+static void wfx_sdio_lock(void *priv)
+{
+   struct wfx_sdio_priv *bus = priv;
+
+   sdio_claim_host(bus->func);
+}
+
+static void wfx_sdio_unlock(void *priv)
+{
+   struct wfx_sdio_priv *bus = priv;
+
+   sdio_release_host(bus->func);
+}
+
+static void wfx_sdio_irq_handler(struct sdio_func *func)
+{
+   struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
+
+   if (bus->core)
+   /* empty */;
+   else
+   WARN(!bus->core, "race condition in driver init/deinit");
+}
+
+static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv)
+{
+   struct wfx_sdio_priv *bus = priv;
+
+   if (!bus->core) {
+   WARN(!bus->core, "race condition in driver init/deinit");
+   return IRQ_NONE;
+   }
+   sdio_claim_host(bus->func);
+   sdio_release_host(bus->func);
+   return IRQ_HANDLED;
+}
+
+static int wfx_sdio_irq_subscribe(struct wfx_sdio_priv *bus)
+{
+   int ret;
+
+   if (bus->of_irq) {
+   ret = request_irq(bus->of_irq, wfx_sdio_irq_handler_ext,
+ IRQF_TRIGGER_RISING, "wfx", bus);
+   } else {
+  

[PATCH v2 14/20] staging: wfx: setup initial chip configuration

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

A few tasks remain to be done in order to finish chip initial
configuration:
   - configure chip to use multi-tx confirmation (speed up data
 transfer)
   - configure chip to use wake-up feature (save power consumption
 during runtime)
   - set hardware configuration (clocks, RF, pinout, etc...) using a
 Platform Data Set (PDS) file

On release, driver completely shutdown the chip to save power
consumption.

Documentation about PDS and PDS data for sample boards are available
here[1]. One day, PDS data may find a place in device tree but,
currently, PDS is too much linked with firmware to allowing that.

This patch also add "send_pds" file in debugfs to be able to dynamically
change PDS (only for debug, of course).

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

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bus_sdio.c |  1 +
 drivers/staging/wfx/bus_spi.c  |  1 +
 drivers/staging/wfx/debug.c| 29 +++
 drivers/staging/wfx/hif_rx.c   | 11 
 drivers/staging/wfx/main.c | 94 ++
 drivers/staging/wfx/main.h |  2 +
 6 files changed, 138 insertions(+)

diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index c0c063c3cfc9..05f02c278782 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -19,6 +19,7 @@
 
 static const struct wfx_platform_data wfx_sdio_pdata = {
.file_fw = "wfm_wf200",
+   .file_pds = "wf200.pds",
 };
 
 struct wfx_sdio_priv {
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index b7cd82b4e5e7..f65f7d75e731 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -29,6 +29,7 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for 
none.");
 
 static const struct wfx_platform_data wfx_spi_pdata = {
.file_fw = "wfm_wf200",
+   .file_pds = "wf200.pds",
.use_rising_clk = true,
 };
 
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index f79693a4be7f..0619c7d1cf79 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -10,6 +10,7 @@
 
 #include "debug.h"
 #include "wfx.h"
+#include "main.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
@@ -54,6 +55,33 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map);
 }
 
+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,
+};
+
 static ssize_t wfx_burn_slk_key_write(struct file *file,
  const char __user *user_buf,
  size_t count, loff_t *ppos)
@@ -162,6 +190,7 @@ int wfx_debug_init(struct wfx_dev *wdev)
struct dentry *d;
 
d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+   debugfs_create_file("send_pds", 0200, d, wdev, _send_pds_fops);
debugfs_create_file("burn_slk_key", 0200, d, wdev, 
_burn_slk_key_fops);
debugfs_create_file("send_hif_msg", 0600, d, wdev, 
_send_hif_msg_fops);
 
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index dd5f1dea4e85..6b9683d69a3f 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -71,6 +71,16 @@ static int hif_startup_indication(struct wfx_dev *wdev, 
struct hif_msg *hif, voi
return 0;
 }
 
+static int hif_wakeup_indication(struct wfx_dev *wdev, struct hif_msg *hif, 
void *buf)
+{
+   if (!wdev->pdata.gpio_wakeup
+   || !gpiod_get_value(wdev->pdata.gpio_wakeup)) {
+   dev_warn(wdev->dev, "unexpected wake-up indication\n");
+   return -EIO;
+   }
+   return 0;
+}
+
 static int hif_keys_indication(struct wfx_dev *wdev, struct hif_msg *hif, void 
*buf)
 {
struct hif_ind_sl_exchange_pub_keys *body = buf;
@@ -89,6 +99,7 @@ static const struct {
int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
 } hif_handlers[] = {
{ HIF_IND_ID_STARTUP,  hif_startup_indication },
+   { HIF_IND_ID_WAKEUP,   hif_wakeup_indication },
{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
 };
 
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 

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

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

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

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

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 1abd3115f11d..35670b86c64f 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -7,6 +7,7 @@ wfx-y := \
bh.o \
hwio.o \
fwio.o \
+   hif_rx.o \
main.o \
debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index 76afecdf579d..c40da3f1f25d 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -12,6 +12,7 @@
 #include "wfx.h"
 #include "hwio.h"
 #include "traces.h"
+#include "hif_rx.h"
 #include "hif_api_cmd.h"
 
 static void device_wakeup(struct wfx_dev *wdev)
@@ -107,7 +108,8 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
}
 
skb_put(skb, hif->len);
-   dev_kfree_skb(skb); /* FIXME: handle received data */
+   // wfx_handle_rx takes care on SKB livetime
+   wfx_handle_rx(wdev, skb);
 
return piggyback;
 
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
new file mode 100644
index ..5c207e6d4348
--- /dev/null
+++ b/drivers/staging/wfx/hif_rx.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
+ * (WSM) API.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#include "hif_rx.h"
+#include "wfx.h"
+#include "hif_api_cmd.h"
+
+static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, 
void *buf)
+{
+   struct hif_ind_startup *body = buf;
+
+   if (body->status || body->firmware_type > 4) {
+   dev_err(wdev->dev, "received invalid startup indication");
+   return -EINVAL;
+   }
+   memcpy(>hw_caps, body, sizeof(struct hif_ind_startup));
+   le32_to_cpus(>hw_caps.status);
+   le16_to_cpus(>hw_caps.hardware_id);
+   le16_to_cpus(>hw_caps.num_inp_ch_bufs);
+   le16_to_cpus(>hw_caps.size_inp_ch_buf);
+
+   complete(>firmware_ready);
+   return 0;
+}
+
+static const struct {
+   int msg_id;
+   int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
+} hif_handlers[] = {
+   { HIF_IND_ID_STARTUP,  hif_startup_indication },
+};
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
+{
+   int i;
+   struct hif_msg *hif = (struct hif_msg *) skb->data;
+   int hif_id = hif->id;
+
+   for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) {
+   if (hif_handlers[i].msg_id == hif_id) {
+   if (hif_handlers[i].handler)
+   hif_handlers[i].handler(wdev, hif, hif->body);
+   goto free;
+   }
+   }
+   dev_err(wdev->dev, "unsupported HIF ID %02x\n", hif_id);
+free:
+   dev_kfree_skb(skb);
+}
diff --git a/drivers/staging/wfx/hif_rx.h b/drivers/staging/wfx/hif_rx.h
new file mode 100644
index ..f07c10c8c6bd
--- /dev/null
+++ b/drivers/staging/wfx/hif_rx.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
+ * (WSM) API.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ * Copyright (C) 2010, ST-Ericsson SA
+ */
+#ifndef WFX_HIF_RX_H
+#define WFX_HIF_RX_H
+
+struct wfx_dev;
+struct sk_buff;
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb);
+
+#endif
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index f0bea053a0d9..5e7e7225f068 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -12,6 +12,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -87,6 +88,9 @@ struct wfx_dev *wfx_init_common(struct device *dev,
wdev->hwbus_ops = hwbus_ops;
wdev->hwbus_priv = hwbus_priv;
memcpy(>pdata, pdata, sizeof(*pdata));
+
+   init_completion(>firmware_ready);
+
return wdev;
 }
 
@@ -96,7 +100,9 @@ void wfx_free_common(struct wfx_dev *wdev)
 
 int wfx_probe(struct wfx_dev *wdev)
 {
+   int i;
int err;
+   const 

[PATCH v2 18/20] staging: wfx: allow to scan networks

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/bh.c |   2 +-
 drivers/staging/wfx/hif_rx.c |  13 ++
 drivers/staging/wfx/main.c   |   5 +
 drivers/staging/wfx/scan.c   | 249 +++
 drivers/staging/wfx/scan.h   |  42 ++
 drivers/staging/wfx/sta.c|  23 +++-
 drivers/staging/wfx/sta.h|   4 +
 drivers/staging/wfx/wfx.h|  11 ++
 9 files changed, 348 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/scan.c
 create mode 100644 drivers/staging/wfx/scan.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index d9e21515d08e..2b8a5fa86fac 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -12,6 +12,7 @@ wfx-y := \
queue.o \
data_tx.o \
data_rx.o \
+   scan.o \
sta.o \
main.o \
sta.o \
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index ed81c3924d98..6000c03bb658 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -268,7 +268,7 @@ static void bh_work(struct work_struct *work)
 
if (last_op_is_rx)
ack_sdio_data(wdev);
-   if (!wdev->hif.tx_buffers_used && !work_pending(work)) {
+   if (!wdev->hif.tx_buffers_used && !work_pending(work) && 
!atomic_read(>scan_in_progress)) {
device_release(wdev);
release_chip = true;
}
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index c07984b0535d..d386fab0a90f 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -11,6 +11,7 @@
 
 #include "hif_rx.h"
 #include "wfx.h"
+#include "scan.h"
 #include "data_rx.h"
 #include "secure_link.h"
 #include "hif_api_cmd.h"
@@ -143,6 +144,17 @@ static int hif_receive_indication(struct wfx_dev *wdev, 
struct hif_msg *hif, voi
return 0;
 }
 
+static int hif_scan_complete_indication(struct wfx_dev *wdev, struct hif_msg 
*hif, void *buf)
+{
+   struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+   struct hif_ind_scan_cmpl *body = buf;
+
+   WARN_ON(!wvif);
+   wfx_scan_complete_cb(wvif, body);
+
+   return 0;
+}
+
 static int hif_join_complete_indication(struct wfx_dev *wdev, struct hif_msg 
*hif, void *buf)
 {
struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
@@ -230,6 +242,7 @@ static const struct {
{ HIF_IND_ID_STARTUP,  hif_startup_indication },
{ HIF_IND_ID_WAKEUP,   hif_wakeup_indication },
{ HIF_IND_ID_JOIN_COMPLETE,hif_join_complete_indication },
+   { HIF_IND_ID_SCAN_CMPL,hif_scan_complete_indication },
{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
{ HIF_IND_ID_GENERIC,  hif_generic_indication },
{ HIF_IND_ID_ERROR,hif_error_indication },
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index cce4e30dd94a..06220bac5b75 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -55,6 +55,7 @@ static const struct ieee80211_ops wfx_ops = {
.add_interface  = wfx_add_interface,
.remove_interface   = wfx_remove_interface,
.tx = wfx_tx,
+   .hw_scan= wfx_hw_scan,
 };
 
 bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor)
@@ -203,6 +204,8 @@ struct wfx_dev *wfx_init_common(struct device *dev,
hw->extra_tx_headroom = sizeof(struct hif_sl_msg_hdr) + sizeof(struct 
hif_msg)
+ sizeof(struct hif_req_tx)
+ 4 /* alignment */ + 8 /* TKIP IV */;
+   hw->wiphy->max_scan_ssids = 2;
+   hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
 
wdev = hw->priv;
wdev->hw = hw;
@@ -214,6 +217,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
wdev->pdata.gpio_wakeup = wfx_get_gpio(dev, gpio_wakeup, "wakeup");
wfx_fill_sl_key(dev, >pdata);
 
+   mutex_init(>conf_mutex);
mutex_init(>rx_stats_lock);
init_completion(>firmware_ready);
wfx_init_hif_cmd(>hif_cmd);
@@ -225,6 +229,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
 void wfx_free_common(struct wfx_dev *wdev)
 {
mutex_destroy(>rx_stats_lock);
+   mutex_destroy(>conf_mutex);
wfx_tx_queues_deinit(wdev);
ieee80211_free_hw(wdev->hw);
 }
diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c
new file mode 100644
index ..207b26ebc9fd
--- /dev/null
+++ b/drivers/staging/wfx/scan.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Scan related functions.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+
+#include "scan.h"
+#include "wfx.h"
+#include "sta.h"
+#include "hif_tx_mib.h"
+
+static void 

[PATCH v3 18/20] staging: wfx: allow to scan networks

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Chip can make foreground scan or background, but both can't be mixed in
same request. So, we need to split each mac80211 requests into multiple
HIF requests.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/bh.c |   2 +-
 drivers/staging/wfx/hif_rx.c |  13 ++
 drivers/staging/wfx/main.c   |   5 +
 drivers/staging/wfx/scan.c   | 249 +++
 drivers/staging/wfx/scan.h   |  42 ++
 drivers/staging/wfx/sta.c|  23 +++-
 drivers/staging/wfx/sta.h|   4 +
 drivers/staging/wfx/wfx.h|  11 ++
 9 files changed, 348 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/scan.c
 create mode 100644 drivers/staging/wfx/scan.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index d9e21515d08e..2b8a5fa86fac 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -12,6 +12,7 @@ wfx-y := \
queue.o \
data_tx.o \
data_rx.o \
+   scan.o \
sta.o \
main.o \
sta.o \
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index ed81c3924d98..6000c03bb658 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -268,7 +268,7 @@ static void bh_work(struct work_struct *work)
 
if (last_op_is_rx)
ack_sdio_data(wdev);
-   if (!wdev->hif.tx_buffers_used && !work_pending(work)) {
+   if (!wdev->hif.tx_buffers_used && !work_pending(work) && 
!atomic_read(>scan_in_progress)) {
device_release(wdev);
release_chip = true;
}
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index c07984b0535d..d386fab0a90f 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -11,6 +11,7 @@
 
 #include "hif_rx.h"
 #include "wfx.h"
+#include "scan.h"
 #include "data_rx.h"
 #include "secure_link.h"
 #include "hif_api_cmd.h"
@@ -143,6 +144,17 @@ static int hif_receive_indication(struct wfx_dev *wdev, 
struct hif_msg *hif, voi
return 0;
 }
 
+static int hif_scan_complete_indication(struct wfx_dev *wdev, struct hif_msg 
*hif, void *buf)
+{
+   struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+   struct hif_ind_scan_cmpl *body = buf;
+
+   WARN_ON(!wvif);
+   wfx_scan_complete_cb(wvif, body);
+
+   return 0;
+}
+
 static int hif_join_complete_indication(struct wfx_dev *wdev, struct hif_msg 
*hif, void *buf)
 {
struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
@@ -230,6 +242,7 @@ static const struct {
{ HIF_IND_ID_STARTUP,  hif_startup_indication },
{ HIF_IND_ID_WAKEUP,   hif_wakeup_indication },
{ HIF_IND_ID_JOIN_COMPLETE,hif_join_complete_indication },
+   { HIF_IND_ID_SCAN_CMPL,hif_scan_complete_indication },
{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
{ HIF_IND_ID_GENERIC,  hif_generic_indication },
{ HIF_IND_ID_ERROR,hif_error_indication },
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index cce4e30dd94a..06220bac5b75 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -55,6 +55,7 @@ static const struct ieee80211_ops wfx_ops = {
.add_interface  = wfx_add_interface,
.remove_interface   = wfx_remove_interface,
.tx = wfx_tx,
+   .hw_scan= wfx_hw_scan,
 };
 
 bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor)
@@ -203,6 +204,8 @@ struct wfx_dev *wfx_init_common(struct device *dev,
hw->extra_tx_headroom = sizeof(struct hif_sl_msg_hdr) + sizeof(struct 
hif_msg)
+ sizeof(struct hif_req_tx)
+ 4 /* alignment */ + 8 /* TKIP IV */;
+   hw->wiphy->max_scan_ssids = 2;
+   hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
 
wdev = hw->priv;
wdev->hw = hw;
@@ -214,6 +217,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
wdev->pdata.gpio_wakeup = wfx_get_gpio(dev, gpio_wakeup, "wakeup");
wfx_fill_sl_key(dev, >pdata);
 
+   mutex_init(>conf_mutex);
mutex_init(>rx_stats_lock);
init_completion(>firmware_ready);
wfx_init_hif_cmd(>hif_cmd);
@@ -225,6 +229,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
 void wfx_free_common(struct wfx_dev *wdev)
 {
mutex_destroy(>rx_stats_lock);
+   mutex_destroy(>conf_mutex);
wfx_tx_queues_deinit(wdev);
ieee80211_free_hw(wdev->hw);
 }
diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c
new file mode 100644
index ..207b26ebc9fd
--- /dev/null
+++ b/drivers/staging/wfx/scan.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Scan related functions.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright 

[PATCH v3 14/20] staging: wfx: setup initial chip configuration

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

A few tasks remain to be done in order to finish chip initial
configuration:
   - configure chip to use multi-tx confirmation (speed up data
 transfer)
   - configure chip to use wake-up feature (save power consumption
 during runtime)
   - set hardware configuration (clocks, RF, pinout, etc...) using a
 Platform Data Set (PDS) file

On release, driver completely shutdown the chip to save power
consumption.

Documentation about PDS and PDS data for sample boards are available
here[1]. One day, PDS data may find a place in device tree but,
currently, PDS is too much linked with firmware to allowing that.

This patch also add "send_pds" file in debugfs to be able to dynamically
change PDS (only for debug, of course).

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

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bus_sdio.c |  1 +
 drivers/staging/wfx/bus_spi.c  |  1 +
 drivers/staging/wfx/debug.c| 29 +++
 drivers/staging/wfx/hif_rx.c   | 11 
 drivers/staging/wfx/main.c | 94 ++
 drivers/staging/wfx/main.h |  2 +
 6 files changed, 138 insertions(+)

diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index c0c063c3cfc9..05f02c278782 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -19,6 +19,7 @@
 
 static const struct wfx_platform_data wfx_sdio_pdata = {
.file_fw = "wfm_wf200",
+   .file_pds = "wf200.pds",
 };
 
 struct wfx_sdio_priv {
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index b7cd82b4e5e7..f65f7d75e731 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -29,6 +29,7 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for 
none.");
 
 static const struct wfx_platform_data wfx_spi_pdata = {
.file_fw = "wfm_wf200",
+   .file_pds = "wf200.pds",
.use_rising_clk = true,
 };
 
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index f79693a4be7f..0619c7d1cf79 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -10,6 +10,7 @@
 
 #include "debug.h"
 #include "wfx.h"
+#include "main.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
@@ -54,6 +55,33 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map);
 }
 
+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,
+};
+
 static ssize_t wfx_burn_slk_key_write(struct file *file,
  const char __user *user_buf,
  size_t count, loff_t *ppos)
@@ -162,6 +190,7 @@ int wfx_debug_init(struct wfx_dev *wdev)
struct dentry *d;
 
d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+   debugfs_create_file("send_pds", 0200, d, wdev, _send_pds_fops);
debugfs_create_file("burn_slk_key", 0200, d, wdev, 
_burn_slk_key_fops);
debugfs_create_file("send_hif_msg", 0600, d, wdev, 
_send_hif_msg_fops);
 
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index dd5f1dea4e85..6b9683d69a3f 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -71,6 +71,16 @@ static int hif_startup_indication(struct wfx_dev *wdev, 
struct hif_msg *hif, voi
return 0;
 }
 
+static int hif_wakeup_indication(struct wfx_dev *wdev, struct hif_msg *hif, 
void *buf)
+{
+   if (!wdev->pdata.gpio_wakeup
+   || !gpiod_get_value(wdev->pdata.gpio_wakeup)) {
+   dev_warn(wdev->dev, "unexpected wake-up indication\n");
+   return -EIO;
+   }
+   return 0;
+}
+
 static int hif_keys_indication(struct wfx_dev *wdev, struct hif_msg *hif, void 
*buf)
 {
struct hif_ind_sl_exchange_pub_keys *body = buf;
@@ -89,6 +99,7 @@ static const struct {
int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
 } hif_handlers[] = {
{ HIF_IND_ID_STARTUP,  hif_startup_indication },
+   { HIF_IND_ID_WAKEUP,   hif_wakeup_indication },
{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
 };
 
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 

[PATCH 07/20] staging: wfx: add IRQ handling

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

bh_work() is in charge to schedule all HIF message from/to chip.

On normal operation, when an IRQ is received, driver can get size of
next message in control register. In order to save control register
access, when chip send a message, it also appends a copy of control
register after the message (this register is not accounted in message
length declared in message header, but must accounted in bus request).
This copy of control register is called "piggyback".

It also handles a power saving mechanism specific to WFxxx series. This
mechanism is based on a GPIO called "wakeup" GPIO. Obviously, this gpio
is not part of SPI/SDIO standard buses and must be declared
independently (this is the main reason for why SDIO mode try to get
parameters from DT).

When wakeup is enabled, host can communicate with chip only if it is
awake. To wake up chip, there are two cases:
- host receive an IRQ from chip (chip initiate communication): host
  just have to set wakeup GPIO before reading data
- host want to send data to chip: host set wakeup GPIO, then wait
  for an IRQ (in fact, wait for an empty message) and finally send data

bh_work() is also in charge to track usage of chip buffers. Normally
each request expect a confirmation. However, you can notice that special
"multi tx" confirmation can acknowledge multiple requests at time.

Finally, note that wfx_bh_request_rx() is not atomic (because of
control_reg_read()). So, in SPI mode, hard-irq handler only postpone all
processing to wfx_spi_request_rx().

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile   |   1 +
 drivers/staging/wfx/bh.c   | 277 +
 drivers/staging/wfx/bh.h   |  32 
 drivers/staging/wfx/bus_sdio.c |   4 +-
 drivers/staging/wfx/bus_spi.c  |   5 +
 drivers/staging/wfx/main.c |  21 +++
 drivers/staging/wfx/main.h |   2 +
 drivers/staging/wfx/wfx.h  |   4 +
 8 files changed, 345 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/wfx/bh.c
 create mode 100644 drivers/staging/wfx/bh.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index e568d7a6fb06..1abd3115f11d 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -4,6 +4,7 @@
 CFLAGS_debug.o = -I$(src)
 
 wfx-y := \
+   bh.o \
hwio.o \
fwio.o \
main.o \
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
new file mode 100644
index ..02a42e5c1e10
--- /dev/null
+++ b/drivers/staging/wfx/bh.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Interrupt bottom half (BH).
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#include "bh.h"
+#include "wfx.h"
+#include "hwio.h"
+#include "hif_api_cmd.h"
+
+static void device_wakeup(struct wfx_dev *wdev)
+{
+   if (!wdev->pdata.gpio_wakeup)
+   return;
+   if (gpiod_get_value(wdev->pdata.gpio_wakeup))
+   return;
+
+   gpiod_set_value(wdev->pdata.gpio_wakeup, 1);
+   if (wfx_api_older_than(wdev, 1, 4)) {
+   if (!completion_done(>hif.ctrl_ready))
+   udelay(2000);
+   } else {
+   // 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(>hif.ctrl_ready, 
msecs_to_jiffies(2) + 1))
+   complete(>hif.ctrl_ready);
+   else
+   dev_err(wdev->dev, "timeout while wake up chip\n");
+   }
+}
+
+static void device_release(struct wfx_dev *wdev)
+{
+   if (!wdev->pdata.gpio_wakeup)
+   return;
+
+   gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
+}
+
+static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
+{
+   struct sk_buff *skb;
+   struct hif_msg *hif;
+   size_t alloc_len;
+   size_t computed_len;
+   int release_count;
+   int piggyback = 0;
+
+   WARN_ON(read_len < 4);
+   WARN(read_len > round_down(0xFFF, 2) * sizeof(u16),
+"%s: request exceed WFx capability", __func__);
+
+   // Add 2 to take into account piggyback size
+   alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2);
+   skb = dev_alloc_skb(alloc_len);
+   if (!skb)
+   return -ENOMEM;
+
+   if (wfx_data_read(wdev, skb->data, alloc_len))
+   goto err;
+
+   piggyback = le16_to_cpup((u16 *) (skb->data + alloc_len - 2));
+
+   hif = (struct hif_msg *) skb->data;
+   WARN(hif->encrypted & 0x1, "unsupported encryption type");
+   if (hif->encrypted == 0x2) {
+   BUG(); // Not yet implemented
+   } else {
+   le16_to_cpus(hif->len);
+   computed_len = 

[PATCH 04/20] staging: wfx: add tracepoints for I/O access

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Some tracepoints are useful for debugging.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   6 +-
 drivers/staging/wfx/debug.c  |  10 +++
 drivers/staging/wfx/hwio.c   |  11 +++
 drivers/staging/wfx/traces.h | 154 +++
 4 files changed, 180 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/wfx/debug.c
 create mode 100644 drivers/staging/wfx/traces.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index e860845186cf..330b7288ebb5 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -1,8 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0
 
+# Necessary for CREATE_TRACE_POINTS
+CFLAGS_debug.o = -I$(src)
+
 wfx-y := \
hwio.o \
-   main.o
+   main.o \
+   debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
 wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
 
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
new file mode 100644
index ..bf44c944640d
--- /dev/null
+++ b/drivers/staging/wfx/debug.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Debugfs interface.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+
+#define CREATE_TRACE_POINTS
+#include "traces.h"
diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c
index fa626a49dd8a..0cf52aee10e7 100644
--- a/drivers/staging/wfx/hwio.c
+++ b/drivers/staging/wfx/hwio.c
@@ -12,6 +12,7 @@
 #include "hwio.h"
 #include "wfx.h"
 #include "bus.h"
+#include "traces.h"
 
 /*
  * Internal helpers.
@@ -63,6 +64,7 @@ static int read32_locked(struct wfx_dev *wdev, int reg, u32 
*val)
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = read32(wdev, reg, val);
+   _trace_io_read32(reg, *val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -73,6 +75,7 @@ static int write32_locked(struct wfx_dev *wdev, int reg, u32 
val)
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = write32(wdev, reg, val);
+   _trace_io_write32(reg, val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -86,11 +89,13 @@ static int write32_bits_locked(struct wfx_dev *wdev, int 
reg, u32 mask, u32 val)
val &= mask;
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = read32(wdev, reg, _r);
+   _trace_io_read32(reg, val_r);
if (ret < 0)
goto err;
val_w = (val_r & ~mask) | val;
if (val_w != val_r) {
ret = write32(wdev, reg, val_w);
+   _trace_io_write32(reg, val_w);
}
 err:
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
@@ -166,6 +171,7 @@ static int indirect_read_locked(struct wfx_dev *wdev, int 
reg, u32 addr, void *b
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_read(wdev, reg, addr, buf, len);
+   _trace_io_ind_read(reg, addr, buf, len);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -176,6 +182,7 @@ static int indirect_write_locked(struct wfx_dev *wdev, int 
reg, u32 addr, const
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_write(wdev, reg, addr, buf, len);
+   _trace_io_ind_write(reg, addr, buf, len);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -190,6 +197,7 @@ static int indirect_read32_locked(struct wfx_dev *wdev, int 
reg, u32 addr, u32 *
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32));
*val = cpu_to_le32(*tmp);
+   _trace_io_ind_read32(reg, addr, *val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
kfree(tmp);
return ret;
@@ -205,6 +213,7 @@ static int indirect_write32_locked(struct wfx_dev *wdev, 
int reg, u32 addr, u32
*tmp = cpu_to_le32(val);
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32));
+   _trace_io_ind_write32(reg, addr, val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
kfree(tmp);
return ret;
@@ -217,6 +226,7 @@ int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t 
len)
WARN((long) buf & 3, "%s: unaligned buffer", __func__);
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, 
WFX_REG_IN_OUT_QUEUE, buf, len);
+   _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
if (ret)
dev_err(wdev->dev, "%s: bus communication error: %d\n", 
__func__, ret);
@@ -230,6 +240,7 @@ int wfx_data_write(struct wfx_dev *wdev, const void *buf, 
size_t len)
WARN((long) buf & 3, "%s: unaligned buffer", __func__);
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, 
WFX_REG_IN_OUT_QUEUE, buf, len);
+   _trace_io_write(WFX_REG_IN_OUT_QUEUE, 

[PATCH 05/20] staging: wfx: load firmware

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

A firmware is necessary to run the chip. wfx_init_device() is in charge
of loading firmware on chip and doing low level initialization.

Firmwares for WF200 are available here:

  https://github.com/SiliconLabs/wfx-firmware/

Note that firmware are encrypted. Driver checks that key used to encrypt
firmware match with key burned into chip.

Currently, "C0" key is used for production chips.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile   |   1 +
 drivers/staging/wfx/bus_sdio.c |   8 +
 drivers/staging/wfx/bus_spi.c  |   7 +
 drivers/staging/wfx/fwio.c | 397 +
 drivers/staging/wfx/fwio.h |  15 ++
 drivers/staging/wfx/main.c |  20 ++
 drivers/staging/wfx/main.h |  10 +
 drivers/staging/wfx/wfx.h  |   2 +
 8 files changed, 460 insertions(+)
 create mode 100644 drivers/staging/wfx/fwio.c
 create mode 100644 drivers/staging/wfx/fwio.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 330b7288ebb5..e568d7a6fb06 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -5,6 +5,7 @@ CFLAGS_debug.o = -I$(src)
 
 wfx-y := \
hwio.o \
+   fwio.o \
main.o \
debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 35bcca7ec5dc..25c587fe2141 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -17,6 +17,7 @@
 #include "main.h"
 
 static const struct wfx_platform_data wfx_sdio_pdata = {
+   .file_fw = "wfm_wf200",
 };
 
 struct wfx_sdio_priv {
@@ -204,8 +205,14 @@ static int wfx_sdio_probe(struct sdio_func *func,
goto err2;
}
 
+   ret = wfx_probe(bus->core);
+   if (ret)
+   goto err3;
+
return 0;
 
+err3:
+   wfx_free_common(bus->core);
 err2:
wfx_sdio_irq_unsubscribe(bus);
 err1:
@@ -220,6 +227,7 @@ static void wfx_sdio_remove(struct sdio_func *func)
 {
struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
 
+   wfx_release(bus->core);
wfx_free_common(bus->core);
wfx_sdio_irq_unsubscribe(bus);
sdio_claim_host(func);
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index b311ff72cf80..c474949a32dd 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -30,6 +30,8 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for 
none.");
 #define SET_READ 0x8000 /* usage: or operation */
 
 static const struct wfx_platform_data wfx_spi_pdata = {
+   .file_fw = "wfm_wf200",
+   .use_rising_clk = true,
 };
 
 struct wfx_spi_priv {
@@ -276,6 +278,10 @@ static int wfx_spi_probe(struct spi_device *func)
if (!bus->core)
return -EIO;
 
+   ret = wfx_probe(bus->core);
+   if (ret)
+   wfx_free_common(bus->core);
+
return ret;
 }
 
@@ -284,6 +290,7 @@ static int wfx_spi_disconnect(struct spi_device *func)
 {
struct wfx_spi_priv *bus = spi_get_drvdata(func);
 
+   wfx_release(bus->core);
wfx_free_common(bus->core);
// A few IRQ will be sent during device release. Hopefully, no IRQ
// should happen after wdev/wvif are released.
diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c
new file mode 100644
index ..8963d0351ee6
--- /dev/null
+++ b/drivers/staging/wfx/fwio.c
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Firmware loading.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+#include 
+#include 
+
+#include "fwio.h"
+#include "wfx.h"
+#include "hwio.h"
+
+#if (KERNEL_VERSION(4, 9, 0) > LINUX_VERSION_CODE)
+#define FIELD_GET(_mask, _reg) (typeof(_mask))(((_reg) & (_mask)) >> 
(__builtin_ffsll(_mask) - 1))
+#else
+#include 
+#endif
+
+// Addresses below are in SRAM area
+#define WFX_DNLD_FIFO 0x09004000
+#define DNLD_BLOCK_SIZE   0x0400
+#define DNLD_FIFO_SIZE0x8000 // (32 * DNLD_BLOCK_SIZE)
+// Download Control Area (DCA)
+#define WFX_DCA_IMAGE_SIZE0x0900C000
+#define WFX_DCA_PUT   0x0900C004
+#define WFX_DCA_GET   0x0900C008
+#define WFX_DCA_HOST_STATUS   0x0900C00C
+#define HOST_READY0x87654321
+#define HOST_INFO_READ0xA753BD99
+#define HOST_UPLOAD_PENDING   0xABCDDCBA
+#define HOST_UPLOAD_COMPLETE  0xD4C64A99
+#define HOST_OK_TO_JUMP   0x174FC882
+#define WFX_DCA_NCP_STATUS0x0900C010
+#define NCP_NOT_READY 0x12345678
+#define NCP_READY 0x87654321
+#define NCP_INFO_READY0xBD53EF99
+#define NCP_DOWNLOAD_PENDING  0xABCDDCBA
+#define NCP_DOWNLOAD_COMPLETE 0xCAFEFECA
+#define NCP_AUTH_OK   0xD4C64A99
+#define NCP_AUTH_FAIL 0x174FC882
+#define 

[PATCH 12/20] staging: wfx: add HIF commands helpers

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Provide an abstraction for HIF commands.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/hif_tx.c | 375 +++
 drivers/staging/wfx/hif_tx.h |  33 +++
 drivers/staging/wfx/hif_tx_mib.h | 281 +++
 drivers/staging/wfx/wfx.h|   6 +
 4 files changed, 695 insertions(+)
 create mode 100644 drivers/staging/wfx/hif_tx_mib.h

diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c
index f81a19089db4..781a6e28dbad 100644
--- a/drivers/staging/wfx/hif_tx.c
+++ b/drivers/staging/wfx/hif_tx.c
@@ -12,6 +12,7 @@
 #include "hif_tx.h"
 #include "wfx.h"
 #include "bh.h"
+#include "hwio.h"
 #include "debug.h"
 
 void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
@@ -21,6 +22,29 @@ void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
mutex_init(_cmd->lock);
 }
 
+static void wfx_fill_header(struct hif_msg *hif, int if_id, unsigned int cmd, 
size_t size)
+{
+   if (if_id == -1)
+   if_id = 2;
+
+   WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd);
+   WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size);
+   WARN(if_id > 0x3, "invalid interface ID %d", if_id);
+
+   hif->len = cpu_to_le16(size + 4);
+   hif->id = cmd;
+   hif->interface = if_id;
+}
+
+static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif)
+{
+   *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL);
+   if (*hif)
+   return (*hif)->body;
+   else
+   return NULL;
+}
+
 int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, 
size_t reply_len, bool async)
 {
const char *mib_name = "";
@@ -85,3 +109,354 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg 
*request, void *reply, siz
 
return ret;
 }
+
+// This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to 
any
+// request anymore. We need to slightly hack struct wfx_hif_cmd for that job. 
Be
+// carefull to only call this funcion during device unregister.
+int hif_shutdown(struct wfx_dev *wdev)
+{
+   int ret;
+   struct hif_msg *hif;
+
+   wfx_alloc_hif(0, );
+   wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0);
+   ret = wfx_cmd_send(wdev, hif, NULL, 0, true);
+   // After this command, chip won't reply. Be sure to give enough time to
+   // bh to send buffer:
+   msleep(100);
+   wdev->hif_cmd.buf_send = NULL;
+   if (wdev->pdata.gpio_wakeup)
+   gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
+   else
+   control_reg_write(wdev, 0);
+   mutex_unlock(>hif_cmd.lock);
+   kfree(hif);
+   return ret;
+}
+
+int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
+{
+   int ret;
+   size_t buf_len = sizeof(struct hif_req_configuration) + len;
+   struct hif_msg *hif;
+   struct hif_req_configuration *body = wfx_alloc_hif(buf_len, );
+
+   body->length = cpu_to_le16(len);
+   memcpy(body->pds_data, conf, len);
+   wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len);
+   ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+   kfree(hif);
+   return ret;
+}
+
+int hif_reset(struct wfx_vif *wvif, bool reset_stat)
+{
+   int ret;
+   struct hif_msg *hif;
+   struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), );
+
+   body->reset_flags.reset_stat = reset_stat;
+   wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body));
+   ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+   kfree(hif);
+   return ret;
+}
+
+int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, 
size_t val_len)
+{
+   int ret;
+   struct hif_msg *hif;
+   int buf_len = sizeof(struct hif_cnf_read_mib) + val_len;
+   struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), );
+   struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
+
+   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 != reply->mib_id) {
+   dev_warn(wdev->dev, "%s: confirmation mismatch request\n", 
__func__);
+   ret = -EIO;
+   }
+   if (ret == -ENOMEM)
+   dev_err(wdev->dev, "buffer is too small to receive %s (%zu < 
%d)\n",
+   get_mib_name(mib_id), val_len, reply->length);
+   if (!ret)
+   memcpy(val, >mib_data, reply->length);
+   else
+   memset(val, 0xFF, val_len);
+   kfree(hif);
+   kfree(reply);
+   return ret;
+}
+
+int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, 
size_t val_len)
+{
+   int ret;
+   struct hif_msg *hif;
+   int buf_len = sizeof(struct hif_req_write_mib) + val_len;
+   struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, );
+

[PATCH 14/20] staging: wfx: setup initial chip configuration

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

A few tasks remain to be done in order to finish chip initial
configuration:
   - configure chip to use multi-tx confirmation (speed up data
 transfer)
   - configure chip to use wake-up feature (save power consumption
 during runtime)
   - set hardware configuration (clocks, RF, pinout, etc...) using a
 Platform Data Set (PDS) file

On release, driver completely shutdown the chip to save power
consumption.

Documentation about PDS and PDS data for sample boards are available
here[1]. One day, PDS data may find a place in device tree but,
currently, PDS is too much linked with firmware to allowing that.

This patch also add "send_pds" file in debugfs to be able to dynamically
change PDS (only for debug, of course).

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

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bus_sdio.c |  1 +
 drivers/staging/wfx/bus_spi.c  |  1 +
 drivers/staging/wfx/debug.c| 29 +++
 drivers/staging/wfx/hif_rx.c   | 11 
 drivers/staging/wfx/main.c | 94 ++
 drivers/staging/wfx/main.h |  2 +
 6 files changed, 138 insertions(+)

diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index c0c063c3cfc9..05f02c278782 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -19,6 +19,7 @@
 
 static const struct wfx_platform_data wfx_sdio_pdata = {
.file_fw = "wfm_wf200",
+   .file_pds = "wf200.pds",
 };
 
 struct wfx_sdio_priv {
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index 8a9aab3e7384..163342b66a5e 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -32,6 +32,7 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for 
none.");
 
 static const struct wfx_platform_data wfx_spi_pdata = {
.file_fw = "wfm_wf200",
+   .file_pds = "wf200.pds",
.use_rising_clk = true,
 };
 
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index f79693a4be7f..0619c7d1cf79 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -10,6 +10,7 @@
 
 #include "debug.h"
 #include "wfx.h"
+#include "main.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
@@ -54,6 +55,33 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map);
 }
 
+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,
+};
+
 static ssize_t wfx_burn_slk_key_write(struct file *file,
  const char __user *user_buf,
  size_t count, loff_t *ppos)
@@ -162,6 +190,7 @@ int wfx_debug_init(struct wfx_dev *wdev)
struct dentry *d;
 
d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+   debugfs_create_file("send_pds", 0200, d, wdev, _send_pds_fops);
debugfs_create_file("burn_slk_key", 0200, d, wdev, 
_burn_slk_key_fops);
debugfs_create_file("send_hif_msg", 0600, d, wdev, 
_send_hif_msg_fops);
 
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index dd5f1dea4e85..6b9683d69a3f 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -71,6 +71,16 @@ static int hif_startup_indication(struct wfx_dev *wdev, 
struct hif_msg *hif, voi
return 0;
 }
 
+static int hif_wakeup_indication(struct wfx_dev *wdev, struct hif_msg *hif, 
void *buf)
+{
+   if (!wdev->pdata.gpio_wakeup
+   || !gpiod_get_value(wdev->pdata.gpio_wakeup)) {
+   dev_warn(wdev->dev, "unexpected wake-up indication\n");
+   return -EIO;
+   }
+   return 0;
+}
+
 static int hif_keys_indication(struct wfx_dev *wdev, struct hif_msg *hif, void 
*buf)
 {
struct hif_ind_sl_exchange_pub_keys *body = buf;
@@ -89,6 +99,7 @@ static const struct {
int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
 } hif_handlers[] = {
{ HIF_IND_ID_STARTUP,  hif_startup_indication },
+   { HIF_IND_ID_WAKEUP,   hif_wakeup_indication },
{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
 };
 
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 

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

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

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

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

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 1abd3115f11d..35670b86c64f 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -7,6 +7,7 @@ wfx-y := \
bh.o \
hwio.o \
fwio.o \
+   hif_rx.o \
main.o \
debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index 76afecdf579d..c40da3f1f25d 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -12,6 +12,7 @@
 #include "wfx.h"
 #include "hwio.h"
 #include "traces.h"
+#include "hif_rx.h"
 #include "hif_api_cmd.h"
 
 static void device_wakeup(struct wfx_dev *wdev)
@@ -107,7 +108,8 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
}
 
skb_put(skb, hif->len);
-   dev_kfree_skb(skb); /* FIXME: handle received data */
+   // wfx_handle_rx takes care on SKB livetime
+   wfx_handle_rx(wdev, skb);
 
return piggyback;
 
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
new file mode 100644
index ..5c207e6d4348
--- /dev/null
+++ b/drivers/staging/wfx/hif_rx.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
+ * (WSM) API.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#include "hif_rx.h"
+#include "wfx.h"
+#include "hif_api_cmd.h"
+
+static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, 
void *buf)
+{
+   struct hif_ind_startup *body = buf;
+
+   if (body->status || body->firmware_type > 4) {
+   dev_err(wdev->dev, "received invalid startup indication");
+   return -EINVAL;
+   }
+   memcpy(>hw_caps, body, sizeof(struct hif_ind_startup));
+   le32_to_cpus(>hw_caps.status);
+   le16_to_cpus(>hw_caps.hardware_id);
+   le16_to_cpus(>hw_caps.num_inp_ch_bufs);
+   le16_to_cpus(>hw_caps.size_inp_ch_buf);
+
+   complete(>firmware_ready);
+   return 0;
+}
+
+static const struct {
+   int msg_id;
+   int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
+} hif_handlers[] = {
+   { HIF_IND_ID_STARTUP,  hif_startup_indication },
+};
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
+{
+   int i;
+   struct hif_msg *hif = (struct hif_msg *) skb->data;
+   int hif_id = hif->id;
+
+   for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) {
+   if (hif_handlers[i].msg_id == hif_id) {
+   if (hif_handlers[i].handler)
+   hif_handlers[i].handler(wdev, hif, hif->body);
+   goto free;
+   }
+   }
+   dev_err(wdev->dev, "unsupported HIF ID %02x\n", hif_id);
+free:
+   dev_kfree_skb(skb);
+}
diff --git a/drivers/staging/wfx/hif_rx.h b/drivers/staging/wfx/hif_rx.h
new file mode 100644
index ..f07c10c8c6bd
--- /dev/null
+++ b/drivers/staging/wfx/hif_rx.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
+ * (WSM) API.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ * Copyright (C) 2010, ST-Ericsson SA
+ */
+#ifndef WFX_HIF_RX_H
+#define WFX_HIF_RX_H
+
+struct wfx_dev;
+struct sk_buff;
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb);
+
+#endif
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index f0bea053a0d9..5e7e7225f068 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -12,6 +12,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -87,6 +88,9 @@ struct wfx_dev *wfx_init_common(struct device *dev,
wdev->hwbus_ops = hwbus_ops;
wdev->hwbus_priv = hwbus_priv;
memcpy(>pdata, pdata, sizeof(*pdata));
+
+   init_completion(>firmware_ready);
+
return wdev;
 }
 
@@ -96,7 +100,9 @@ void wfx_free_common(struct wfx_dev *wdev)
 
 int wfx_probe(struct wfx_dev *wdev)
 {
+   int i;
int err;
+   const 

[PATCH 10/20] staging: wfx: instantiate mac80211 data

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Allocate a struct ieee80211_hw but do not yet register it.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |  1 +
 drivers/staging/wfx/debug.c  | 12 ++
 drivers/staging/wfx/debug.h  | 15 
 drivers/staging/wfx/main.c   | 41 ++--
 drivers/staging/wfx/sta.c| 46 
 drivers/staging/wfx/sta.h| 24 +++
 drivers/staging/wfx/wfx.h|  8 +++
 7 files changed, 145 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/debug.h
 create mode 100644 drivers/staging/wfx/sta.c
 create mode 100644 drivers/staging/wfx/sta.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 35670b86c64f..2896a2127c88 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -9,6 +9,7 @@ wfx-y := \
fwio.o \
hif_rx.o \
main.o \
+   sta.o \
debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
 wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index bf44c944640d..f28c94d8de89 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -5,6 +5,18 @@
  * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include 
+
+#include "wfx.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
+
+int wfx_debug_init(struct wfx_dev *wdev)
+{
+   struct dentry *d;
+
+   d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+
+   return 0;
+}
diff --git a/drivers/staging/wfx/debug.h b/drivers/staging/wfx/debug.h
new file mode 100644
index ..8bfba1a9fa20
--- /dev/null
+++ b/drivers/staging/wfx/debug.h
@@ -0,0 +1,15 @@
+/* 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);
+
+#endif /* WFX_DEBUG_H */
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 5e7e7225f068..ca0ca873bd7d 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -25,6 +25,9 @@
 #include "hwio.h"
 #include "bus.h"
 #include "bh.h"
+#include "sta.h"
+#include "debug.h"
+#include "hif_api_cmd.h"
 #include "wfx_version.h"
 
 MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx");
@@ -36,6 +39,13 @@ static int gpio_wakeup = -2;
 module_param(gpio_wakeup, int, 0644);
 MODULE_PARM_DESC(gpio_wakeup, "gpio number for wakeup. -1 for none.");
 
+static const struct ieee80211_ops wfx_ops = {
+   .start  = wfx_start,
+   .stop   = wfx_stop,
+   .add_interface  = wfx_add_interface,
+   .remove_interface   = wfx_remove_interface,
+};
+
 bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor)
 {
if (wdev->hw_caps.api_version_major < major)
@@ -79,11 +89,26 @@ struct wfx_dev *wfx_init_common(struct device *dev,
const struct hwbus_ops *hwbus_ops,
void *hwbus_priv)
 {
+   struct ieee80211_hw *hw;
struct wfx_dev *wdev;
 
-   wdev = devm_kmalloc(dev, sizeof(*wdev), GFP_KERNEL);
-   if (!wdev)
+   hw = ieee80211_alloc_hw(sizeof(struct wfx_dev), _ops);
+   if (!hw)
return NULL;
+
+   SET_IEEE80211_DEV(hw, dev);
+
+   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 = 15;
+   hw->extra_tx_headroom = sizeof(struct hif_sl_msg_hdr) + sizeof(struct 
hif_msg)
+   + sizeof(struct hif_req_tx)
+   + 4 /* alignment */ + 8 /* TKIP IV */;
+
+   wdev = hw->priv;
+   wdev->hw = hw;
wdev->dev = dev;
wdev->hwbus_ops = hwbus_ops;
wdev->hwbus_priv = hwbus_priv;
@@ -96,6 +121,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
 
 void wfx_free_common(struct wfx_dev *wdev)
 {
+   ieee80211_free_hw(wdev->hw);
 }
 
 int wfx_probe(struct wfx_dev *wdev)
@@ -127,6 +153,11 @@ int wfx_probe(struct wfx_dev *wdev)
 wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label,
 wdev->hw_caps.api_version_major, 
wdev->hw_caps.api_version_minor,
 wdev->keyset, *((u32 *) >hw_caps.capabilities));
+   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",
@@ -150,8 

[PATCH 19/20] staging: wfx: implement 802.11 key handling

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/key.c| 272 +++
 drivers/staging/wfx/key.h|  22 +++
 drivers/staging/wfx/main.c   |   2 +
 drivers/staging/wfx/sta.c|   4 +
 drivers/staging/wfx/wfx.h|  19 +++
 6 files changed, 320 insertions(+)
 create mode 100644 drivers/staging/wfx/key.c
 create mode 100644 drivers/staging/wfx/key.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 2b8a5fa86fac..0d9c1ed092f6 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -14,6 +14,7 @@ wfx-y := \
data_rx.o \
scan.o \
sta.o \
+   key.o \
main.o \
sta.o \
debug.o
diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c
new file mode 100644
index ..696424f244cb
--- /dev/null
+++ b/drivers/staging/wfx/key.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Key management related functions.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#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);
+   wdev->keys[idx].entry_index = idx;
+   return idx;
+}
+
+static void wfx_free_key(struct wfx_dev *wdev, int idx)
+{
+   BUG_ON(!(wdev->key_map & BIT(idx)));
+   memset(>keys[idx], 0, sizeof(wdev->keys[idx]));
+   wdev->key_map &= ~BIT(idx);
+}
+
+static uint8_t fill_wep_pair(struct hif_wep_pairwise_key *msg,
+struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+   WARN_ON(key->keylen > sizeof(msg->key_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 uint8_t fill_wep_group(struct hif_wep_group_key *msg,
+ struct ieee80211_key_conf *key)
+{
+   WARN_ON(key->keylen > sizeof(msg->key_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 uint8_t fill_tkip_pair(struct hif_tkip_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+   uint8_t *keybuf = key->key;
+
+   WARN_ON(key->keylen != sizeof(msg->tkip_key_data)
+  + sizeof(msg->tx_mic_key)
+  + sizeof(msg->rx_mic_key));
+   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 uint8_t fill_tkip_group(struct hif_tkip_group_key *msg,
+  struct ieee80211_key_conf *key,
+  struct ieee80211_key_seq *seq,
+  enum nl80211_iftype iftype)
+{
+   uint8_t *keybuf = key->key;
+
+   WARN_ON(key->keylen != sizeof(msg->tkip_key_data)
+  + 2 * sizeof(msg->rx_mic_key));
+   msg->key_id = key->keyidx;
+   memcpy(msg->rx_sequence_counter, >tkip.iv16, 
sizeof(seq->tkip.iv16));
+   memcpy(msg->rx_sequence_counter + sizeof(uint16_t), >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 uint8_t fill_ccmp_pair(struct hif_aes_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+   WARN_ON(key->keylen != sizeof(msg->aes_key_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 uint8_t fill_ccmp_group(struct hif_aes_group_key *msg,
+  struct ieee80211_key_conf *key,
+  struct ieee80211_key_seq *seq)
+{
+   WARN_ON(key->keylen != sizeof(msg->aes_key_data));
+   memcpy(msg->aes_key_data, key->key, key->keylen);
+   

[PATCH 17/20] staging: wfx: allow to receive 802.11 frames

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Again, this task is more complex than it should since driver try to
handle itself power saving of stations.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile  |   1 +
 drivers/staging/wfx/data_rx.c | 187 ++
 drivers/staging/wfx/data_rx.h |  18 
 drivers/staging/wfx/hif_rx.c  |  23 +
 4 files changed, 229 insertions(+)
 create mode 100644 drivers/staging/wfx/data_rx.c
 create mode 100644 drivers/staging/wfx/data_rx.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index d5ac9fafd1f1..d9e21515d08e 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -11,6 +11,7 @@ wfx-y := \
hif_rx.o \
queue.o \
data_tx.o \
+   data_rx.o \
sta.o \
main.o \
sta.o \
diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c
new file mode 100644
index ..6544d00d1657
--- /dev/null
+++ b/drivers/staging/wfx/data_rx.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Datapath implementation.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+#include 
+
+#include "data_rx.h"
+#include "wfx.h"
+#include "bh.h"
+#include "sta.h"
+
+static int wfx_handle_pspoll(struct wfx_vif *wvif, struct sk_buff *skb)
+{
+   struct ieee80211_sta *sta;
+   struct ieee80211_pspoll *pspoll = (struct ieee80211_pspoll *)skb->data;
+   int link_id = 0;
+   u32 pspoll_mask = 0;
+   int i;
+
+   if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid))
+   return 1;
+
+   rcu_read_lock();
+   sta = ieee80211_find_sta(wvif->vif, pspoll->ta);
+   if (sta)
+   link_id = ((struct wfx_sta_priv *) >drv_priv)->link_id;
+   rcu_read_unlock();
+   if (link_id)
+   pspoll_mask = BIT(link_id);
+   else
+   return 1;
+
+   wvif->pspoll_mask |= pspoll_mask;
+   /* Do not report pspols if data for given link id is queued already. */
+   for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
+   if (wfx_tx_queue_get_num_queued(>wdev->tx_queue[i],
+   pspoll_mask)) {
+   wfx_bh_request_tx(wvif->wdev);
+   return 1;
+   }
+   }
+   return 0;
+}
+
+static int wfx_drop_encrypt_data(struct wfx_dev *wdev, struct hif_ind_rx *arg, 
struct sk_buff *skb)
+{
+   struct ieee80211_hdr *frame = (struct ieee80211_hdr *) skb->data;
+   size_t hdrlen = ieee80211_hdrlen(frame->frame_control);
+   size_t iv_len, icv_len;
+
+   /* Oops... There is no fast way to ask mac80211 about
+* IV/ICV lengths. Even defineas are not exposed.
+*/
+   switch (arg->rx_flags.encryp) {
+   case HIF_RI_FLAGS_WEP_ENCRYPTED:
+   iv_len = 4 /* WEP_IV_LEN */;
+   icv_len = 4 /* WEP_ICV_LEN */;
+   break;
+   case HIF_RI_FLAGS_TKIP_ENCRYPTED:
+   iv_len = 8 /* TKIP_IV_LEN */;
+   icv_len = 4 /* TKIP_ICV_LEN */
+   + 8 /*MICHAEL_MIC_LEN*/;
+   break;
+   case HIF_RI_FLAGS_AES_ENCRYPTED:
+   iv_len = 8 /* CCMP_HDR_LEN */;
+   icv_len = 8 /* CCMP_MIC_LEN */;
+   break;
+   case HIF_RI_FLAGS_WAPI_ENCRYPTED:
+   iv_len = 18 /* WAPI_HDR_LEN */;
+   icv_len = 16 /* WAPI_MIC_LEN */;
+   break;
+   default:
+   dev_err(wdev->dev, "unknown encryption type %d\n",
+arg->rx_flags.encryp);
+   return -EIO;
+   }
+
+   /* Firmware strips ICV in case of MIC failure. */
+   if (arg->status == HIF_STATUS_MICFAILURE)
+   icv_len = 0;
+
+   if (skb->len < hdrlen + iv_len + icv_len) {
+   dev_warn(wdev->dev, "malformed SDU received\n");
+   return -EIO;
+   }
+
+   /* Remove IV, ICV and MIC */
+   skb_trim(skb, skb->len - icv_len);
+   memmove(skb->data + iv_len, skb->data, hdrlen);
+   skb_pull(skb, iv_len);
+   return 0;
+
+}
+
+void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx *arg, struct sk_buff 
*skb)
+{
+   int link_id = arg->rx_flags.peer_sta_id;
+   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;
+   struct wfx_link_entry *entry = NULL;
+   bool early_data = false;
+
+   memset(hdr, 0, sizeof(*hdr));
+
+   // FIXME: Why do we drop these frames?
+   if (!arg->rcpi_rssi &&
+   (ieee80211_is_probe_resp(frame->frame_control) ||
+ieee80211_is_beacon(frame->frame_control)))
+   goto drop;
+
+   if (link_id && link_id <= WFX_MAX_STA_IN_AP_MODE) {
+   

[PATCH v3 16/20] staging: wfx: allow to send 802.11 frames

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Three things make this task more complex than it should:
  - Chip necessitate to associate a link-id to each station. It is same
thing than association ID but, using 8 bits only.
  - Rate policy is sent separately from Tx frames
  - Driver try to handle itself power saving of stations and multicast
data

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile  |   3 +
 drivers/staging/wfx/bh.c  |   2 +
 drivers/staging/wfx/data_tx.c | 783 ++
 drivers/staging/wfx/data_tx.h |  93 
 drivers/staging/wfx/hif_rx.c  |  37 ++
 drivers/staging/wfx/hif_tx.c  |   1 +
 drivers/staging/wfx/main.c|   4 +
 drivers/staging/wfx/queue.c   | 526 +++
 drivers/staging/wfx/queue.h   |  59 +++
 drivers/staging/wfx/sta.c | 135 ++
 drivers/staging/wfx/sta.h |   8 +
 drivers/staging/wfx/traces.h  |  74 
 drivers/staging/wfx/wfx.h |  58 +++
 13 files changed, 1783 insertions(+)
 create mode 100644 drivers/staging/wfx/data_tx.c
 create mode 100644 drivers/staging/wfx/data_tx.h
 create mode 100644 drivers/staging/wfx/queue.c
 create mode 100644 drivers/staging/wfx/queue.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index e158589468a3..d5ac9fafd1f1 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -9,6 +9,9 @@ wfx-y := \
fwio.o \
hif_tx.o \
hif_rx.o \
+   queue.o \
+   data_tx.o \
+   sta.o \
main.o \
sta.o \
debug.o
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index d321fd312d55..ed81c3924d98 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -220,6 +220,8 @@ static int bh_work_tx(struct wfx_dev *wdev, int max_msg)
if (try_wait_for_completion(>hif_cmd.ready)) {
WARN(!mutex_is_locked(>hif_cmd.lock), 
"data locking error");
hif = wdev->hif_cmd.buf_send;
+   } else {
+   hif = wfx_tx_queues_get(wdev);
}
}
if (!hif)
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
new file mode 100644
index ..217d3c270706
--- /dev/null
+++ b/drivers/staging/wfx/data_tx.c
@@ -0,0 +1,783 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Datapath implementation.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+
+#include "data_tx.h"
+#include "wfx.h"
+#include "bh.h"
+#include "queue.h"
+#include "debug.h"
+#include "traces.h"
+#include "hif_tx_mib.h"
+
+#define WFX_INVALID_RATE_ID (0xFF)
+#define WFX_LINK_ID_GC_TIMEOUT ((unsigned long)(10 * HZ))
+
+static int wfx_get_hw_rate(struct wfx_dev *wdev, const struct 
ieee80211_tx_rate *rate)
+{
+   if (rate->idx < 0)
+   return -1;
+   if (rate->flags & IEEE80211_TX_RC_MCS) {
+   if (rate->idx > 7) {
+   WARN(1, "wrong rate->idx value: %d", rate->idx);
+   return -1;
+   }
+   return rate->idx + 14;
+   }
+   // WFx only support 2GHz, else band information should be retreived
+   // from ieee80211_tx_info
+   return 
wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->bitrates[rate->idx].hw_value;
+}
+
+/* TX policy cache implementation */
+
+static void tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy,
+   struct ieee80211_tx_rate *rates)
+{
+   int i;
+   size_t count;
+   struct wfx_dev *wdev = wvif->wdev;
+
+   BUG_ON(rates[0].idx < 0);
+   memset(policy, 0, sizeof(*policy));
+   for (i = 1; i < IEEE80211_TX_MAX_RATES; i++)
+   if (rates[i].idx < 0)
+   break;
+   count = i;
+
+   /* HACK!!! Device has problems (at least) switching from
+* 54Mbps CTS to 1Mbps. This switch takes enormous amount
+* of time (100-200 ms), leading to valuable throughput drop.
+* As a workaround, additional g-rates are injected to the
+* policy.
+*/
+   if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) &&
+   rates[0].idx > 4 && rates[0].count > 2 &&
+   rates[1].idx < 2) {
+   int mid_rate = (rates[0].idx + 4) >> 1;
+
+   /* Decrease number of retries for the initial rate */
+   rates[0].count -= 2;
+
+   if (mid_rate != 4) {
+   /* Keep fallback rate at 1Mbps. */
+   rates[3] = rates[1];
+
+   /* Inject 1 transmission on lowest g-rate */
+   rates[2].idx = 4;
+   rates[2].count = 1;
+   rates[2].flags = rates[1].flags;
+
+   /* Inject 1 transmission on mid-rate */
+   rates[1].idx = 

[PATCH v3 15/20] staging: wfx: add debug files and trace debug events

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Add traces when debug events happen and allow to ask internal
information to chip.

These features work independently from mac80211.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/debug.c  | 105 +++
 drivers/staging/wfx/hif_rx.c |  80 ++
 drivers/staging/wfx/main.c   |   2 +
 drivers/staging/wfx/wfx.h|  16 ++
 4 files changed, 203 insertions(+)

diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 0619c7d1cf79..1e23bb5bde3e 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -6,11 +6,13 @@
  * Copyright (c) 2010, ST-Ericsson
  */
 #include 
+#include 
 #include 
 
 #include "debug.h"
 #include "wfx.h"
 #include "main.h"
+#include "hif_tx_mib.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
@@ -55,6 +57,107 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map);
 }
 
+static int wfx_counters_show(struct seq_file *seq, void *v)
+{
+   int ret;
+   struct wfx_dev *wdev = seq->private;
+   struct hif_mib_extended_count_table counters;
+
+   ret = hif_get_counters_table(wdev, );
+   if (ret < 0)
+   return ret;
+   if (ret > 0)
+   return -EIO;
+
+#define PUT_COUNTER(name) \
+   seq_printf(seq, "%24s %d\n", #name ":", 
le32_to_cpu(counters.count_##name))
+
+   PUT_COUNTER(tx_packets);
+   PUT_COUNTER(tx_multicast_frames);
+   PUT_COUNTER(tx_frames_success);
+   PUT_COUNTER(tx_frame_failures);
+   PUT_COUNTER(tx_frames_retried);
+   PUT_COUNTER(tx_frames_multi_retried);
+
+   PUT_COUNTER(rts_success);
+   PUT_COUNTER(rts_failures);
+   PUT_COUNTER(ack_failures);
+
+   PUT_COUNTER(rx_packets);
+   PUT_COUNTER(rx_frames_success);
+   PUT_COUNTER(rx_packet_errors);
+   PUT_COUNTER(plcp_errors);
+   PUT_COUNTER(fcs_errors);
+   PUT_COUNTER(rx_decryption_failures);
+   PUT_COUNTER(rx_mic_failures);
+   PUT_COUNTER(rx_no_key_failures);
+   PUT_COUNTER(rx_frame_duplicates);
+   PUT_COUNTER(rx_multicast_frames);
+   PUT_COUNTER(rx_cmacicv_errors);
+   PUT_COUNTER(rx_cmac_replays);
+   PUT_COUNTER(rx_mgmt_ccmp_replays);
+
+   PUT_COUNTER(rx_beacon);
+   PUT_COUNTER(miss_beacon);
+
+#undef PUT_COUNTER
+
+   return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_counters);
+
+static const char * const channel_names[] = {
+   [0] = "1M",
+   [1] = "2M",
+   [2] = "5.5M",
+   [3] = "11M",
+   /* Entries 4 and 5 does not exist */
+   [6] = "6M",
+   [7] = "9M",
+   [8] = "12M",
+   [9] = "18M",
+   [10] = "24M",
+   [11] = "36M",
+   [12] = "48M",
+   [13] = "54M",
+   [14] = "MCS0",
+   [15] = "MCS1",
+   [16] = "MCS2",
+   [17] = "MCS3",
+   [18] = "MCS4",
+   [19] = "MCS5",
+   [20] = "MCS6",
+   [21] = "MCS7",
+};
+
+static int wfx_rx_stats_show(struct seq_file *seq, void *v)
+{
+   struct wfx_dev *wdev = seq->private;
+   struct hif_rx_stats *st = >rx_stats;
+   int i;
+
+   mutex_lock(>rx_stats_lock);
+   seq_printf(seq, "Timestamp: %dus\n", st->date);
+   seq_printf(seq, "Low power clock: frequency %uHz, external %s\n",
+   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], st->nb_rx_by_rate[i],
+  st->per[i], st->rssi[i] / 100,
+  st->snr[i] / 100, st->cfo[i]);
+   }
+   mutex_unlock(>rx_stats_lock);
+
+   return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats);
+
 static ssize_t wfx_send_pds_write(struct file *file, const char __user 
*user_buf,
 size_t count, loff_t *ppos)
 {
@@ -190,6 +293,8 @@ 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, _counters_fops);
+   debugfs_create_file("rx_stats", 0444, d, wdev, _rx_stats_fops);
debugfs_create_file("send_pds", 0200, d, wdev, _send_pds_fops);
debugfs_create_file("burn_slk_key", 0200, d, wdev, 
_burn_slk_key_fops);
debugfs_create_file("send_hif_msg", 0600, d, wdev, 
_send_hif_msg_fops);
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index 6b9683d69a3f..c93bae1b6acf 100644
--- 

[PATCH v3 02/20] staging: wfx: add support for I/O access

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Introduce bus level communication layer. At this level, 7 registers can
be addressed.

Notice that SPI driver is able to manage chip reset. SDIO mode relies
on an external driver (`mmc-pwrseq`) to reset chip.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bus.h  |  17 +++
 drivers/staging/wfx/bus_sdio.c | 189 ++-
 drivers/staging/wfx/bus_spi.c  | 200 -
 drivers/staging/wfx/hwio.h |  48 
 drivers/staging/wfx/main.c |  53 +
 drivers/staging/wfx/main.h |  32 ++
 drivers/staging/wfx/wfx.h  |  24 
 7 files changed, 561 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/hwio.h
 create mode 100644 drivers/staging/wfx/main.h
 create mode 100644 drivers/staging/wfx/wfx.h

diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h
index 8ce871a8a9ff..eb77abc09ec2 100644
--- a/drivers/staging/wfx/bus.h
+++ b/drivers/staging/wfx/bus.h
@@ -11,6 +11,23 @@
 #include 
 #include 
 
+#define WFX_REG_CONFIG0x0
+#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_DPORT0x5
+#define WFX_REG_SET_GEN_R_W   0x6
+#define WFX_REG_FRAME_OUT 0x7
+
+struct hwbus_ops {
+   int (*copy_from_io)(void *bus_priv, unsigned int addr, void *dst, 
size_t count);
+   int (*copy_to_io)(void *bus_priv, unsigned int addr, const void *src, 
size_t count);
+   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;
 
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 4b26c994f43c..35bcca7ec5dc 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -8,36 +8,223 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "bus.h"
+#include "wfx.h"
+#include "hwio.h"
+#include "main.h"
+
+static const struct wfx_platform_data wfx_sdio_pdata = {
+};
+
+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;
+
+   BUG_ON(reg_id > 7);
+   WARN(((uintptr_t) dst) & 3, "unaligned buffer size");
+   WARN(count & 3, "unaligned buffer address");
+
+   /* Use queue mode buffers */
+   if (reg_id == WFX_REG_IN_OUT_QUEUE)
+   sdio_addr |= (bus->buf_id_rx + 1) << 7;
+   ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count);
+   if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
+   bus->buf_id_rx = (bus->buf_id_rx + 1) % 4;
+
+   return ret;
+}
+
+static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id,
+  const void *src, size_t count)
+{
+   struct wfx_sdio_priv *bus = priv;
+   unsigned int sdio_addr = reg_id << 2;
+   int ret;
+
+   BUG_ON(reg_id > 7);
+   WARN(((uintptr_t) src) & 3, "unaligned buffer size");
+   WARN(count & 3, "unaligned buffer address");
+
+   /* Use queue mode buffers */
+   if (reg_id == WFX_REG_IN_OUT_QUEUE)
+   sdio_addr |= bus->buf_id_tx << 7;
+   // FIXME: discards 'const' qualifier for src
+   ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *) src, count);
+   if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
+   bus->buf_id_tx = (bus->buf_id_tx + 1) % 32;
+
+   return ret;
+}
+
+static void wfx_sdio_lock(void *priv)
+{
+   struct wfx_sdio_priv *bus = priv;
+
+   sdio_claim_host(bus->func);
+}
+
+static void wfx_sdio_unlock(void *priv)
+{
+   struct wfx_sdio_priv *bus = priv;
+
+   sdio_release_host(bus->func);
+}
+
+static void wfx_sdio_irq_handler(struct sdio_func *func)
+{
+   struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
+
+   if (bus->core)
+   /* empty */;
+   else
+   WARN(!bus->core, "race condition in driver init/deinit");
+}
+
+static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv)
+{
+   struct wfx_sdio_priv *bus = priv;
+
+   if (!bus->core) {
+   WARN(!bus->core, "race condition in driver init/deinit");
+   return IRQ_NONE;
+   }
+   sdio_claim_host(bus->func);
+   sdio_release_host(bus->func);
+   return IRQ_HANDLED;
+}
+
+static int wfx_sdio_irq_subscribe(struct wfx_sdio_priv *bus)
+{
+   int ret;
+
+   if (bus->of_irq) {
+   ret = request_irq(bus->of_irq, wfx_sdio_irq_handler_ext,
+ IRQF_TRIGGER_RISING, "wfx", bus);
+   } else {
+  

[PATCH v3 19/20] staging: wfx: implement 802.11 key handling

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

wfx_set_key() mostly copy bytes on correct offsets. A big piece of code
for a simple work. Unfortunately, I did not found any way to factorize
it.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/key.c| 258 +++
 drivers/staging/wfx/key.h|  22 +++
 drivers/staging/wfx/main.c   |   2 +
 drivers/staging/wfx/sta.c|   4 +
 drivers/staging/wfx/wfx.h|  19 +++
 6 files changed, 306 insertions(+)
 create mode 100644 drivers/staging/wfx/key.c
 create mode 100644 drivers/staging/wfx/key.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 2b8a5fa86fac..0d9c1ed092f6 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -14,6 +14,7 @@ wfx-y := \
data_rx.o \
scan.o \
sta.o \
+   key.o \
main.o \
sta.o \
debug.o
diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c
new file mode 100644
index ..4e7d2b510a9c
--- /dev/null
+++ b/drivers/staging/wfx/key.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Key management related functions.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+
+#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);
+   wdev->keys[idx].entry_index = idx;
+   return idx;
+}
+
+static void wfx_free_key(struct wfx_dev *wdev, int idx)
+{
+   BUG_ON(!(wdev->key_map & BIT(idx)));
+   memset(>keys[idx], 0, sizeof(wdev->keys[idx]));
+   wdev->key_map &= ~BIT(idx);
+}
+
+static uint8_t fill_wep_pair(struct hif_wep_pairwise_key *msg,
+struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+   WARN_ON(key->keylen > sizeof(msg->key_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 uint8_t fill_wep_group(struct hif_wep_group_key *msg,
+ struct ieee80211_key_conf *key)
+{
+   WARN_ON(key->keylen > sizeof(msg->key_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 uint8_t fill_tkip_pair(struct hif_tkip_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+   uint8_t *keybuf = key->key;
+
+   WARN_ON(key->keylen != sizeof(msg->tkip_key_data)
+  + sizeof(msg->tx_mic_key)
+  + sizeof(msg->rx_mic_key));
+   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 uint8_t fill_tkip_group(struct hif_tkip_group_key *msg,
+  struct ieee80211_key_conf *key,
+  struct ieee80211_key_seq *seq,
+  enum nl80211_iftype iftype)
+{
+   uint8_t *keybuf = key->key;
+
+   WARN_ON(key->keylen != sizeof(msg->tkip_key_data)
+  + 2 * sizeof(msg->rx_mic_key));
+   msg->key_id = key->keyidx;
+   memcpy(msg->rx_sequence_counter, >tkip.iv16, 
sizeof(seq->tkip.iv16));
+   memcpy(msg->rx_sequence_counter + sizeof(uint16_t), >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 uint8_t fill_ccmp_pair(struct hif_aes_pairwise_key *msg,
+ struct ieee80211_key_conf *key, u8 *peer_addr)
+{
+   WARN_ON(key->keylen != sizeof(msg->aes_key_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 uint8_t fill_ccmp_group(struct hif_aes_group_key *msg,
+  struct ieee80211_key_conf *key,
+  struct ieee80211_key_seq *seq)
+{
+   

[PATCH 20/20] staging: wfx: implement the rest of mac80211 API

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/data_rx.c |   26 +
 drivers/staging/wfx/data_tx.c |   16 +
 drivers/staging/wfx/debug.c   |2 +
 drivers/staging/wfx/hif_rx.c  |   53 ++
 drivers/staging/wfx/hif_tx.c  |1 +
 drivers/staging/wfx/main.c|  137 +++
 drivers/staging/wfx/queue.c   |   80 ++
 drivers/staging/wfx/scan.c|   40 +
 drivers/staging/wfx/sta.c | 1472 -
 drivers/staging/wfx/sta.h |   80 ++
 drivers/staging/wfx/wfx.h |   60 ++
 11 files changed, 1964 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c
index 6544d00d1657..0d73b52eee36 100644
--- a/drivers/staging/wfx/data_rx.c
+++ b/drivers/staging/wfx/data_rx.c
@@ -22,6 +22,8 @@ static int wfx_handle_pspoll(struct wfx_vif *wvif, struct 
sk_buff *skb)
u32 pspoll_mask = 0;
int i;
 
+   if (wvif->state != WFX_STATE_AP)
+   return 1;
if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid))
return 1;
 
@@ -167,6 +169,30 @@ void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx 
*arg, struct sk_buff *skb
&& arg->rx_flags.match_uc_addr
&& mgmt->u.action.category == WLAN_CATEGORY_BACK)
goto drop;
+   if (ieee80211_is_beacon(frame->frame_control)
+   && !arg->status && wvif->vif
+   && ether_addr_equal(ieee80211_get_SA(frame), 
wvif->vif->bss_conf.bssid)) {
+   const u8 *tim_ie;
+   u8 *ies = mgmt->u.beacon.variable;
+   size_t ies_len = skb->len - (ies - skb->data);
+
+   tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len);
+   if (tim_ie) {
+   struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie 
*) _ie[2];
+
+   if (wvif->dtim_period != tim->dtim_period) {
+   wvif->dtim_period = tim->dtim_period;
+   
schedule_work(>set_beacon_wakeup_period_work);
+   }
+   }
+
+   /* Disable beacon filter once we're associated... */
+   if (wvif->disable_beacon_filter &&
+   (wvif->vif->bss_conf.assoc || 
wvif->vif->bss_conf.ibss_joined)) {
+   wvif->disable_beacon_filter = false;
+   schedule_work(>update_filtering_work);
+   }
+   }
 
if (early_data) {
spin_lock_bh(>ps_state_lock);
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
index 217d3c270706..7f2799fbdafe 100644
--- a/drivers/staging/wfx/data_tx.c
+++ b/drivers/staging/wfx/data_tx.c
@@ -10,6 +10,7 @@
 #include "data_tx.h"
 #include "wfx.h"
 #include "bh.h"
+#include "sta.h"
 #include "queue.h"
 #include "debug.h"
 #include "traces.h"
@@ -359,6 +360,9 @@ void wfx_link_id_gc_work(struct work_struct *work)
u32 mask;
int i;
 
+   if (wvif->state != WFX_STATE_AP)
+   return;
+
wfx_tx_lock_flush(wvif->wdev);
spin_lock_bh(>ps_state_lock);
for (i = 0; i < WFX_MAX_STA_IN_AP_MODE; ++i) {
@@ -729,14 +733,26 @@ void wfx_tx_confirm_cb(struct wfx_vif *wvif, struct 
hif_cnf_tx *arg)
memset(tx_info->pad, 0, sizeof(tx_info->pad));
 
if (!arg->status) {
+   if (wvif->bss_loss_state && arg->packet_id == 
wvif->bss_loss_confirm_id)
+   wfx_cqm_bssloss_sm(wvif, 0, 1, 0);
tx_info->status.tx_time = arg->media_delay - 
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_REQUEUE) {
+   /* "REQUEUE" means "implicit suspend" */
+   struct hif_ind_suspend_resume_tx suspend = {
+   .suspend_resume_flags.resume = 0,
+   .suspend_resume_flags.bc_mc_only = 1,
+   };
+
WARN(!arg->tx_result_flags.requeue, "incoherent status and 
result_flags");
+   wfx_suspend_resume(wvif, );
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+   } else {
+   if (wvif->bss_loss_state && arg->packet_id == 
wvif->bss_loss_confirm_id)
+   wfx_cqm_bssloss_sm(wvif, 0, 0, 1);
}
wfx_pending_remove(wvif->wdev, skb);
 }
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 4bd9a079cbd9..14642471f4a9 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -12,7 +12,9 @@
 
 #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
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index 

[PATCH 03/20] staging: wfx: add I/O API

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

hwio.c provides an abstraction to access different types of register of
the chip.

Note that only data register (aka FRAME_OUT) and control register are
used normal communication. Other registers are only used during chip
start up.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/hwio.c   | 327 +++
 drivers/staging/wfx/hwio.h   |  27 +++
 3 files changed, 355 insertions(+)
 create mode 100644 drivers/staging/wfx/hwio.c

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 74939a5a0a1c..e860845186cf 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 wfx-y := \
+   hwio.o \
main.o
 wfx-$(CONFIG_SPI) += bus_spi.o
 wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c
new file mode 100644
index ..fa626a49dd8a
--- /dev/null
+++ b/drivers/staging/wfx/hwio.c
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Low-level I/O functions.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+#include 
+
+#include "hwio.h"
+#include "wfx.h"
+#include "bus.h"
+
+/*
+ * Internal helpers.
+ *
+ * About CONFIG_VMAP_STACK:
+ * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack
+ * allocated data. Functions below that work with registers (aka functions
+ * ending with "32") automatically reallocate buffers with kmalloc. However,
+ * functions that work with arbitrary length buffers let's caller to handle
+ * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located
+ * buffer.
+ */
+
+static int read32(struct wfx_dev *wdev, int reg, u32 *val)
+{
+   int ret;
+   __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
+
+   *val = ~0; // Never return undefined value
+   if (!tmp)
+   return -ENOMEM;
+   ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, 
sizeof(u32));
+   if (ret >= 0)
+   *val = le32_to_cpu(*tmp);
+   kfree(tmp);
+   if (ret)
+   dev_err(wdev->dev, "%s: bus communication error: %d\n", 
__func__, ret);
+   return ret;
+}
+
+static int write32(struct wfx_dev *wdev, int reg, u32 val)
+{
+   int ret;
+   __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
+
+   if (!tmp)
+   return -ENOMEM;
+   *tmp = cpu_to_le32(val);
+   ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, 
sizeof(u32));
+   kfree(tmp);
+   if (ret)
+   dev_err(wdev->dev, "%s: bus communication error: %d\n", 
__func__, ret);
+   return ret;
+}
+
+static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val)
+{
+   int ret;
+
+   wdev->hwbus_ops->lock(wdev->hwbus_priv);
+   ret = read32(wdev, reg, val);
+   wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+   return ret;
+}
+
+static int write32_locked(struct wfx_dev *wdev, int reg, u32 val)
+{
+   int ret;
+
+   wdev->hwbus_ops->lock(wdev->hwbus_priv);
+   ret = write32(wdev, reg, val);
+   wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+   return ret;
+}
+
+static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 
val)
+{
+   int ret;
+   u32 val_r, val_w;
+
+   WARN_ON(~mask & val);
+   val &= mask;
+   wdev->hwbus_ops->lock(wdev->hwbus_priv);
+   ret = read32(wdev, reg, _r);
+   if (ret < 0)
+   goto err;
+   val_w = (val_r & ~mask) | val;
+   if (val_w != val_r) {
+   ret = write32(wdev, reg, val_w);
+   }
+err:
+   wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+   return ret;
+}
+
+static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf, 
size_t len)
+{
+   int ret;
+   int i;
+   u32 cfg;
+   u32 prefetch;
+
+   WARN_ON(len >= 0x2000);
+   WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
+
+   if (reg == WFX_REG_AHB_DPORT)
+   prefetch = CFG_PREFETCH_AHB;
+   else if (reg == WFX_REG_SRAM_DPORT)
+   prefetch = CFG_PREFETCH_SRAM;
+   else
+   return -ENODEV;
+
+   ret = write32(wdev, WFX_REG_BASE_ADDR, addr);
+   if (ret < 0)
+   goto err;
+
+   ret = read32(wdev, WFX_REG_CONFIG, );
+   if (ret < 0)
+   goto err;
+
+   ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch);
+   if (ret < 0)
+   goto err;
+
+   for (i = 0; i < 20; i++) {
+   ret = read32(wdev, WFX_REG_CONFIG, );
+   if (ret < 0)
+   goto err;
+   if (!(cfg & prefetch))
+   break;
+   udelay(200);
+   }
+   if (i == 20) {
+   ret = -ETIMEDOUT;
+   goto err;
+   }
+
+  

[PATCH v2 20/20] staging: wfx: implement the rest of mac80211 API

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/data_rx.c |   26 +
 drivers/staging/wfx/data_tx.c |   16 +
 drivers/staging/wfx/debug.c   |2 +
 drivers/staging/wfx/hif_rx.c  |   53 ++
 drivers/staging/wfx/hif_tx.c  |1 +
 drivers/staging/wfx/main.c|  133 +++
 drivers/staging/wfx/queue.c   |   80 ++
 drivers/staging/wfx/scan.c|   40 +
 drivers/staging/wfx/sta.c | 1443 -
 drivers/staging/wfx/sta.h |   65 ++
 drivers/staging/wfx/wfx.h |   51 ++
 11 files changed, 1907 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c
index 3b3117b2edac..3a79089c8501 100644
--- a/drivers/staging/wfx/data_rx.c
+++ b/drivers/staging/wfx/data_rx.c
@@ -21,6 +21,8 @@ static int wfx_handle_pspoll(struct wfx_vif *wvif, struct 
sk_buff *skb)
u32 pspoll_mask = 0;
int i;
 
+   if (wvif->state != WFX_STATE_AP)
+   return 1;
if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid))
return 1;
 
@@ -162,6 +164,30 @@ void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx 
*arg, struct sk_buff *skb
&& arg->rx_flags.match_uc_addr
&& mgmt->u.action.category == WLAN_CATEGORY_BACK)
goto drop;
+   if (ieee80211_is_beacon(frame->frame_control)
+   && !arg->status && wvif->vif
+   && ether_addr_equal(ieee80211_get_SA(frame), 
wvif->vif->bss_conf.bssid)) {
+   const u8 *tim_ie;
+   u8 *ies = mgmt->u.beacon.variable;
+   size_t ies_len = skb->len - (ies - skb->data);
+
+   tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len);
+   if (tim_ie) {
+   struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie 
*) _ie[2];
+
+   if (wvif->dtim_period != tim->dtim_period) {
+   wvif->dtim_period = tim->dtim_period;
+   
schedule_work(>set_beacon_wakeup_period_work);
+   }
+   }
+
+   /* Disable beacon filter once we're associated... */
+   if (wvif->disable_beacon_filter &&
+   (wvif->vif->bss_conf.assoc || 
wvif->vif->bss_conf.ibss_joined)) {
+   wvif->disable_beacon_filter = false;
+   schedule_work(>update_filtering_work);
+   }
+   }
 
if (early_data) {
spin_lock_bh(>ps_state_lock);
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
index 217d3c270706..7f2799fbdafe 100644
--- a/drivers/staging/wfx/data_tx.c
+++ b/drivers/staging/wfx/data_tx.c
@@ -10,6 +10,7 @@
 #include "data_tx.h"
 #include "wfx.h"
 #include "bh.h"
+#include "sta.h"
 #include "queue.h"
 #include "debug.h"
 #include "traces.h"
@@ -359,6 +360,9 @@ void wfx_link_id_gc_work(struct work_struct *work)
u32 mask;
int i;
 
+   if (wvif->state != WFX_STATE_AP)
+   return;
+
wfx_tx_lock_flush(wvif->wdev);
spin_lock_bh(>ps_state_lock);
for (i = 0; i < WFX_MAX_STA_IN_AP_MODE; ++i) {
@@ -729,14 +733,26 @@ void wfx_tx_confirm_cb(struct wfx_vif *wvif, struct 
hif_cnf_tx *arg)
memset(tx_info->pad, 0, sizeof(tx_info->pad));
 
if (!arg->status) {
+   if (wvif->bss_loss_state && arg->packet_id == 
wvif->bss_loss_confirm_id)
+   wfx_cqm_bssloss_sm(wvif, 0, 1, 0);
tx_info->status.tx_time = arg->media_delay - 
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_REQUEUE) {
+   /* "REQUEUE" means "implicit suspend" */
+   struct hif_ind_suspend_resume_tx suspend = {
+   .suspend_resume_flags.resume = 0,
+   .suspend_resume_flags.bc_mc_only = 1,
+   };
+
WARN(!arg->tx_result_flags.requeue, "incoherent status and 
result_flags");
+   wfx_suspend_resume(wvif, );
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+   } else {
+   if (wvif->bss_loss_state && arg->packet_id == 
wvif->bss_loss_confirm_id)
+   wfx_cqm_bssloss_sm(wvif, 0, 0, 1);
}
wfx_pending_remove(wvif->wdev, skb);
 }
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 1e23bb5bde3e..3261b267c385 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -11,7 +11,9 @@
 
 #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
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index 

[PATCH v2 16/20] staging: wfx: allow to send 802.11 frames

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Three things make this task more complex than it should:
  - Chip necessitate to associate a link-id to each station. It is same
thing than association ID but, using 8 bits only.
  - Rate policy is sent separately from Tx frames
  - Driver try to handle itself power saving of stations and multicast
data

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile  |   3 +
 drivers/staging/wfx/bh.c  |   2 +
 drivers/staging/wfx/data_tx.c | 783 ++
 drivers/staging/wfx/data_tx.h |  93 
 drivers/staging/wfx/hif_rx.c  |  37 ++
 drivers/staging/wfx/hif_tx.c  |   1 +
 drivers/staging/wfx/main.c|   4 +
 drivers/staging/wfx/queue.c   | 526 +++
 drivers/staging/wfx/queue.h   |  59 +++
 drivers/staging/wfx/sta.c | 135 ++
 drivers/staging/wfx/sta.h |   8 +
 drivers/staging/wfx/traces.h  |  74 
 drivers/staging/wfx/wfx.h |  58 +++
 13 files changed, 1783 insertions(+)
 create mode 100644 drivers/staging/wfx/data_tx.c
 create mode 100644 drivers/staging/wfx/data_tx.h
 create mode 100644 drivers/staging/wfx/queue.c
 create mode 100644 drivers/staging/wfx/queue.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index e158589468a3..d5ac9fafd1f1 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -9,6 +9,9 @@ wfx-y := \
fwio.o \
hif_tx.o \
hif_rx.o \
+   queue.o \
+   data_tx.o \
+   sta.o \
main.o \
sta.o \
debug.o
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index d321fd312d55..ed81c3924d98 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -220,6 +220,8 @@ static int bh_work_tx(struct wfx_dev *wdev, int max_msg)
if (try_wait_for_completion(>hif_cmd.ready)) {
WARN(!mutex_is_locked(>hif_cmd.lock), 
"data locking error");
hif = wdev->hif_cmd.buf_send;
+   } else {
+   hif = wfx_tx_queues_get(wdev);
}
}
if (!hif)
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
new file mode 100644
index ..217d3c270706
--- /dev/null
+++ b/drivers/staging/wfx/data_tx.c
@@ -0,0 +1,783 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Datapath implementation.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+
+#include "data_tx.h"
+#include "wfx.h"
+#include "bh.h"
+#include "queue.h"
+#include "debug.h"
+#include "traces.h"
+#include "hif_tx_mib.h"
+
+#define WFX_INVALID_RATE_ID (0xFF)
+#define WFX_LINK_ID_GC_TIMEOUT ((unsigned long)(10 * HZ))
+
+static int wfx_get_hw_rate(struct wfx_dev *wdev, const struct 
ieee80211_tx_rate *rate)
+{
+   if (rate->idx < 0)
+   return -1;
+   if (rate->flags & IEEE80211_TX_RC_MCS) {
+   if (rate->idx > 7) {
+   WARN(1, "wrong rate->idx value: %d", rate->idx);
+   return -1;
+   }
+   return rate->idx + 14;
+   }
+   // WFx only support 2GHz, else band information should be retreived
+   // from ieee80211_tx_info
+   return 
wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->bitrates[rate->idx].hw_value;
+}
+
+/* TX policy cache implementation */
+
+static void tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy,
+   struct ieee80211_tx_rate *rates)
+{
+   int i;
+   size_t count;
+   struct wfx_dev *wdev = wvif->wdev;
+
+   BUG_ON(rates[0].idx < 0);
+   memset(policy, 0, sizeof(*policy));
+   for (i = 1; i < IEEE80211_TX_MAX_RATES; i++)
+   if (rates[i].idx < 0)
+   break;
+   count = i;
+
+   /* HACK!!! Device has problems (at least) switching from
+* 54Mbps CTS to 1Mbps. This switch takes enormous amount
+* of time (100-200 ms), leading to valuable throughput drop.
+* As a workaround, additional g-rates are injected to the
+* policy.
+*/
+   if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) &&
+   rates[0].idx > 4 && rates[0].count > 2 &&
+   rates[1].idx < 2) {
+   int mid_rate = (rates[0].idx + 4) >> 1;
+
+   /* Decrease number of retries for the initial rate */
+   rates[0].count -= 2;
+
+   if (mid_rate != 4) {
+   /* Keep fallback rate at 1Mbps. */
+   rates[3] = rates[1];
+
+   /* Inject 1 transmission on lowest g-rate */
+   rates[2].idx = 4;
+   rates[2].count = 1;
+   rates[2].flags = rates[1].flags;
+
+   /* Inject 1 transmission on mid-rate */
+   rates[1].idx = 

[PATCH v3 10/20] staging: wfx: instantiate mac80211 data

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Allocate a struct ieee80211_hw but do not yet register it.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |  1 +
 drivers/staging/wfx/debug.c  | 12 ++
 drivers/staging/wfx/debug.h  | 15 
 drivers/staging/wfx/main.c   | 41 ++--
 drivers/staging/wfx/sta.c| 46 
 drivers/staging/wfx/sta.h| 24 +++
 drivers/staging/wfx/wfx.h|  8 +++
 7 files changed, 145 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/debug.h
 create mode 100644 drivers/staging/wfx/sta.c
 create mode 100644 drivers/staging/wfx/sta.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 35670b86c64f..2896a2127c88 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -9,6 +9,7 @@ wfx-y := \
fwio.o \
hif_rx.o \
main.o \
+   sta.o \
debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
 wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index bf44c944640d..f28c94d8de89 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -5,6 +5,18 @@
  * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include 
+
+#include "wfx.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
+
+int wfx_debug_init(struct wfx_dev *wdev)
+{
+   struct dentry *d;
+
+   d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+
+   return 0;
+}
diff --git a/drivers/staging/wfx/debug.h b/drivers/staging/wfx/debug.h
new file mode 100644
index ..8bfba1a9fa20
--- /dev/null
+++ b/drivers/staging/wfx/debug.h
@@ -0,0 +1,15 @@
+/* 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);
+
+#endif /* WFX_DEBUG_H */
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 5e7e7225f068..ca0ca873bd7d 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -25,6 +25,9 @@
 #include "hwio.h"
 #include "bus.h"
 #include "bh.h"
+#include "sta.h"
+#include "debug.h"
+#include "hif_api_cmd.h"
 #include "wfx_version.h"
 
 MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx");
@@ -36,6 +39,13 @@ static int gpio_wakeup = -2;
 module_param(gpio_wakeup, int, 0644);
 MODULE_PARM_DESC(gpio_wakeup, "gpio number for wakeup. -1 for none.");
 
+static const struct ieee80211_ops wfx_ops = {
+   .start  = wfx_start,
+   .stop   = wfx_stop,
+   .add_interface  = wfx_add_interface,
+   .remove_interface   = wfx_remove_interface,
+};
+
 bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor)
 {
if (wdev->hw_caps.api_version_major < major)
@@ -79,11 +89,26 @@ struct wfx_dev *wfx_init_common(struct device *dev,
const struct hwbus_ops *hwbus_ops,
void *hwbus_priv)
 {
+   struct ieee80211_hw *hw;
struct wfx_dev *wdev;
 
-   wdev = devm_kmalloc(dev, sizeof(*wdev), GFP_KERNEL);
-   if (!wdev)
+   hw = ieee80211_alloc_hw(sizeof(struct wfx_dev), _ops);
+   if (!hw)
return NULL;
+
+   SET_IEEE80211_DEV(hw, dev);
+
+   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 = 15;
+   hw->extra_tx_headroom = sizeof(struct hif_sl_msg_hdr) + sizeof(struct 
hif_msg)
+   + sizeof(struct hif_req_tx)
+   + 4 /* alignment */ + 8 /* TKIP IV */;
+
+   wdev = hw->priv;
+   wdev->hw = hw;
wdev->dev = dev;
wdev->hwbus_ops = hwbus_ops;
wdev->hwbus_priv = hwbus_priv;
@@ -96,6 +121,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
 
 void wfx_free_common(struct wfx_dev *wdev)
 {
+   ieee80211_free_hw(wdev->hw);
 }
 
 int wfx_probe(struct wfx_dev *wdev)
@@ -127,6 +153,11 @@ int wfx_probe(struct wfx_dev *wdev)
 wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label,
 wdev->hw_caps.api_version_major, 
wdev->hw_caps.api_version_minor,
 wdev->keyset, *((u32 *) >hw_caps.capabilities));
+   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",
@@ -150,8 

[PATCH v3 12/20] staging: wfx: add HIF commands helpers

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Provide an abstraction for HIF commands.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/hif_tx.c | 375 +++
 drivers/staging/wfx/hif_tx.h |  33 +++
 drivers/staging/wfx/hif_tx_mib.h | 281 +++
 3 files changed, 689 insertions(+)
 create mode 100644 drivers/staging/wfx/hif_tx_mib.h

diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c
index f81a19089db4..781a6e28dbad 100644
--- a/drivers/staging/wfx/hif_tx.c
+++ b/drivers/staging/wfx/hif_tx.c
@@ -12,6 +12,7 @@
 #include "hif_tx.h"
 #include "wfx.h"
 #include "bh.h"
+#include "hwio.h"
 #include "debug.h"
 
 void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
@@ -21,6 +22,29 @@ void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
mutex_init(_cmd->lock);
 }
 
+static void wfx_fill_header(struct hif_msg *hif, int if_id, unsigned int cmd, 
size_t size)
+{
+   if (if_id == -1)
+   if_id = 2;
+
+   WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd);
+   WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size);
+   WARN(if_id > 0x3, "invalid interface ID %d", if_id);
+
+   hif->len = cpu_to_le16(size + 4);
+   hif->id = cmd;
+   hif->interface = if_id;
+}
+
+static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif)
+{
+   *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL);
+   if (*hif)
+   return (*hif)->body;
+   else
+   return NULL;
+}
+
 int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, 
size_t reply_len, bool async)
 {
const char *mib_name = "";
@@ -85,3 +109,354 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg 
*request, void *reply, siz
 
return ret;
 }
+
+// This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to 
any
+// request anymore. We need to slightly hack struct wfx_hif_cmd for that job. 
Be
+// carefull to only call this funcion during device unregister.
+int hif_shutdown(struct wfx_dev *wdev)
+{
+   int ret;
+   struct hif_msg *hif;
+
+   wfx_alloc_hif(0, );
+   wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0);
+   ret = wfx_cmd_send(wdev, hif, NULL, 0, true);
+   // After this command, chip won't reply. Be sure to give enough time to
+   // bh to send buffer:
+   msleep(100);
+   wdev->hif_cmd.buf_send = NULL;
+   if (wdev->pdata.gpio_wakeup)
+   gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
+   else
+   control_reg_write(wdev, 0);
+   mutex_unlock(>hif_cmd.lock);
+   kfree(hif);
+   return ret;
+}
+
+int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
+{
+   int ret;
+   size_t buf_len = sizeof(struct hif_req_configuration) + len;
+   struct hif_msg *hif;
+   struct hif_req_configuration *body = wfx_alloc_hif(buf_len, );
+
+   body->length = cpu_to_le16(len);
+   memcpy(body->pds_data, conf, len);
+   wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len);
+   ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
+   kfree(hif);
+   return ret;
+}
+
+int hif_reset(struct wfx_vif *wvif, bool reset_stat)
+{
+   int ret;
+   struct hif_msg *hif;
+   struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), );
+
+   body->reset_flags.reset_stat = reset_stat;
+   wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body));
+   ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+   kfree(hif);
+   return ret;
+}
+
+int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, 
size_t val_len)
+{
+   int ret;
+   struct hif_msg *hif;
+   int buf_len = sizeof(struct hif_cnf_read_mib) + val_len;
+   struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), );
+   struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
+
+   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 != reply->mib_id) {
+   dev_warn(wdev->dev, "%s: confirmation mismatch request\n", 
__func__);
+   ret = -EIO;
+   }
+   if (ret == -ENOMEM)
+   dev_err(wdev->dev, "buffer is too small to receive %s (%zu < 
%d)\n",
+   get_mib_name(mib_id), val_len, reply->length);
+   if (!ret)
+   memcpy(val, >mib_data, reply->length);
+   else
+   memset(val, 0xFF, val_len);
+   kfree(hif);
+   kfree(reply);
+   return ret;
+}
+
+int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, 
size_t val_len)
+{
+   int ret;
+   struct hif_msg *hif;
+   int buf_len = sizeof(struct hif_req_write_mib) + val_len;
+   struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, );
+
+   body->mib_id = 

[PATCH v3 06/20] staging: wfx: import HIF API headers

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

These files are shared with firmware sources. Only a subset of these
definitions are used by driver but, for now, it is easier to import all.

API defines 3 kinds of messages:
   - Requests (req) are sent from host to chip
   - Confirmations (cnf) are sent by chip and are always in reply to a
 request
   - Indications (ind) are spontaneous message from chip to host

One request normally generate one confirmation. There are a few
exceptions to this rule:
   - "shutdown" request is not acknowledged
   - multiple tx request can be acknowledged a unique "multi-tx"
 confirmation

In add, API defines MIB. They are sub-structures for write_mib and
read_mib API.

Note that all numbers in API have to be little endian when sent/received
from/to chip (I didn't declared them with __le32 because driver also use
them internally).

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/hif_api_cmd.h | 681 ++
 drivers/staging/wfx/hif_api_general.h | 437 +
 drivers/staging/wfx/hif_api_mib.h | 558 +
 3 files changed, 1676 insertions(+)
 create mode 100644 drivers/staging/wfx/hif_api_cmd.h
 create mode 100644 drivers/staging/wfx/hif_api_general.h
 create mode 100644 drivers/staging/wfx/hif_api_mib.h

diff --git a/drivers/staging/wfx/hif_api_cmd.h 
b/drivers/staging/wfx/hif_api_cmd.h
new file mode 100644
index ..7c5d1ea6098d
--- /dev/null
+++ b/drivers/staging/wfx/hif_api_cmd.h
@@ -0,0 +1,681 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * WFx hardware interface definitions
+ *
+ * Copyright (c) 2018-2019, Silicon Laboratories Inc.
+ */
+
+#ifndef WFX_HIF_API_CMD_H
+#define WFX_HIF_API_CMD_H
+
+#include "hif_api_general.h"
+
+#define HIF_NUM_AC 4
+
+#define HIF_API_SSID_SIZE  API_SSID_SIZE
+
+enum hif_requests_ids {
+   HIF_REQ_ID_RESET = 0x0a,
+   HIF_REQ_ID_READ_MIB  = 0x05,
+   HIF_REQ_ID_WRITE_MIB = 0x06,
+   HIF_REQ_ID_START_SCAN= 0x07,
+   HIF_REQ_ID_STOP_SCAN = 0x08,
+   HIF_REQ_ID_TX= 0x04,
+   HIF_REQ_ID_JOIN  = 0x0b,
+   HIF_REQ_ID_SET_PM_MODE   = 0x10,
+   HIF_REQ_ID_SET_BSS_PARAMS= 0x11,
+   HIF_REQ_ID_ADD_KEY   = 0x0c,
+   HIF_REQ_ID_REMOVE_KEY= 0x0d,
+   HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13,
+   HIF_REQ_ID_START = 0x17,
+   HIF_REQ_ID_BEACON_TRANSMIT   = 0x18,
+   HIF_REQ_ID_UPDATE_IE = 0x1b,
+   HIF_REQ_ID_MAP_LINK  = 0x1c,
+};
+
+enum hif_confirmations_ids {
+   HIF_CNF_ID_RESET = 0x0a,
+   HIF_CNF_ID_READ_MIB  = 0x05,
+   HIF_CNF_ID_WRITE_MIB = 0x06,
+   HIF_CNF_ID_START_SCAN= 0x07,
+   HIF_CNF_ID_STOP_SCAN = 0x08,
+   HIF_CNF_ID_TX= 0x04,
+   HIF_CNF_ID_MULTI_TRANSMIT= 0x1e,
+   HIF_CNF_ID_JOIN  = 0x0b,
+   HIF_CNF_ID_SET_PM_MODE   = 0x10,
+   HIF_CNF_ID_SET_BSS_PARAMS= 0x11,
+   HIF_CNF_ID_ADD_KEY   = 0x0c,
+   HIF_CNF_ID_REMOVE_KEY= 0x0d,
+   HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13,
+   HIF_CNF_ID_START = 0x17,
+   HIF_CNF_ID_BEACON_TRANSMIT   = 0x18,
+   HIF_CNF_ID_UPDATE_IE = 0x1b,
+   HIF_CNF_ID_MAP_LINK  = 0x1c,
+};
+
+enum hif_indications_ids {
+   HIF_IND_ID_RX= 0x84,
+   HIF_IND_ID_SCAN_CMPL = 0x86,
+   HIF_IND_ID_JOIN_COMPLETE = 0x8f,
+   HIF_IND_ID_SET_PM_MODE_CMPL  = 0x89,
+   HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c,
+   HIF_IND_ID_EVENT = 0x85
+};
+
+union hif_commands_ids {
+   enum hif_requests_ids request;
+   enum hif_confirmations_ids confirmation;
+   enum hif_indications_ids indication;
+};
+
+enum hif_status {
+   HIF_STATUS_SUCCESS = 0x0,
+   HIF_STATUS_FAILURE = 0x1,
+   HIF_INVALID_PARAMETER  = 0x2,
+   HIF_STATUS_WARNING = 0x3,
+   HIF_ERROR_UNSUPPORTED_MSG_ID   = 0x4,
+   HIF_STATUS_DECRYPTFAILURE  = 0x10,
+   HIF_STATUS_MICFAILURE  = 0x11,
+   HIF_STATUS_NO_KEY_FOUND= 0x12,

[PATCH v3 17/20] staging: wfx: allow to receive 802.11 frames

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Again, this task is more complex than it should since driver try to
handle itself power saving of stations.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile  |   1 +
 drivers/staging/wfx/data_rx.c | 182 ++
 drivers/staging/wfx/data_rx.h |  18 
 drivers/staging/wfx/hif_rx.c  |  23 +
 4 files changed, 224 insertions(+)
 create mode 100644 drivers/staging/wfx/data_rx.c
 create mode 100644 drivers/staging/wfx/data_rx.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index d5ac9fafd1f1..d9e21515d08e 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -11,6 +11,7 @@ wfx-y := \
hif_rx.o \
queue.o \
data_tx.o \
+   data_rx.o \
sta.o \
main.o \
sta.o \
diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c
new file mode 100644
index ..3b3117b2edac
--- /dev/null
+++ b/drivers/staging/wfx/data_rx.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Datapath implementation.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#include "data_rx.h"
+#include "wfx.h"
+#include "bh.h"
+#include "sta.h"
+
+static int wfx_handle_pspoll(struct wfx_vif *wvif, struct sk_buff *skb)
+{
+   struct ieee80211_sta *sta;
+   struct ieee80211_pspoll *pspoll = (struct ieee80211_pspoll *)skb->data;
+   int link_id = 0;
+   u32 pspoll_mask = 0;
+   int i;
+
+   if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid))
+   return 1;
+
+   rcu_read_lock();
+   sta = ieee80211_find_sta(wvif->vif, pspoll->ta);
+   if (sta)
+   link_id = ((struct wfx_sta_priv *) >drv_priv)->link_id;
+   rcu_read_unlock();
+   if (link_id)
+   pspoll_mask = BIT(link_id);
+   else
+   return 1;
+
+   wvif->pspoll_mask |= pspoll_mask;
+   /* Do not report pspols if data for given link id is queued already. */
+   for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
+   if (wfx_tx_queue_get_num_queued(>wdev->tx_queue[i],
+   pspoll_mask)) {
+   wfx_bh_request_tx(wvif->wdev);
+   return 1;
+   }
+   }
+   return 0;
+}
+
+static int wfx_drop_encrypt_data(struct wfx_dev *wdev, struct hif_ind_rx *arg, 
struct sk_buff *skb)
+{
+   struct ieee80211_hdr *frame = (struct ieee80211_hdr *) skb->data;
+   size_t hdrlen = ieee80211_hdrlen(frame->frame_control);
+   size_t iv_len, icv_len;
+
+   /* Oops... There is no fast way to ask mac80211 about
+* IV/ICV lengths. Even defineas are not exposed.
+*/
+   switch (arg->rx_flags.encryp) {
+   case HIF_RI_FLAGS_WEP_ENCRYPTED:
+   iv_len = 4 /* WEP_IV_LEN */;
+   icv_len = 4 /* WEP_ICV_LEN */;
+   break;
+   case HIF_RI_FLAGS_TKIP_ENCRYPTED:
+   iv_len = 8 /* TKIP_IV_LEN */;
+   icv_len = 4 /* TKIP_ICV_LEN */
+   + 8 /*MICHAEL_MIC_LEN*/;
+   break;
+   case HIF_RI_FLAGS_AES_ENCRYPTED:
+   iv_len = 8 /* CCMP_HDR_LEN */;
+   icv_len = 8 /* CCMP_MIC_LEN */;
+   break;
+   case HIF_RI_FLAGS_WAPI_ENCRYPTED:
+   iv_len = 18 /* WAPI_HDR_LEN */;
+   icv_len = 16 /* WAPI_MIC_LEN */;
+   break;
+   default:
+   dev_err(wdev->dev, "unknown encryption type %d\n",
+arg->rx_flags.encryp);
+   return -EIO;
+   }
+
+   /* Firmware strips ICV in case of MIC failure. */
+   if (arg->status == HIF_STATUS_MICFAILURE)
+   icv_len = 0;
+
+   if (skb->len < hdrlen + iv_len + icv_len) {
+   dev_warn(wdev->dev, "malformed SDU received\n");
+   return -EIO;
+   }
+
+   /* Remove IV, ICV and MIC */
+   skb_trim(skb, skb->len - icv_len);
+   memmove(skb->data + iv_len, skb->data, hdrlen);
+   skb_pull(skb, iv_len);
+   return 0;
+
+}
+
+void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx *arg, struct sk_buff 
*skb)
+{
+   int link_id = arg->rx_flags.peer_sta_id;
+   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;
+   struct wfx_link_entry *entry = NULL;
+   bool early_data = false;
+
+   memset(hdr, 0, sizeof(*hdr));
+
+   // FIXME: Why do we drop these frames?
+   if (!arg->rcpi_rssi &&
+   (ieee80211_is_probe_resp(frame->frame_control) ||
+ieee80211_is_beacon(frame->frame_control)))
+   goto drop;
+
+   if (link_id && link_id <= WFX_MAX_STA_IN_AP_MODE) {
+   entry = 

[PATCH v3 13/20] staging: wfx: introduce "secure link"

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Chip support encryption of the link between host and chip. This feature
is called "secure link". Driver code on github[1] support it. However,
it relies on mbedtls for cryptographic functions. So, I decided to not
import this feature in current patch. However, in order to keep code
synchronized between github and kernel, I imported all code related to
this feature, even if most of it is just no-op.

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

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bh.c  | 31 +++--
 drivers/staging/wfx/debug.c   | 17 
 drivers/staging/wfx/hif_rx.c  | 17 
 drivers/staging/wfx/hif_tx.c  |  6 
 drivers/staging/wfx/hif_tx.h  |  1 +
 drivers/staging/wfx/main.c| 36 
 drivers/staging/wfx/main.h|  2 ++
 drivers/staging/wfx/secure_link.h | 46 +++
 drivers/staging/wfx/wfx.h |  2 ++
 9 files changed, 156 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/wfx/secure_link.h

diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index c94c9c401a69..d321fd312d55 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -12,6 +12,7 @@
 #include "wfx.h"
 #include "hwio.h"
 #include "traces.h"
+#include "secure_link.h"
 #include "hif_rx.h"
 #include "hif_api_cmd.h"
 
@@ -74,7 +75,18 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
hif = (struct hif_msg *) skb->data;
WARN(hif->encrypted & 0x1, "unsupported encryption type");
if (hif->encrypted == 0x2) {
-   BUG(); // Not yet implemented
+   if (wfx_sl_decode(wdev, (void *) hif)) {
+   dev_kfree_skb(skb);
+   // If frame was a confirmation, expect trouble in next
+   // exchange. However, it is harmless to fail to decode
+   // an indication frame, so try to continue. Anyway,
+   // piggyback is probably correct.
+   return piggyback;
+   }
+   le16_to_cpus(hif->len);
+   computed_len = round_up(hif->len - sizeof(hif->len), 16)
+  + sizeof(struct hif_sl_msg)
+  + sizeof(struct hif_sl_tag);
} else {
le16_to_cpus(hif->len);
computed_len = round_up(hif->len, 2);
@@ -166,7 +178,22 @@ static void tx_helper(struct wfx_dev *wdev, struct hif_msg 
*hif)
hif->seqnum = wdev->hif.tx_seqnum;
wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1);
 
-   data = hif;
+   if (wfx_is_secure_command(wdev, hif->id)) {
+   len = round_up(len - sizeof(hif->len), 16) + sizeof(hif->len)
+ + sizeof(struct hif_sl_msg_hdr) + sizeof(struct 
hif_sl_tag);
+   // AES support encryption in-place. However, mac80211 access to
+   // 802.11 header after frame was sent (to get MAC addresses).
+   // So, keep origin buffer clear.
+   data = kmalloc(len, GFP_KERNEL);
+   if (!data)
+   goto end;
+   is_encrypted = true;
+   ret = wfx_sl_encode(wdev, hif, data);
+   if (ret)
+   goto end;
+   } else {
+   data = hif;
+   }
WARN(len > wdev->hw_caps.size_inp_ch_buf,
 "%s: request exceed WFx capability: %zu > %d\n", __func__,
 len, wdev->hw_caps.size_inp_ch_buf);
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 0a328c96eaa0..f79693a4be7f 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -6,6 +6,7 @@
  * Copyright (c) 2010, ST-Ericsson
  */
 #include 
+#include 
 
 #include "debug.h"
 #include "wfx.h"
@@ -53,6 +54,21 @@ const char *get_reg_name(unsigned long id)
return get_symbol(id, wfx_reg_print_map);
 }
 
+static ssize_t wfx_burn_slk_key_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+   struct wfx_dev *wdev = file->private_data;
+
+   dev_info(wdev->dev, "this driver does not support secure link\n");
+   return -EINVAL;
+}
+
+static const struct file_operations wfx_burn_slk_key_fops = {
+   .open = simple_open,
+   .write = wfx_burn_slk_key_write,
+};
+
 struct dbgfs_hif_msg {
struct wfx_dev *wdev;
struct completion complete;
@@ -146,6 +162,7 @@ int wfx_debug_init(struct wfx_dev *wdev)
struct dentry *d;
 
d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+   debugfs_create_file("burn_slk_key", 0200, d, wdev, 
_burn_slk_key_fops);
debugfs_create_file("send_hif_msg", 0600, d, wdev, 
_send_hif_msg_fops);
 
return 0;
diff --git 

[PATCH v3 05/20] staging: wfx: load firmware

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

A firmware is necessary to run the chip. wfx_init_device() is in charge
of loading firmware on chip and doing low level initialization.

Firmwares for WF200 are available here:

  https://github.com/SiliconLabs/wfx-firmware/

Note that firmware are encrypted. Driver checks that key used to encrypt
firmware match with key burned into chip.

Currently, "C0" key is used for production chips.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile   |   1 +
 drivers/staging/wfx/bus_sdio.c |   8 +
 drivers/staging/wfx/bus_spi.c  |   7 +
 drivers/staging/wfx/fwio.c | 387 +
 drivers/staging/wfx/fwio.h |  15 ++
 drivers/staging/wfx/main.c |  20 ++
 drivers/staging/wfx/main.h |  10 +
 drivers/staging/wfx/wfx.h  |   2 +
 8 files changed, 450 insertions(+)
 create mode 100644 drivers/staging/wfx/fwio.c
 create mode 100644 drivers/staging/wfx/fwio.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 330b7288ebb5..e568d7a6fb06 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -5,6 +5,7 @@ CFLAGS_debug.o = -I$(src)
 
 wfx-y := \
hwio.o \
+   fwio.o \
main.o \
debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 35bcca7ec5dc..25c587fe2141 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -17,6 +17,7 @@
 #include "main.h"
 
 static const struct wfx_platform_data wfx_sdio_pdata = {
+   .file_fw = "wfm_wf200",
 };
 
 struct wfx_sdio_priv {
@@ -204,8 +205,14 @@ static int wfx_sdio_probe(struct sdio_func *func,
goto err2;
}
 
+   ret = wfx_probe(bus->core);
+   if (ret)
+   goto err3;
+
return 0;
 
+err3:
+   wfx_free_common(bus->core);
 err2:
wfx_sdio_irq_unsubscribe(bus);
 err1:
@@ -220,6 +227,7 @@ static void wfx_sdio_remove(struct sdio_func *func)
 {
struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
 
+   wfx_release(bus->core);
wfx_free_common(bus->core);
wfx_sdio_irq_unsubscribe(bus);
sdio_claim_host(func);
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index 5e8f84baf2ca..b73b9416273f 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -27,6 +27,8 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for 
none.");
 #define SET_READ 0x8000 /* usage: or operation */
 
 static const struct wfx_platform_data wfx_spi_pdata = {
+   .file_fw = "wfm_wf200",
+   .use_rising_clk = true,
 };
 
 struct wfx_spi_priv {
@@ -205,6 +207,10 @@ static int wfx_spi_probe(struct spi_device *func)
if (!bus->core)
return -EIO;
 
+   ret = wfx_probe(bus->core);
+   if (ret)
+   wfx_free_common(bus->core);
+
return ret;
 }
 
@@ -213,6 +219,7 @@ static int wfx_spi_disconnect(struct spi_device *func)
 {
struct wfx_spi_priv *bus = spi_get_drvdata(func);
 
+   wfx_release(bus->core);
wfx_free_common(bus->core);
// A few IRQ will be sent during device release. Hopefully, no IRQ
// should happen after wdev/wvif are released.
diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c
new file mode 100644
index ..8fb4a9f6d1a6
--- /dev/null
+++ b/drivers/staging/wfx/fwio.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Firmware loading.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+#include 
+#include 
+
+#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_SIZE0x8000 // (32 * DNLD_BLOCK_SIZE)
+// Download Control Area (DCA)
+#define WFX_DCA_IMAGE_SIZE0x0900C000
+#define WFX_DCA_PUT   0x0900C004
+#define WFX_DCA_GET   0x0900C008
+#define WFX_DCA_HOST_STATUS   0x0900C00C
+#define HOST_READY0x87654321
+#define HOST_INFO_READ0xA753BD99
+#define HOST_UPLOAD_PENDING   0xABCDDCBA
+#define HOST_UPLOAD_COMPLETE  0xD4C64A99
+#define HOST_OK_TO_JUMP   0x174FC882
+#define WFX_DCA_NCP_STATUS0x0900C010
+#define NCP_NOT_READY 0x12345678
+#define NCP_READY 0x87654321
+#define NCP_INFO_READY0xBD53EF99
+#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

[PATCH v3 01/20] staging: wfx: add infrastructure for new driver

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Instantiate build infrastructure WFx driver. This driver provides support
for Wifi chipset Silicon Labs WF200 and further:

   https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf

This chip support SPI and SDIO bus.

SDIO interface has two particularities:
1. Some parameters may be useful for end user (I will talk about
   gpio_wakeup later).
2. The SDIO VID and PID of WF200 are :0001 which are too much
   generic to rely on.

So, current code checks VID/PID and looks for a node in DT (since WF200
targets embedded platforms, I don't think it is a problem to rely on
DT). DT can also be used to define to parameters for driver. Currently,
if no node is found, a warning is emitted, but it could be changed in
error.

Signed-off-by: Jérôme Pouiller 
---
 MAINTAINERS   |  5 +
 drivers/staging/Kconfig   |  2 +
 drivers/staging/Makefile  |  1 +
 .../bindings/net/wireless/siliabs,wfx.txt | 97 +++
 drivers/staging/wfx/Kconfig   |  7 ++
 drivers/staging/wfx/Makefile  |  8 ++
 drivers/staging/wfx/TODO  | 20 
 drivers/staging/wfx/bus.h | 17 
 drivers/staging/wfx/bus_sdio.c| 70 +
 drivers/staging/wfx/bus_spi.c | 53 ++
 drivers/staging/wfx/main.c| 47 +
 drivers/staging/wfx/wfx_version.h |  3 +
 12 files changed, 330 insertions(+)
 create mode 100644 
drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
 create mode 100644 drivers/staging/wfx/Kconfig
 create mode 100644 drivers/staging/wfx/Makefile
 create mode 100644 drivers/staging/wfx/TODO
 create mode 100644 drivers/staging/wfx/bus.h
 create mode 100644 drivers/staging/wfx/bus_sdio.c
 create mode 100644 drivers/staging/wfx/bus_spi.c
 create mode 100644 drivers/staging/wfx/main.c
 create mode 100644 drivers/staging/wfx/wfx_version.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b2326dece28e..0ad6fbde3ac9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14755,6 +14755,11 @@ S: Maintained
 F: drivers/input/touchscreen/silead.c
 F: drivers/platform/x86/touchscreen_dmi.c
 
+SILICON LABS WIRELESS DRIVERS (for WFxxx series)
+M: Jérôme Pouiller 
+S: Supported
+F: drivers/staging/wfx/
+
 SILICON MOTION SM712 FRAME BUFFER DRIVER
 M: Sudip Mukherjee 
 M: Teddy Wang 
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 6f1fa4c849a1..a490141a0e88 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig"
 
 source "drivers/staging/qlge/Kconfig"
 
+source "drivers/staging/wfx/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index a90f9b308c8d..4cb548a0ff87 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_UWB) += uwb/
 obj-$(CONFIG_USB_WUSB) += wusbcore/
 obj-$(CONFIG_EXFAT_FS) += exfat/
 obj-$(CONFIG_QLGE) += qlge/
+obj-$(CONFIG_WFX)  += wfx/
diff --git 
a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
 
b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
new file mode 100644
index ..15965c9b4180
--- /dev/null
+++ 
b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
@@ -0,0 +1,97 @@
+The WFxxx chip series can be connected via SPI or via SDIO.
+
+SPI
+---
+
+You have to declare the WFxxx chip in your device tree.
+
+Required properties:
+ - compatible: Should be "silabs,wfx-spi"
+ - reg: Chip select address of device
+ - spi-max-frequency: Maximum SPI clocking speed of device in Hz
+ - interrupts-extended: Should contain interrupt line (interrupt-parent +
+   interrupt can also been used). Trigger should be `IRQ_TYPE_EDGE_RISING`.
+
+Optional properties:
+ - reset-gpios: phandle of gpio that will be used to reset chip during probe.
+   Without this property, you may encounter issues with warm boot.
+
+Please consult Documentation/devicetree/bindings/spi/spi-bus.txt for optional
+SPI connection related properties,
+
+Example:
+
+ {
+   wfx {
+   compatible = "silabs,wfx-spi";
+   pinctrl-names = "default";
+   pinctrl-0 = <_irq _gpios>;
+   interrupts-extended = < 16 IRQ_TYPE_EDGE_RISING>;
+   wakeup-gpios = < 12 GPIO_ACTIVE_HIGH>;
+   reset-gpios = < 13 GPIO_ACTIVE_HIGH>;
+   reg = <0>;
+   spi-max-frequency = <4200>;
+   };
+};
+
+
+SDIO
+
+
+The driver is able to detect a WFxxx chip on SDIO bus by matching its Vendor ID
+and Product ID. However, driver will only provide limited features in this
+case. Thus declaring WFxxx chip in device tree is strongly 

[PATCH v3 20/20] staging: wfx: implement the rest of mac80211 API

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Finish to fill struct ieee80211_ops with necessary callbacks. Driver is
now ready to be registered to mac80211.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/data_rx.c |   26 +
 drivers/staging/wfx/data_tx.c |   16 +
 drivers/staging/wfx/debug.c   |2 +
 drivers/staging/wfx/hif_rx.c  |   53 ++
 drivers/staging/wfx/hif_tx.c  |1 +
 drivers/staging/wfx/main.c|  133 +++
 drivers/staging/wfx/queue.c   |   80 ++
 drivers/staging/wfx/scan.c|   40 +
 drivers/staging/wfx/sta.c | 1443 -
 drivers/staging/wfx/sta.h |   65 ++
 drivers/staging/wfx/wfx.h |   51 ++
 11 files changed, 1907 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c
index 3b3117b2edac..3a79089c8501 100644
--- a/drivers/staging/wfx/data_rx.c
+++ b/drivers/staging/wfx/data_rx.c
@@ -21,6 +21,8 @@ static int wfx_handle_pspoll(struct wfx_vif *wvif, struct 
sk_buff *skb)
u32 pspoll_mask = 0;
int i;
 
+   if (wvif->state != WFX_STATE_AP)
+   return 1;
if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid))
return 1;
 
@@ -162,6 +164,30 @@ void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx 
*arg, struct sk_buff *skb
&& arg->rx_flags.match_uc_addr
&& mgmt->u.action.category == WLAN_CATEGORY_BACK)
goto drop;
+   if (ieee80211_is_beacon(frame->frame_control)
+   && !arg->status && wvif->vif
+   && ether_addr_equal(ieee80211_get_SA(frame), 
wvif->vif->bss_conf.bssid)) {
+   const u8 *tim_ie;
+   u8 *ies = mgmt->u.beacon.variable;
+   size_t ies_len = skb->len - (ies - skb->data);
+
+   tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len);
+   if (tim_ie) {
+   struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie 
*) _ie[2];
+
+   if (wvif->dtim_period != tim->dtim_period) {
+   wvif->dtim_period = tim->dtim_period;
+   
schedule_work(>set_beacon_wakeup_period_work);
+   }
+   }
+
+   /* Disable beacon filter once we're associated... */
+   if (wvif->disable_beacon_filter &&
+   (wvif->vif->bss_conf.assoc || 
wvif->vif->bss_conf.ibss_joined)) {
+   wvif->disable_beacon_filter = false;
+   schedule_work(>update_filtering_work);
+   }
+   }
 
if (early_data) {
spin_lock_bh(>ps_state_lock);
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
index 217d3c270706..7f2799fbdafe 100644
--- a/drivers/staging/wfx/data_tx.c
+++ b/drivers/staging/wfx/data_tx.c
@@ -10,6 +10,7 @@
 #include "data_tx.h"
 #include "wfx.h"
 #include "bh.h"
+#include "sta.h"
 #include "queue.h"
 #include "debug.h"
 #include "traces.h"
@@ -359,6 +360,9 @@ void wfx_link_id_gc_work(struct work_struct *work)
u32 mask;
int i;
 
+   if (wvif->state != WFX_STATE_AP)
+   return;
+
wfx_tx_lock_flush(wvif->wdev);
spin_lock_bh(>ps_state_lock);
for (i = 0; i < WFX_MAX_STA_IN_AP_MODE; ++i) {
@@ -729,14 +733,26 @@ void wfx_tx_confirm_cb(struct wfx_vif *wvif, struct 
hif_cnf_tx *arg)
memset(tx_info->pad, 0, sizeof(tx_info->pad));
 
if (!arg->status) {
+   if (wvif->bss_loss_state && arg->packet_id == 
wvif->bss_loss_confirm_id)
+   wfx_cqm_bssloss_sm(wvif, 0, 1, 0);
tx_info->status.tx_time = arg->media_delay - 
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_REQUEUE) {
+   /* "REQUEUE" means "implicit suspend" */
+   struct hif_ind_suspend_resume_tx suspend = {
+   .suspend_resume_flags.resume = 0,
+   .suspend_resume_flags.bc_mc_only = 1,
+   };
+
WARN(!arg->tx_result_flags.requeue, "incoherent status and 
result_flags");
+   wfx_suspend_resume(wvif, );
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+   } else {
+   if (wvif->bss_loss_state && arg->packet_id == 
wvif->bss_loss_confirm_id)
+   wfx_cqm_bssloss_sm(wvif, 0, 0, 1);
}
wfx_pending_remove(wvif->wdev, skb);
 }
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 1e23bb5bde3e..3261b267c385 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -11,7 +11,9 @@
 
 #include "debug.h"
 #include "wfx.h"
+#include "sta.h"
 #include "main.h"
+#include "hif_tx.h"
 #include "hif_tx_mib.h"
 
 #define 

[PATCH v3 08/20] staging: wfx: add tracepoints for HIF

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

These tracepoints decode HIF headers and provide more human readable
results.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bh.c |   5 +
 drivers/staging/wfx/traces.h | 211 +++
 2 files changed, 216 insertions(+)

diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index 02a42e5c1e10..76afecdf579d 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -11,6 +11,7 @@
 #include "bh.h"
 #include "wfx.h"
 #include "hwio.h"
+#include "traces.h"
 #include "hif_api_cmd.h"
 
 static void device_wakeup(struct wfx_dev *wdev)
@@ -67,6 +68,7 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
goto err;
 
piggyback = le16_to_cpup((u16 *) (skb->data + alloc_len - 2));
+   _trace_piggyback(piggyback, false);
 
hif = (struct hif_msg *) skb->data;
WARN(hif->encrypted & 0x1, "unsupported encryption type");
@@ -95,6 +97,7 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
if (!wdev->hif.tx_buffers_used)
wake_up(>hif.tx_buffers_empty);
}
+   _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)
@@ -171,6 +174,7 @@ static void tx_helper(struct wfx_dev *wdev, struct hif_msg 
*hif)
goto end;
 
wdev->hif.tx_buffers_used++;
+   _trace_hif_send(hif, wdev->hif.tx_buffers_used);
 end:
if (is_encrypted)
kfree(data);
@@ -234,6 +238,7 @@ static void bh_work(struct work_struct *work)
device_release(wdev);
release_chip = true;
}
+   _trace_bh_stats(stats_ind, stats_req, stats_cnf, 
wdev->hif.tx_buffers_used, release_chip);
 }
 
 /*
diff --git a/drivers/staging/wfx/traces.h b/drivers/staging/wfx/traces.h
index 34642f3451b5..e7b03b940535 100644
--- a/drivers/staging/wfx/traces.h
+++ b/drivers/staging/wfx/traces.h
@@ -14,6 +14,8 @@
 #include 
 
 #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.
@@ -45,6 +47,167 @@
  *  #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_WAKEUP_PERIOD)   \
+   hif_mib_name(BLOCK_ACK_POLICY)   \
+   hif_mib_name(CONFIG_DATA_FILTER) 

[PATCH v3 00/20] Add support for Silicon Labs WiFi chip WF200 and further

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Hello all,

This series add support for Silicon Labs WiFi chip WF200 and further:

   https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf

This driver is an export from:

   https://github.com/SiliconLabs/wfx-linux-driver/
   
I squashed all commits from github (it definitely does not make sense to
import history). Then I split it in comprehensible (at least try to be)
commits. I hope it will help readers to understand driver architecture.
IMHO, firsts commits are clean enough to be reviewed. Things get more
difficult when I introduce mac8011 API. I tried to extract important
parts like Rx/Tx process but, big and complex patches seem unavoidable
in this part.

Architecture itself is described in commit messages.

The series below is aligned on version 2.3.1 on github. If compare this
series with github, you will find traditional differences between
external and a in-tree driver: Documentation, build infrastructure,
compatibility with older kernel revisions, etc... In add, I dropped all
code in CONFIG_WFX_SECURE_LINK. Indeed, "Secure Link" feature depends
on mbedtls and I don't think to pull mbedtls in kernel is an option
(see "TODO" file in first commit).

v3:
  - Fill commit log of patches 18, 19 and 20

v2:
  - Add TODO file (and dropped todo list from cover letter)
  - Drop code relative to compatibility with older kernels

Jérôme Pouiller (20):
  staging: wfx: add infrastructure for new driver
  staging: wfx: add support for I/O access
  staging: wfx: add I/O API
  staging: wfx: add tracepoints for I/O access
  staging: wfx: load firmware
  staging: wfx: import HIF API headers
  staging: wfx: add IRQ handling
  staging: wfx: add tracepoints for HIF
  staging: wfx: add support for start-up indication
  staging: wfx: instantiate mac80211 data
  staging: wfx: allow to send commands to chip
  staging: wfx: add HIF commands helpers
  staging: wfx: introduce "secure link"
  staging: wfx: setup initial chip configuration
  staging: wfx: add debug files and trace debug events
  staging: wfx: allow to send 802.11 frames
  staging: wfx: allow to receive 802.11 frames
  staging: wfx: allow to scan networks
  staging: wfx: implement 802.11 key handling
  staging: wfx: implement the rest of mac80211 API

 MAINTAINERS   |5 +
 drivers/staging/Kconfig   |2 +
 drivers/staging/Makefile  |1 +
 .../bindings/net/wireless/siliabs,wfx.txt |   97 +
 drivers/staging/wfx/Kconfig   |7 +
 drivers/staging/wfx/Makefile  |   24 +
 drivers/staging/wfx/TODO  |   20 +
 drivers/staging/wfx/bh.c  |  316 
 drivers/staging/wfx/bh.h  |   32 +
 drivers/staging/wfx/bus.h |   34 +
 drivers/staging/wfx/bus_sdio.c|  268 +++
 drivers/staging/wfx/bus_spi.c |  264 +++
 drivers/staging/wfx/data_rx.c |  208 +++
 drivers/staging/wfx/data_rx.h |   18 +
 drivers/staging/wfx/data_tx.c |  799 
 drivers/staging/wfx/data_tx.h |   93 +
 drivers/staging/wfx/debug.c   |  305 +++
 drivers/staging/wfx/debug.h   |   19 +
 drivers/staging/wfx/fwio.c|  387 
 drivers/staging/wfx/fwio.h|   15 +
 drivers/staging/wfx/hif_api_cmd.h |  681 +++
 drivers/staging/wfx/hif_api_general.h |  437 +
 drivers/staging/wfx/hif_api_mib.h |  558 ++
 drivers/staging/wfx/hif_rx.c  |  336 
 drivers/staging/wfx/hif_rx.h  |   18 +
 drivers/staging/wfx/hif_tx.c  |  470 +
 drivers/staging/wfx/hif_tx.h  |   67 +
 drivers/staging/wfx/hif_tx_mib.h  |  281 +++
 drivers/staging/wfx/hwio.c|  338 
 drivers/staging/wfx/hwio.h|   75 +
 drivers/staging/wfx/key.c |  258 +++
 drivers/staging/wfx/key.h |   22 +
 drivers/staging/wfx/main.c|  500 +
 drivers/staging/wfx/main.h|   48 +
 drivers/staging/wfx/queue.c   |  606 ++
 drivers/staging/wfx/queue.h   |   59 +
 drivers/staging/wfx/scan.c|  289 +++
 drivers/staging/wfx/scan.h|   42 +
 drivers/staging/wfx/secure_link.h |   46 +
 drivers/staging/wfx/sta.c | 1643 +
 drivers/staging/wfx/sta.h |  101 +
 drivers/staging/wfx/traces.h  |  434 +
 drivers/staging/wfx/wfx.h |  204 ++
 drivers/staging/wfx/wfx_version.h |3 +
 44 files changed, 10430 insertions(+)
 create mode 100644 
drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
 create mode 100644 

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

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

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

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

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 1abd3115f11d..35670b86c64f 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -7,6 +7,7 @@ wfx-y := \
bh.o \
hwio.o \
fwio.o \
+   hif_rx.o \
main.o \
debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index 76afecdf579d..c40da3f1f25d 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -12,6 +12,7 @@
 #include "wfx.h"
 #include "hwio.h"
 #include "traces.h"
+#include "hif_rx.h"
 #include "hif_api_cmd.h"
 
 static void device_wakeup(struct wfx_dev *wdev)
@@ -107,7 +108,8 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
}
 
skb_put(skb, hif->len);
-   dev_kfree_skb(skb); /* FIXME: handle received data */
+   // wfx_handle_rx takes care on SKB livetime
+   wfx_handle_rx(wdev, skb);
 
return piggyback;
 
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
new file mode 100644
index ..5c207e6d4348
--- /dev/null
+++ b/drivers/staging/wfx/hif_rx.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
+ * (WSM) API.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#include "hif_rx.h"
+#include "wfx.h"
+#include "hif_api_cmd.h"
+
+static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, 
void *buf)
+{
+   struct hif_ind_startup *body = buf;
+
+   if (body->status || body->firmware_type > 4) {
+   dev_err(wdev->dev, "received invalid startup indication");
+   return -EINVAL;
+   }
+   memcpy(>hw_caps, body, sizeof(struct hif_ind_startup));
+   le32_to_cpus(>hw_caps.status);
+   le16_to_cpus(>hw_caps.hardware_id);
+   le16_to_cpus(>hw_caps.num_inp_ch_bufs);
+   le16_to_cpus(>hw_caps.size_inp_ch_buf);
+
+   complete(>firmware_ready);
+   return 0;
+}
+
+static const struct {
+   int msg_id;
+   int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
+} hif_handlers[] = {
+   { HIF_IND_ID_STARTUP,  hif_startup_indication },
+};
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
+{
+   int i;
+   struct hif_msg *hif = (struct hif_msg *) skb->data;
+   int hif_id = hif->id;
+
+   for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) {
+   if (hif_handlers[i].msg_id == hif_id) {
+   if (hif_handlers[i].handler)
+   hif_handlers[i].handler(wdev, hif, hif->body);
+   goto free;
+   }
+   }
+   dev_err(wdev->dev, "unsupported HIF ID %02x\n", hif_id);
+free:
+   dev_kfree_skb(skb);
+}
diff --git a/drivers/staging/wfx/hif_rx.h b/drivers/staging/wfx/hif_rx.h
new file mode 100644
index ..f07c10c8c6bd
--- /dev/null
+++ b/drivers/staging/wfx/hif_rx.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
+ * (WSM) API.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ * Copyright (C) 2010, ST-Ericsson SA
+ */
+#ifndef WFX_HIF_RX_H
+#define WFX_HIF_RX_H
+
+struct wfx_dev;
+struct sk_buff;
+
+void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb);
+
+#endif
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index f0bea053a0d9..5e7e7225f068 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -12,6 +12,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -87,6 +88,9 @@ struct wfx_dev *wfx_init_common(struct device *dev,
wdev->hwbus_ops = hwbus_ops;
wdev->hwbus_priv = hwbus_priv;
memcpy(>pdata, pdata, sizeof(*pdata));
+
+   init_completion(>firmware_ready);
+
return wdev;
 }
 
@@ -96,7 +100,9 @@ void wfx_free_common(struct wfx_dev *wdev)
 
 int wfx_probe(struct wfx_dev *wdev)
 {
+   int i;
int err;
+   const 

[PATCH v3 11/20] staging: wfx: allow to send commands to chip

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Chip has multiple input buffers and can handle multiple 802.11 frames
in parallel. However, other HIF command must be sent sequentially.
wsm_send_cmd() handles these requests.

This commit also add send_hif_cmd in debugfs. This file allows to send
arbitrary commands to chip. It can be used for debug and testing.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/bh.c |   5 +-
 drivers/staging/wfx/debug.c  | 130 +++
 drivers/staging/wfx/debug.h  |   4 ++
 drivers/staging/wfx/hif_rx.c |  45 
 drivers/staging/wfx/hif_tx.c |  87 +++
 drivers/staging/wfx/hif_tx.h |  33 +
 drivers/staging/wfx/main.c   |   1 +
 drivers/staging/wfx/wfx.h|   4 ++
 9 files changed, 309 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/wfx/hif_tx.c
 create mode 100644 drivers/staging/wfx/hif_tx.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 2896a2127c88..e158589468a3 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -7,6 +7,7 @@ wfx-y := \
bh.o \
hwio.o \
fwio.o \
+   hif_tx.o \
hif_rx.o \
main.o \
sta.o \
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index c40da3f1f25d..c94c9c401a69 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -190,7 +190,10 @@ static int bh_work_tx(struct wfx_dev *wdev, int max_msg)
for (i = 0; i < max_msg; i++) {
hif = NULL;
if (wdev->hif.tx_buffers_used < wdev->hw_caps.num_inp_ch_bufs) {
-   /* FIXME: get queued data */
+   if (try_wait_for_completion(>hif_cmd.ready)) {
+   WARN(!mutex_is_locked(>hif_cmd.lock), 
"data locking error");
+   hif = wdev->hif_cmd.buf_send;
+   }
}
if (!hif)
return i;
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index f28c94d8de89..0a328c96eaa0 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -7,16 +7,146 @@
  */
 #include 
 
+#include "debug.h"
 #include "wfx.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
 
+static const struct trace_print_flags hif_msg_print_map[] = {
+   hif_msg_list,
+};
+
+static const struct trace_print_flags hif_mib_print_map[] = {
+   hif_mib_list,
+};
+
+static const struct trace_print_flags wfx_reg_print_map[] = {
+   wfx_reg_list,
+};
+
+static const char *get_symbol(unsigned long val,
+   const struct trace_print_flags *symbol_array)
+{
+   int i;
+
+   for (i = 0; symbol_array[i].mask != -1; i++) {
+   if (val == symbol_array[i].mask)
+   return symbol_array[i].name;
+   }
+
+   return "unknown";
+}
+
+const char *get_hif_name(unsigned long id)
+{
+   return get_symbol(id, hif_msg_print_map);
+}
+
+const char *get_mib_name(unsigned long id)
+{
+   return get_symbol(id, hif_mib_print_map);
+}
+
+const char *get_reg_name(unsigned long id)
+{
+   return get_symbol(id, wfx_reg_print_map);
+}
+
+struct dbgfs_hif_msg {
+   struct wfx_dev *wdev;
+   struct completion complete;
+   u8 reply[1024];
+   int ret;
+};
+
+static ssize_t wfx_send_hif_msg_write(struct file *file, const char __user 
*user_buf,
+ size_t count, loff_t *ppos)
+{
+   struct dbgfs_hif_msg *context = file->private_data;
+   struct wfx_dev *wdev = context->wdev;
+   struct hif_msg *request;
+
+   if (completion_done(>complete)) {
+   dev_dbg(wdev->dev, "read previous result before start a new 
one\n");
+   return -EBUSY;
+   }
+   if (count < sizeof(struct hif_msg))
+   return -EINVAL;
+
+   // wfx_cmd_send() chekc that reply buffer is wide enough, but do 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, sizeof(context->reply), 0xFF);
+   request = memdup_user(user_buf, count);
+   if (IS_ERR(request))
+   return PTR_ERR(request);
+   if (request->len != count) {
+   kfree(request);
+   return -EINVAL;
+   }
+   context->ret = wfx_cmd_send(wdev, request, context->reply, 
sizeof(context->reply), false);
+
+   kfree(request);
+   complete(>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 = 

[PATCH v3 07/20] staging: wfx: add IRQ handling

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

bh_work() is in charge to schedule all HIF message from/to chip.

On normal operation, when an IRQ is received, driver can get size of
next message in control register. In order to save control register
access, when chip send a message, it also appends a copy of control
register after the message (this register is not accounted in message
length declared in message header, but must accounted in bus request).
This copy of control register is called "piggyback".

It also handles a power saving mechanism specific to WFxxx series. This
mechanism is based on a GPIO called "wakeup" GPIO. Obviously, this gpio
is not part of SPI/SDIO standard buses and must be declared
independently (this is the main reason for why SDIO mode try to get
parameters from DT).

When wakeup is enabled, host can communicate with chip only if it is
awake. To wake up chip, there are two cases:
- host receive an IRQ from chip (chip initiate communication): host
  just have to set wakeup GPIO before reading data
- host want to send data to chip: host set wakeup GPIO, then wait
  for an IRQ (in fact, wait for an empty message) and finally send data

bh_work() is also in charge to track usage of chip buffers. Normally
each request expect a confirmation. However, you can notice that special
"multi tx" confirmation can acknowledge multiple requests at time.

Finally, note that wfx_bh_request_rx() is not atomic (because of
control_reg_read()). So, in SPI mode, hard-irq handler only postpone all
processing to wfx_spi_request_rx().

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile   |   1 +
 drivers/staging/wfx/bh.c   | 277 +
 drivers/staging/wfx/bh.h   |  32 
 drivers/staging/wfx/bus_sdio.c |   4 +-
 drivers/staging/wfx/bus_spi.c  |   5 +
 drivers/staging/wfx/main.c |  21 +++
 drivers/staging/wfx/main.h |   2 +
 drivers/staging/wfx/wfx.h  |   4 +
 8 files changed, 345 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/wfx/bh.c
 create mode 100644 drivers/staging/wfx/bh.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index e568d7a6fb06..1abd3115f11d 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -4,6 +4,7 @@
 CFLAGS_debug.o = -I$(src)
 
 wfx-y := \
+   bh.o \
hwio.o \
fwio.o \
main.o \
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
new file mode 100644
index ..02a42e5c1e10
--- /dev/null
+++ b/drivers/staging/wfx/bh.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Interrupt bottom half (BH).
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+
+#include "bh.h"
+#include "wfx.h"
+#include "hwio.h"
+#include "hif_api_cmd.h"
+
+static void device_wakeup(struct wfx_dev *wdev)
+{
+   if (!wdev->pdata.gpio_wakeup)
+   return;
+   if (gpiod_get_value(wdev->pdata.gpio_wakeup))
+   return;
+
+   gpiod_set_value(wdev->pdata.gpio_wakeup, 1);
+   if (wfx_api_older_than(wdev, 1, 4)) {
+   if (!completion_done(>hif.ctrl_ready))
+   udelay(2000);
+   } else {
+   // 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(>hif.ctrl_ready, 
msecs_to_jiffies(2) + 1))
+   complete(>hif.ctrl_ready);
+   else
+   dev_err(wdev->dev, "timeout while wake up chip\n");
+   }
+}
+
+static void device_release(struct wfx_dev *wdev)
+{
+   if (!wdev->pdata.gpio_wakeup)
+   return;
+
+   gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
+}
+
+static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
+{
+   struct sk_buff *skb;
+   struct hif_msg *hif;
+   size_t alloc_len;
+   size_t computed_len;
+   int release_count;
+   int piggyback = 0;
+
+   WARN_ON(read_len < 4);
+   WARN(read_len > round_down(0xFFF, 2) * sizeof(u16),
+"%s: request exceed WFx capability", __func__);
+
+   // Add 2 to take into account piggyback size
+   alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2);
+   skb = dev_alloc_skb(alloc_len);
+   if (!skb)
+   return -ENOMEM;
+
+   if (wfx_data_read(wdev, skb->data, alloc_len))
+   goto err;
+
+   piggyback = le16_to_cpup((u16 *) (skb->data + alloc_len - 2));
+
+   hif = (struct hif_msg *) skb->data;
+   WARN(hif->encrypted & 0x1, "unsupported encryption type");
+   if (hif->encrypted == 0x2) {
+   BUG(); // Not yet implemented
+   } else {
+   le16_to_cpus(hif->len);
+   computed_len = 

[PATCH v3 04/20] staging: wfx: add tracepoints for I/O access

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

Some tracepoints are useful for debugging.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   6 +-
 drivers/staging/wfx/debug.c  |  10 +++
 drivers/staging/wfx/hwio.c   |  11 +++
 drivers/staging/wfx/traces.h | 149 +++
 4 files changed, 175 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/wfx/debug.c
 create mode 100644 drivers/staging/wfx/traces.h

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index e860845186cf..330b7288ebb5 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -1,8 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0
 
+# Necessary for CREATE_TRACE_POINTS
+CFLAGS_debug.o = -I$(src)
+
 wfx-y := \
hwio.o \
-   main.o
+   main.o \
+   debug.o
 wfx-$(CONFIG_SPI) += bus_spi.o
 wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
 
diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
new file mode 100644
index ..bf44c944640d
--- /dev/null
+++ b/drivers/staging/wfx/debug.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Debugfs interface.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+
+#define CREATE_TRACE_POINTS
+#include "traces.h"
diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c
index fa626a49dd8a..0cf52aee10e7 100644
--- a/drivers/staging/wfx/hwio.c
+++ b/drivers/staging/wfx/hwio.c
@@ -12,6 +12,7 @@
 #include "hwio.h"
 #include "wfx.h"
 #include "bus.h"
+#include "traces.h"
 
 /*
  * Internal helpers.
@@ -63,6 +64,7 @@ static int read32_locked(struct wfx_dev *wdev, int reg, u32 
*val)
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = read32(wdev, reg, val);
+   _trace_io_read32(reg, *val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -73,6 +75,7 @@ static int write32_locked(struct wfx_dev *wdev, int reg, u32 
val)
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = write32(wdev, reg, val);
+   _trace_io_write32(reg, val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -86,11 +89,13 @@ static int write32_bits_locked(struct wfx_dev *wdev, int 
reg, u32 mask, u32 val)
val &= mask;
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = read32(wdev, reg, _r);
+   _trace_io_read32(reg, val_r);
if (ret < 0)
goto err;
val_w = (val_r & ~mask) | val;
if (val_w != val_r) {
ret = write32(wdev, reg, val_w);
+   _trace_io_write32(reg, val_w);
}
 err:
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
@@ -166,6 +171,7 @@ static int indirect_read_locked(struct wfx_dev *wdev, int 
reg, u32 addr, void *b
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_read(wdev, reg, addr, buf, len);
+   _trace_io_ind_read(reg, addr, buf, len);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -176,6 +182,7 @@ static int indirect_write_locked(struct wfx_dev *wdev, int 
reg, u32 addr, const
 
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_write(wdev, reg, addr, buf, len);
+   _trace_io_ind_write(reg, addr, buf, len);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
return ret;
 }
@@ -190,6 +197,7 @@ static int indirect_read32_locked(struct wfx_dev *wdev, int 
reg, u32 addr, u32 *
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32));
*val = cpu_to_le32(*tmp);
+   _trace_io_ind_read32(reg, addr, *val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
kfree(tmp);
return ret;
@@ -205,6 +213,7 @@ static int indirect_write32_locked(struct wfx_dev *wdev, 
int reg, u32 addr, u32
*tmp = cpu_to_le32(val);
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32));
+   _trace_io_ind_write32(reg, addr, val);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
kfree(tmp);
return ret;
@@ -217,6 +226,7 @@ int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t 
len)
WARN((long) buf & 3, "%s: unaligned buffer", __func__);
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, 
WFX_REG_IN_OUT_QUEUE, buf, len);
+   _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len);
wdev->hwbus_ops->unlock(wdev->hwbus_priv);
if (ret)
dev_err(wdev->dev, "%s: bus communication error: %d\n", 
__func__, ret);
@@ -230,6 +240,7 @@ int wfx_data_write(struct wfx_dev *wdev, const void *buf, 
size_t len)
WARN((long) buf & 3, "%s: unaligned buffer", __func__);
wdev->hwbus_ops->lock(wdev->hwbus_priv);
ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, 
WFX_REG_IN_OUT_QUEUE, buf, len);
+   _trace_io_write(WFX_REG_IN_OUT_QUEUE, 

[PATCH v3 03/20] staging: wfx: add I/O API

2019-09-19 Thread Jerome Pouiller
From: Jérôme Pouiller 

hwio.c provides an abstraction to access different types of register of
the chip.

Note that only data register (aka FRAME_OUT) and control register are
used normal communication. Other registers are only used during chip
start up.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Makefile |   1 +
 drivers/staging/wfx/hwio.c   | 327 +++
 drivers/staging/wfx/hwio.h   |  27 +++
 3 files changed, 355 insertions(+)
 create mode 100644 drivers/staging/wfx/hwio.c

diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile
index 74939a5a0a1c..e860845186cf 100644
--- a/drivers/staging/wfx/Makefile
+++ b/drivers/staging/wfx/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 wfx-y := \
+   hwio.o \
main.o
 wfx-$(CONFIG_SPI) += bus_spi.o
 wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o
diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c
new file mode 100644
index ..fa626a49dd8a
--- /dev/null
+++ b/drivers/staging/wfx/hwio.c
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Low-level I/O functions.
+ *
+ * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
+ * Copyright (c) 2010, ST-Ericsson
+ */
+#include 
+#include 
+#include 
+
+#include "hwio.h"
+#include "wfx.h"
+#include "bus.h"
+
+/*
+ * Internal helpers.
+ *
+ * About CONFIG_VMAP_STACK:
+ * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack
+ * allocated data. Functions below that work with registers (aka functions
+ * ending with "32") automatically reallocate buffers with kmalloc. However,
+ * functions that work with arbitrary length buffers let's caller to handle
+ * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located
+ * buffer.
+ */
+
+static int read32(struct wfx_dev *wdev, int reg, u32 *val)
+{
+   int ret;
+   __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
+
+   *val = ~0; // Never return undefined value
+   if (!tmp)
+   return -ENOMEM;
+   ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, 
sizeof(u32));
+   if (ret >= 0)
+   *val = le32_to_cpu(*tmp);
+   kfree(tmp);
+   if (ret)
+   dev_err(wdev->dev, "%s: bus communication error: %d\n", 
__func__, ret);
+   return ret;
+}
+
+static int write32(struct wfx_dev *wdev, int reg, u32 val)
+{
+   int ret;
+   __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
+
+   if (!tmp)
+   return -ENOMEM;
+   *tmp = cpu_to_le32(val);
+   ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, 
sizeof(u32));
+   kfree(tmp);
+   if (ret)
+   dev_err(wdev->dev, "%s: bus communication error: %d\n", 
__func__, ret);
+   return ret;
+}
+
+static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val)
+{
+   int ret;
+
+   wdev->hwbus_ops->lock(wdev->hwbus_priv);
+   ret = read32(wdev, reg, val);
+   wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+   return ret;
+}
+
+static int write32_locked(struct wfx_dev *wdev, int reg, u32 val)
+{
+   int ret;
+
+   wdev->hwbus_ops->lock(wdev->hwbus_priv);
+   ret = write32(wdev, reg, val);
+   wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+   return ret;
+}
+
+static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 
val)
+{
+   int ret;
+   u32 val_r, val_w;
+
+   WARN_ON(~mask & val);
+   val &= mask;
+   wdev->hwbus_ops->lock(wdev->hwbus_priv);
+   ret = read32(wdev, reg, _r);
+   if (ret < 0)
+   goto err;
+   val_w = (val_r & ~mask) | val;
+   if (val_w != val_r) {
+   ret = write32(wdev, reg, val_w);
+   }
+err:
+   wdev->hwbus_ops->unlock(wdev->hwbus_priv);
+   return ret;
+}
+
+static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf, 
size_t len)
+{
+   int ret;
+   int i;
+   u32 cfg;
+   u32 prefetch;
+
+   WARN_ON(len >= 0x2000);
+   WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
+
+   if (reg == WFX_REG_AHB_DPORT)
+   prefetch = CFG_PREFETCH_AHB;
+   else if (reg == WFX_REG_SRAM_DPORT)
+   prefetch = CFG_PREFETCH_SRAM;
+   else
+   return -ENODEV;
+
+   ret = write32(wdev, WFX_REG_BASE_ADDR, addr);
+   if (ret < 0)
+   goto err;
+
+   ret = read32(wdev, WFX_REG_CONFIG, );
+   if (ret < 0)
+   goto err;
+
+   ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch);
+   if (ret < 0)
+   goto err;
+
+   for (i = 0; i < 20; i++) {
+   ret = read32(wdev, WFX_REG_CONFIG, );
+   if (ret < 0)
+   goto err;
+   if (!(cfg & prefetch))
+   break;
+   udelay(200);
+   }
+   if (i == 20) {
+   ret = -ETIMEDOUT;
+   goto err;
+   }
+
+  

Re: [PATCH 02/20] staging: wfx: add support for I/O access

2019-10-02 Thread Jerome Pouiller
On Thursday 19 September 2019 18:34:48 CEST Andrew Lunn wrote:
> On Thu, Sep 19, 2019 at 10:52:35AM +0000, Jerome Pouiller wrote:
> > +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;
> > +
> > + BUG_ON(reg_id > 7);
> 
> Hi Jerome
> 
> BUG_ON should only be used when the system is corrupted, and there is
> no alternative than to stop the machine, so it does not further
> corrupt itself. Accessing a register which does not exist is not a
> reason the kill the machine. A WARN() and a return of -EINVAL would be
> better.

Hi Andrew,

I did not forget your suggestion. However, if everyone is agree with that, I'd 
prefer to address it in a next pull request. Indeed, I'd prefer to keep this 
version in sync with version 2.3.1 published on github.

-- 
Jérôme Pouiller

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


Re: [PATCH 02/20] staging: wfx: add support for I/O access

2019-10-02 Thread Jerome Pouiller
On Wednesday 2 October 2019 18:42:14 CEST Greg Kroah-Hartman wrote:
> On Wed, Oct 02, 2019 at 04:29:09PM +0000, Jerome Pouiller wrote:
[...]
> >
> > Hi Andrew,
> >
> > I did not forget your suggestion. However, if everyone is agree with that, 
> > I'd
> > prefer to address it in a next pull request. Indeed, I'd prefer to keep this
> > version in sync with version 2.3.1 published on github.
> 
> Ugh, you aren't doing development outside of the kernel tree and
> expecting things to stay in sync somehow are you?  That way lies madness
> and a sure way to get me to just delete the staging driver.  Just work
> on it in-tree please.

Sure, I will just work in-tree. But, I think that if someone want to
follow history, it is easier if it exists a version exactly identical
in kernel and on github.


-- 
Jérôme Pouiller

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


Re: [PATCH v2 1/3] staging: wfx: replace uintXX_t to uXX and intXX_t to sXX

2019-11-11 Thread Jerome Pouiller
On Monday 11 November 2019 14:30:53 CET Jules Irenge wrote:
> CAUTION: This email originated from outside of the organization. Do 
not click links or open attachments unless you recognize the sender and 
know the content is safe.
> 
> 
> Replace uint8_t to u8, uint16_t to u16, uint32_t to u32
> int8_t to s8,int16_t to s16 and int32_t to s32
> As per recommendation of checkpatch tool.
> 
> Signed-off-by: Jules Irenge 
> ---
> Changes
> v1 had a spacing error
> v2 fixes the error and includes all the changes related to this patch 
in
> the driver.
> 
>  drivers/staging/wfx/bh.c  |   2 +-
>  drivers/staging/wfx/data_tx.c |  10 +-
>  drivers/staging/wfx/data_tx.h |  18 +-
>  drivers/staging/wfx/hif_api_cmd.h | 498 
+-
>  drivers/staging/wfx/hif_api_general.h | 212 +--
>  drivers/staging/wfx/hif_api_mib.h | 477 
>  drivers/staging/wfx/hif_tx.c  |   3 +-
>  drivers/staging/wfx/hif_tx.h  |   7 +-
>  drivers/staging/wfx/hif_tx_mib.h  |   2 +-
>  drivers/staging/wfx/key.c |  32 +-
>  drivers/staging/wfx/secure_link.h |   6 +-
>  drivers/staging/wfx/sta.c |  13 +-
>  drivers/staging/wfx/sta.h |   2 +-
>  drivers/staging/wfx/wfx.h |  10 +-
>  14 files changed, 649 insertions(+), 643 deletions(-)
> 
> diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
> index 955ed3a1dd73..2432ba95c2f5 100644
> --- a/drivers/staging/wfx/bh.c
> +++ b/drivers/staging/wfx/bh.c
> @@ -239,7 +239,7 @@ static int bh_work_tx(struct wfx_dev *wdev, int 
max_msg)
>   */
>  static void ack_sdio_data(struct wfx_dev *wdev)
>  {
> -   uint32_t cfg_reg;
> +   u32 cfg_reg;
> 
> config_reg_read(wdev, _reg);
> if (cfg_reg & 0xFF) {
> diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/
data_tx.c
> index ea4205ac2149..b722e9773232 100644
> --- a/drivers/staging/wfx/data_tx.c
> +++ b/drivers/staging/wfx/data_tx.c
> @@ -107,7 +107,7 @@ static void wfx_tx_policy_build(struct wfx_vif 
*wvif, struct tx_policy *policy,
> 
> for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) {
> int rateid;
> -   uint8_t count;
> +   u8 count;
> 
> if (rates[i].idx < 0)
> break;
> @@ -477,7 +477,7 @@ static void wfx_tx_manage_pm(struct wfx_vif *wvif, 
struct ieee80211_hdr *hdr,
> ieee80211_sta_set_buffered(sta, tx_priv->tid, true);
>  }
> 
> -static uint8_t wfx_tx_get_raw_link_id(struct wfx_vif *wvif,
> +static u8 wfx_tx_get_raw_link_id(struct wfx_vif *wvif,
>   struct ieee80211_sta *sta,
>   struct ieee80211_hdr *hdr)
>  {
> @@ -542,11 +542,11 @@ static void wfx_tx_fixup_rates(struct 
ieee80211_tx_rate *rates)
> rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI;
>  }
> 
> -static uint8_t wfx_tx_get_rate_id(struct wfx_vif *wvif,
> +static u8 wfx_tx_get_rate_id(struct wfx_vif *wvif,
>   struct ieee80211_tx_info *tx_info)
>  {
> bool tx_policy_renew = false;
> -   uint8_t rate_id;
> +   u8 rate_id;
> 
> rate_id = wfx_tx_policy_get(wvif,
> tx_info->driver_rates, 
_policy_renew);
> @@ -584,7 +584,7 @@ static struct hif_ht_tx_parameters 
wfx_tx_get_tx_parms(struct wfx_dev *wdev, str
> return ret;
>  }
> 
> -static uint8_t wfx_tx_get_tid(struct ieee80211_hdr *hdr)
> +static u8 wfx_tx_get_tid(struct ieee80211_hdr *hdr)
>  {
> // FIXME: ieee80211_get_tid(hdr) should be sufficient for all 
cases.
> if (!ieee80211_is_data(hdr->frame_control))
> diff --git a/drivers/staging/wfx/data_tx.h b/drivers/staging/wfx/
data_tx.h
> index f74d1988925d..29faa5640516 100644
> --- a/drivers/staging/wfx/data_tx.h
> +++ b/drivers/staging/wfx/data_tx.h
> @@ -31,17 +31,17 @@ enum wfx_link_status {
>  struct wfx_link_entry {
> unsigned long   timestamp;
> enum wfx_link_statusstatus;
> -   uint8_t mac[ETH_ALEN];
> -   uint8_t old_mac[ETH_ALEN];
> -   uint8_t buffered[WFX_MAX_TID];
> +   u8  mac[ETH_ALEN];
> +   u8  old_mac[ETH_ALEN];
> +   u8  buffered[WFX_MAX_TID];
> struct sk_buff_head rx_queue;
>  };
> 
>  struct tx_policy {
> struct list_head link;
> -   uint8_t rates[12];
> -   uint8_t usage_count;
> -   uint8_t uploaded;
> +   u8 rates[12];
> +   u8 usage_count;
> +   u8 uploaded;
>  };
> 
>  struct tx_policy_cache {
> @@ -55,9 +55,9 @@ struct tx_policy_cache {
>  struct wfx_tx_priv {
> ktime_t xmit_timestamp;
> struct ieee80211_key_conf *hw_key;
> -   uint8_t link_id;
> -   uint8_t raw_link_id;
> -   uint8_t tid;
> +   u8 link_id;
> +   u8 raw_link_id;
> +   

Re: [PATCH v2 3/3] staging: wfx: replace u32 by __le32

2019-11-11 Thread Jerome Pouiller
On Monday 11 November 2019 14:30:55 CET Jules Irenge wrote:
[...]
> -   u32   count_rts_failures;
> -   u32   count_ack_failures;
> -   u32   count_rx_multicast_frames;
> -   u32   count_rx_frames_success;
> -   u32   count_rx_cmacicv_errors;
> -   u32   count_rx_cmac_replays;
> -   u32   count_rx_mgmt_ccmp_replays;
[...]
> +   __le32   count_rts_failures;
> +   __le32   count_rx_multicast_frames;
> +   __le32   count_rx_cmacicv_errors;
> +   __le32   count_rx_cmac_replays;
> +   __le32   count_rx_mgmt_ccmp_replays;
> +   __le32   count_rx_beacon;
> +   __le32   count_miss_beacon;
> +   __le32   count_ack_failures;
> +   __le32   count_rx_frames_success;
> u32   count_rx_bipmic_errors;
> -   u32   count_rx_beacon;
> -   u32   count_miss_beacon;

Hello Jules,

Your patch reorders members of the structure. It will break API with the 
chip.

-- 
Jérôme Pouiller

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


Re: [PATCH] staging: wfx: add gcc extension __force cast

2019-11-12 Thread Jerome Pouiller
On Tuesday 12 November 2019 00:16:59 CET Al Viro wrote:
[...]
> More fun:
> int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, 
> size_t val_len)
> {
> int ret;
> struct hif_msg *hif;
> int buf_len = sizeof(struct hif_cnf_read_mib) + val_len;
> struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), );
> struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
> 
> OK, allocated request and reply buffers, by the look of it; request one
> being struct hif_msg with struct hif_req_read_mib for payload
> and reply - struct hif_cnf_read_mib {
> uint32_t   status;
> uint16_t   mib_id;
> uint16_t   length;
> uint8_tmib_data[];
> } with val_len bytes in mib_data.
> 
> body->mib_id = cpu_to_le16(mib_id);
> wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body));
> 
> Filled request, {.len = cpu_to_le16(4 + 4),
>  .id = HIF_REQ_ID_READ_MIB,
>  .interface = vif_id,
>  .body = {
> .mib_id = cpu_to_le16(mib_id)
> }
> }
> Note that mib_id is host-endian here; what we send is little-endian.
> 
> ret = wfx_cmd_send(wdev, hif, reply, buf_len, false);
> send it, get reply
> 
> if (!ret && mib_id != reply->mib_id) {
> Wha...?  Now we are comparing two bytes at offset 4 into reply with a 
> host-endian
> value?  Oh, well...

Agree.

> 
> dev_warn(wdev->dev, "%s: confirmation mismatch request\n", 
> __func__);
> ret = -EIO;
> }
> if (ret == -ENOMEM)
> dev_err(wdev->dev, "buffer is too small to receive %s (%zu < 
> %d)\n",
> get_mib_name(mib_id), val_len, reply->length);
> if (!ret)
> memcpy(val, >mib_data, reply->length);
> What.  The.  Hell?
> 
> We are copying data from the reply.  Into caller-supplied object.
> With length taken from the same reply and no validation even
> attempted?  Not even "um, maybe we shouldn't copy more than the caller
> told us to copy, especially since that's as much as there is in the
> source of that memcpy"?

In fact, hif_generic_confirm() check that data from hardware is smaller
than "buf_len". If it is not the case, ret will contains -ENOMEM. But
indeed, if size of data is correct but reply->length is corrupted, we
will have big trouble.

(In add, I am not sure that -ENOMEM is well chosen for this case)

> And that's besides the endianness questions.  Note that getting the
> endianness wrong here is just about certain to blow up - small value
> will be misinterpreted by factor of 256.
> 
> In any case, even if this is talking to firmware on a card, that's
> an unhealthy degree of trust, especially since the same function
> does consider the possibility of bogus replies.

It is obvious that the errors paths have not been sufficiently checked.
If you continue to search, I think you will find many similar problems.

I will update the TODO list attached to the driver.

-- 
Jérôme Pouiller

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


Re: [PATCH] staging: wfx: add gcc extension __force cast

2019-11-12 Thread Jerome Pouiller
Hello Al,

Thank you for your extensive review.

On Monday 11 November 2019 21:28:52 CET Al Viro wrote:
> On Mon, Nov 11, 2019 at 01:51:33PM +, Jules Irenge wrote:
> >
> > > NAK.  force-cast (and it's not a gcc extension, BTW - it's sparse) is 
> > > basically
> > > "I know better; the code is right, so STFU already".  *IF* 
> > > counters.count_...
> > > is really little-endian 32bit, then why isn't it declared that way?  And 
> > > if
> > > it's host-endian, you've just papered over a real bug here.
> > >
> > > As a general rule "fix" doesn't mean "tell it to shut up"...
> > >
> >
> > Thanks for the comments, I have updated  but I have a mixed mind on the
> > __le32. I have to read more about it.
> >
> > I would appreciate if you can comment again on the update.
> 
> From the look at the driver, it seems that all these counters are a part of
> structure that is read from the hardware and only used as little-endian.
> So just declare all fields in struct hif_mib_extended_count_table as
> __le32; easy enough.  Looking a bit further, the same goes for
> struct hif_mib_bcn_filter_table ->num_of_info_elmts
> struct hif_mib_keep_alive_period ->keep_alive_period (__le16)
> struct hif_mib_template_frame ->frame_length (__le16)
> struct hif_mib_set_association_mode ->basic_rate_set (__le32)
> struct hif_req_update_ie ->num_i_es (__le16)
> struct hif_req_write_mib ->mib_id, ->length (__le16 both)
> struct hif_req_read_mib ->mib_id (__le16)
> struct hif_req_configuration ->length (__le16)

Indeed, structs declared in hif_api* are shared with the hardware and
should use __le16/__le32. However, as you noticed below, these structs
are sometime used in other parts of the code that are not related to
the hardware. 

I have in my local queue a set of patches that improve the situation.
Objective is to limit usage of hif structs to hif_tx.c, hif_tx_mib.c
and hif_rx.c (which are correct places to handle hardware
communication). I hope to be able to submit these patches in 2 weeks.


[...]
> and that's where the real bugs start to show up; leaving the misbegotten
> forest of macros in misbegotten tracing shite aside, we have this:
> 
> 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 = 65,
> drivers/staging/wfx/main.c:108:39: refering to this initializer.
> Sparse say that it expects rx_highest to be __le16.  And that's
> not a driver-specific structure; it's generic ieee80211 one.  Which
> says
> struct ieee80211_mcs_info {
> u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN];
> __le16 rx_highest;
> u8 tx_params;
> u8 reserved[3];
> } __packed;
> and grepping for rx_highest through the tree shows that everything else
> is treating it as little-endian 16bit.
> 
> Almost certainly a bug on big-endian hosts; should be .rx_highest = 
> cpu_to_le16(65),
> instead.

Agree.


> Looking for more low-hanging fruits, we have
> static int indirect_read32_locked(struct wfx_dev *wdev, int reg, u32 addr, 
> u32 *val)
> {
> int ret;
> __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
> 
> if (!tmp)
> return -ENOMEM;
> wdev->hwbus_ops->lock(wdev->hwbus_priv);
> ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32));
> *val = cpu_to_le32(*tmp);
> _trace_io_ind_read32(reg, addr, *val);
> wdev->hwbus_ops->unlock(wdev->hwbus_priv);
> kfree(tmp);
> return ret;
> }
> with warnings about val = cpu_to_le32(*tmp); fair enough, since *val is
> host-endian (u32) and *tmp - little-endian.  Trivial misannotation -
> it should've been le32_to_cpu(), not cpu_to_le32().  Same mapping on
> all CPUs we are ever likely to support, so it's just a misannotation,
> not a bug per se.

Agree.


> drivers/staging/wfx/hif_tx_mib.h:34:38: warning: incorrect type in 
> initializer (different base types)
> drivers/staging/wfx/hif_tx_mib.h:34:38:expected unsigned char [usertype] 
> wakeup_period_max
> drivers/staging/wfx/hif_tx_mib.h:34:38:got restricted __le16 [usertype]
> 
> is about
> static inline int hif_set_beacon_wakeup_period(struct wfx_vif *wvif,
>unsigned int dtim_interval,
>unsigned int listen_interval)
> {
> struct 

Re: [PATCH v1 1/5] staging: wfx: fix warnings of no space is necessary

2019-10-21 Thread Jerome Pouiller
On Saturday 19 October 2019 16:24:43 CEST Dan Carpenter wrote:
> On Sat, Oct 19, 2019 at 03:07:15PM +0100, Jules Irenge wrote:
> > diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
> > index 3355183fc86c..573216b08042 100644
> > --- a/drivers/staging/wfx/bh.c
> > +++ b/drivers/staging/wfx/bh.c
> > @@ -69,13 +69,13 @@ static int rx_helper(struct wfx_dev *wdev, size_t 
> > read_len, int *is_cnf)
> >   if (wfx_data_read(wdev, skb->data, alloc_len))
> >   goto err;
> >
> > - piggyback = le16_to_cpup((u16 *) (skb->data + alloc_len - 2));
> > + piggyback = le16_to_cpup((u16 *)(skb->data + alloc_len - 2));
> >   _trace_piggyback(piggyback, false);
> >
> > - hif = (struct hif_msg *) skb->data;
> > + hif = (struct hif_msg *)skb->data;
> >   WARN(hif->encrypted & 0x1, "unsupported encryption type");
> >   if (hif->encrypted == 0x2) {
> > - if (wfx_sl_decode(wdev, (void *) hif)) {
> > + if (wfx_sl_decode(wdev, (void *)hif)) {
> 
> In the future you may want to go through and remove the (void *) casts.
> It's not required here.
> 
> > diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
> > index f65f7d75e731..effd07957753 100644
> > --- a/drivers/staging/wfx/bus_spi.c
> > +++ b/drivers/staging/wfx/bus_spi.c
> > @@ -90,7 +90,7 @@ static int wfx_spi_copy_to_io(void *priv, unsigned int 
> > addr,
> >   struct wfx_spi_priv *bus = priv;
> >   u16 regaddr = (addr << 12) | (count / 2);
> >   // FIXME: use a bounce buffer
> > - u16 *src16 = (void *) src;
> > + u16 *src16 = (void *)src;
> 
> Here we are just getting rid of the constness.  Apparently we are doing
> that so we can modify it without GCC pointing out the bug!!  I don't
> know the code but this seems very wrong.

Hello Dan, Jules,

Indeed, this code should be improved.

Each u16 from src is byte-swapped before to be sent to SPI and restored
before to return from the function:

for (i = 0; i < count / 2; i++)
swab16s([i]);
[...]
spi_sync(bus->func, );
   [...]
for (i = 0; i < count / 2; i++)
swab16s([i]);

So, src is same than original, but it is not const.

This is exactly the purpose of the FIXME just before the cast: "use a
bounce buffer". However, I did not yet make this change because I worry
about a possible performance penalty.

-- 
Jérôme Pouiller



Re: [PATCH] staging: wfx: remove unnecessary void pointer

2019-10-21 Thread Jerome Pouiller
On Monday 21 October 2019 14:24:49 CEST Jules Irenge wrote:
> Remove unnecessary void pointers.
> Issue detected and solved by coccinelle tool.
> semantic use
> @@expression e ;@@
> -(void*)(e)
> +e
> 
> Signed-off-by: Jules Irenge 
> ---
>  drivers/staging/wfx/bh.c   | 2 +-
>  drivers/staging/wfx/bus_sdio.c | 2 +-
>  drivers/staging/wfx/bus_spi.c  | 2 +-
>  drivers/staging/wfx/sta.c  | 2 +-
>  4 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
> index 955ed3a1dd73..d7ad9227c9c4 100644
> --- a/drivers/staging/wfx/bh.c
> +++ b/drivers/staging/wfx/bh.c
> @@ -76,7 +76,7 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
> int *is_cnf)
> hif = (struct hif_msg *)skb->data;
> WARN(hif->encrypted & 0x1, "unsupported encryption type");
> if (hif->encrypted == 0x2) {
> -   if (wfx_sl_decode(wdev, (void *)hif)) {
> +   if (wfx_sl_decode(wdev, hif)) {
> dev_kfree_skb(skb);
> // If frame was a confirmation, expect trouble in next
> // exchange. However, it is harmless to fail to decode
> diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
> index 375e07d6d9ae..237a19b5fd16 100644
> --- a/drivers/staging/wfx/bus_sdio.c
> +++ b/drivers/staging/wfx/bus_sdio.c
> @@ -66,7 +66,7 @@ static int wfx_sdio_copy_to_io(void *priv, unsigned int 
> reg_id,
> 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);
> +   ret = sdio_memcpy_toio(bus->func, sdio_addr, src, count);
> if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
> bus->buf_id_tx = (bus->buf_id_tx + 1) % 32;
> 
> diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
> index ab0cda1e124f..bd74801e7461 100644
> --- a/drivers/staging/wfx/bus_spi.c
> +++ b/drivers/staging/wfx/bus_spi.c
> @@ -90,7 +90,7 @@ static int wfx_spi_copy_to_io(void *priv, unsigned int addr,
> struct wfx_spi_priv *bus = priv;
> u16 regaddr = (addr << 12) | (count / 2);
> // FIXME: use a bounce buffer
> -   u16 *src16 = (void *)src;
> +   u16 *src16 = src;
> int ret, i;
> struct spi_message  m;
> struct spi_transfer t_addr = {
> diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c
> index 688586e823c0..842158b7e805 100644
> --- a/drivers/staging/wfx/sta.c
> +++ b/drivers/staging/wfx/sta.c
> @@ -896,7 +896,7 @@ static int wfx_upload_beacon(struct wfx_vif *wvif)
> /* TODO: Distill probe resp; remove TIM and any other beacon-specific
>  * IEs
>  */
> -   mgmt = (void *)skb->data;
> +   mgmt = skb->data;
> mgmt->frame_control =
> cpu_to_le16(IEEE80211_FTYPE_MGMT | 
> IEEE80211_STYPE_PROBE_RESP);
> 
Hello Jules,

Thank you for your work.

Did you check that the code continue to compile without warnings after
applying this patch?

-- 
Jérôme Pouiller

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


[PATCH 4/6] staging: wfx: fix Oops when CONFIG_OF_NET is not set

2019-10-17 Thread Jerome Pouiller
From: Jérôme Pouiller 

In most case, of_get_mac_address() return NULL in case of error.
However, if CONFIG_OF_NET is not set, it return -ENODEV.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 3a43f190d96a..205b5bc8872e 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -407,7 +407,7 @@ int wfx_probe(struct wfx_dev *wdev)
for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
eth_zero_addr(wdev->addresses[i].addr);
macaddr = of_get_mac_address(wdev->dev->of_node);
-   if (macaddr) {
+   if (!IS_ERR_OR_NULL(macaddr)) {
ether_addr_copy(wdev->addresses[i].addr, macaddr);
wdev->addresses[i].addr[ETH_ALEN - 1] += i;
}
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 3/6] staging: wfx: fix CONFIG_MMC=m with CONFIG_WFX=y

2019-10-17 Thread Jerome Pouiller
From: Jérôme Pouiller 

If CONFIG_MMC=m and CONFIG_WFX=y, compilation complains with undefined
references:

drivers/staging/wfx/main.o: In function `wfx_core_init': 
/linux/drivers/staging/wfx/main.c:488: undefined reference to 
`sdio_register_driver'
drivers/staging/wfx/main.o: In function `wfx_core_exit': 
/linux/drivers/staging/wfx/main.c:496: undefined reference to 
`sdio_unregister_driver'
drivers/staging/wfx/main.o:(.debug_addr+0x1a8): undefined reference to 
`sdio_register_driver'
drivers/staging/wfx/main.o:(.debug_addr+0x6f0): undefined reference to 
`sdio_unregister_driver'

Indeed, symbols sdio_* are not present in kernel image.

This patch disallows CONFIG_WFX=y if CONFIG_MMC=m.

This solution impacts users who want to use SPI bus with configuration:
CONFIG_WFX=y + CONFIG_SPI=y + CONFIG_MMC=m. However, I think this is a
twisted case. So, I think it won't be missed.

Reported-by: zhong jiang 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/staging/wfx/Kconfig b/drivers/staging/wfx/Kconfig
index 9b8a1c7a9e90..83ee4d0ca8c6 100644
--- a/drivers/staging/wfx/Kconfig
+++ b/drivers/staging/wfx/Kconfig
@@ -1,6 +1,7 @@
 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)
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 1/6] staging: wfx: drop module version

2019-10-17 Thread Jerome Pouiller
From: Jérôme Pouiller 

wfx_version.h says that this code is same same than driver 2.3.1 hosted
on github:

https://github.com/siliconlabs/wfx-linux-driver/tree/2.3.1-public

However, it is inaccurate, driver in-tree contains multiple small
patches ahead 2.3.1.

I prefer to drop this confusing information.

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/TODO  | 3 ---
 drivers/staging/wfx/main.c| 4 
 drivers/staging/wfx/wfx_version.h | 3 ---
 3 files changed, 10 deletions(-)
 delete mode 100644 drivers/staging/wfx/wfx_version.h

diff --git a/drivers/staging/wfx/TODO b/drivers/staging/wfx/TODO
index be990e8f18b1..e44772289af8 100644
--- a/drivers/staging/wfx/TODO
+++ b/drivers/staging/wfx/TODO
@@ -1,9 +1,6 @@
 This is a list of things that need to be done to get this driver out of the
 staging directory.
 
-  - wfx_version.h is still there in order to ensure synchronization with 
github.
-It can be dropped as soon as development is entirely in kernel
-
   - I have to take a decision about secure link support. I can:
   - drop completely
   - keep it in an external patch (my preferred option)
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index d2508bc950fa..157e0fc0107e 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -33,14 +33,12 @@
 #include "secure_link.h"
 #include "hif_tx_mib.h"
 #include "hif_api_cmd.h"
-#include "wfx_version.h"
 
 #define WFX_PDS_MAX_SIZE 1500
 
 MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx");
 MODULE_AUTHOR("Jérôme Pouiller ");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(WFX_LABEL);
 
 static int gpio_wakeup = -2;
 module_param(gpio_wakeup, int, 0644);
@@ -480,8 +478,6 @@ static int __init wfx_core_init(void)
 {
int ret = 0;
 
-   pr_info("wfx: Silicon Labs " WFX_LABEL "\n");
-
if (IS_ENABLED(CONFIG_SPI))
ret = spi_register_driver(_spi_driver);
if (IS_ENABLED(CONFIG_MMC) && !ret)
diff --git a/drivers/staging/wfx/wfx_version.h 
b/drivers/staging/wfx/wfx_version.h
deleted file mode 100644
index 6e7f30207c73..
--- a/drivers/staging/wfx/wfx_version.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT! */
-#define WFX_LABEL "2.3.1"
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 5/6] staging: wfx: fix setting MAC address from DT

2019-10-17 Thread Jerome Pouiller
From: Jérôme Pouiller 

MAC address read from chip is unconditionally used even if a MAC
address is configured in device tree.

Reported-by: Marc Dorval 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/main.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 205b5bc8872e..18f07f7ad347 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -410,8 +410,9 @@ int wfx_probe(struct wfx_dev *wdev)
if (!IS_ERR_OR_NULL(macaddr)) {
ether_addr_copy(wdev->addresses[i].addr, macaddr);
wdev->addresses[i].addr[ETH_ALEN - 1] += i;
+   } else {
+   ether_addr_copy(wdev->addresses[i].addr, 
wdev->hw_caps.mac_addr[i]);
}
-   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);
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 2/6] staging: wfx: relocate wfx_fill_sl_key() in secure_link.h

2019-10-17 Thread Jerome Pouiller
From: Jérôme Pouiller 

"Secure link" feature is not available in in-tree driver (because it
depends on mbedtls). Thus, secure_link.h only empty functions.

Module parameter "slk_key" and associated function wfx_fill_sl_key() had
an unjustifiable place in main.c. This patch relocate them to
secure_link.h.

BTW, content of wfx_fill_sl_key() is now useless. Just keep a warning if
user try to use "slk_key" attribute (unsupported by this driver).

Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/main.c| 29 +
 drivers/staging/wfx/main.h|  1 -
 drivers/staging/wfx/secure_link.h |  9 +
 3 files changed, 10 insertions(+), 29 deletions(-)

diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 157e0fc0107e..3a43f190d96a 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -44,10 +44,6 @@ static int gpio_wakeup = -2;
 module_param(gpio_wakeup, int, 0644);
 MODULE_PARM_DESC(gpio_wakeup, "gpio number for wakeup. -1 for none.");
 
-static char *slk_key;
-module_param(slk_key, charp, 0600);
-MODULE_PARM_DESC(slk_key, "secret key for secure link (expect 64 hexadecimal 
digits).");
-
 #define RATETAB_ENT(_rate, _rateid, _flags) { \
.bitrate  = (_rate),   \
.hw_value = (_rateid), \
@@ -194,29 +190,6 @@ struct gpio_desc *wfx_get_gpio(struct device *dev, int 
override, const char *lab
return ret;
 }
 
-static void wfx_fill_sl_key(struct device *dev, struct wfx_platform_data 
*pdata)
-{
-   const char *ascii_key = NULL;
-   int ret = 0;
-
-   if (slk_key)
-   ascii_key = slk_key;
-   if (!ascii_key)
-   ret = of_property_read_string(dev->of_node, "slk_key", 
_key);
-   if (ret == -EILSEQ || ret == -ENODATA)
-   dev_err(dev, "ignoring malformatted key from DT\n");
-   if (!ascii_key)
-   return;
-
-   ret = hex2bin(pdata->slk_key, ascii_key, sizeof(pdata->slk_key));
-   if (ret) {
-   dev_err(dev, "ignoring malformatted key: %s\n", ascii_key);
-   memset(pdata->slk_key, 0, sizeof(pdata->slk_key));
-   return;
-   }
-   dev_err(dev, "secure link is not supported by this driver, ignoring 
provided key\n");
-}
-
 /* NOTE: wfx_send_pds() destroy buf */
 int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len)
 {
@@ -334,7 +307,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
memcpy(>pdata, pdata, sizeof(*pdata));
of_property_read_string(dev->of_node, "config-file", 
>pdata.file_pds);
wdev->pdata.gpio_wakeup = wfx_get_gpio(dev, gpio_wakeup, "wakeup");
-   wfx_fill_sl_key(dev, >pdata);
+   wfx_sl_fill_pdata(dev, >pdata);
 
mutex_init(>conf_mutex);
mutex_init(>rx_stats_lock);
diff --git a/drivers/staging/wfx/main.h b/drivers/staging/wfx/main.h
index f2b07ed1627c..875f8c227803 100644
--- a/drivers/staging/wfx/main.h
+++ b/drivers/staging/wfx/main.h
@@ -22,7 +22,6 @@ struct wfx_platform_data {
/* Keyset and ".sec" extention will appended to this string */
const char *file_fw;
const char *file_pds;
-   unsigned char slk_key[API_KEY_VALUE_SIZE];
struct gpio_desc *gpio_wakeup;
/*
 * if true HIF D_out is sampled on the rising edge of the clock
diff --git a/drivers/staging/wfx/secure_link.h 
b/drivers/staging/wfx/secure_link.h
index e2da1c73c760..376d7bc4c0c4 100644
--- a/drivers/staging/wfx/secure_link.h
+++ b/drivers/staging/wfx/secure_link.h
@@ -5,6 +5,8 @@
 #ifndef WFX_SECURE_LINK_H
 #define WFX_SECURE_LINK_H
 
+#include 
+
 #include "hif_api_general.h"
 
 struct wfx_dev;
@@ -33,6 +35,13 @@ static inline int wfx_sl_check_pubkey(struct wfx_dev *wdev, 
uint8_t *ncp_pubkey,
return -EIO;
 }
 
+static inline void wfx_sl_fill_pdata(struct device *dev,
+struct wfx_platform_data *pdata)
+{
+   if (of_find_property(dev->of_node, "slk_key", NULL))
+   dev_err(dev, "secure link is not supported by this driver, 
ignoring provided key\n");
+}
+
 static inline int wfx_sl_init(struct wfx_dev *wdev)
 {
return -EIO;
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 6/6] staging: wfx: fix number of available tx_policies

2019-10-17 Thread Jerome Pouiller
From: Jérôme Pouiller 

Original API declares 16 tx_policies. But in fact, the 16th is used
internally by the firmware. So, only 15 tx_policies are available for
driver.

Reported-by: Alban Jeantheau 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/hif_api_mib.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/wfx/hif_api_mib.h 
b/drivers/staging/wfx/hif_api_mib.h
index 3c56ef2978a2..af657555f894 100644
--- a/drivers/staging/wfx/hif_api_mib.h
+++ b/drivers/staging/wfx/hif_api_mib.h
@@ -507,7 +507,7 @@ struct hif_mib_tx_rate_retry_policy {
uint8_trates[12];
 } __packed;
 
-#define HIF_MIB_NUM_TX_RATE_RETRY_POLICIES16
+#define HIF_MIB_NUM_TX_RATE_RETRY_POLICIES15
 
 struct hif_mib_set_tx_rate_retry_policy {
uint8_tnum_tx_rate_policies;
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH v2] staging: wfx: Fix a memory leak in 'wfx_upload_beacon'

2019-11-04 Thread Jerome Pouiller
On Saturday 2 November 2019 16:59:45 CET Christophe JAILLET wrote:
> The current code is a no-op, because all it can do is 'dev_kfree_skb(NULL)'
> Remove the test before 'dev_kfree_skb()'
> 
> Signed-off-by: Christophe JAILLET 
> ---
> V2: remove the 'if(...)', 'dev_kfree_skb()' can handle NULL.
> ---
>  drivers/staging/wfx/sta.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c
> index 688586e823c0..93f3739b5f3a 100644
> --- a/drivers/staging/wfx/sta.c
> +++ b/drivers/staging/wfx/sta.c
> @@ -906,8 +906,7 @@ static int wfx_upload_beacon(struct wfx_vif *wvif)
> wfx_fwd_probe_req(wvif, false);
> 
>  done:
> -   if (!skb)
> -   dev_kfree_skb(skb);
> +   dev_kfree_skb(skb);
> return ret;
>  }
> 
> --
> 2.20.1
> 

In add, value of skb is tested earlier in function. So, it is guaranteed to be 
never NULL.

Reviewed-by: Jérôme Pouiller 

-- 
Jérôme Pouiller

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


Re: [staging:staging-testing 41/59] drivers/staging/wfx/main.c:47:14-21: ERROR: PTR_ERR applied after initialization to constant on line 42

2019-10-07 Thread Jerome Pouiller
On Friday 4 October 2019 12:48:32 CEST kbuild test robot wrote:
[...]
> >> drivers/staging/wfx/main.c:47:14-21: ERROR: PTR_ERR applied after 
> >> initialization to constant on line 42
> 
> vim +47 drivers/staging/wfx/main.c
> 
> 30
> 31  struct gpio_desc *wfx_get_gpio(struct device *dev, int override, 
> const char *label)
> 32  {
> 33  struct gpio_desc *ret;
> 34  char label_buf[256];
> 35
> 36  if (override >= 0) {
> 37  snprintf(label_buf, sizeof(label_buf), "wfx_%s", 
> label);
> 38  ret = ERR_PTR(devm_gpio_request_one(dev, override, 
> GPIOF_OUT_INIT_LOW, label_buf));
> 39  if (!ret)
> 40  ret = gpio_to_desc(override);
> 41  } else if (override == -1) {
>   > 42  ret = NULL;
> 43  } else {
> 44  ret = devm_gpiod_get(dev, label, GPIOD_OUT_LOW);
> 45  }
> 46  if (IS_ERR(ret) || !ret) {
>   > 47  if (!ret || PTR_ERR(ret) == -ENOENT)
> 48  dev_warn(dev, "gpio %s is not defined\n", 
> label);
> 49  else
> 50  dev_warn(dev, "error while requesting gpio 
> %s\n", label);
> 51  ret = NULL;
> 52  } else {
> 53  dev_dbg(dev, "using gpio %d for %s\n", 
> desc_to_gpio(ret), label);
> 54  }
> 55  return ret;
> 56  }
> 57

I think that this report is a false positive or I missed something?

-- 
Jérôme Pouiller
-- 
Jérôme Pouiller

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


[PATCH 0/7] Fix various compilation issues with wfx driver

2019-10-08 Thread Jerome Pouiller
From: Jérôme Pouiller 

Most of problems are related to big-endian architectures.

Jérôme Pouiller (7):
  staging: wfx: simplify memory allocation in wfx_update_filtering()
  staging: wfx: remove misused call to cpu_to_le16()
  staging: wfx: le16_to_cpus() takes a reference as parameter
  staging: wfx: correctly cast data on big-endian targets
  staging: wfx: fix copy_{to,from}_user() usage
  staging: wfx: drop calls to BUG_ON()
  staging: wfx: avoid namespace contamination

 drivers/staging/wfx/bh.c |  8 +++
 drivers/staging/wfx/bus_sdio.c   |  4 ++--
 drivers/staging/wfx/data_tx.c| 40 
 drivers/staging/wfx/data_tx.h|  2 +-
 drivers/staging/wfx/debug.c  |  5 ++--
 drivers/staging/wfx/hif_tx_mib.h | 23 --
 drivers/staging/wfx/key.c| 32 -
 drivers/staging/wfx/queue.c  |  6 ++---
 drivers/staging/wfx/scan.c   |  2 +-
 drivers/staging/wfx/sta.c| 21 +++--
 10 files changed, 74 insertions(+), 69 deletions(-)

-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 1/7] staging: wfx: simplify memory allocation in wfx_update_filtering()

2019-10-08 Thread Jerome Pouiller
From: Jérôme Pouiller 

Original code did not handle case where kmalloc failed. By the way, it
is more convenient to allocate and build HIF message in
hif_set_beacon_filter_table() instead of to ask to caller function to
build it.

Fixes: 40115bbc40e2 ("staging: wfx: implement the rest of mac80211 API")
Reported-by: kbuild test robot 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/hif_tx_mib.h | 19 ++-
 drivers/staging/wfx/sta.c| 17 +++--
 2 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/drivers/staging/wfx/hif_tx_mib.h b/drivers/staging/wfx/hif_tx_mib.h
index f6624a403016..167c5dec009f 100644
--- a/drivers/staging/wfx/hif_tx_mib.h
+++ b/drivers/staging/wfx/hif_tx_mib.h
@@ -86,13 +86,22 @@ static inline int hif_set_rx_filter(struct wfx_vif *wvif, 
bool filter_bssid,
 }
 
 static inline int hif_set_beacon_filter_table(struct wfx_vif *wvif,
- struct hif_mib_bcn_filter_table 
*ft)
+ int tbl_len,
+ struct hif_ie_table_entry *tbl)
 {
-   size_t buf_len = struct_size(ft, ie_table, ft->num_of_info_elmts);
+   int ret;
+   struct hif_mib_bcn_filter_table *val;
+   int buf_len = struct_size(val, ie_table, tbl_len);
 
-   cpu_to_le32s(>num_of_info_elmts);
-   return hif_write_mib(wvif->wdev, wvif->id,
-HIF_MIB_ID_BEACON_FILTER_TABLE, ft, buf_len);
+   val = kzalloc(buf_len, GFP_KERNEL);
+   if (!val)
+   return -ENOMEM;
+   val->num_of_info_elmts = cpu_to_le32(tbl_len);
+   memcpy(val->ie_table, tbl, tbl_len * sizeof(*tbl));
+   ret = hif_write_mib(wvif->wdev, wvif->id,
+   HIF_MIB_ID_BEACON_FILTER_TABLE, val, buf_len);
+   kfree(val);
+   return ret;
 }
 
 static inline int hif_beacon_filter_control(struct wfx_vif *wvif,
diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c
index 2855d14a709c..12198b8f3685 100644
--- a/drivers/staging/wfx/sta.c
+++ b/drivers/staging/wfx/sta.c
@@ -217,14 +217,13 @@ void wfx_update_filtering(struct wfx_vif *wvif)
bool filter_bssid = wvif->filter_bssid;
bool fwd_probe_req = wvif->fwd_probe_req;
struct hif_mib_bcn_filter_enable bf_ctrl;
-   struct hif_mib_bcn_filter_table *bf_tbl;
-   struct hif_ie_table_entry ie_tbl[] = {
+   struct hif_ie_table_entry filter_ies[] = {
{
.ie_id= WLAN_EID_VENDOR_SPECIFIC,
.has_changed  = 1,
.no_longer= 1,
.has_appeared = 1,
-   .oui = { 0x50, 0x6F, 0x9A},
+   .oui  = { 0x50, 0x6F, 0x9A },
}, {
.ie_id= WLAN_EID_HT_OPERATION,
.has_changed  = 1,
@@ -237,36 +236,34 @@ void wfx_update_filtering(struct wfx_vif *wvif)
.has_appeared = 1,
}
};
+   int n_filter_ies;
 
if (wvif->state == WFX_STATE_PASSIVE)
return;
 
-   bf_tbl = kmalloc(sizeof(struct hif_mib_bcn_filter_table) + 
sizeof(ie_tbl), GFP_KERNEL);
-   memcpy(bf_tbl->ie_table, ie_tbl, sizeof(ie_tbl));
if (wvif->disable_beacon_filter) {
bf_ctrl.enable = 0;
bf_ctrl.bcn_count = 1;
-   bf_tbl->num_of_info_elmts = 0;
+   n_filter_ies = 0;
} else if (!is_sta) {
bf_ctrl.enable = HIF_BEACON_FILTER_ENABLE | 
HIF_BEACON_FILTER_AUTO_ERP;
bf_ctrl.bcn_count = 0;
-   bf_tbl->num_of_info_elmts = 2;
+   n_filter_ies = 2;
} else {
bf_ctrl.enable = HIF_BEACON_FILTER_ENABLE;
bf_ctrl.bcn_count = 0;
-   bf_tbl->num_of_info_elmts = 3;
+   n_filter_ies = 3;
}
 
ret = hif_set_rx_filter(wvif, filter_bssid, fwd_probe_req);
if (!ret)
-   ret = hif_set_beacon_filter_table(wvif, bf_tbl);
+   ret = hif_set_beacon_filter_table(wvif, n_filter_ies, 
filter_ies);
if (!ret)
ret = hif_beacon_filter_control(wvif, bf_ctrl.enable, 
bf_ctrl.bcn_count);
if (!ret)
ret = wfx_set_mcast_filter(wvif, >mcast_filter);
if (ret)
dev_err(wvif->wdev->dev, "update filtering failed: %d\n", ret);
-   kfree(bf_tbl);
 }
 
 void wfx_update_filtering_work(struct work_struct *work)
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 2/7] staging: wfx: remove misused call to cpu_to_le16()

2019-10-08 Thread Jerome Pouiller
From: Jérôme Pouiller 

Indeed, hif_msg->id is a uint8_t, so use of cpu_to_le16() is a madness.

Fixes: 9bca45f3d692 ("staging: wfx: allow to send 802.11 frames")
Reported-by: kbuild test robot 
Reported-by: Stephen Rothwell 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/data_tx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
index 7f2799fbdafe..1891bcaaf9fc 100644
--- a/drivers/staging/wfx/data_tx.c
+++ b/drivers/staging/wfx/data_tx.c
@@ -620,7 +620,7 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct 
ieee80211_sta *sta, struct
memset(skb->data, 0, wmsg_len);
hif_msg = (struct hif_msg *) skb->data;
hif_msg->len = cpu_to_le16(skb->len);
-   hif_msg->id = cpu_to_le16(HIF_REQ_ID_TX);
+   hif_msg->id = HIF_REQ_ID_TX;
hif_msg->interface = wvif->id;
if (skb->len > wvif->wdev->hw_caps.size_inp_ch_buf) {
dev_warn(wvif->wdev->dev, "requested frame size (%d) is larger 
than maximum supported (%d)\n",
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 4/7] staging: wfx: correctly cast data on big-endian targets

2019-10-08 Thread Jerome Pouiller
From: Jérôme Pouiller 

When built for a big-endian target, original code caused error:

include/uapi/linux/swab.h:242:29: note: expected '__u32 * {aka unsigned int 
*}' but argument is of type 'struct hif_mib_protected_mgmt_policy *'

Fixes: f95a29d40782 ("staging: wfx: add HIF commands helpers")
Reported-by: kbuild test robot 
Reported-by: Stephen Rothwell 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/hif_tx_mib.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/wfx/hif_tx_mib.h b/drivers/staging/wfx/hif_tx_mib.h
index 167c5dec009f..4f132348f5fa 100644
--- a/drivers/staging/wfx/hif_tx_mib.h
+++ b/drivers/staging/wfx/hif_tx_mib.h
@@ -145,7 +145,7 @@ static inline int hif_set_mfp(struct wfx_vif *wvif, bool 
capable, bool required)
}
if (!required)
val.unpmf_allowed = 1;
-   cpu_to_le32s();
+   cpu_to_le32s((uint32_t *) );
return hif_write_mib(wvif->wdev, wvif->id,
 HIF_MIB_ID_PROTECTED_MGMT_POLICY,
 , sizeof(val));
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 5/7] staging: wfx: fix copy_{to,from}_user() usage

2019-10-08 Thread Jerome Pouiller
From: Jérôme Pouiller 

On error, copy_to_user() returns number of bytes remaining. Driver
should return -EFAULT.

Fixes: 4f8b7fabb15d ("staging: wfx: allow to send commands to chip")
Reported-by: kbuild test robot 
Reported-by: Dan Carpenter 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/debug.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 3261b267c385..8de16ad7c710 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -256,9 +256,8 @@ static ssize_t wfx_send_hif_msg_read(struct file *file, 
char __user *user_buf,
return context->ret;
// Be carefull, write() is waiting for a full message while read()
// only return a payload
-   ret = copy_to_user(user_buf, context->reply, count);
-   if (ret)
-   return ret;
+   if (copy_to_user(user_buf, context->reply, count))
+   return -EFAULT;
 
return count;
 }
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 7/7] staging: wfx: avoid namespace contamination

2019-10-08 Thread Jerome Pouiller
From: Jérôme Pouiller 

tx_policy_init() was already defined in driver cw1200. So, compilation
failed when wfx and cw1200 were both built-in.

In order to keep a coherent naming scheme, this patch prefixes all
"tx_policy_*" functions with "wfx_".

Fixes: 9bca45f3d692 ("staging: wfx: allow to send 802.11 frames")
Reported-by: kbuild test robot 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/data_tx.c | 34 +-
 drivers/staging/wfx/data_tx.h |  2 +-
 drivers/staging/wfx/sta.c |  2 +-
 3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
index b2ca3986c6d0..6e4dd4ac5544 100644
--- a/drivers/staging/wfx/data_tx.c
+++ b/drivers/staging/wfx/data_tx.c
@@ -37,7 +37,7 @@ static int wfx_get_hw_rate(struct wfx_dev *wdev, const struct 
ieee80211_tx_rate
 
 /* TX policy cache implementation */
 
-static void tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy,
+static void wfx_tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy,
struct ieee80211_tx_rate *rates)
 {
int i;
@@ -124,7 +124,7 @@ static bool tx_policy_is_equal(const struct tx_policy *a, 
const struct tx_policy
return !memcmp(a->rates, b->rates, sizeof(a->rates));
 }
 
-static int tx_policy_find(struct tx_policy_cache *cache, struct tx_policy 
*wanted)
+static int wfx_tx_policy_find(struct tx_policy_cache *cache, struct tx_policy 
*wanted)
 {
struct tx_policy *it;
 
@@ -137,13 +137,13 @@ static int tx_policy_find(struct tx_policy_cache *cache, 
struct tx_policy *wante
return -1;
 }
 
-static void tx_policy_use(struct tx_policy_cache *cache, struct tx_policy 
*entry)
+static void wfx_tx_policy_use(struct tx_policy_cache *cache, struct tx_policy 
*entry)
 {
++entry->usage_count;
list_move(>link, >used);
 }
 
-static int tx_policy_release(struct tx_policy_cache *cache, struct tx_policy 
*entry)
+static int wfx_tx_policy_release(struct tx_policy_cache *cache, struct 
tx_policy *entry)
 {
int ret = --entry->usage_count;
 
@@ -152,21 +152,21 @@ static int tx_policy_release(struct tx_policy_cache 
*cache, struct tx_policy *en
return ret;
 }
 
-static int tx_policy_get(struct wfx_vif *wvif, struct ieee80211_tx_rate *rates,
+static int wfx_tx_policy_get(struct wfx_vif *wvif, struct ieee80211_tx_rate 
*rates,
 bool *renew)
 {
int idx;
struct tx_policy_cache *cache = >tx_policy_cache;
struct tx_policy wanted;
 
-   tx_policy_build(wvif, , rates);
+   wfx_tx_policy_build(wvif, , rates);
 
spin_lock_bh(>lock);
if (WARN_ON(list_empty(>free))) {
spin_unlock_bh(>lock);
return WFX_INVALID_RATE_ID;
}
-   idx = tx_policy_find(cache, );
+   idx = wfx_tx_policy_find(cache, );
if (idx >= 0) {
*renew = false;
} else {
@@ -181,7 +181,7 @@ static int tx_policy_get(struct wfx_vif *wvif, struct 
ieee80211_tx_rate *rates,
entry->usage_count = 0;
idx = entry - cache->cache;
}
-   tx_policy_use(cache, >cache[idx]);
+   wfx_tx_policy_use(cache, >cache[idx]);
if (list_empty(>free)) {
/* Lock TX queues. */
wfx_tx_queues_lock(wvif->wdev);
@@ -190,14 +190,14 @@ static int tx_policy_get(struct wfx_vif *wvif, struct 
ieee80211_tx_rate *rates,
return idx;
 }
 
-static void tx_policy_put(struct wfx_vif *wvif, int idx)
+static void wfx_tx_policy_put(struct wfx_vif *wvif, int idx)
 {
int usage, locked;
struct tx_policy_cache *cache = >tx_policy_cache;
 
spin_lock_bh(>lock);
locked = list_empty(>free);
-   usage = tx_policy_release(cache, >cache[idx]);
+   usage = wfx_tx_policy_release(cache, >cache[idx]);
if (locked && !usage) {
/* Unlock TX queues. */
wfx_tx_queues_unlock(wvif->wdev);
@@ -205,7 +205,7 @@ static void tx_policy_put(struct wfx_vif *wvif, int idx)
spin_unlock_bh(>lock);
 }
 
-static int tx_policy_upload(struct wfx_vif *wvif)
+static int wfx_tx_policy_upload(struct wfx_vif *wvif)
 {
int i;
struct tx_policy_cache *cache = >tx_policy_cache;
@@ -238,18 +238,18 @@ static int tx_policy_upload(struct wfx_vif *wvif)
return 0;
 }
 
-static void tx_policy_upload_work(struct work_struct *work)
+static void wfx_tx_policy_upload_work(struct work_struct *work)
 {
struct wfx_vif *wvif =
container_of(work, struct wfx_vif, tx_policy_upload_work);
 
-   tx_policy_upload(wvif);
+   wfx_tx_policy_upload(wvif);
 
wfx_tx_unlock(wvif->wdev);
wfx_tx_queues_unlock(wvif->wdev);
 }
 
-void tx_policy_init(struct wfx_vif *wvif)
+void wfx_tx_policy_init(struct wfx_vif *wvif)
 {
struct tx_policy_cache *cache = >tx_policy_cache;
int i;
@@ -259,7 +259,7 @@ void 

[PATCH 6/7] staging: wfx: drop calls to BUG_ON()

2019-10-08 Thread Jerome Pouiller
From: Jérôme Pouiller 

Most of calls to BUG_ON() could replaced by WARN().

By the way, this patch also try to favor WARN() (that include a comment
about the problem) instead of WARN_ON().

Reported-by: Andrew Lunn 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bh.c |  4 ++--
 drivers/staging/wfx/bus_sdio.c   |  4 ++--
 drivers/staging/wfx/data_tx.c|  4 ++--
 drivers/staging/wfx/hif_tx_mib.h |  2 +-
 drivers/staging/wfx/key.c| 32 
 drivers/staging/wfx/queue.c  |  6 +++---
 drivers/staging/wfx/scan.c   |  2 +-
 drivers/staging/wfx/sta.c|  2 +-
 8 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index 3715bb18bd78..3355183fc86c 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -56,7 +56,7 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
int release_count;
int piggyback = 0;
 
-   WARN_ON(read_len < 4);
+   WARN(read_len < 4, "corrupted read");
WARN(read_len > round_down(0xFFF, 2) * sizeof(u16),
 "%s: request exceed WFx capability", __func__);
 
@@ -173,7 +173,7 @@ static void tx_helper(struct wfx_dev *wdev, struct hif_msg 
*hif)
bool is_encrypted = false;
size_t len = le16_to_cpu(hif->len);
 
-   BUG_ON(len < sizeof(*hif));
+   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);
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 05f02c278782..f97360513150 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -37,7 +37,7 @@ static int wfx_sdio_copy_from_io(void *priv, unsigned int 
reg_id,
unsigned int sdio_addr = reg_id << 2;
int ret;
 
-   BUG_ON(reg_id > 7);
+   WARN(reg_id > 7, "chip only has 7 registers");
WARN(((uintptr_t) dst) & 3, "unaligned buffer size");
WARN(count & 3, "unaligned buffer address");
 
@@ -58,7 +58,7 @@ static int wfx_sdio_copy_to_io(void *priv, unsigned int 
reg_id,
unsigned int sdio_addr = reg_id << 2;
int ret;
 
-   BUG_ON(reg_id > 7);
+   WARN(reg_id > 7, "chip only has 7 registers");
WARN(((uintptr_t) src) & 3, "unaligned buffer size");
WARN(count & 3, "unaligned buffer address");
 
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c
index 1891bcaaf9fc..b2ca3986c6d0 100644
--- a/drivers/staging/wfx/data_tx.c
+++ b/drivers/staging/wfx/data_tx.c
@@ -44,7 +44,7 @@ static void tx_policy_build(struct wfx_vif *wvif, struct 
tx_policy *policy,
size_t count;
struct wfx_dev *wdev = wvif->wdev;
 
-   BUG_ON(rates[0].idx < 0);
+   WARN(rates[0].idx < 0, "invalid rate policy");
memset(policy, 0, sizeof(*policy));
for (i = 1; i < IEEE80211_TX_MAX_RATES; i++)
if (rates[i].idx < 0)
@@ -162,7 +162,7 @@ static int tx_policy_get(struct wfx_vif *wvif, struct 
ieee80211_tx_rate *rates,
tx_policy_build(wvif, , rates);
 
spin_lock_bh(>lock);
-   if (WARN_ON_ONCE(list_empty(>free))) {
+   if (WARN_ON(list_empty(>free))) {
spin_unlock_bh(>lock);
return WFX_INVALID_RATE_ID;
}
diff --git a/drivers/staging/wfx/hif_tx_mib.h b/drivers/staging/wfx/hif_tx_mib.h
index 4f132348f5fa..3339ad95f732 100644
--- a/drivers/staging/wfx/hif_tx_mib.h
+++ b/drivers/staging/wfx/hif_tx_mib.h
@@ -138,7 +138,7 @@ static inline int hif_set_mfp(struct wfx_vif *wvif, bool 
capable, bool required)
 {
struct hif_mib_protected_mgmt_policy val = { };
 
-   WARN_ON(required && !capable);
+   WARN(required && !capable, "incoherent arguments");
if (capable) {
val.pmf_enable = 1;
val.host_enc_auth_frames = 1;
diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c
index 4e7d2b510a9c..6d03abec20e4 100644
--- a/drivers/staging/wfx/key.c
+++ b/drivers/staging/wfx/key.c
@@ -26,7 +26,7 @@ static int wfx_alloc_key(struct wfx_dev *wdev)
 
 static void wfx_free_key(struct wfx_dev *wdev, int idx)
 {
-   BUG_ON(!(wdev->key_map & BIT(idx)));
+   WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation");
memset(>keys[idx], 0, sizeof(wdev->keys[idx]));
wdev->key_map &= ~BIT(idx);
 }
@@ -34,7 +34,7 @@ static void wfx_free_key(struct wfx_dev *wdev, int idx)
 static uint8_t fill_wep_pair(struct hif_wep_pairwise_key *msg,
 struct ieee80211_key_conf *key, u8 *peer_addr)
 {
-   WARN_ON(key->keylen > sizeof(msg->key_data));
+   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);
@@ -44,7 +44,7 @@ 

[PATCH 3/7] staging: wfx: le16_to_cpus() takes a reference as parameter

2019-10-08 Thread Jerome Pouiller
From: Jérôme Pouiller 

Original code caused an (100% reproducible) invalid memory access on
big-endian targets.

Fixes: b0998f0c040d "staging: wfx: add IRQ handling"
Reported-by: kbuild test robot 
Reported-by: Stephen Rothwell 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/bh.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index 6000c03bb658..3715bb18bd78 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -83,12 +83,12 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, 
int *is_cnf)
// piggyback is probably correct.
return piggyback;
}
-   le16_to_cpus(hif->len);
+   le16_to_cpus(>len);
computed_len = round_up(hif->len - sizeof(hif->len), 16)
   + sizeof(struct hif_sl_msg)
   + sizeof(struct hif_sl_tag);
} else {
-   le16_to_cpus(hif->len);
+   le16_to_cpus(>len);
computed_len = round_up(hif->len, 2);
}
if (computed_len != read_len) {
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH][next] staging: wfx: fix spelling mistake "hexdecimal" -> "hexadecimal"

2019-10-08 Thread Jerome Pouiller
On Tuesday 8 October 2019 10:22:05 CEST Colin King wrote:
> From: Colin Ian King 
> 
> There is a spelling mistake in the documentation and a module parameter
> description. Fix these.
> 
> Signed-off-by: Colin Ian King 
> ---
>  .../devicetree/bindings/net/wireless/siliabs,wfx.txt| 2 +-
>  drivers/staging/wfx/main.c  | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git 
> a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
>  
> b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
> index 15965c9b4180..26de6762b942 100644
> --- 
> a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
> +++ 
> b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
> @@ -89,7 +89,7 @@ Some properties are recognized either by SPI and SDIO 
> versions:
> this property, driver will disable most of power saving features.
>   - config-file: Use an alternative file as PDS. Default is `wf200.pds`. Only
> necessary for development/debug purpose.
> - - slk_key: String representing hexdecimal value of secure link key to use.
> + - slk_key: String representing hexadecimal value of secure link key to use.
> Must contains 64 hexadecimal digits. Not supported in current version.
> 
>  WFx driver also supports `mac-address` and `local-mac-address` as described 
> in
> diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
> index fe9a89703897..d2508bc950fa 100644
> --- a/drivers/staging/wfx/main.c
> +++ b/drivers/staging/wfx/main.c
> @@ -48,7 +48,7 @@ MODULE_PARM_DESC(gpio_wakeup, "gpio number for wakeup. -1 
> for none.");
> 
>  static char *slk_key;
>  module_param(slk_key, charp, 0600);
> -MODULE_PARM_DESC(slk_key, "secret key for secure link (expect 64 hexdecimal 
> digits).");
> +MODULE_PARM_DESC(slk_key, "secret key for secure link (expect 64 hexadecimal 
> digits).");
> 
>  #define RATETAB_ENT(_rate, _rateid, _flags) { \
> .bitrate  = (_rate),   \
> --
> 2.20.1
> 

Thank you!

Acked-by: Jérôme Pouiller 

-- 
Jérôme Pouiller

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


Re: [PATCH][next] staging: wfx: fix swapped arguments in memset call

2019-10-09 Thread Jerome Pouiller
On Wednesday 9 October 2019 11:46:08 CEST Colin King wrote:
> From: Colin Ian King 
> 
> The memset appears to have the 2nd and 3rd arguments in the wrong
> order, fix this by swapping these around into the correct order.
> 
> Addresses-Coverity: ("Memset fill truncated")
> Fixes: 4f8b7fabb15d ("staging: wfx: allow to send commands to chip")
> Signed-off-by: Colin Ian King 
> ---
>  drivers/staging/wfx/debug.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
> index 8de16ad7c710..761ad9b4f27e 100644
> --- a/drivers/staging/wfx/debug.c
> +++ b/drivers/staging/wfx/debug.c
> @@ -226,7 +226,7 @@ static ssize_t wfx_send_hif_msg_write(struct file *file, 
> const char __user *user
> // wfx_cmd_send() chekc that reply buffer is wide enough, but do 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, sizeof(context->reply), 0xFF);
> +   memset(context->reply, 0xFF, sizeof(context->reply));
> request = memdup_user(user_buf, count);
> if (IS_ERR(request))
> return PTR_ERR(request);

Ouch! I realize that "-Wmemset-transposed-args" and/or "-Wmemset-elt-size"
don't catch this case.

Thank you for your attentive reading.

Reviewed-by: Jérôme Pouiller 

-- 
Jérôme Pouiller

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


Re: [staging:staging-testing 57/111] drivers/staging/wfx/scan.c:207 wfx_scan_work() warn: inconsistent returns 'sem:>scan.lock'.

2019-10-09 Thread Jerome Pouiller
On Wednesday 9 October 2019 09:38:31 CEST kbuild test robot wrote:
> tree:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 
> staging-testing
> head:   d49d1c76b96ebf39539e93d5ab7943a01ef70e4f
> commit: 1a61af0f8cbecd1610c6fc380d0fb00f57fd43f2 [57/111] staging: wfx: allow 
> to scan networks
> 
> If you fix the issue, kindly add following tag
> Reported-by: kbuild test robot 
> Reported-by: Dan Carpenter 
> 
> New smatch warnings:
> drivers/staging/wfx/scan.c:207 wfx_scan_work() warn: inconsistent returns 
> 'sem:>scan.lock'.
>   Locked on:   line 201
>   Unlocked on: line 145
> 
> # 
> https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/commit/?id=1a61af0f8cbecd1610c6fc380d0fb00f57fd43f2
> git remote add staging 
> https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
> git remote update staging
> git checkout 1a61af0f8cbecd1610c6fc380d0fb00f57fd43f2
> vim +207 drivers/staging/wfx/scan.c
> 
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  116  void wfx_scan_work(struct 
> work_struct *work)
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  117  {
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  118  struct wfx_vif *wvif 
> = container_of(work, struct wfx_vif, scan.work);
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  119  struct 
> ieee80211_channel **it;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  120  struct 
> wfx_scan_params scan = {
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  121  
> .scan_req.scan_type.type = 0,/* Foreground */
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  122  };
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  123  struct 
> ieee80211_channel *first;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  124  int i;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  125
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  126  
> down(>scan.lock);
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  127  
> mutex_lock(>wdev->conf_mutex);
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  128
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  129  if (!wvif->scan.req 
> || wvif->scan.curr == wvif->scan.end) {
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  130  if 
> (wvif->scan.output_power != wvif->wdev->output_power)
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  131  
> hif_set_output_power(wvif, wvif->wdev->output_power * 10);
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  132
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  133  if 
> (wvif->scan.status < 0)
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  134  
> dev_warn(wvif->wdev->dev, "scan failed\n");
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  135  else if 
> (wvif->scan.req)
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  136  
> dev_dbg(wvif->wdev->dev, "scan completed\n");
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  137  else
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  138  
> dev_dbg(wvif->wdev->dev, "scan canceled\n");
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  139
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  140  
> wvif->scan.req = NULL;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  141  
> wfx_tx_unlock(wvif->wdev);
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  142  
> mutex_unlock(>wdev->conf_mutex);
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  143  
> __ieee80211_scan_completed_compat(wvif->wdev->hw, wvif->scan.status ? 1 : 0);
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  144  
> up(>scan.lock);
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  145  return;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  146  }
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  147  first = 
> *wvif->scan.curr;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  148
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  149  for (it = 
> wvif->scan.curr + 1, i = 1;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  150   it != 
> wvif->scan.end && i < HIF_API_MAX_NB_CHANNELS;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  151   ++it, ++i) {
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  152  if 
> ((*it)->band != first->band)
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  153  break;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  154  if 
> (((*it)->flags ^ first->flags) &
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  155
>   IEEE80211_CHAN_NO_IR)
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  156  break;
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  157  if 
> (!(first->flags & IEEE80211_CHAN_NO_IR) &&
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  158  
> (*it)->max_power != first->max_power)
> 1a61af0f8cbecd Jérôme Pouiller 2019-09-19  159  

Re: [PATCH v2 3/3] staging: wfx: Make some functions static in sta.c

2019-10-09 Thread Jerome Pouiller
On Wednesday 9 October 2019 15:43:35 CEST zhengbin wrote:
> Fix sparse warnings:
> 
> drivers/staging/wfx/sta.c:269:6: warning: symbol 'wfx_update_filtering_work' 
> was not declared. Should it be static?
> drivers/staging/wfx/sta.c:475:6: warning: symbol 'wfx_event_handler_work' was 
> not declared. Should it be static?
> drivers/staging/wfx/sta.c:521:6: warning: symbol 'wfx_bss_loss_work' was not 
> declared. Should it be static?
> drivers/staging/wfx/sta.c:528:6: warning: symbol 'wfx_bss_params_work' was 
> not declared. Should it be static?
> drivers/staging/wfx/sta.c:539:6: warning: symbol 
> 'wfx_set_beacon_wakeup_period_work' was not declared. Should it be static?
> drivers/staging/wfx/sta.c:732:6: warning: symbol 'wfx_unjoin_work' was not 
> declared. Should it be static?
> drivers/staging/wfx/sta.c:794:6: warning: symbol 'wfx_set_cts_work' was not 
> declared. Should it be static?
> drivers/staging/wfx/sta.c:1234:6: warning: symbol 'wfx_set_tim_work' was not 
> declared. Should it be static?
> 
> Reported-by: Hulk Robot 
> Signed-off-by: zhengbin 
> ---
>  drivers/staging/wfx/sta.c | 16 
>  1 file changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c
> index 2855d14..d19bab6 100644
> --- a/drivers/staging/wfx/sta.c
> +++ b/drivers/staging/wfx/sta.c
> @@ -269,7 +269,7 @@ void wfx_update_filtering(struct wfx_vif *wvif)
> kfree(bf_tbl);
>  }
> 
> -void wfx_update_filtering_work(struct work_struct *work)
> +static void wfx_update_filtering_work(struct work_struct *work)
>  {
> struct wfx_vif *wvif = container_of(work, struct wfx_vif, 
> update_filtering_work);
> 
> @@ -475,7 +475,7 @@ static void wfx_event_report_rssi(struct wfx_vif *wvif, 
> uint8_t raw_rcpi_rssi)
> ieee80211_cqm_rssi_notify(wvif->vif, cqm_evt, rcpi_rssi, GFP_KERNEL);
>  }
> 
> -void wfx_event_handler_work(struct work_struct *work)
> +static void wfx_event_handler_work(struct work_struct *work)
>  {
> struct wfx_vif *wvif =
> container_of(work, struct wfx_vif, event_handler_work);
> @@ -521,14 +521,14 @@ void wfx_event_handler_work(struct work_struct *work)
> __wfx_free_event_queue();
>  }
> 
> -void wfx_bss_loss_work(struct work_struct *work)
> +static void wfx_bss_loss_work(struct work_struct *work)
>  {
> struct wfx_vif *wvif = container_of(work, struct wfx_vif, 
> bss_loss_work.work);
> 
> ieee80211_connection_loss(wvif->vif);
>  }
> 
> -void wfx_bss_params_work(struct work_struct *work)
> +static void wfx_bss_params_work(struct work_struct *work)
>  {
> struct wfx_vif *wvif = container_of(work, struct wfx_vif, 
> bss_params_work);
> 
> @@ -539,7 +539,7 @@ void wfx_bss_params_work(struct work_struct *work)
> mutex_unlock(>wdev->conf_mutex);
>  }
> 
> -void wfx_set_beacon_wakeup_period_work(struct work_struct *work)
> +static void wfx_set_beacon_wakeup_period_work(struct work_struct *work)
>  {
> struct wfx_vif *wvif = container_of(work, struct wfx_vif, 
> set_beacon_wakeup_period_work);
> 
> @@ -732,7 +732,7 @@ static void wfx_do_join(struct wfx_vif *wvif)
> cfg80211_put_bss(wvif->wdev->hw->wiphy, bss);
>  }
> 
> -void wfx_unjoin_work(struct work_struct *work)
> +static void wfx_unjoin_work(struct work_struct *work)
>  {
> struct wfx_vif *wvif = container_of(work, struct wfx_vif, 
> unjoin_work);
> 
> @@ -794,7 +794,7 @@ int wfx_sta_remove(struct ieee80211_hw *hw, struct 
> ieee80211_vif *vif,
> return 0;
>  }
> 
> -void wfx_set_cts_work(struct work_struct *work)
> +static void wfx_set_cts_work(struct work_struct *work)
>  {
> struct wfx_vif *wvif = container_of(work, struct wfx_vif, 
> set_cts_work);
> u8 erp_ie[3] = { WLAN_EID_ERP_INFO, 1, 0 };
> @@ -1234,7 +1234,7 @@ static int wfx_set_tim_impl(struct wfx_vif *wvif, bool 
> aid0_bit_set)
> return 0;
>  }
> 
> -void wfx_set_tim_work(struct work_struct *work)
> +static void wfx_set_tim_work(struct work_struct *work)
>  {
> struct wfx_vif *wvif = container_of(work, struct wfx_vif, 
> set_tim_work);
> 
> --
> 2.7.4
> 

Reviewed-by: Jérôme Pouiller 

-- 
Jérôme Pouiller

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


Re: [PATCH v2 1/3] staging: wfx: Make function 'sram_write_dma_safe','load_firmware_secure' static

2019-10-09 Thread Jerome Pouiller
On Wednesday 9 October 2019 15:43:31 CEST zhengbin wrote:
> CAUTION: This email originated from outside of the organization. Do not click 
> links or open attachments unless you recognize the sender and know the 
> content is safe.
> 
> 
> Fix sparse warnings:
> 
> drivers/staging/wfx/fwio.c:83:5: warning: symbol 'sram_write_dma_safe' was 
> not declared. Should it be static?
> drivers/staging/wfx/fwio.c:229:5: warning: symbol 'load_firmware_secure' was 
> not declared. Should it be static?
> 
> Reported-by: Hulk Robot 
> Signed-off-by: zhengbin 
> ---
>  drivers/staging/wfx/fwio.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c
> index 8fb4a9f..6d82c62 100644
> --- a/drivers/staging/wfx/fwio.c
> +++ b/drivers/staging/wfx/fwio.c
> @@ -80,7 +80,8 @@ static const char * const fwio_error_strings[] = {
>   * NOTE: it may also be possible to use 'pages' from struct firmware and 
> avoid
>   * bounce buffer
>   */
> -int sram_write_dma_safe(struct wfx_dev *wdev, u32 addr, const u8 *buf, 
> size_t len)
> +static int sram_write_dma_safe(struct wfx_dev *wdev, u32 addr, const u8 *buf,
> +  size_t len)
>  {
> int ret;
> const u8 *tmp;
> @@ -226,7 +227,7 @@ static void print_boot_status(struct wfx_dev *wdev)
> }
>  }
> 
> -int load_firmware_secure(struct wfx_dev *wdev)
> +static int load_firmware_secure(struct wfx_dev *wdev)
>  {
> const struct firmware *fw = NULL;
> int header_size;
> --
> 2.7.4
> 

Reviewed-by: Jérôme Pouiller 

-- 
Jérôme Pouiller

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


Re: [PATCH v2 2/3] staging: wfx: Make function 'wfx_tx_queue_get' static

2019-10-09 Thread Jerome Pouiller
On Wednesday 9 October 2019 15:43:35 CEST zhengbin wrote:
> CAUTION: This email originated from outside of the organization. Do not click 
> links or open attachments unless you recognize the sender and know the 
> content is safe.
> 
> 
> Fix sparse warnings:
> 
> drivers/staging/wfx/queue.c:218:16: warning: symbol 'wfx_tx_queue_get' was 
> not declared. Should it be static?
> 
> Reported-by: Hulk Robot 
> Signed-off-by: zhengbin 
> ---
>  drivers/staging/wfx/queue.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/staging/wfx/queue.c b/drivers/staging/wfx/queue.c
> index 6f1be4f..c44ffdf 100644
> --- a/drivers/staging/wfx/queue.c
> +++ b/drivers/staging/wfx/queue.c
> @@ -215,7 +215,9 @@ void wfx_tx_queue_put(struct wfx_dev *wdev, struct 
> wfx_queue *queue, struct sk_b
> spin_unlock_bh(>queue.lock);
>  }
> 
> -struct sk_buff *wfx_tx_queue_get(struct wfx_dev *wdev, struct wfx_queue 
> *queue, u32 link_id_map)
> +static struct sk_buff *wfx_tx_queue_get(struct wfx_dev *wdev,
> +   struct wfx_queue *queue,
> +   u32 link_id_map)
>  {
> struct sk_buff *skb = NULL;
> struct sk_buff *item;
> --
> 2.7.4
> 

Reviewed-by: Jérôme Pouiller 

-- 
Jérôme Pouiller

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


Re: [staging:staging-testing 41/59] drivers/staging/wfx/main.c:47:14-21: ERROR: PTR_ERR applied after initialization to constant on line 42

2019-10-09 Thread Jerome Pouiller
On Wednesday 9 October 2019 08:51:10 CEST Rong Chen wrote:
> On 10/7/19 4:36 PM, Jerome Pouiller wrote:
> > On Friday 4 October 2019 12:48:32 CEST kbuild test robot wrote:
> > [...]
> >>>> drivers/staging/wfx/main.c:47:14-21: ERROR: PTR_ERR applied after 
> >>>> initialization to constant on line 42
> >> vim +47 drivers/staging/wfx/main.c
> >>
> >>  30
> >>  31  struct gpio_desc *wfx_get_gpio(struct device *dev, int override, 
> >> const char *label)
> >>  32  {
> >>  33  struct gpio_desc *ret;
> >>  34  char label_buf[256];
> >>  35
> >>  36  if (override >= 0) {
> >>  37  snprintf(label_buf, sizeof(label_buf), "wfx_%s", 
> >> label);
> >>  38  ret = ERR_PTR(devm_gpio_request_one(dev, 
> >> override, GPIOF_OUT_INIT_LOW, label_buf));
> >>  39  if (!ret)
> >>  40  ret = gpio_to_desc(override);
> >>  41  } else if (override == -1) {
> >>> 42  ret = NULL;
> >>  43  } else {
> >>  44  ret = devm_gpiod_get(dev, label, GPIOD_OUT_LOW);
> >>  45  }
> >>  46  if (IS_ERR(ret) || !ret) {
> >>> 47  if (!ret || PTR_ERR(ret) == -ENOENT)
> >>  48  dev_warn(dev, "gpio %s is not defined\n", 
> >> label);
> >>  49  else
> >>  50  dev_warn(dev, "error while requesting 
> >> gpio %s\n", label);
> >>  51  ret = NULL;
> >>  52  } else {
> >>  53  dev_dbg(dev, "using gpio %d for %s\n", 
> >> desc_to_gpio(ret), label);
> >>  54  }
> >>  55  return ret;
> >>  56  }
> >>  57
> > I think that this report is a false positive or I missed something?
> >
> Sorry for the inconvenience, but we confirmed that the error first
> appeared since commit 0096214a59.

Hi Rong,

Err... I continue to not understand the meaning of this warning. If
override != -1 then ret is not constant, isn't?

-- 
Jérôme Pouiller

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


Re: [PATCH 0/7] Fix various compilation issues with wfx driver

2019-10-09 Thread Jerome Pouiller
On Tuesday 8 October 2019 17:10:56 CEST Greg Kroah-Hartman wrote:
> On Tue, Oct 08, 2019 at 09:42:47AM +0000, Jerome Pouiller wrote:
> > From: Jérôme Pouiller 
> >
> > Most of problems are related to big-endian architectures.
> 
> kbuild still reports 2 errors with these patches applied:
> 
> Regressions in current branch:
> 
> drivers/staging/wfx/hif_tx.c:82:2-8: preceding lock on line 65

As I replied to Julia, this behavior is intended.

> drivers/staging/wfx/main.c:188:14-21: ERROR: PTR_ERR applied after 
> initialization to constant on line 183

This is a false positive, as confirmed by Dan.

You may also notice:

  drivers/staging/wfx/scan.c:207 wfx_scan_work() warn: inconsistent returns 
'sem:>scan.lock'

I also consider it as a false positive.

> Can you please fix those up as well?

Beside these ones, I will address the other reported problems.

-- 
Jérôme Pouiller

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


Re: [staging:staging-testing 50/59] drivers/staging/wfx/hif_tx.c:53:2-8: preceding lock on line 38 (fwd)

2019-10-04 Thread Jerome Pouiller
On Friday 4 October 2019 13:18:16 CEST Julia Lawall wrote:
> Hello,
> 
> Is an unlock needed on line 53?
> 
> julia
> 
> -- Forwarded message --
> Date: Fri, 4 Oct 2019 19:14:33 +0800
> From: kbuild test robot 
> To: kbu...@01.org
> Cc: Julia Lawall 
> Subject: [staging:staging-testing 50/59] drivers/staging/wfx/hif_tx.c:53:2-8:
> preceding lock on line 38
[...]
> # 
> https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/commit/?id=4f8b7fabb15df3658564a98971fc67029be1815d
> git remote add staging 
> https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
> git remote update staging
> git checkout 4f8b7fabb15df3658564a98971fc67029be1815d
> vim +53 drivers/staging/wfx/hif_tx.c
> 
[...]
> 4f8b7fabb15df3 Jérôme Pouiller 2019-09-19 @38   
> mutex_lock(>hif_cmd.lock);
[...]
> 4f8b7fabb15df3 Jérôme Pouiller 2019-09-19  51   // NOTE: no timeout is 
> catched async is enabled
> 4f8b7fabb15df3 Jérôme Pouiller 2019-09-19  52   if (async)
> 4f8b7fabb15df3 Jérôme Pouiller 2019-09-19 @53   return 0;

Hello Julia,

No, when async is enabled, unlock is done in hif_generic_confirm()
(hif_rx.c:53).

Note that async is never true in current driver code. Indeed, it implies
to unlock mutex from a different context and lockdep does not seem
to like that.

-- 
Jérôme Pouiller

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


[PATCH v3] staging: wfx: fix potential vulnerability to spectre

2019-10-11 Thread Jerome Pouiller
From: Jérôme Pouiller 

array_index_nospec() should be applied after a bound check.

Fixes: 9bca45f3d692 ("staging: wfx: allow to send 802.11 frames")
Reported-by: kbuild test robot 
Reported-by: Dan Carpenter 
Signed-off-by: Jérôme Pouiller 
---
v2: cut down commit-id to 12 characters
v3: fix missing include

 drivers/staging/wfx/wfx.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
index 489836837b0a..d678b5a08873 100644
--- a/drivers/staging/wfx/wfx.h
+++ b/drivers/staging/wfx/wfx.h
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "bh.h"
@@ -138,6 +139,7 @@ static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev 
*wdev, int vif_id)
dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id);
return NULL;
}
+   vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif));
if (!wdev->vif[vif_id]) {
dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n", 
vif_id);
return NULL;
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH v2] staging: wfx: fix potential vulnerability to spectre

2019-10-11 Thread Jerome Pouiller
From: Jérôme Pouiller 

array_index_nospec() should be applied after a bound check.

Fixes: 9bca45f3d692 ("staging: wfx: allow to send 802.11 frames")
Reported-by: kbuild test robot 
Reported-by: Dan Carpenter 
Signed-off-by: Jérôme Pouiller 
---
v2: cut down commit-id to 12 characters

 drivers/staging/wfx/wfx.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
index 489836837b0a..4c0f2836015c 100644
--- a/drivers/staging/wfx/wfx.h
+++ b/drivers/staging/wfx/wfx.h
@@ -138,6 +138,7 @@ static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev 
*wdev, int vif_id)
dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id);
return NULL;
}
+   vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif));
if (!wdev->vif[vif_id]) {
dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n", 
vif_id);
return NULL;
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH] staging: wfx: fix potential vulnerability to spectre

2019-10-11 Thread Jerome Pouiller
On Friday 11 October 2019 14:10:35 CEST Greg Kroah-Hartman wrote:
> On Fri, Oct 11, 2019 at 10:15:54AM +0000, Jerome Pouiller wrote:
> > From: Jérôme Pouiller 
> >
> > array_index_nospec() should be applied after a bound check.
> >
> > Fixes: 9bca45f3d6924f19f29c0d019e961af3f41bdc9e ("staging: wfx: allow to 
> > send 802.11 frames")
> 
> No need for the full sha1, this should be:
> Fixes: 9bca45f3d692 ("staging: wfx: allow to send 802.11 frames")

I copy-pasted information from kbuild robot notification.

I suggest that commit-id in robot notification is also cut down to 12
characters. Or even better, to use this snippet:

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot 
Fixes: 9bca45f3d692 ("staging: wfx: allow to send 802.11 frames")

(I added l...@lists.01.org in CC but, I am not sure it is the correct
ML. I am sorry if it is not the case)

-- 
Jérôme Pouiller

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


[PATCH] staging: wfx: fix potential vulnerability to spectre

2019-10-11 Thread Jerome Pouiller
From: Jérôme Pouiller 

array_index_nospec() should be applied after a bound check.

Fixes: 9bca45f3d6924f19f29c0d019e961af3f41bdc9e ("staging: wfx: allow to send 
802.11 frames")
Reported-by: kbuild test robot 
Reported-by: Dan Carpenter 
Signed-off-by: Jérôme Pouiller 
---
 drivers/staging/wfx/wfx.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
index 489836837b0a..4c0f2836015c 100644
--- a/drivers/staging/wfx/wfx.h
+++ b/drivers/staging/wfx/wfx.h
@@ -138,6 +138,7 @@ static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev 
*wdev, int vif_id)
dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id);
return NULL;
}
+   vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif));
if (!wdev->vif[vif_id]) {
dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n", 
vif_id);
return NULL;
-- 
2.20.1
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


  1   2   3   4   5   6   7   8   >