2020-03-02 16:35:49

by Ajay Singh

[permalink] [raw]
Subject: [PATCH v4 00/18] wilc1000: move out of staging

From: Ajay Singh <[email protected]>

This patch series is to review and move wilc1000 driver out of staging.
Most of the review comments received in [1] & [2] are addressed in the
latest code. Please review and provide your inputs.

[1]. https://lore.kernel.org/linux-wireless/[email protected]/
[2]. https://lore.kernel.org/linux-wireless/[email protected]/

Changes since v3:
- handle few Smatch static checker reported issues.
- use flexible-array member instead of zero-length array.

Changes since v2:
- use 'struct' to extract FW info from received commands.
- make use of C style comments instead of C++.
- remove use of bool type for firmware struct.
- deleted unused code related to interrupt handling.
- make use of RCU list to maintain interfaces list.
- remove 'wilc_' prefix from file name.
- added 'WILC_' prefix for header guard macro.
- remove use of infinite loops(i.e. while(1)).
- move firmware realted struct to a separate file.
- refactor SPI command handling by using 'struct'.
- use different functions to handle different SPI commands.
- cleanup spi.c and sdio.c by removing unused code.
- remove use of vendor specific IE for p2p handling.
- refactor p2p related code to avoid use of buf pointer operation.
- make use of FIELD_GET/PREP macro.
- use #define instead of magic values.
- use YAML schemes for DT binding documentation.
- deleted unused code from spi.c and sdio.c.
- added changes for few issues reported by smatch static code analyzer.

Changes since v1:
- remove use of shadow buffer to keep scan result.
- remove internal messaging flow to handle cfg80211_ops.
- make use of cfg80211 provide API.
- use 'struct' for packing firmware commands.
- make use of kernel API's and Macro.
- remove unnecessary log messages
- supported dynamically add/remove interfaces.
- cleanup and deleted around 3.3k lines of code.

Ajay Singh (18):
wilc1000: add hif.h
wilc1000: add hif.c
wilc1000: add wlan_if.h
wilc1000: add wlan_cfg.h
wilc1000: add wlan_cfg.c
wilc1000: add cfg80211.c
wilc1000: add cfg80211.h
wilc1000: add netdev.h
wilc1000: add netdev.c
wilc1000: add mon.c
wilc1000: add spi.c
wilc1000: add wlan.h
wilc1000: add wlan.c
wilc1000: add sdio.c
wilc1000: add fw.h
dt: bindings: net: add microchip,wilc1000,sdio.yaml
dt: bindings: net: add microchip,wilc1000,spi.yaml
wilc1000: add Makefile and Kconfig files for wilc1000 compilation

.../net/wireless/microchip,wilc1000,sdio.yaml | 68 +
.../net/wireless/microchip,wilc1000,spi.yaml | 61 +
drivers/net/wireless/Kconfig | 1 +
drivers/net/wireless/Makefile | 1 +
drivers/net/wireless/microchip/Kconfig | 15 +
drivers/net/wireless/microchip/Makefile | 2 +
.../net/wireless/microchip/wilc1000/Kconfig | 42 +
.../net/wireless/microchip/wilc1000/Makefile | 14 +
.../wireless/microchip/wilc1000/cfg80211.c | 1850 ++++++++++++++++
.../wireless/microchip/wilc1000/cfg80211.h | 29 +
drivers/net/wireless/microchip/wilc1000/fw.h | 119 +
drivers/net/wireless/microchip/wilc1000/hif.c | 1959 +++++++++++++++++
drivers/net/wireless/microchip/wilc1000/hif.h | 214 ++
drivers/net/wireless/microchip/wilc1000/mon.c | 260 +++
.../net/wireless/microchip/wilc1000/netdev.c | 940 ++++++++
.../net/wireless/microchip/wilc1000/netdev.h | 295 +++
.../net/wireless/microchip/wilc1000/sdio.c | 1030 +++++++++
drivers/net/wireless/microchip/wilc1000/spi.c | 1001 +++++++++
.../net/wireless/microchip/wilc1000/wlan.c | 1238 +++++++++++
.../net/wireless/microchip/wilc1000/wlan.h | 398 ++++
.../wireless/microchip/wilc1000/wlan_cfg.c | 413 ++++
.../wireless/microchip/wilc1000/wlan_cfg.h | 54 +
.../net/wireless/microchip/wilc1000/wlan_if.h | 803 +++++++
drivers/staging/Kconfig | 2 -
drivers/staging/Makefile | 1 -
25 files changed, 10807 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml
create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml
create mode 100644 drivers/net/wireless/microchip/Kconfig
create mode 100644 drivers/net/wireless/microchip/Makefile
create mode 100644 drivers/net/wireless/microchip/wilc1000/Kconfig
create mode 100644 drivers/net/wireless/microchip/wilc1000/Makefile
create mode 100644 drivers/net/wireless/microchip/wilc1000/cfg80211.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/cfg80211.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/fw.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/hif.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/hif.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/mon.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/netdev.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/netdev.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/sdio.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/spi.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wlan.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wlan.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/wlan_cfg.c
create mode 100644 drivers/net/wireless/microchip/wilc1000/wlan_cfg.h
create mode 100644 drivers/net/wireless/microchip/wilc1000/wlan_if.h

--
2.24.0


2020-03-02 16:35:52

by Ajay Singh

[permalink] [raw]
Subject: [PATCH v4 16/18] dt: bindings: net: add microchip,wilc1000,sdio.yaml

From: Ajay Singh <[email protected]>

Moved '/drivers/staging/wilc1000/microchip,wilc1000,sdio.yaml' to
'Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml'.

Signed-off-by: Ajay Singh <[email protected]>
---
.../net/wireless/microchip,wilc1000,sdio.yaml | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml

diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml
new file mode 100644
index 000000000000..b338f569f7e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/wireless/microchip,wilc1000,sdio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip WILC wireless SDIO devicetree bindings
+
+maintainers:
+ - Adham Abozaeid <[email protected]>
+ - Ajay Singh <[email protected]>
+
+description:
+ The wilc1000 chips can be connected via SDIO. The node is used to
+ specify child node to the SDIO controller that connects the device
+ to the system.
+
+properties:
+ compatible:
+ const: microchip,wilc1000-sdio
+
+ irq-gpios:
+ description: The GPIO phandle connect to a host IRQ.
+ maxItems: 1
+
+ reg:
+ description: Slot ID used in the controller.
+ maxItems: 1
+
+ clocks:
+ description: phandle to the clock connected on rtc clock line.
+ maxItems: 1
+
+ bus-width:
+ description: The number of data lines wired up the slot.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - enum: [1, 4, 8]
+ - default: 1
+
+required:
+ - compatible
+ - irq-gpios
+ - reg
+
+examples:
+ - |
+ mmc1: mmc@fc000000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3>;
+ non-removable;
+ vmmc-supply = <&vcc_mmc1_reg>;
+ vqmmc-supply = <&vcc_3v3_reg>;
+ status = "okay";
+ wilc_sdio@0 {
+ compatible = "microchip,wilc1000-sdio";
+ irq-gpios = <&pioC 27 0>;
+ reg = <0>;
+ clocks = <&pck1>;
+ clock-names = "rtc_clk";
+ assigned-clocks = <&pck1>;
+ assigned-clock-rates = <32768>;
+ status = "okay";
+ bus-width = <4>;
+ };
+ };
--
2.24.0

2020-03-02 16:35:54

by Ajay Singh

[permalink] [raw]
Subject: [PATCH v4 11/18] wilc1000: add spi.c

From: Ajay Singh <[email protected]>

Moved 'drivers/staging/wilc1000/spi.c' to
'drivers/net/wireless/microchip/wilc1000/spi.c'.

Signed-off-by: Ajay Singh <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/spi.c | 1001 +++++++++++++++++
1 file changed, 1001 insertions(+)
create mode 100644 drivers/net/wireless/microchip/wilc1000/spi.c

diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
new file mode 100644
index 000000000000..dfd25df75780
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -0,0 +1,1001 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+
+#include "netdev.h"
+#include "cfg80211.h"
+
+struct wilc_spi {
+ int crc_off;
+};
+
+static const struct wilc_hif_func wilc_hif_spi;
+
+/********************************************
+ *
+ * Crc7
+ *
+ ********************************************/
+
+static const u8 crc7_syndrome_table[256] = {
+ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
+ 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
+ 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
+ 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
+ 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
+ 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
+ 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
+ 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
+ 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
+ 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
+ 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
+ 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
+ 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
+ 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
+ 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
+ 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
+ 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
+ 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
+ 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
+ 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
+ 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
+ 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
+ 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
+ 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
+ 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
+ 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
+ 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
+ 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
+ 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
+ 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
+ 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
+ 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
+};
+
+static u8 crc7_byte(u8 crc, u8 data)
+{
+ return crc7_syndrome_table[(crc << 1) ^ data];
+}
+
+static u8 crc7(u8 crc, const u8 *buffer, u32 len)
+{
+ while (len--)
+ crc = crc7_byte(crc, *buffer++);
+ return crc;
+}
+
+static u8 wilc_get_crc7(u8 *buffer, u32 len)
+{
+ return crc7(0x7f, (const u8 *)buffer, len) << 1;
+}
+
+/********************************************
+ *
+ * Spi protocol Function
+ *
+ ********************************************/
+
+#define CMD_DMA_WRITE 0xc1
+#define CMD_DMA_READ 0xc2
+#define CMD_INTERNAL_WRITE 0xc3
+#define CMD_INTERNAL_READ 0xc4
+#define CMD_TERMINATE 0xc5
+#define CMD_REPEAT 0xc6
+#define CMD_DMA_EXT_WRITE 0xc7
+#define CMD_DMA_EXT_READ 0xc8
+#define CMD_SINGLE_WRITE 0xc9
+#define CMD_SINGLE_READ 0xca
+#define CMD_RESET 0xcf
+
+#define DATA_PKT_SZ_256 256
+#define DATA_PKT_SZ_512 512
+#define DATA_PKT_SZ_1K 1024
+#define DATA_PKT_SZ_4K (4 * 1024)
+#define DATA_PKT_SZ_8K (8 * 1024)
+#define DATA_PKT_SZ DATA_PKT_SZ_8K
+
+#define USE_SPI_DMA 0
+
+#define WILC_SPI_COMMAND_STAT_SUCCESS 0
+#define WILC_GET_RESP_HDR_START(h) (((h) >> 4) & 0xf)
+
+struct wilc_spi_cmd {
+ u8 cmd_type;
+ union {
+ struct {
+ u8 addr[3];
+ u8 crc[];
+ } __packed simple_cmd;
+ struct {
+ u8 addr[3];
+ u8 size[2];
+ u8 crc[];
+ } __packed dma_cmd;
+ struct {
+ u8 addr[3];
+ u8 size[3];
+ u8 crc[];
+ } __packed dma_cmd_ext;
+ struct {
+ u8 addr[2];
+ __be32 data;
+ u8 crc[];
+ } __packed internal_w_cmd;
+ struct {
+ u8 addr[3];
+ __be32 data;
+ u8 crc[];
+ } __packed w_cmd;
+ } u;
+} __packed;
+
+struct wilc_spi_read_rsp_data {
+ u8 rsp_cmd_type;
+ u8 status;
+ u8 resp_header;
+ u8 resp_data[4];
+ u8 crc[];
+} __packed;
+
+struct wilc_spi_rsp_data {
+ u8 rsp_cmd_type;
+ u8 status;
+} __packed;
+
+static int wilc_bus_probe(struct spi_device *spi)
+{
+ int ret;
+ struct wilc *wilc;
+ struct gpio_desc *gpio;
+ struct wilc_spi *spi_priv;
+
+ spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL);
+ if (!spi_priv)
+ return -ENOMEM;
+
+ gpio = gpiod_get(&spi->dev, "irq", GPIOD_IN);
+ if (IS_ERR(gpio)) {
+ /* get the GPIO descriptor from hardcode GPIO number */
+ gpio = gpio_to_desc(GPIO_NUM);
+ if (!gpio)
+ dev_err(&spi->dev, "failed to get the irq gpio\n");
+ }
+
+ ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi);
+ if (ret) {
+ kfree(spi_priv);
+ return ret;
+ }
+
+ spi_set_drvdata(spi, wilc);
+ wilc->dev = &spi->dev;
+ wilc->bus_data = spi_priv;
+ wilc->gpio_irq = gpio;
+
+ wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk");
+ if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else if (!IS_ERR(wilc->rtc_clk))
+ clk_prepare_enable(wilc->rtc_clk);
+
+ return 0;
+}
+
+static int wilc_bus_remove(struct spi_device *spi)
+{
+ struct wilc *wilc = spi_get_drvdata(spi);
+
+ /* free the GPIO in module remove */
+ if (wilc->gpio_irq)
+ gpiod_put(wilc->gpio_irq);
+
+ if (!IS_ERR(wilc->rtc_clk))
+ clk_disable_unprepare(wilc->rtc_clk);
+
+ wilc_netdev_cleanup(wilc);
+ return 0;
+}
+
+static const struct of_device_id wilc_of_match[] = {
+ { .compatible = "microchip,wilc1000-spi", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, wilc_of_match);
+
+static struct spi_driver wilc_spi_driver = {
+ .driver = {
+ .name = MODALIAS,
+ .of_match_table = wilc_of_match,
+ },
+ .probe = wilc_bus_probe,
+ .remove = wilc_bus_remove,
+};
+module_spi_driver(wilc_spi_driver);
+MODULE_LICENSE("GPL");
+
+static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int ret;
+ struct spi_message msg;
+
+ if (len > 0 && b) {
+ struct spi_transfer tr = {
+ .tx_buf = b,
+ .len = len,
+ .delay_usecs = 0,
+ };
+ char *r_buffer = kzalloc(len, GFP_KERNEL);
+
+ if (!r_buffer)
+ return -ENOMEM;
+
+ tr.rx_buf = r_buffer;
+ dev_dbg(&spi->dev, "Request writing %d bytes\n", len);
+
+ memset(&msg, 0, sizeof(msg));
+ spi_message_init(&msg);
+ msg.spi = spi;
+ msg.is_dma_mapped = USE_SPI_DMA;
+ spi_message_add_tail(&tr, &msg);
+
+ ret = spi_sync(spi, &msg);
+ if (ret < 0)
+ dev_err(&spi->dev, "SPI transaction failed\n");
+
+ kfree(r_buffer);
+ } else {
+ dev_err(&spi->dev,
+ "can't write data with the following length: %d\n",
+ len);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int ret;
+
+ if (rlen > 0) {
+ struct spi_message msg;
+ struct spi_transfer tr = {
+ .rx_buf = rb,
+ .len = rlen,
+ .delay_usecs = 0,
+
+ };
+ char *t_buffer = kzalloc(rlen, GFP_KERNEL);
+
+ if (!t_buffer)
+ return -ENOMEM;
+
+ tr.tx_buf = t_buffer;
+
+ memset(&msg, 0, sizeof(msg));
+ spi_message_init(&msg);
+ msg.spi = spi;
+ msg.is_dma_mapped = USE_SPI_DMA;
+ spi_message_add_tail(&tr, &msg);
+
+ ret = spi_sync(spi, &msg);
+ if (ret < 0)
+ dev_err(&spi->dev, "SPI transaction failed\n");
+ kfree(t_buffer);
+ } else {
+ dev_err(&spi->dev,
+ "can't read data with the following length: %u\n",
+ rlen);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int ret;
+
+ if (rlen > 0) {
+ struct spi_message msg;
+ struct spi_transfer tr = {
+ .rx_buf = rb,
+ .tx_buf = wb,
+ .len = rlen,
+ .bits_per_word = 8,
+ .delay_usecs = 0,
+
+ };
+
+ memset(&msg, 0, sizeof(msg));
+ spi_message_init(&msg);
+ msg.spi = spi;
+ msg.is_dma_mapped = USE_SPI_DMA;
+
+ spi_message_add_tail(&tr, &msg);
+ ret = spi_sync(spi, &msg);
+ if (ret < 0)
+ dev_err(&spi->dev, "SPI transaction failed\n");
+ } else {
+ dev_err(&spi->dev,
+ "can't read data with the following length: %u\n",
+ rlen);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ int ix, nbytes;
+ int result = 0;
+ u8 cmd, order, crc[2] = {0};
+
+ /*
+ * Data
+ */
+ ix = 0;
+ do {
+ if (sz <= DATA_PKT_SZ) {
+ nbytes = sz;
+ order = 0x3;
+ } else {
+ nbytes = DATA_PKT_SZ;
+ if (ix == 0)
+ order = 0x1;
+ else
+ order = 0x02;
+ }
+
+ /*
+ * Write command
+ */
+ cmd = 0xf0;
+ cmd |= order;
+
+ if (wilc_spi_tx(wilc, &cmd, 1)) {
+ dev_err(&spi->dev,
+ "Failed data block cmd write, bus error...\n");
+ result = -EINVAL;
+ break;
+ }
+
+ /*
+ * Write data
+ */
+ if (wilc_spi_tx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev,
+ "Failed data block write, bus error...\n");
+ result = -EINVAL;
+ break;
+ }
+
+ /*
+ * Write Crc
+ */
+ if (!spi_priv->crc_off) {
+ if (wilc_spi_tx(wilc, crc, 2)) {
+ dev_err(&spi->dev, "Failed data block crc write, bus error...\n");
+ result = -EINVAL;
+ break;
+ }
+ }
+
+ /*
+ * No need to wait for response
+ */
+ ix += nbytes;
+ sz -= nbytes;
+ } while (sz);
+
+ return result;
+}
+
+/********************************************
+ *
+ * Spi Internal Read/Write Function
+ *
+ ********************************************/
+static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b,
+ u8 clockless)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ u8 wb[32], rb[32];
+ int cmd_len, resp_len;
+ u8 crc[2];
+ struct wilc_spi_cmd *c;
+ struct wilc_spi_read_rsp_data *r;
+
+ memset(wb, 0x0, sizeof(wb));
+ memset(rb, 0x0, sizeof(rb));
+ c = (struct wilc_spi_cmd *)wb;
+ c->cmd_type = cmd;
+ if (cmd == CMD_SINGLE_READ) {
+ c->u.simple_cmd.addr[0] = adr >> 16;
+ c->u.simple_cmd.addr[1] = adr >> 8;
+ c->u.simple_cmd.addr[2] = adr;
+ } else if (cmd == CMD_INTERNAL_READ) {
+ c->u.simple_cmd.addr[0] = adr >> 8;
+ if (clockless == 1)
+ c->u.simple_cmd.addr[0] |= BIT(7);
+ c->u.simple_cmd.addr[1] = adr;
+ c->u.simple_cmd.addr[2] = 0x0;
+ } else {
+ dev_err(&spi->dev, "cmd [%x] not supported\n", cmd);
+ return -EINVAL;
+ }
+
+ cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc);
+ resp_len = sizeof(*r);
+ if (!spi_priv->crc_off) {
+ c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len);
+ cmd_len += 1;
+ resp_len += 2;
+ }
+
+ if (cmd_len + resp_len > ARRAY_SIZE(wb)) {
+ dev_err(&spi->dev,
+ "spi buffer size too small (%d) (%d) (%zu)\n",
+ cmd_len, resp_len, ARRAY_SIZE(wb));
+ return -EINVAL;
+ }
+
+ if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) {
+ dev_err(&spi->dev, "Failed cmd write, bus error...\n");
+ return -EINVAL;
+ }
+
+ r = (struct wilc_spi_read_rsp_data *)&rb[cmd_len];
+ if (r->rsp_cmd_type != cmd) {
+ dev_err(&spi->dev,
+ "Failed cmd response, cmd (%02x), resp (%02x)\n",
+ cmd, r->rsp_cmd_type);
+ return -EINVAL;
+ }
+
+ if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) {
+ dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
+ r->status);
+ return -EINVAL;
+ }
+
+ if (WILC_GET_RESP_HDR_START(r->resp_header) != 0xf) {
+ dev_err(&spi->dev, "Error, data read response (%02x)\n",
+ r->resp_header);
+ return -EINVAL;
+ }
+
+ if (b)
+ memcpy(b, r->resp_data, 4);
+
+ if (!spi_priv->crc_off)
+ memcpy(crc, r->crc, 2);
+
+ return 0;
+}
+
+static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data,
+ u8 clockless)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ u8 wb[32], rb[32];
+ int cmd_len, resp_len;
+ struct wilc_spi_cmd *c;
+ struct wilc_spi_rsp_data *r;
+
+ memset(wb, 0x0, sizeof(wb));
+ memset(rb, 0x0, sizeof(rb));
+ c = (struct wilc_spi_cmd *)wb;
+ c->cmd_type = cmd;
+ if (cmd == CMD_INTERNAL_WRITE) {
+ c->u.internal_w_cmd.addr[0] = adr >> 8;
+ if (clockless == 1)
+ c->u.internal_w_cmd.addr[0] |= BIT(7);
+
+ c->u.internal_w_cmd.addr[1] = adr;
+ c->u.internal_w_cmd.data = cpu_to_be32(data);
+ cmd_len = offsetof(struct wilc_spi_cmd, u.internal_w_cmd.crc);
+ if (!spi_priv->crc_off)
+ c->u.internal_w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len);
+ } else if (cmd == CMD_SINGLE_WRITE) {
+ c->u.w_cmd.addr[0] = adr >> 16;
+ c->u.w_cmd.addr[1] = adr >> 8;
+ c->u.w_cmd.addr[2] = adr;
+ c->u.w_cmd.data = cpu_to_be32(data);
+ cmd_len = offsetof(struct wilc_spi_cmd, u.w_cmd.crc);
+ if (!spi_priv->crc_off)
+ c->u.w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len);
+ } else {
+ dev_err(&spi->dev, "write cmd [%x] not supported\n", cmd);
+ return -EINVAL;
+ }
+
+ if (!spi_priv->crc_off)
+ cmd_len += 1;
+
+ resp_len = sizeof(*r);
+
+ if (cmd_len + resp_len > ARRAY_SIZE(wb)) {
+ dev_err(&spi->dev,
+ "spi buffer size too small (%d) (%d) (%zu)\n",
+ cmd_len, resp_len, ARRAY_SIZE(wb));
+ return -EINVAL;
+ }
+
+ if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) {
+ dev_err(&spi->dev, "Failed cmd write, bus error...\n");
+ return -EINVAL;
+ }
+
+ r = (struct wilc_spi_rsp_data *)&rb[cmd_len];
+ if (r->rsp_cmd_type != cmd) {
+ dev_err(&spi->dev,
+ "Failed cmd response, cmd (%02x), resp (%02x)\n",
+ cmd, r->rsp_cmd_type);
+ return -EINVAL;
+ }
+
+ if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) {
+ dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
+ r->status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ u8 wb[32], rb[32];
+ int cmd_len, resp_len;
+ int retry, ix = 0;
+ u8 crc[2];
+ struct wilc_spi_cmd *c;
+ struct wilc_spi_rsp_data *r;
+
+ memset(wb, 0x0, sizeof(wb));
+ memset(rb, 0x0, sizeof(rb));
+ c = (struct wilc_spi_cmd *)wb;
+ c->cmd_type = cmd;
+ if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_READ) {
+ c->u.dma_cmd.addr[0] = adr >> 16;
+ c->u.dma_cmd.addr[1] = adr >> 8;
+ c->u.dma_cmd.addr[2] = adr;
+ c->u.dma_cmd.size[0] = sz >> 8;
+ c->u.dma_cmd.size[1] = sz;
+ cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd.crc);
+ if (!spi_priv->crc_off)
+ c->u.dma_cmd.crc[0] = wilc_get_crc7(wb, cmd_len);
+ } else if (cmd == CMD_DMA_EXT_WRITE || cmd == CMD_DMA_EXT_READ) {
+ c->u.dma_cmd_ext.addr[0] = adr >> 16;
+ c->u.dma_cmd_ext.addr[1] = adr >> 8;
+ c->u.dma_cmd_ext.addr[2] = adr;
+ c->u.dma_cmd_ext.size[0] = sz >> 16;
+ c->u.dma_cmd_ext.size[1] = sz >> 8;
+ c->u.dma_cmd_ext.size[2] = sz;
+ cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd_ext.crc);
+ if (!spi_priv->crc_off)
+ c->u.dma_cmd_ext.crc[0] = wilc_get_crc7(wb, cmd_len);
+ } else {
+ dev_err(&spi->dev, "dma read write cmd [%x] not supported\n",
+ cmd);
+ return -EINVAL;
+ }
+ if (!spi_priv->crc_off)
+ cmd_len += 1;
+
+ resp_len = sizeof(*r);
+
+ if (cmd_len + resp_len > ARRAY_SIZE(wb)) {
+ dev_err(&spi->dev, "spi buffer size too small (%d)(%d) (%zu)\n",
+ cmd_len, resp_len, ARRAY_SIZE(wb));
+ return -EINVAL;
+ }
+
+ if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) {
+ dev_err(&spi->dev, "Failed cmd write, bus error...\n");
+ return -EINVAL;
+ }
+
+ r = (struct wilc_spi_rsp_data *)&rb[cmd_len];
+ if (r->rsp_cmd_type != cmd) {
+ dev_err(&spi->dev,
+ "Failed cmd response, cmd (%02x), resp (%02x)\n",
+ cmd, r->rsp_cmd_type);
+ return -EINVAL;
+ }
+
+ if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) {
+ dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
+ r->status);
+ return -EINVAL;
+ }
+
+ if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_EXT_WRITE)
+ return 0;
+
+ while (sz > 0) {
+ int nbytes;
+ u8 rsp;
+
+ if (sz <= DATA_PKT_SZ)
+ nbytes = sz;
+ else
+ nbytes = DATA_PKT_SZ;
+
+ /*
+ * Data Response header
+ */
+ retry = 100;
+ do {
+ if (wilc_spi_rx(wilc, &rsp, 1)) {
+ dev_err(&spi->dev,
+ "Failed resp read, bus err\n");
+ return -EINVAL;
+ }
+ if (WILC_GET_RESP_HDR_START(rsp) == 0xf)
+ break;
+ } while (retry--);
+
+ /*
+ * Read bytes
+ */
+ if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev,
+ "Failed block read, bus err\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Read Crc
+ */
+ if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) {
+ dev_err(&spi->dev,
+ "Failed block crc read, bus err\n");
+ return -EINVAL;
+ }
+
+ ix += nbytes;
+ sz -= nbytes;
+ }
+ return 0;
+}
+
+static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result;
+ u8 cmd = CMD_SINGLE_READ;
+ u8 clockless = 0;
+
+ if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) {
+ /* Clockless register */
+ cmd = CMD_INTERNAL_READ;
+ clockless = 1;
+ }
+
+ result = wilc_spi_single_read(wilc, cmd, addr, data, clockless);
+ if (result) {
+ dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr);
+ return result;
+ }
+
+ le32_to_cpus(data);
+
+ return 0;
+}
+
+static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result;
+
+ if (size <= 4)
+ return -EINVAL;
+
+ result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_READ, addr, buf, size);
+ if (result) {
+ dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr);
+ return result;
+ }
+
+ return 0;
+}
+
+static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result;
+
+ result = wilc_spi_write_cmd(wilc, CMD_INTERNAL_WRITE, adr, dat, 0);
+ if (result) {
+ dev_err(&spi->dev, "Failed internal write cmd...\n");
+ return result;
+ }
+
+ return 0;
+}
+
+static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result;
+
+ result = wilc_spi_single_read(wilc, CMD_INTERNAL_READ, adr, data, 0);
+ if (result) {
+ dev_err(&spi->dev, "Failed internal read cmd...\n");
+ return result;
+ }
+
+ le32_to_cpus(data);
+
+ return 0;
+}
+
+/********************************************
+ *
+ * Spi interfaces
+ *
+ ********************************************/
+
+static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result;
+ u8 cmd = CMD_SINGLE_WRITE;
+ u8 clockless = 0;
+
+ if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) {
+ /* Clockless register */
+ cmd = CMD_INTERNAL_WRITE;
+ clockless = 1;
+ }
+
+ result = wilc_spi_write_cmd(wilc, cmd, addr, data, clockless);
+ if (result) {
+ dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr);
+ return result;
+ }
+
+ return 0;
+}
+
+static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result;
+
+ /*
+ * has to be greated than 4
+ */
+ if (size <= 4)
+ return -EINVAL;
+
+ result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size);
+ if (result) {
+ dev_err(&spi->dev,
+ "Failed cmd, write block (%08x)...\n", addr);
+ return result;
+ }
+
+ /*
+ * Data
+ */
+ result = spi_data_write(wilc, buf, size);
+ if (result) {
+ dev_err(&spi->dev, "Failed block data write...\n");
+ return result;
+ }
+
+ return 0;
+}
+
+/********************************************
+ *
+ * Bus interfaces
+ *
+ ********************************************/
+
+static int wilc_spi_deinit(struct wilc *wilc)
+{
+ /*
+ * TODO:
+ */
+ return 0;
+}
+
+static int wilc_spi_init(struct wilc *wilc, bool resume)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ u32 reg;
+ u32 chipid;
+ static int isinit;
+ int ret;
+
+ if (isinit) {
+ ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid);
+ if (ret)
+ dev_err(&spi->dev, "Fail cmd read chip id...\n");
+
+ return ret;
+ }
+
+ /*
+ * configure protocol
+ */
+
+ /*
+ * TODO: We can remove the CRC trials if there is a definite
+ * way to reset
+ */
+ /* the SPI to it's initial value. */
+ ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg);
+ if (ret) {
+ /*
+ * Read failed. Try with CRC off. This might happen when module
+ * is removed but chip isn't reset
+ */
+ spi_priv->crc_off = 1;
+ dev_err(&spi->dev,
+ "Failed read with CRC on, retrying with CRC off\n");
+ ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg);
+ if (ret) {
+ /*
+ * Read failed with both CRC on and off,
+ * something went bad
+ */
+ dev_err(&spi->dev, "Failed internal read protocol\n");
+ return ret;
+ }
+ }
+ if (spi_priv->crc_off == 0) {
+ reg &= ~0xc; /* disable crc checking */
+ reg &= ~0x70;
+ reg |= (0x5 << 4);
+ ret = spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg);
+ if (ret) {
+ dev_err(&spi->dev,
+ "[wilc spi %d]: Failed internal write reg\n",
+ __LINE__);
+ return ret;
+ }
+ spi_priv->crc_off = 1;
+ }
+
+ /*
+ * make sure can read back chip id correctly
+ */
+ ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid);
+ if (ret) {
+ dev_err(&spi->dev, "Fail cmd read chip id...\n");
+ return ret;
+ }
+
+ isinit = 1;
+
+ return 0;
+}
+
+static int wilc_spi_read_size(struct wilc *wilc, u32 *size)
+{
+ int ret;
+
+ ret = spi_internal_read(wilc,
+ WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, size);
+ *size = FIELD_GET(IRQ_DMA_WD_CNT_MASK, *size);
+
+ return ret;
+}
+
+static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
+{
+ return spi_internal_read(wilc, WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE,
+ int_status);
+}
+
+static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
+{
+ return spi_internal_write(wilc, WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE,
+ val);
+}
+
+static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ u32 reg;
+ int ret, i;
+
+ if (nint > MAX_NUM_INT) {
+ dev_err(&spi->dev, "Too many interrupts (%d)...\n", nint);
+ return -EINVAL;
+ }
+
+ /*
+ * interrupt pin mux select
+ */
+ ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, &reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed read reg (%08x)...\n",
+ WILC_PIN_MUX_0);
+ return ret;
+ }
+ reg |= BIT(8);
+ ret = wilc_spi_write_reg(wilc, WILC_PIN_MUX_0, reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed write reg (%08x)...\n",
+ WILC_PIN_MUX_0);
+ return ret;
+ }
+
+ /*
+ * interrupt enable
+ */
+ ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, &reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed read reg (%08x)...\n",
+ WILC_INTR_ENABLE);
+ return ret;
+ }
+
+ for (i = 0; (i < 5) && (nint > 0); i++, nint--)
+ reg |= (BIT((27 + i)));
+
+ ret = wilc_spi_write_reg(wilc, WILC_INTR_ENABLE, reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed write reg (%08x)...\n",
+ WILC_INTR_ENABLE);
+ return ret;
+ }
+ if (nint) {
+ ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed read reg (%08x)...\n",
+ WILC_INTR2_ENABLE);
+ return ret;
+ }
+
+ for (i = 0; (i < 3) && (nint > 0); i++, nint--)
+ reg |= BIT(i);
+
+ ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed write reg (%08x)...\n",
+ WILC_INTR2_ENABLE);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Global spi HIF function table */
+static const struct wilc_hif_func wilc_hif_spi = {
+ .hif_init = wilc_spi_init,
+ .hif_deinit = wilc_spi_deinit,
+ .hif_read_reg = wilc_spi_read_reg,
+ .hif_write_reg = wilc_spi_write_reg,
+ .hif_block_rx = wilc_spi_read,
+ .hif_block_tx = wilc_spi_write,
+ .hif_read_int = wilc_spi_read_int,
+ .hif_clear_int_ext = wilc_spi_clear_int_ext,
+ .hif_read_size = wilc_spi_read_size,
+ .hif_block_tx_ext = wilc_spi_write,
+ .hif_block_rx_ext = wilc_spi_read,
+ .hif_sync_ext = wilc_spi_sync_ext,
+};
--
2.24.0

2020-03-02 16:35:57

by Ajay Singh

[permalink] [raw]
Subject: [PATCH v4 01/18] wilc1000: add hif.h

From: Ajay Singh <[email protected]>

Moved 'drivers/staging/wilc1000/hif.h' to
'drivers/net/wireless/microchip/wilc1000/hif.h'.

Signed-off-by: Ajay Singh <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/hif.h | 214 ++++++++++++++++++
1 file changed, 214 insertions(+)
create mode 100644 drivers/net/wireless/microchip/wilc1000/hif.h

diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h
new file mode 100644
index 000000000000..db9179171f05
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc1000/hif.h
@@ -0,0 +1,214 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries
+ * All rights reserved.
+ */
+
+#ifndef WILC_HIF_H
+#define WILC_HIF_H
+#include <linux/ieee80211.h>
+#include "wlan_if.h"
+
+enum {
+ WILC_IDLE_MODE = 0x0,
+ WILC_AP_MODE = 0x1,
+ WILC_STATION_MODE = 0x2,
+ WILC_GO_MODE = 0x3,
+ WILC_CLIENT_MODE = 0x4
+};
+
+#define WILC_MAX_NUM_PROBED_SSID 10
+
+#define WILC_TX_MIC_KEY_LEN 8
+#define WILC_RX_MIC_KEY_LEN 8
+
+#define WILC_ADD_STA_LENGTH 40
+#define WILC_NUM_CONCURRENT_IFC 2
+
+enum {
+ WILC_SET_CFG = 0,
+ WILC_GET_CFG
+};
+
+#define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256
+
+struct rf_info {
+ u8 link_speed;
+ s8 rssi;
+ u32 tx_cnt;
+ u32 rx_cnt;
+ u32 tx_fail_cnt;
+};
+
+enum host_if_state {
+ HOST_IF_IDLE = 0,
+ HOST_IF_SCANNING = 1,
+ HOST_IF_CONNECTING = 2,
+ HOST_IF_WAITING_CONN_RESP = 3,
+ HOST_IF_CONNECTED = 4,
+ HOST_IF_P2P_LISTEN = 5,
+ HOST_IF_FORCE_32BIT = 0xFFFFFFFF
+};
+
+struct cfg_param_attr {
+ u32 flag;
+ u16 short_retry_limit;
+ u16 long_retry_limit;
+ u16 frag_threshold;
+ u16 rts_threshold;
+};
+
+enum cfg_param {
+ WILC_CFG_PARAM_RETRY_SHORT = BIT(0),
+ WILC_CFG_PARAM_RETRY_LONG = BIT(1),
+ WILC_CFG_PARAM_FRAG_THRESHOLD = BIT(2),
+ WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3)
+};
+
+enum scan_event {
+ SCAN_EVENT_NETWORK_FOUND = 0,
+ SCAN_EVENT_DONE = 1,
+ SCAN_EVENT_ABORTED = 2,
+ SCAN_EVENT_FORCE_32BIT = 0xFFFFFFFF
+};
+
+enum conn_event {
+ CONN_DISCONN_EVENT_CONN_RESP = 0,
+ CONN_DISCONN_EVENT_DISCONN_NOTIF = 1,
+ CONN_DISCONN_EVENT_FORCE_32BIT = 0xFFFFFFFF
+};
+
+enum {
+ WILC_HIF_SDIO = 0,
+ WILC_HIF_SPI = BIT(0)
+};
+
+enum {
+ WILC_MAC_STATUS_INIT = -1,
+ WILC_MAC_STATUS_DISCONNECTED = 0,
+ WILC_MAC_STATUS_CONNECTED = 1
+};
+
+struct wilc_rcvd_net_info {
+ s8 rssi;
+ u8 ch;
+ u16 frame_len;
+ struct ieee80211_mgmt *mgmt;
+};
+
+struct wilc_user_scan_req {
+ void (*scan_result)(enum scan_event evt,
+ struct wilc_rcvd_net_info *info, void *priv);
+ void *arg;
+ u32 ch_cnt;
+};
+
+struct wilc_conn_info {
+ u8 bssid[ETH_ALEN];
+ u8 security;
+ enum authtype auth_type;
+ u8 ch;
+ u8 *req_ies;
+ size_t req_ies_len;
+ u8 *resp_ies;
+ u16 resp_ies_len;
+ u16 status;
+ void (*conn_result)(enum conn_event evt, u8 status, void *priv_data);
+ void *arg;
+ void *param;
+};
+
+struct wilc_remain_ch {
+ u16 ch;
+ u32 duration;
+ void (*expired)(void *priv, u64 cookie);
+ void *arg;
+ u32 cookie;
+};
+
+struct wilc;
+struct host_if_drv {
+ struct wilc_user_scan_req usr_scan_req;
+ struct wilc_conn_info conn_info;
+ struct wilc_remain_ch remain_on_ch;
+ u64 p2p_timeout;
+
+ enum host_if_state hif_state;
+
+ u8 assoc_bssid[ETH_ALEN];
+
+ struct timer_list scan_timer;
+ struct wilc_vif *scan_timer_vif;
+
+ struct timer_list connect_timer;
+ struct wilc_vif *connect_timer_vif;
+
+ struct timer_list remain_on_ch_timer;
+ struct wilc_vif *remain_on_ch_timer_vif;
+
+ bool ifc_up;
+ u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
+};
+
+struct wilc_vif;
+int wilc_remove_wep_key(struct wilc_vif *vif, u8 index);
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index);
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index);
+int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index, u8 mode, enum authtype auth_type);
+int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
+ const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
+ u8 mode, u8 cipher_mode, u8 index);
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
+ u32 *out_val);
+int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
+ u8 index, u32 key_rsc_len, const u8 *key_rsc,
+ const u8 *rx_mic, const u8 *tx_mic, u8 mode,
+ u8 cipher_mode);
+int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid);
+int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr);
+int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
+ size_t ies_len);
+int wilc_disconnect(struct wilc_vif *vif);
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel);
+int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level);
+int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
+ u8 *ch_freq_list, u8 ch_list_len,
+ void (*scan_result_fn)(enum scan_event,
+ struct wilc_rcvd_net_info *, void *),
+ void *user_arg, struct cfg80211_scan_request *request);
+int wilc_hif_set_cfg(struct wilc_vif *vif,
+ struct cfg_param_attr *cfg_param);
+int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler);
+int wilc_deinit(struct wilc_vif *vif);
+int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
+ struct cfg80211_beacon_data *params);
+int wilc_del_beacon(struct wilc_vif *vif);
+int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params);
+int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]);
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr);
+int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params);
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
+int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
+ u8 *mc_list);
+int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
+ u32 duration, u16 chan,
+ void (*expired)(void *, u64),
+ void *user_arg);
+int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie);
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
+int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id);
+int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats);
+int wilc_get_vif_idx(struct wilc_vif *vif);
+int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
+int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
+void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length);
+void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length);
+void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length);
+void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
+ struct cfg80211_crypto_settings *crypto);
+#endif
--
2.24.0

2020-03-02 16:36:14

by Ajay Singh

[permalink] [raw]
Subject: [PATCH v4 10/18] wilc1000: add mon.c

From: Ajay Singh <[email protected]>

Moved 'drivers/staging/wilc1000/mon.c' to
'drivers/net/wireless/microchip/wilc1000/mon.c'.

Signed-off-by: Ajay Singh <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/mon.c | 260 ++++++++++++++++++
1 file changed, 260 insertions(+)
create mode 100644 drivers/net/wireless/microchip/wilc1000/mon.c

diff --git a/drivers/net/wireless/microchip/wilc1000/mon.c b/drivers/net/wireless/microchip/wilc1000/mon.c
new file mode 100644
index 000000000000..60331417bd98
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc1000/mon.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "cfg80211.h"
+
+struct wilc_wfi_radiotap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 rate;
+} __packed;
+
+struct wilc_wfi_radiotap_cb_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 rate;
+ u8 dump;
+ u16 tx_flags;
+} __packed;
+
+#define TX_RADIOTAP_PRESENT ((1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_TX_FLAGS))
+
+void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size)
+{
+ u32 header, pkt_offset;
+ struct sk_buff *skb = NULL;
+ struct wilc_wfi_radiotap_hdr *hdr;
+ struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
+
+ if (!mon_dev)
+ return;
+
+ if (!netif_running(mon_dev))
+ return;
+
+ /* Get WILC header */
+ header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
+ /*
+ * The packet offset field contain info about what type of management
+ * the frame we are dealing with and ack status
+ */
+ pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header);
+
+ if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
+ /* hostapd callback mgmt frame */
+
+ skb = dev_alloc_skb(size + sizeof(*cb_hdr));
+ if (!skb)
+ return;
+
+ skb_put_data(skb, buff, size);
+
+ cb_hdr = skb_push(skb, sizeof(*cb_hdr));
+ memset(cb_hdr, 0, sizeof(*cb_hdr));
+
+ cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
+
+ cb_hdr->hdr.it_len = cpu_to_le16(sizeof(*cb_hdr));
+
+ cb_hdr->hdr.it_present = cpu_to_le32(TX_RADIOTAP_PRESENT);
+
+ cb_hdr->rate = 5;
+
+ if (pkt_offset & IS_MGMT_STATUS_SUCCES) {
+ /* success */
+ cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS;
+ } else {
+ cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL;
+ }
+
+ } else {
+ skb = dev_alloc_skb(size + sizeof(*hdr));
+
+ if (!skb)
+ return;
+
+ skb_put_data(skb, buff, size);
+ hdr = skb_push(skb, sizeof(*hdr));
+ memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr));
+ hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
+ hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr));
+ hdr->hdr.it_present = cpu_to_le32
+ (1 << IEEE80211_RADIOTAP_RATE);
+ hdr->rate = 5;
+ }
+
+ skb->dev = mon_dev;
+ skb_reset_mac_header(skb);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+
+ netif_rx(skb);
+}
+
+struct tx_complete_mon_data {
+ int size;
+ void *buff;
+};
+
+static void mgmt_tx_complete(void *priv, int status)
+{
+ struct tx_complete_mon_data *pv_data = priv;
+ /*
+ * in case of fully hosting mode, the freeing will be done
+ * in response to the cfg packet
+ */
+ kfree(pv_data->buff);
+
+ kfree(pv_data);
+}
+
+static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
+{
+ struct tx_complete_mon_data *mgmt_tx = NULL;
+
+ if (!dev)
+ return -EFAULT;
+
+ netif_stop_queue(dev);
+ mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_ATOMIC);
+ if (!mgmt_tx)
+ return -ENOMEM;
+
+ mgmt_tx->buff = kmemdup(buf, len, GFP_ATOMIC);
+ if (!mgmt_tx->buff) {
+ kfree(mgmt_tx);
+ return -ENOMEM;
+ }
+
+ mgmt_tx->size = len;
+
+ wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
+ mgmt_tx_complete);
+
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static netdev_tx_t wilc_wfi_mon_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ u32 rtap_len, ret = 0;
+ struct wilc_wfi_mon_priv *mon_priv;
+ struct sk_buff *skb2;
+ struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
+ u8 srcadd[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+
+ mon_priv = netdev_priv(dev);
+ if (!mon_priv)
+ return -EFAULT;
+
+ rtap_len = ieee80211_get_radiotap_len(skb->data);
+ if (skb->len < rtap_len)
+ return -1;
+
+ skb_pull(skb, rtap_len);
+
+ if (skb->data[0] == 0xc0 && is_broadcast_ether_addr(&skb->data[4])) {
+ skb2 = dev_alloc_skb(skb->len + sizeof(*cb_hdr));
+ if (!skb2)
+ return -ENOMEM;
+
+ skb_put_data(skb2, skb->data, skb->len);
+
+ cb_hdr = skb_push(skb2, sizeof(*cb_hdr));
+ memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
+
+ cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
+
+ cb_hdr->hdr.it_len = cpu_to_le16(sizeof(*cb_hdr));
+
+ cb_hdr->hdr.it_present = cpu_to_le32(TX_RADIOTAP_PRESENT);
+
+ cb_hdr->rate = 5;
+ cb_hdr->tx_flags = 0x0004;
+
+ skb2->dev = dev;
+ skb_reset_mac_header(skb2);
+ skb2->ip_summed = CHECKSUM_UNNECESSARY;
+ skb2->pkt_type = PACKET_OTHERHOST;
+ skb2->protocol = htons(ETH_P_802_2);
+ memset(skb2->cb, 0, sizeof(skb2->cb));
+
+ netif_rx(skb2);
+
+ return 0;
+ }
+ skb->dev = mon_priv->real_ndev;
+
+ ether_addr_copy(srcadd, &skb->data[10]);
+ ether_addr_copy(bssid, &skb->data[16]);
+ /*
+ * Identify if data or mgmt packet, if source address and bssid
+ * fields are equal send it to mgmt frames handler
+ */
+ if (!(memcmp(srcadd, bssid, 6))) {
+ ret = mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len);
+ if (ret)
+ netdev_err(dev, "fail to mgmt tx\n");
+ dev_kfree_skb(skb);
+ } else {
+ ret = wilc_mac_xmit(skb, mon_priv->real_ndev);
+ }
+
+ return ret;
+}
+
+static const struct net_device_ops wilc_wfi_netdev_ops = {
+ .ndo_start_xmit = wilc_wfi_mon_xmit,
+
+};
+
+struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
+ const char *name,
+ struct net_device *real_dev)
+{
+ struct wilc_wfi_mon_priv *priv;
+
+ /* If monitor interface is already initialized, return it */
+ if (wl->monitor_dev)
+ return wl->monitor_dev;
+
+ wl->monitor_dev = alloc_etherdev(sizeof(struct wilc_wfi_mon_priv));
+ if (!wl->monitor_dev)
+ return NULL;
+
+ wl->monitor_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ strncpy(wl->monitor_dev->name, name, IFNAMSIZ);
+ wl->monitor_dev->name[IFNAMSIZ - 1] = 0;
+ wl->monitor_dev->netdev_ops = &wilc_wfi_netdev_ops;
+ wl->monitor_dev->needs_free_netdev = true;
+
+ if (register_netdevice(wl->monitor_dev)) {
+ netdev_err(real_dev, "register_netdevice failed\n");
+ return NULL;
+ }
+ priv = netdev_priv(wl->monitor_dev);
+ if (!priv)
+ return NULL;
+
+ priv->real_ndev = real_dev;
+
+ return wl->monitor_dev;
+}
+
+void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked)
+{
+ if (!wl->monitor_dev)
+ return;
+
+ if (rtnl_locked)
+ unregister_netdevice(wl->monitor_dev);
+ else
+ unregister_netdev(wl->monitor_dev);
+ wl->monitor_dev = NULL;
+}
--
2.24.0

2020-03-02 16:36:14

by Ajay Singh

[permalink] [raw]
Subject: [PATCH v4 06/18] wilc1000: add cfg80211.c

From: Ajay Singh <[email protected]>

Moved 'drivers/staging/wilc1000/cfg80211.c' to
'drivers/net/wireless/microchip/wilc1000/cfg80211.c'.

Signed-off-by: Ajay Singh <[email protected]>
---
.../wireless/microchip/wilc1000/cfg80211.c | 1850 +++++++++++++++++
1 file changed, 1850 insertions(+)
create mode 100644 drivers/net/wireless/microchip/wilc1000/cfg80211.c

diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
new file mode 100644
index 000000000000..54e02807cebf
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -0,0 +1,1850 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "cfg80211.h"
+
+#define GO_NEG_REQ 0x00
+#define GO_NEG_RSP 0x01
+#define GO_NEG_CONF 0x02
+#define P2P_INV_REQ 0x03
+#define P2P_INV_RSP 0x04
+
+#define WILC_INVALID_CHANNEL 0
+
+/* Operation at 2.4 GHz with channels 1-13 */
+#define WILC_WLAN_OPERATING_CLASS_2_4GHZ 0x51
+
+static const struct ieee80211_txrx_stypes
+ wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4)
+ }
+};
+
+static const struct wiphy_wowlan_support wowlan_support = {
+ .flags = WIPHY_WOWLAN_ANY
+};
+
+struct wilc_p2p_mgmt_data {
+ int size;
+ u8 *buff;
+};
+
+struct wilc_p2p_pub_act_frame {
+ u8 category;
+ u8 action;
+ u8 oui[3];
+ u8 oui_type;
+ u8 oui_subtype;
+ u8 dialog_token;
+ u8 elem[];
+} __packed;
+
+struct wilc_vendor_specific_ie {
+ u8 tag_number;
+ u8 tag_len;
+ u8 oui[3];
+ u8 oui_type;
+ u8 attr[];
+} __packed;
+
+struct wilc_attr_entry {
+ u8 attr_type;
+ __le16 attr_len;
+ u8 val[];
+} __packed;
+
+struct wilc_attr_oper_ch {
+ u8 attr_type;
+ __le16 attr_len;
+ u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+ u8 op_class;
+ u8 op_channel;
+} __packed;
+
+struct wilc_attr_ch_list {
+ u8 attr_type;
+ __le16 attr_len;
+ u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+ u8 elem[];
+} __packed;
+
+struct wilc_ch_list_elem {
+ u8 op_class;
+ u8 no_of_channels;
+ u8 ch_list[];
+} __packed;
+
+static void cfg_scan_result(enum scan_event scan_event,
+ struct wilc_rcvd_net_info *info, void *user_void)
+{
+ struct wilc_priv *priv = user_void;
+
+ if (!priv->cfg_scanning)
+ return;
+
+ if (scan_event == SCAN_EVENT_NETWORK_FOUND) {
+ s32 freq;
+ struct ieee80211_channel *channel;
+ struct cfg80211_bss *bss;
+ struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy;
+
+ if (!wiphy || !info)
+ return;
+
+ freq = ieee80211_channel_to_frequency((s32)info->ch,
+ NL80211_BAND_2GHZ);
+ channel = ieee80211_get_channel(wiphy, freq);
+ if (!channel)
+ return;
+
+ bss = cfg80211_inform_bss_frame(wiphy, channel, info->mgmt,
+ info->frame_len,
+ (s32)info->rssi * 100,
+ GFP_KERNEL);
+ if (!bss)
+ cfg80211_put_bss(wiphy, bss);
+ } else if (scan_event == SCAN_EVENT_DONE) {
+ mutex_lock(&priv->scan_req_lock);
+
+ if (priv->scan_req) {
+ struct cfg80211_scan_info info = {
+ .aborted = false,
+ };
+
+ cfg80211_scan_done(priv->scan_req, &info);
+ priv->cfg_scanning = false;
+ priv->scan_req = NULL;
+ }
+ mutex_unlock(&priv->scan_req_lock);
+ } else if (scan_event == SCAN_EVENT_ABORTED) {
+ mutex_lock(&priv->scan_req_lock);
+
+ if (priv->scan_req) {
+ struct cfg80211_scan_info info = {
+ .aborted = false,
+ };
+
+ cfg80211_scan_done(priv->scan_req, &info);
+ priv->cfg_scanning = false;
+ priv->scan_req = NULL;
+ }
+ mutex_unlock(&priv->scan_req_lock);
+ }
+}
+
+static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status,
+ void *priv_data)
+{
+ struct wilc_priv *priv = priv_data;
+ struct net_device *dev = priv->dev;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ struct wilc_conn_info *conn_info = &wfi_drv->conn_info;
+ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+
+ vif->connecting = false;
+
+ if (conn_disconn_evt == CONN_DISCONN_EVENT_CONN_RESP) {
+ u16 connect_status = conn_info->status;
+
+ if (mac_status == WILC_MAC_STATUS_DISCONNECTED &&
+ connect_status == WLAN_STATUS_SUCCESS) {
+ connect_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
+
+ if (vif->iftype != WILC_CLIENT_MODE)
+ wl->sta_ch = WILC_INVALID_CHANNEL;
+
+ netdev_err(dev, "Unspecified failure\n");
+ }
+
+ if (connect_status == WLAN_STATUS_SUCCESS)
+ memcpy(priv->associated_bss, conn_info->bssid,
+ ETH_ALEN);
+
+ cfg80211_ref_bss(wiphy, vif->bss);
+ cfg80211_connect_bss(dev, conn_info->bssid, vif->bss,
+ conn_info->req_ies,
+ conn_info->req_ies_len,
+ conn_info->resp_ies,
+ conn_info->resp_ies_len,
+ connect_status, GFP_KERNEL,
+ NL80211_TIMEOUT_UNSPECIFIED);
+
+ vif->bss = NULL;
+ } else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) {
+ u16 reason = 0;
+
+ eth_zero_addr(priv->associated_bss);
+ wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
+
+ if (vif->iftype != WILC_CLIENT_MODE) {
+ wl->sta_ch = WILC_INVALID_CHANNEL;
+ } else {
+ if (wfi_drv->ifc_up)
+ reason = 3;
+ else
+ reason = 1;
+ }
+
+ cfg80211_disconnected(dev, reason, NULL, 0, false, GFP_KERNEL);
+ }
+}
+
+struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl)
+{
+ struct wilc_vif *vif;
+
+ vif = list_first_or_null_rcu(&wl->vif_list, typeof(*vif), list);
+ if (!vif)
+ return ERR_PTR(-EINVAL);
+
+ return vif;
+}
+
+static int set_channel(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ u32 channelnum;
+ int result;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif)) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return PTR_ERR(vif);
+ }
+
+ channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq);
+
+ wl->op_ch = channelnum;
+ result = wilc_set_mac_chnl_num(vif, channelnum);
+ if (result)
+ netdev_err(vif->ndev, "Error in setting channel\n");
+
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return result;
+}
+
+static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
+{
+ struct wilc_vif *vif = netdev_priv(request->wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+ u32 i;
+ int ret = 0;
+ u8 scan_ch_list[WILC_MAX_NUM_SCANNED_CH];
+ u8 scan_type;
+
+ if (request->n_channels > WILC_MAX_NUM_SCANNED_CH) {
+ netdev_err(vif->ndev, "Requested scanned channels over\n");
+ return -EINVAL;
+ }
+
+ priv->scan_req = request;
+ priv->cfg_scanning = true;
+ for (i = 0; i < request->n_channels; i++) {
+ u16 freq = request->channels[i]->center_freq;
+
+ scan_ch_list[i] = ieee80211_frequency_to_channel(freq);
+ }
+
+ if (request->n_ssids)
+ scan_type = WILC_FW_ACTIVE_SCAN;
+ else
+ scan_type = WILC_FW_PASSIVE_SCAN;
+
+ ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list,
+ request->n_channels, cfg_scan_result, (void *)priv,
+ request);
+
+ if (ret) {
+ priv->scan_req = NULL;
+ priv->cfg_scanning = false;
+ }
+
+ return ret;
+}
+
+static int connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ int ret;
+ u32 i;
+ u8 security = WILC_FW_SEC_NO;
+ enum authtype auth_type = WILC_FW_AUTH_ANY;
+ u32 cipher_group;
+ struct cfg80211_bss *bss;
+ void *join_params;
+ u8 ch;
+
+ vif->connecting = true;
+
+ memset(priv->wep_key, 0, sizeof(priv->wep_key));
+ memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
+
+ cipher_group = sme->crypto.cipher_group;
+ if (cipher_group != 0) {
+ if (cipher_group == WLAN_CIPHER_SUITE_WEP40) {
+ security = WILC_FW_SEC_WEP;
+
+ priv->wep_key_len[sme->key_idx] = sme->key_len;
+ memcpy(priv->wep_key[sme->key_idx], sme->key,
+ sme->key_len);
+
+ wilc_set_wep_default_keyid(vif, sme->key_idx);
+ wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
+ sme->key_idx);
+ } else if (cipher_group == WLAN_CIPHER_SUITE_WEP104) {
+ security = WILC_FW_SEC_WEP_EXTENDED;
+
+ priv->wep_key_len[sme->key_idx] = sme->key_len;
+ memcpy(priv->wep_key[sme->key_idx], sme->key,
+ sme->key_len);
+
+ wilc_set_wep_default_keyid(vif, sme->key_idx);
+ wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
+ sme->key_idx);
+ } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
+ if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
+ security = WILC_FW_SEC_WPA2_TKIP;
+ else
+ security = WILC_FW_SEC_WPA2_AES;
+ } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) {
+ if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
+ security = WILC_FW_SEC_WPA_TKIP;
+ else
+ security = WILC_FW_SEC_WPA_AES;
+ } else {
+ ret = -ENOTSUPP;
+ netdev_err(dev, "%s: Unsupported cipher\n",
+ __func__);
+ goto out_error;
+ }
+ }
+
+ if ((sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ||
+ (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
+ for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) {
+ u32 ciphers_pairwise = sme->crypto.ciphers_pairwise[i];
+
+ if (ciphers_pairwise == WLAN_CIPHER_SUITE_TKIP)
+ security |= WILC_FW_TKIP;
+ else
+ security |= WILC_FW_AES;
+ }
+ }
+
+ switch (sme->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ auth_type = WILC_FW_AUTH_OPEN_SYSTEM;
+ break;
+
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ auth_type = WILC_FW_AUTH_SHARED_KEY;
+ break;
+
+ default:
+ break;
+ }
+
+ if (sme->crypto.n_akm_suites) {
+ if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X)
+ auth_type = WILC_FW_AUTH_IEEE8021;
+ }
+
+ if (wfi_drv->usr_scan_req.scan_result) {
+ netdev_err(vif->ndev, "%s: Scan in progress\n", __func__);
+ ret = -EBUSY;
+ goto out_error;
+ }
+
+ bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid,
+ sme->ssid_len, IEEE80211_BSS_TYPE_ANY,
+ IEEE80211_PRIVACY(sme->privacy));
+ if (!bss) {
+ ret = -EINVAL;
+ goto out_error;
+ }
+
+ if (ether_addr_equal_unaligned(vif->bssid, bss->bssid)) {
+ ret = -EALREADY;
+ goto out_put_bss;
+ }
+
+ join_params = wilc_parse_join_bss_param(bss, &sme->crypto);
+ if (!join_params) {
+ netdev_err(dev, "%s: failed to construct join param\n",
+ __func__);
+ ret = -EINVAL;
+ goto out_put_bss;
+ }
+
+ ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
+ vif->wilc->op_ch = ch;
+ if (vif->iftype != WILC_CLIENT_MODE)
+ vif->wilc->sta_ch = ch;
+
+ wilc_wlan_set_bssid(dev, bss->bssid, WILC_STATION_MODE);
+
+ wfi_drv->conn_info.security = security;
+ wfi_drv->conn_info.auth_type = auth_type;
+ wfi_drv->conn_info.ch = ch;
+ wfi_drv->conn_info.conn_result = cfg_connect_result;
+ wfi_drv->conn_info.arg = priv;
+ wfi_drv->conn_info.param = join_params;
+
+ ret = wilc_set_join_req(vif, bss->bssid, sme->ie, sme->ie_len);
+ if (ret) {
+ netdev_err(dev, "wilc_set_join_req(): Error\n");
+ ret = -ENOENT;
+ if (vif->iftype != WILC_CLIENT_MODE)
+ vif->wilc->sta_ch = WILC_INVALID_CHANNEL;
+ wilc_wlan_set_bssid(dev, NULL, WILC_STATION_MODE);
+ wfi_drv->conn_info.conn_result = NULL;
+ kfree(join_params);
+ goto out_put_bss;
+ }
+ kfree(join_params);
+ vif->bss = bss;
+ cfg80211_put_bss(wiphy, bss);
+ return 0;
+
+out_put_bss:
+ cfg80211_put_bss(wiphy, bss);
+
+out_error:
+ vif->connecting = false;
+ return ret;
+}
+
+static int disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+ struct wilc *wilc = vif->wilc;
+ int ret;
+
+ vif->connecting = false;
+
+ if (!wilc)
+ return -EIO;
+
+ if (wilc->close) {
+ /* already disconnected done */
+ cfg80211_disconnected(dev, 0, NULL, 0, true, GFP_KERNEL);
+ return 0;
+ }
+
+ if (vif->iftype != WILC_CLIENT_MODE)
+ wilc->sta_ch = WILC_INVALID_CHANNEL;
+ wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
+
+ priv->hif_drv->p2p_timeout = 0;
+
+ ret = wilc_disconnect(vif);
+ if (ret != 0) {
+ netdev_err(priv->dev, "Error in disconnecting\n");
+ ret = -EINVAL;
+ }
+
+ vif->bss = NULL;
+
+ return ret;
+}
+
+static inline void wilc_wfi_cfg_copy_wep_info(struct wilc_priv *priv,
+ u8 key_index,
+ struct key_params *params)
+{
+ priv->wep_key_len[key_index] = params->key_len;
+ memcpy(priv->wep_key[key_index], params->key, params->key_len);
+}
+
+static int wilc_wfi_cfg_allocate_wpa_entry(struct wilc_priv *priv, u8 idx)
+{
+ if (!priv->wilc_gtk[idx]) {
+ priv->wilc_gtk[idx] = kzalloc(sizeof(*priv->wilc_gtk[idx]),
+ GFP_KERNEL);
+ if (!priv->wilc_gtk[idx])
+ return -ENOMEM;
+ }
+
+ if (!priv->wilc_ptk[idx]) {
+ priv->wilc_ptk[idx] = kzalloc(sizeof(*priv->wilc_ptk[idx]),
+ GFP_KERNEL);
+ if (!priv->wilc_ptk[idx])
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info,
+ struct key_params *params)
+{
+ kfree(key_info->key);
+
+ key_info->key = kmemdup(params->key, params->key_len, GFP_KERNEL);
+ if (!key_info->key)
+ return -ENOMEM;
+
+ kfree(key_info->seq);
+
+ if (params->seq_len > 0) {
+ key_info->seq = kmemdup(params->seq, params->seq_len,
+ GFP_KERNEL);
+ if (!key_info->seq)
+ return -ENOMEM;
+ }
+
+ key_info->cipher = params->cipher;
+ key_info->key_len = params->key_len;
+ key_info->seq_len = params->seq_len;
+
+ return 0;
+}
+
+static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
+ bool pairwise, const u8 *mac_addr, struct key_params *params)
+
+{
+ int ret = 0, keylen = params->key_len;
+ const u8 *rx_mic = NULL;
+ const u8 *tx_mic = NULL;
+ u8 mode = WILC_FW_SEC_NO;
+ u8 op_mode;
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ if (priv->wdev.iftype == NL80211_IFTYPE_AP) {
+ wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
+
+ if (params->cipher == WLAN_CIPHER_SUITE_WEP40)
+ mode = WILC_FW_SEC_WEP;
+ else
+ mode = WILC_FW_SEC_WEP_EXTENDED;
+
+ ret = wilc_add_wep_key_bss_ap(vif, params->key,
+ params->key_len,
+ key_index, mode,
+ WILC_FW_AUTH_OPEN_SYSTEM);
+ break;
+ }
+ if (memcmp(params->key, priv->wep_key[key_index],
+ params->key_len)) {
+ wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
+
+ ret = wilc_add_wep_key_bss_sta(vif, params->key,
+ params->key_len,
+ key_index);
+ }
+
+ break;
+
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
+ priv->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
+ struct wilc_wfi_key *key;
+
+ ret = wilc_wfi_cfg_allocate_wpa_entry(priv, key_index);
+ if (ret)
+ return -ENOMEM;
+
+ if (params->key_len > 16 &&
+ params->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ tx_mic = params->key + 24;
+ rx_mic = params->key + 16;
+ keylen = params->key_len - 16;
+ }
+
+ if (!pairwise) {
+ if (params->cipher == WLAN_CIPHER_SUITE_TKIP)
+ mode = WILC_FW_SEC_WPA_TKIP;
+ else
+ mode = WILC_FW_SEC_WPA2_AES;
+
+ priv->wilc_groupkey = mode;
+
+ key = priv->wilc_gtk[key_index];
+ } else {
+ if (params->cipher == WLAN_CIPHER_SUITE_TKIP)
+ mode = WILC_FW_SEC_WPA_TKIP;
+ else
+ mode = priv->wilc_groupkey | WILC_FW_AES;
+
+ key = priv->wilc_ptk[key_index];
+ }
+ ret = wilc_wfi_cfg_copy_wpa_info(key, params);
+ if (ret)
+ return -ENOMEM;
+
+ op_mode = WILC_AP_MODE;
+ } else {
+ if (params->key_len > 16 &&
+ params->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ rx_mic = params->key + 24;
+ tx_mic = params->key + 16;
+ keylen = params->key_len - 16;
+ }
+
+ op_mode = WILC_STATION_MODE;
+ }
+
+ if (!pairwise)
+ ret = wilc_add_rx_gtk(vif, params->key, keylen,
+ key_index, params->seq_len,
+ params->seq, rx_mic, tx_mic,
+ op_mode, mode);
+ else
+ ret = wilc_add_ptk(vif, params->key, keylen, mac_addr,
+ rx_mic, tx_mic, op_mode, mode,
+ key_index);
+
+ break;
+
+ default:
+ netdev_err(netdev, "%s: Unsupported cipher\n", __func__);
+ ret = -ENOTSUPP;
+ }
+
+ return ret;
+}
+
+static int del_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index,
+ bool pairwise,
+ const u8 *mac_addr)
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+
+ if (priv->wilc_gtk[key_index]) {
+ kfree(priv->wilc_gtk[key_index]->key);
+ priv->wilc_gtk[key_index]->key = NULL;
+ kfree(priv->wilc_gtk[key_index]->seq);
+ priv->wilc_gtk[key_index]->seq = NULL;
+
+ kfree(priv->wilc_gtk[key_index]);
+ priv->wilc_gtk[key_index] = NULL;
+ }
+
+ if (priv->wilc_ptk[key_index]) {
+ kfree(priv->wilc_ptk[key_index]->key);
+ priv->wilc_ptk[key_index]->key = NULL;
+ kfree(priv->wilc_ptk[key_index]->seq);
+ priv->wilc_ptk[key_index]->seq = NULL;
+ kfree(priv->wilc_ptk[key_index]);
+ priv->wilc_ptk[key_index] = NULL;
+ }
+
+ if (key_index <= 3 && priv->wep_key_len[key_index]) {
+ memset(priv->wep_key[key_index], 0,
+ priv->wep_key_len[key_index]);
+ priv->wep_key_len[key_index] = 0;
+ wilc_remove_wep_key(vif, key_index);
+ }
+
+ return 0;
+}
+
+static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
+ bool pairwise, const u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie, struct key_params *))
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+ struct key_params key_params;
+
+ if (!pairwise) {
+ key_params.key = priv->wilc_gtk[key_index]->key;
+ key_params.cipher = priv->wilc_gtk[key_index]->cipher;
+ key_params.key_len = priv->wilc_gtk[key_index]->key_len;
+ key_params.seq = priv->wilc_gtk[key_index]->seq;
+ key_params.seq_len = priv->wilc_gtk[key_index]->seq_len;
+ } else {
+ key_params.key = priv->wilc_ptk[key_index]->key;
+ key_params.cipher = priv->wilc_ptk[key_index]->cipher;
+ key_params.key_len = priv->wilc_ptk[key_index]->key_len;
+ key_params.seq = priv->wilc_ptk[key_index]->seq;
+ key_params.seq_len = priv->wilc_ptk[key_index]->seq_len;
+ }
+
+ callback(cookie, &key_params);
+
+ return 0;
+}
+
+static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, bool unicast, bool multicast)
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+
+ wilc_set_wep_default_keyid(vif, key_index);
+
+ return 0;
+}
+
+static int get_station(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *mac, struct station_info *sinfo)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+ u32 i = 0;
+ u32 associatedsta = ~0;
+ u32 inactive_time = 0;
+
+ if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
+ for (i = 0; i < NUM_STA_ASSOCIATED; i++) {
+ if (!(memcmp(mac,
+ priv->assoc_stainfo.sta_associated_bss[i],
+ ETH_ALEN))) {
+ associatedsta = i;
+ break;
+ }
+ }
+
+ if (associatedsta == ~0) {
+ netdev_err(dev, "sta required is not associated\n");
+ return -ENOENT;
+ }
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME);
+
+ wilc_get_inactive_time(vif, mac, &inactive_time);
+ sinfo->inactive_time = 1000 * inactive_time;
+ } else if (vif->iftype == WILC_STATION_MODE) {
+ struct rf_info stats;
+
+ wilc_get_statistics(vif, &stats);
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL) |
+ BIT_ULL(NL80211_STA_INFO_RX_PACKETS) |
+ BIT_ULL(NL80211_STA_INFO_TX_PACKETS) |
+ BIT_ULL(NL80211_STA_INFO_TX_FAILED) |
+ BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
+
+ sinfo->signal = stats.rssi;
+ sinfo->rx_packets = stats.rx_cnt;
+ sinfo->tx_packets = stats.tx_cnt + stats.tx_fail_cnt;
+ sinfo->tx_failed = stats.tx_fail_cnt;
+ sinfo->txrate.legacy = stats.link_speed * 10;
+
+ if (stats.link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
+ stats.link_speed != DEFAULT_LINK_SPEED)
+ wilc_enable_tcp_ack_filter(vif, true);
+ else if (stats.link_speed != DEFAULT_LINK_SPEED)
+ wilc_enable_tcp_ack_filter(vif, false);
+ }
+ return 0;
+}
+
+static int change_bss(struct wiphy *wiphy, struct net_device *dev,
+ struct bss_parameters *params)
+{
+ return 0;
+}
+
+static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ int ret = -EINVAL;
+ struct cfg_param_attr cfg_param_val;
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ struct wilc_priv *priv;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif))
+ goto out;
+
+ priv = &vif->priv;
+ cfg_param_val.flag = 0;
+
+ if (changed & WIPHY_PARAM_RETRY_SHORT) {
+ netdev_dbg(vif->ndev,
+ "Setting WIPHY_PARAM_RETRY_SHORT %d\n",
+ wiphy->retry_short);
+ cfg_param_val.flag |= WILC_CFG_PARAM_RETRY_SHORT;
+ cfg_param_val.short_retry_limit = wiphy->retry_short;
+ }
+ if (changed & WIPHY_PARAM_RETRY_LONG) {
+ netdev_dbg(vif->ndev,
+ "Setting WIPHY_PARAM_RETRY_LONG %d\n",
+ wiphy->retry_long);
+ cfg_param_val.flag |= WILC_CFG_PARAM_RETRY_LONG;
+ cfg_param_val.long_retry_limit = wiphy->retry_long;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ if (wiphy->frag_threshold > 255 &&
+ wiphy->frag_threshold < 7937) {
+ netdev_dbg(vif->ndev,
+ "Setting WIPHY_PARAM_FRAG_THRESHOLD %d\n",
+ wiphy->frag_threshold);
+ cfg_param_val.flag |= WILC_CFG_PARAM_FRAG_THRESHOLD;
+ cfg_param_val.frag_threshold = wiphy->frag_threshold;
+ } else {
+ netdev_err(vif->ndev,
+ "Fragmentation threshold out of range\n");
+ goto out;
+ }
+ }
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ if (wiphy->rts_threshold > 255) {
+ netdev_dbg(vif->ndev,
+ "Setting WIPHY_PARAM_RTS_THRESHOLD %d\n",
+ wiphy->rts_threshold);
+ cfg_param_val.flag |= WILC_CFG_PARAM_RTS_THRESHOLD;
+ cfg_param_val.rts_threshold = wiphy->rts_threshold;
+ } else {
+ netdev_err(vif->ndev, "RTS threshold out of range\n");
+ goto out;
+ }
+ }
+
+ ret = wilc_hif_set_cfg(vif, &cfg_param_val);
+ if (ret)
+ netdev_err(priv->dev, "Error in setting WIPHY PARAMS\n");
+
+out:
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return ret;
+}
+
+static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+ u32 i;
+ int ret = 0;
+ u8 flag = 0;
+
+ for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
+ if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
+ ETH_ALEN)) {
+ flag = PMKID_FOUND;
+ break;
+ }
+ }
+ if (i < WILC_MAX_NUM_PMKIDS) {
+ memcpy(priv->pmkid_list.pmkidlist[i].bssid, pmksa->bssid,
+ ETH_ALEN);
+ memcpy(priv->pmkid_list.pmkidlist[i].pmkid, pmksa->pmkid,
+ WLAN_PMKID_LEN);
+ if (!(flag == PMKID_FOUND))
+ priv->pmkid_list.numpmkid++;
+ } else {
+ netdev_err(netdev, "Invalid PMKID index\n");
+ ret = -EINVAL;
+ }
+
+ if (!ret)
+ ret = wilc_set_pmkid_info(vif, &priv->pmkid_list);
+
+ return ret;
+}
+
+static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_pmksa *pmksa)
+{
+ u32 i;
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+
+ for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
+ if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
+ ETH_ALEN)) {
+ memset(&priv->pmkid_list.pmkidlist[i], 0,
+ sizeof(struct wilc_pmkid));
+ break;
+ }
+ }
+
+ if (i == priv->pmkid_list.numpmkid)
+ return -EINVAL;
+
+ for (; i < (priv->pmkid_list.numpmkid - 1); i++) {
+ memcpy(priv->pmkid_list.pmkidlist[i].bssid,
+ priv->pmkid_list.pmkidlist[i + 1].bssid,
+ ETH_ALEN);
+ memcpy(priv->pmkid_list.pmkidlist[i].pmkid,
+ priv->pmkid_list.pmkidlist[i + 1].pmkid,
+ WLAN_PMKID_LEN);
+ }
+ priv->pmkid_list.numpmkid--;
+
+ return 0;
+}
+
+static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+
+ memset(&vif->priv.pmkid_list, 0, sizeof(struct wilc_pmkid_attr));
+
+ return 0;
+}
+
+static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch)
+{
+ struct wilc_attr_entry *e;
+ struct wilc_attr_ch_list *ch_list;
+ struct wilc_attr_oper_ch *op_ch;
+ u32 index = 0;
+ u8 ch_list_idx = 0;
+ u8 op_ch_idx = 0;
+
+ if (sta_ch == WILC_INVALID_CHANNEL)
+ return;
+
+ while (index + sizeof(*e) <= len) {
+ e = (struct wilc_attr_entry *)&buf[index];
+ if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST)
+ ch_list_idx = index;
+ else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL)
+ op_ch_idx = index;
+ if (ch_list_idx && op_ch_idx)
+ break;
+ index += le16_to_cpu(e->attr_len) + sizeof(*e);
+ }
+
+ if (ch_list_idx) {
+ u16 attr_size;
+ struct wilc_ch_list_elem *e;
+ int i;
+
+ ch_list = (struct wilc_attr_ch_list *)&buf[ch_list_idx];
+ attr_size = le16_to_cpu(ch_list->attr_len);
+ for (i = 0; i < attr_size;) {
+ e = (struct wilc_ch_list_elem *)(ch_list->elem + i);
+ if (e->op_class == WILC_WLAN_OPERATING_CLASS_2_4GHZ) {
+ memset(e->ch_list, sta_ch, e->no_of_channels);
+ break;
+ }
+ i += e->no_of_channels;
+ }
+ }
+
+ if (op_ch_idx) {
+ op_ch = (struct wilc_attr_oper_ch *)&buf[op_ch_idx];
+ op_ch->op_class = WILC_WLAN_OPERATING_CLASS_2_4GHZ;
+ op_ch->op_channel = sta_ch;
+ }
+}
+
+void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
+{
+ struct wilc *wl = vif->wilc;
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ struct ieee80211_mgmt *mgmt;
+ struct wilc_vendor_specific_ie *p;
+ struct wilc_p2p_pub_act_frame *d;
+ int ie_offset = offsetof(struct ieee80211_mgmt, u) + sizeof(*d);
+ const u8 *vendor_ie;
+ u32 header, pkt_offset;
+ s32 freq;
+
+ header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
+ pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header);
+
+ if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
+ bool ack = false;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)buff;
+
+ if (ieee80211_is_probe_resp(hdr->frame_control) ||
+ pkt_offset & IS_MGMT_STATUS_SUCCES)
+ ack = true;
+
+ cfg80211_mgmt_tx_status(&priv->wdev, priv->tx_cookie, buff,
+ size, ack, GFP_KERNEL);
+ return;
+ }
+
+ freq = ieee80211_channel_to_frequency(wl->op_ch, NL80211_BAND_2GHZ);
+
+ mgmt = (struct ieee80211_mgmt *)buff;
+ if (!ieee80211_is_action(mgmt->frame_control))
+ goto out_rx_mgmt;
+
+ if (priv->cfg_scanning &&
+ time_after_eq(jiffies, (unsigned long)wfi_drv->p2p_timeout)) {
+ netdev_dbg(vif->ndev, "Receiving action wrong ch\n");
+ return;
+ }
+
+ if (!ieee80211_is_public_action((struct ieee80211_hdr *)buff, size))
+ goto out_rx_mgmt;
+
+ d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
+ if (d->oui_subtype != GO_NEG_REQ && d->oui_subtype != GO_NEG_RSP &&
+ d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP)
+ goto out_rx_mgmt;
+
+ vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
+ buff + ie_offset, size - ie_offset);
+ if (!vendor_ie)
+ goto out_rx_mgmt;
+
+ p = (struct wilc_vendor_specific_ie *)vendor_ie;
+ wilc_wfi_cfg_parse_ch_attr(p->attr, p->tag_len - 4, vif->wilc->sta_ch);
+
+out_rx_mgmt:
+ cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
+}
+
+static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
+{
+ struct wilc_p2p_mgmt_data *pv_data = priv;
+
+ kfree(pv_data->buff);
+ kfree(pv_data);
+}
+
+static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
+{
+ struct wilc_vif *vif = data;
+ struct wilc_priv *priv = &vif->priv;
+ struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params;
+
+ if (cookie != params->listen_cookie)
+ return;
+
+ priv->p2p_listen_state = false;
+
+ cfg80211_remain_on_channel_expired(&priv->wdev, params->listen_cookie,
+ params->listen_ch, GFP_KERNEL);
+}
+
+static int remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct ieee80211_channel *chan,
+ unsigned int duration, u64 *cookie)
+{
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+ u64 id;
+
+ if (wdev->iftype == NL80211_IFTYPE_AP) {
+ netdev_dbg(vif->ndev, "Required while in AP mode\n");
+ return ret;
+ }
+
+ id = ++priv->inc_roc_cookie;
+ if (id == 0)
+ id = ++priv->inc_roc_cookie;
+
+ ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value,
+ wilc_wfi_remain_on_channel_expired,
+ (void *)vif);
+ if (ret)
+ return ret;
+
+ vif->wilc->op_ch = chan->hw_value;
+
+ priv->remain_on_ch_params.listen_ch = chan;
+ priv->remain_on_ch_params.listen_cookie = id;
+ *cookie = id;
+ priv->p2p_listen_state = true;
+ priv->remain_on_ch_params.listen_duration = duration;
+
+ cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_KERNEL);
+ mod_timer(&vif->hif_drv->remain_on_ch_timer,
+ jiffies + msecs_to_jiffies(duration + 1000));
+
+ return ret;
+}
+
+static int cancel_remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u64 cookie)
+{
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+
+ if (cookie != priv->remain_on_ch_params.listen_cookie)
+ return -ENOENT;
+
+ return wilc_listen_state_expired(vif, cookie);
+}
+
+static int mgmt_tx(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_mgmt_tx_params *params,
+ u64 *cookie)
+{
+ struct ieee80211_channel *chan = params->chan;
+ unsigned int wait = params->wait;
+ const u8 *buf = params->buf;
+ size_t len = params->len;
+ const struct ieee80211_mgmt *mgmt;
+ struct wilc_p2p_mgmt_data *mgmt_tx;
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ struct wilc_vendor_specific_ie *p;
+ struct wilc_p2p_pub_act_frame *d;
+ int ie_offset = offsetof(struct ieee80211_mgmt, u) + sizeof(*d);
+ const u8 *vendor_ie;
+ int ret = 0;
+
+ *cookie = prandom_u32();
+ priv->tx_cookie = *cookie;
+ mgmt = (const struct ieee80211_mgmt *)buf;
+
+ if (!ieee80211_is_mgmt(mgmt->frame_control))
+ goto out;
+
+ mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_KERNEL);
+ if (!mgmt_tx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mgmt_tx->buff = kmalloc(len, GFP_KERNEL);
+ if (!mgmt_tx->buff) {
+ ret = -ENOMEM;
+ kfree(mgmt_tx);
+ goto out;
+ }
+
+ memcpy(mgmt_tx->buff, buf, len);
+ mgmt_tx->size = len;
+
+ if (ieee80211_is_probe_resp(mgmt->frame_control)) {
+ wilc_set_mac_chnl_num(vif, chan->hw_value);
+ vif->wilc->op_ch = chan->hw_value;
+ goto out_txq_add_pkt;
+ }
+
+ if (!ieee80211_is_public_action((struct ieee80211_hdr *)buf, len))
+ goto out_set_timeout;
+
+ d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
+ if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P ||
+ d->oui_subtype != GO_NEG_CONF) {
+ wilc_set_mac_chnl_num(vif, chan->hw_value);
+ vif->wilc->op_ch = chan->hw_value;
+ }
+
+ if (d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP)
+ goto out_set_timeout;
+
+ vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
+ mgmt_tx->buff + ie_offset,
+ len - ie_offset);
+ if (!vendor_ie)
+ goto out_set_timeout;
+
+ p = (struct wilc_vendor_specific_ie *)vendor_ie;
+ wilc_wfi_cfg_parse_ch_attr(p->attr, p->tag_len - 4, vif->wilc->sta_ch);
+
+out_set_timeout:
+ wfi_drv->p2p_timeout = (jiffies + msecs_to_jiffies(wait));
+
+out_txq_add_pkt:
+
+ wilc_wlan_txq_add_mgmt_pkt(wdev->netdev, mgmt_tx,
+ mgmt_tx->buff, mgmt_tx->size,
+ wilc_wfi_mgmt_tx_complete);
+
+out:
+
+ return ret;
+}
+
+static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u64 cookie)
+{
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+
+ wfi_drv->p2p_timeout = jiffies;
+
+ if (!priv->p2p_listen_state) {
+ struct wilc_wfi_p2p_listen_params *params;
+
+ params = &priv->remain_on_ch_params;
+
+ cfg80211_remain_on_channel_expired(wdev,
+ params->listen_cookie,
+ params->listen_ch,
+ GFP_KERNEL);
+ }
+
+ return 0;
+}
+
+void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
+ u16 frame_type, bool reg)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+
+ if (!frame_type)
+ return;
+
+ switch (frame_type) {
+ case IEEE80211_STYPE_PROBE_REQ:
+ vif->frame_reg[0].type = frame_type;
+ vif->frame_reg[0].reg = reg;
+ break;
+
+ case IEEE80211_STYPE_ACTION:
+ vif->frame_reg[1].type = frame_type;
+ vif->frame_reg[1].reg = reg;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!wl->initialized)
+ return;
+ wilc_frame_register(vif, frame_type, reg);
+}
+
+static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst)
+{
+ return 0;
+}
+
+static int dump_station(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *mac, struct station_info *sinfo)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ int ret;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
+
+ ret = wilc_get_rssi(vif, &sinfo->signal);
+ if (ret)
+ return ret;
+
+ memcpy(mac, vif->priv.associated_bss, ETH_ALEN);
+ return 0;
+}
+
+static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+
+ if (!priv->hif_drv)
+ return -EIO;
+
+ wilc_set_power_mgmt(vif, enabled, timeout);
+
+ return 0;
+}
+
+static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
+ enum nl80211_iftype type,
+ struct vif_params *params)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ vif->connecting = false;
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev.iftype = type;
+ vif->monitor_flag = 0;
+ if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)
+ wilc_wfi_deinit_mon_interface(wl, true);
+ vif->iftype = WILC_STATION_MODE;
+
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_STATION_MODE, vif->idx);
+
+ memset(priv->assoc_stainfo.sta_associated_bss, 0,
+ WILC_MAX_NUM_STA * ETH_ALEN);
+ break;
+
+ case NL80211_IFTYPE_P2P_CLIENT:
+ vif->connecting = false;
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev.iftype = type;
+ vif->monitor_flag = 0;
+ vif->iftype = WILC_CLIENT_MODE;
+
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_STATION_MODE, vif->idx);
+ break;
+
+ case NL80211_IFTYPE_AP:
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev.iftype = type;
+ vif->iftype = WILC_AP_MODE;
+
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_AP_MODE, vif->idx);
+ break;
+
+ case NL80211_IFTYPE_P2P_GO:
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev.iftype = type;
+ vif->iftype = WILC_GO_MODE;
+
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_AP_MODE, vif->idx);
+ break;
+
+ default:
+ netdev_err(dev, "Unknown interface type= %d\n", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int start_ap(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ap_settings *settings)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ int ret;
+
+ ret = set_channel(wiphy, &settings->chandef);
+ if (ret != 0)
+ netdev_err(dev, "Error in setting channel\n");
+
+ wilc_wlan_set_bssid(dev, dev->dev_addr, WILC_AP_MODE);
+
+ return wilc_add_beacon(vif, settings->beacon_interval,
+ settings->dtim_period, &settings->beacon);
+}
+
+static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_beacon_data *beacon)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+
+ return wilc_add_beacon(vif, 0, 0, beacon);
+}
+
+static int stop_ap(struct wiphy *wiphy, struct net_device *dev)
+{
+ int ret;
+ struct wilc_vif *vif = netdev_priv(dev);
+
+ wilc_wlan_set_bssid(dev, NULL, WILC_AP_MODE);
+
+ ret = wilc_del_beacon(vif);
+
+ if (ret)
+ netdev_err(dev, "Host delete beacon fail\n");
+
+ return ret;
+}
+
+static int add_station(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *mac, struct station_parameters *params)
+{
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+
+ if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
+ memcpy(priv->assoc_stainfo.sta_associated_bss[params->aid], mac,
+ ETH_ALEN);
+
+ ret = wilc_add_station(vif, mac, params);
+ if (ret)
+ netdev_err(dev, "Host add station fail\n");
+ }
+
+ return ret;
+}
+
+static int del_station(struct wiphy *wiphy, struct net_device *dev,
+ struct station_del_parameters *params)
+{
+ const u8 *mac = params->mac;
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+ struct sta_info *info;
+
+ if (!(vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE))
+ return ret;
+
+ info = &priv->assoc_stainfo;
+
+ if (!mac)
+ ret = wilc_del_allstation(vif, info->sta_associated_bss);
+
+ ret = wilc_del_station(vif, mac);
+ if (ret)
+ netdev_err(dev, "Host delete station fail\n");
+ return ret;
+}
+
+static int change_station(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *mac, struct station_parameters *params)
+{
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+
+ if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
+ ret = wilc_edit_station(vif, mac, params);
+ if (ret)
+ netdev_err(dev, "Host edit station fail\n");
+ }
+ return ret;
+}
+
+static struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type)
+{
+ struct wilc_vif *vif;
+
+ list_for_each_entry_rcu(vif, &wl->vif_list, list) {
+ if (vif->iftype == type)
+ return vif;
+ }
+
+ return NULL;
+}
+
+static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
+ const char *name,
+ unsigned char name_assign_type,
+ enum nl80211_iftype type,
+ struct vif_params *params)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ struct wireless_dev *wdev;
+ int iftype;
+
+ if (type == NL80211_IFTYPE_MONITOR) {
+ struct net_device *ndev;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_vif_from_type(wl, WILC_AP_MODE);
+ if (!vif) {
+ vif = wilc_get_vif_from_type(wl, WILC_GO_MODE);
+ if (!vif) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ goto validate_interface;
+ }
+ }
+
+ if (vif->monitor_flag) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ goto validate_interface;
+ }
+
+ ndev = wilc_wfi_init_mon_interface(wl, name, vif->ndev);
+ if (ndev) {
+ vif->monitor_flag = 1;
+ } else {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ wdev = &vif->priv.wdev;
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return wdev;
+ }
+
+validate_interface:
+ mutex_lock(&wl->vif_mutex);
+ if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) {
+ pr_err("Reached maximum number of interface\n");
+ mutex_unlock(&wl->vif_mutex);
+ return ERR_PTR(-EINVAL);
+ }
+ mutex_unlock(&wl->vif_mutex);
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ iftype = WILC_STATION_MODE;
+ break;
+ case NL80211_IFTYPE_AP:
+ iftype = WILC_AP_MODE;
+ break;
+ default:
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
+ vif = wilc_netdev_ifc_init(wl, name, iftype, type, true);
+ if (IS_ERR(vif))
+ return ERR_CAST(vif);
+
+ return &vif->priv.wdev;
+}
+
+static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+
+ if (wdev->iftype == NL80211_IFTYPE_AP ||
+ wdev->iftype == NL80211_IFTYPE_P2P_GO)
+ wilc_wfi_deinit_mon_interface(wl, true);
+ vif = netdev_priv(wdev->netdev);
+ cfg80211_stop_iface(wiphy, wdev, GFP_KERNEL);
+ unregister_netdevice(vif->ndev);
+ vif->monitor_flag = 0;
+
+ wilc_set_operation_mode(vif, 0, 0, 0);
+ mutex_lock(&wl->vif_mutex);
+ list_del_rcu(&vif->list);
+ wl->vif_num--;
+ mutex_unlock(&wl->vif_mutex);
+ synchronize_srcu(&wl->srcu);
+ return 0;
+}
+
+static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+
+ if (!wow && wilc_wlan_get_num_conn_ifcs(wl))
+ wl->suspend_event = true;
+ else
+ wl->suspend_event = false;
+
+ return 0;
+}
+
+static int wilc_resume(struct wiphy *wiphy)
+{
+ return 0;
+}
+
+static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif)) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return;
+ }
+
+ netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled);
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+}
+
+static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, int mbm)
+{
+ int ret;
+ int srcu_idx;
+ s32 tx_power = MBM_TO_DBM(mbm);
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+
+ if (!wl->initialized)
+ return -EIO;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif)) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return -EINVAL;
+ }
+
+ netdev_info(vif->ndev, "Setting tx power %d\n", tx_power);
+ if (tx_power < 0)
+ tx_power = 0;
+ else if (tx_power > 18)
+ tx_power = 18;
+ ret = wilc_set_tx_power(vif, tx_power);
+ if (ret)
+ netdev_err(vif->ndev, "Failed to set tx power\n");
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+
+ return ret;
+}
+
+static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ int *dbm)
+{
+ int ret;
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc *wl = vif->wilc;
+
+ /* If firmware is not started, return. */
+ if (!wl->initialized)
+ return -EIO;
+
+ ret = wilc_get_tx_power(vif, (u8 *)dbm);
+ if (ret)
+ netdev_err(vif->ndev, "Failed to get tx power\n");
+
+ return ret;
+}
+
+static const struct cfg80211_ops wilc_cfg80211_ops = {
+ .set_monitor_channel = set_channel,
+ .scan = scan,
+ .connect = connect,
+ .disconnect = disconnect,
+ .add_key = add_key,
+ .del_key = del_key,
+ .get_key = get_key,
+ .set_default_key = set_default_key,
+ .add_virtual_intf = add_virtual_intf,
+ .del_virtual_intf = del_virtual_intf,
+ .change_virtual_intf = change_virtual_intf,
+
+ .start_ap = start_ap,
+ .change_beacon = change_beacon,
+ .stop_ap = stop_ap,
+ .add_station = add_station,
+ .del_station = del_station,
+ .change_station = change_station,
+ .get_station = get_station,
+ .dump_station = dump_station,
+ .change_bss = change_bss,
+ .set_wiphy_params = set_wiphy_params,
+
+ .set_pmksa = set_pmksa,
+ .del_pmksa = del_pmksa,
+ .flush_pmksa = flush_pmksa,
+ .remain_on_channel = remain_on_channel,
+ .cancel_remain_on_channel = cancel_remain_on_channel,
+ .mgmt_tx_cancel_wait = mgmt_tx_cancel_wait,
+ .mgmt_tx = mgmt_tx,
+ .mgmt_frame_register = wilc_mgmt_frame_register,
+ .set_power_mgmt = set_power_mgmt,
+ .set_cqm_rssi_config = set_cqm_rssi_config,
+
+ .suspend = wilc_suspend,
+ .resume = wilc_resume,
+ .set_wakeup = wilc_set_wakeup,
+ .set_tx_power = set_tx_power,
+ .get_tx_power = get_tx_power,
+
+};
+
+static void wlan_init_locks(struct wilc *wl)
+{
+ mutex_init(&wl->hif_cs);
+ mutex_init(&wl->rxq_cs);
+ mutex_init(&wl->cfg_cmd_lock);
+ mutex_init(&wl->vif_mutex);
+
+ spin_lock_init(&wl->txq_spinlock);
+ mutex_init(&wl->txq_add_to_head_cs);
+
+ init_completion(&wl->txq_event);
+ init_completion(&wl->cfg_event);
+ init_completion(&wl->sync_event);
+ init_completion(&wl->txq_thread_started);
+ init_srcu_struct(&wl->srcu);
+}
+
+void wlan_deinit_locks(struct wilc *wilc)
+{
+ mutex_destroy(&wilc->hif_cs);
+ mutex_destroy(&wilc->rxq_cs);
+ mutex_destroy(&wilc->cfg_cmd_lock);
+ mutex_destroy(&wilc->txq_add_to_head_cs);
+ mutex_destroy(&wilc->vif_mutex);
+ cleanup_srcu_struct(&wilc->srcu);
+}
+
+int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
+ const struct wilc_hif_func *ops)
+{
+ struct wilc *wl;
+ struct wilc_vif *vif;
+ int ret;
+
+ wl = wilc_create_wiphy(dev);
+ if (!wl)
+ return -EINVAL;
+
+ wlan_init_locks(wl);
+
+ ret = wilc_wlan_cfg_init(wl);
+ if (ret)
+ goto free_wl;
+
+ *wilc = wl;
+ wl->io_type = io_type;
+ wl->hif_func = ops;
+ wl->chip_ps_state = WILC_CHIP_WAKEDUP;
+ INIT_LIST_HEAD(&wl->txq_head.list);
+ INIT_LIST_HEAD(&wl->rxq_head.list);
+ INIT_LIST_HEAD(&wl->vif_list);
+
+ wl->hif_workqueue = create_singlethread_workqueue("WILC_wq");
+ if (!wl->hif_workqueue) {
+ ret = -ENOMEM;
+ goto free_cfg;
+ }
+ vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE,
+ NL80211_IFTYPE_STATION, false);
+ if (IS_ERR(vif)) {
+ ret = PTR_ERR(vif);
+ goto free_hq;
+ }
+
+ return 0;
+
+free_hq:
+ destroy_workqueue(wl->hif_workqueue);
+
+free_cfg:
+ wilc_wlan_cfg_deinit(wl);
+
+free_wl:
+ wlan_deinit_locks(wl);
+ wiphy_unregister(wl->wiphy);
+ wiphy_free(wl->wiphy);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
+
+struct wilc *wilc_create_wiphy(struct device *dev)
+{
+ struct wiphy *wiphy;
+ struct wilc *wl;
+ int ret;
+
+ wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl));
+ if (!wiphy)
+ return NULL;
+
+ wl = wiphy_priv(wiphy);
+
+ memcpy(wl->bitrates, wilc_bitrates, sizeof(wilc_bitrates));
+ memcpy(wl->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels));
+ wl->band.bitrates = wl->bitrates;
+ wl->band.n_bitrates = ARRAY_SIZE(wl->bitrates);
+ wl->band.channels = wl->channels;
+ wl->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels);
+
+ wl->band.ht_cap.ht_supported = 1;
+ wl->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+ wl->band.ht_cap.mcs.rx_mask[0] = 0xff;
+ wl->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
+ wl->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
+
+ wiphy->bands[NL80211_BAND_2GHZ] = &wl->band;
+
+ wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID;
+#ifdef CONFIG_PM
+ wiphy->wowlan = &wowlan_support;
+#endif
+ wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
+ wiphy->max_scan_ie_len = 1000;
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ memcpy(wl->cipher_suites, wilc_cipher_suites,
+ sizeof(wilc_cipher_suites));
+ wiphy->cipher_suites = wl->cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites);
+ wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
+
+ wiphy->max_remain_on_channel_duration = 500;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MONITOR) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT);
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
+ set_wiphy_dev(wiphy, dev);
+ wl->wiphy = wiphy;
+ ret = wiphy_register(wiphy);
+ if (ret) {
+ wiphy_free(wiphy);
+ return NULL;
+ }
+ return wl;
+}
+
+int wilc_init_host_int(struct net_device *net)
+{
+ int ret;
+ struct wilc_vif *vif = netdev_priv(net);
+ struct wilc_priv *priv = &vif->priv;
+
+ priv->p2p_listen_state = false;
+
+ mutex_init(&priv->scan_req_lock);
+ ret = wilc_init(net, &priv->hif_drv);
+ if (ret)
+ netdev_err(net, "Error while initializing hostinterface\n");
+
+ return ret;
+}
+
+void wilc_deinit_host_int(struct net_device *net)
+{
+ int ret;
+ struct wilc_vif *vif = netdev_priv(net);
+ struct wilc_priv *priv = &vif->priv;
+
+ priv->p2p_listen_state = false;
+
+ flush_workqueue(vif->wilc->hif_workqueue);
+ mutex_destroy(&priv->scan_req_lock);
+ ret = wilc_deinit(vif);
+
+ if (ret)
+ netdev_err(net, "Error while deinitializing host interface\n");
+}
+
--
2.24.0

2020-03-02 16:36:16

by Ajay Singh

[permalink] [raw]
Subject: [PATCH v4 09/18] wilc1000: add netdev.c

From: Ajay Singh <[email protected]>

Moved 'drivers/staging/wilc1000/netdev.c' to
'drivers/net/wireless/microchip/wilc1000/netdev.c'.

Signed-off-by: Ajay Singh <[email protected]>
---
.../net/wireless/microchip/wilc1000/netdev.c | 940 ++++++++++++++++++
1 file changed, 940 insertions(+)
create mode 100644 drivers/net/wireless/microchip/wilc1000/netdev.c

diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c
new file mode 100644
index 000000000000..045f5cdfdca0
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.c
@@ -0,0 +1,940 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+
+#include "cfg80211.h"
+#include "wlan_cfg.h"
+
+#define WILC_MULTICAST_TABLE_SIZE 8
+
+static irqreturn_t isr_uh_routine(int irq, void *user_data)
+{
+ struct net_device *dev = user_data;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ if (wilc->close) {
+ netdev_err(dev, "Can't handle UH interrupt\n");
+ return IRQ_HANDLED;
+ }
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t isr_bh_routine(int irq, void *userdata)
+{
+ struct net_device *dev = userdata;
+ struct wilc_vif *vif = netdev_priv(userdata);
+ struct wilc *wilc = vif->wilc;
+
+ if (wilc->close) {
+ netdev_err(dev, "Can't handle BH interrupt\n");
+ return IRQ_HANDLED;
+ }
+
+ wilc_handle_isr(wilc);
+
+ return IRQ_HANDLED;
+}
+
+static int init_irq(struct net_device *dev)
+{
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+
+ ret = gpiod_direction_input(wl->gpio_irq);
+ if (ret) {
+ netdev_err(dev, "could not obtain gpio for WILC_INTR\n");
+ return ret;
+ }
+
+ wl->dev_irq_num = gpiod_to_irq(wl->gpio_irq);
+
+ ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine,
+ isr_bh_routine,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "WILC_IRQ", dev);
+ if (ret < 0)
+ netdev_err(dev, "Failed to request IRQ\n");
+ else
+ netdev_dbg(dev, "IRQ request succeeded IRQ-NUM= %d\n",
+ wl->dev_irq_num);
+
+ return ret;
+}
+
+static void deinit_irq(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ /* Deinitialize IRQ */
+ if (wilc->dev_irq_num)
+ free_irq(wilc->dev_irq_num, wilc);
+}
+
+void wilc_mac_indicate(struct wilc *wilc)
+{
+ s8 status;
+
+ wilc_wlan_cfg_get_val(wilc, WID_STATUS, &status, 1);
+ if (wilc->mac_status == WILC_MAC_STATUS_INIT) {
+ wilc->mac_status = status;
+ complete(&wilc->sync_event);
+ } else {
+ wilc->mac_status = status;
+ }
+}
+
+static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
+{
+ struct net_device *ndev = NULL;
+ struct wilc_vif *vif;
+ struct ieee80211_hdr *h = (struct ieee80211_hdr *)mac_header;
+
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ if (vif->mode == WILC_STATION_MODE)
+ if (ether_addr_equal_unaligned(h->addr2, vif->bssid)) {
+ ndev = vif->ndev;
+ goto out;
+ }
+ if (vif->mode == WILC_AP_MODE)
+ if (ether_addr_equal_unaligned(h->addr1, vif->bssid)) {
+ ndev = vif->ndev;
+ goto out;
+ }
+ }
+out:
+ return ndev;
+}
+
+void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
+{
+ struct wilc_vif *vif = netdev_priv(wilc_netdev);
+
+ if (bssid)
+ ether_addr_copy(vif->bssid, bssid);
+ else
+ eth_zero_addr(vif->bssid);
+
+ vif->mode = mode;
+}
+
+int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
+{
+ int srcu_idx;
+ u8 ret_val = 0;
+ struct wilc_vif *vif;
+
+ srcu_idx = srcu_read_lock(&wilc->srcu);
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ if (!is_zero_ether_addr(vif->bssid))
+ ret_val++;
+ }
+ srcu_read_unlock(&wilc->srcu, srcu_idx);
+ return ret_val;
+}
+
+static int wilc_txq_task(void *vp)
+{
+ int ret;
+ u32 txq_count;
+ struct wilc *wl = vp;
+
+ complete(&wl->txq_thread_started);
+ while (1) {
+ wait_for_completion(&wl->txq_event);
+
+ if (wl->close) {
+ complete(&wl->txq_thread_started);
+
+ while (!kthread_should_stop())
+ schedule();
+ break;
+ }
+ do {
+ ret = wilc_wlan_handle_txq(wl, &txq_count);
+ if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
+ int srcu_idx;
+ struct wilc_vif *ifc;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ list_for_each_entry_rcu(ifc, &wl->vif_list,
+ list) {
+ if (ifc->mac_opened && ifc->ndev)
+ netif_wake_queue(ifc->ndev);
+ }
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ }
+ } while (ret == WILC_VMM_ENTRY_FULL_RETRY && !wl->close);
+ }
+ return 0;
+}
+
+static int wilc_wlan_get_firmware(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+ int chip_id;
+ const struct firmware *wilc_firmware;
+ char *firmware;
+
+ chip_id = wilc_get_chipid(wilc, false);
+
+ if (chip_id < 0x1003a0)
+ firmware = FIRMWARE_1002;
+ else
+ firmware = FIRMWARE_1003;
+
+ netdev_info(dev, "loading firmware %s\n", firmware);
+
+ if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) {
+ netdev_err(dev, "%s - firmware not available\n", firmware);
+ return -EINVAL;
+ }
+ wilc->firmware = wilc_firmware;
+
+ return 0;
+}
+
+static int wilc_start_firmware(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+ int ret = 0;
+
+ ret = wilc_wlan_start(wilc);
+ if (ret)
+ return ret;
+
+ if (!wait_for_completion_timeout(&wilc->sync_event,
+ msecs_to_jiffies(5000)))
+ return -ETIME;
+
+ return 0;
+}
+
+static int wilc1000_firmware_download(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+ int ret = 0;
+
+ if (!wilc->firmware) {
+ netdev_err(dev, "Firmware buffer is NULL\n");
+ return -ENOBUFS;
+ }
+
+ ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data,
+ wilc->firmware->size);
+ if (ret)
+ return ret;
+
+ release_firmware(wilc->firmware);
+ wilc->firmware = NULL;
+
+ netdev_dbg(dev, "Download Succeeded\n");
+
+ return 0;
+}
+
+static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif)
+{
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *hif_drv;
+ u8 b;
+ u16 hw;
+ u32 w;
+
+ netdev_dbg(dev, "Start configuring Firmware\n");
+ hif_drv = (struct host_if_drv *)priv->hif_drv;
+ netdev_dbg(dev, "Host = %p\n", hif_drv);
+
+ w = vif->iftype;
+ cpu_to_le32s(&w);
+ if (!wilc_wlan_cfg_set(vif, 1, WID_SET_OPERATION_MODE, (u8 *)&w, 4,
+ 0, 0))
+ goto fail;
+
+ b = WILC_FW_BSS_TYPE_INFRA;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_TX_RATE_AUTO;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_OPER_MODE_G_MIXED_11B_2;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_PREAMBLE_SHORT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_11N_PROT_AUTO;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_ACTIVE_SCAN;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_SITE_SURVEY_OFF;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, &b, 1, 0, 0))
+ goto fail;
+
+ hw = 0xffff;
+ cpu_to_le16s(&hw);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, (u8 *)&hw, 2, 0, 0))
+ goto fail;
+
+ hw = 2346;
+ cpu_to_le16s(&hw);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, (u8 *)&hw, 2, 0, 0))
+ goto fail;
+
+ b = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, &b, 1, 0, 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_NO_POWERSAVE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_SEC_NO;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_AUTH_OPEN_SYSTEM;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = 3;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, &b, 1, 0, 0))
+ goto fail;
+
+ b = 3;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_ACK_POLICY_NORMAL;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, &b, 1, 0, 0))
+ goto fail;
+
+ b = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, &b, 1,
+ 0, 0))
+ goto fail;
+
+ b = 48;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, &b, 1, 0, 0))
+ goto fail;
+
+ b = 28;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, &b, 1, 0, 0))
+ goto fail;
+
+ hw = 100;
+ cpu_to_le16s(&hw);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, (u8 *)&hw, 2, 0, 0))
+ goto fail;
+
+ b = WILC_FW_REKEY_POLICY_DISABLE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, &b, 1, 0, 0))
+ goto fail;
+
+ w = 84600;
+ cpu_to_le32s(&w);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, (u8 *)&w, 4, 0, 0))
+ goto fail;
+
+ w = 500;
+ cpu_to_le32s(&w);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, (u8 *)&w, 4, 0,
+ 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, &b, 1, 0,
+ 0))
+ goto fail;
+
+ b = WILC_FW_ERP_PROT_SELF_CTS;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_11N_OP_MODE_HT_MIXED;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, &b, 1, 0, 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_OBBS_NONHT_DETECT_PROTECT_REPORT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, &b, 1,
+ 0, 0))
+ goto fail;
+
+ b = WILC_FW_HT_PROT_RTS_CTS_NONHT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, &b, 1, 0,
+ 0))
+ goto fail;
+
+ b = 7;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, &b, 1, 0, 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, &b, 1,
+ 1, 1))
+ goto fail;
+
+ return 0;
+
+fail:
+ return -EINVAL;
+}
+
+static void wlan_deinitialize_threads(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+
+ wl->close = 1;
+
+ complete(&wl->txq_event);
+
+ if (wl->txq_thread) {
+ kthread_stop(wl->txq_thread);
+ wl->txq_thread = NULL;
+ }
+}
+
+static void wilc_wlan_deinitialize(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+
+ if (!wl) {
+ netdev_err(dev, "wl is NULL\n");
+ return;
+ }
+
+ if (wl->initialized) {
+ netdev_info(dev, "Deinitializing wilc1000...\n");
+
+ if (!wl->dev_irq_num &&
+ wl->hif_func->disable_interrupt) {
+ mutex_lock(&wl->hif_cs);
+ wl->hif_func->disable_interrupt(wl);
+ mutex_unlock(&wl->hif_cs);
+ }
+ complete(&wl->txq_event);
+
+ wlan_deinitialize_threads(dev);
+ deinit_irq(dev);
+
+ wilc_wlan_stop(wl, vif);
+ wilc_wlan_cleanup(dev);
+
+ wl->initialized = false;
+
+ netdev_dbg(dev, "wilc1000 deinitialization Done\n");
+ } else {
+ netdev_dbg(dev, "wilc1000 is not initialized\n");
+ }
+}
+
+static int wlan_initialize_threads(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc,
+ "K_TXQ_TASK");
+ if (IS_ERR(wilc->txq_thread)) {
+ netdev_err(dev, "couldn't create TXQ thread\n");
+ wilc->close = 0;
+ return PTR_ERR(wilc->txq_thread);
+ }
+ wait_for_completion(&wilc->txq_thread_started);
+
+ return 0;
+}
+
+static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
+{
+ int ret = 0;
+ struct wilc *wl = vif->wilc;
+
+ if (!wl->initialized) {
+ wl->mac_status = WILC_MAC_STATUS_INIT;
+ wl->close = 0;
+
+ ret = wilc_wlan_init(dev);
+ if (ret)
+ return ret;
+
+ ret = wlan_initialize_threads(dev);
+ if (ret)
+ goto fail_wilc_wlan;
+
+ if (wl->gpio_irq && init_irq(dev)) {
+ ret = -EIO;
+ goto fail_threads;
+ }
+
+ if (!wl->dev_irq_num &&
+ wl->hif_func->enable_interrupt &&
+ wl->hif_func->enable_interrupt(wl)) {
+ ret = -EIO;
+ goto fail_irq_init;
+ }
+
+ ret = wilc_wlan_get_firmware(dev);
+ if (ret)
+ goto fail_irq_enable;
+
+ ret = wilc1000_firmware_download(dev);
+ if (ret)
+ goto fail_irq_enable;
+
+ ret = wilc_start_firmware(dev);
+ if (ret)
+ goto fail_irq_enable;
+
+ if (wilc_wlan_cfg_get(vif, 1, WID_FIRMWARE_VERSION, 1, 0)) {
+ int size;
+ char firmware_ver[20];
+
+ size = wilc_wlan_cfg_get_val(wl, WID_FIRMWARE_VERSION,
+ firmware_ver,
+ sizeof(firmware_ver));
+ firmware_ver[size] = '\0';
+ netdev_dbg(dev, "Firmware Ver = %s\n", firmware_ver);
+ }
+
+ ret = wilc_init_fw_config(dev, vif);
+ if (ret) {
+ netdev_err(dev, "Failed to configure firmware\n");
+ goto fail_fw_start;
+ }
+ wl->initialized = true;
+ return 0;
+
+fail_fw_start:
+ wilc_wlan_stop(wl, vif);
+
+fail_irq_enable:
+ if (!wl->dev_irq_num &&
+ wl->hif_func->disable_interrupt)
+ wl->hif_func->disable_interrupt(wl);
+fail_irq_init:
+ if (wl->dev_irq_num)
+ deinit_irq(dev);
+fail_threads:
+ wlan_deinitialize_threads(dev);
+fail_wilc_wlan:
+ wilc_wlan_cleanup(dev);
+ netdev_err(dev, "WLAN initialization FAILED\n");
+ } else {
+ netdev_dbg(dev, "wilc1000 already initialized\n");
+ }
+ return ret;
+}
+
+static int mac_init_fn(struct net_device *ndev)
+{
+ netif_start_queue(ndev);
+ netif_stop_queue(ndev);
+
+ return 0;
+}
+
+static int wilc_mac_open(struct net_device *ndev)
+{
+ struct wilc_vif *vif = netdev_priv(ndev);
+ struct wilc *wl = vif->wilc;
+ unsigned char mac_add[ETH_ALEN] = {0};
+ int ret = 0;
+
+ if (!wl || !wl->dev) {
+ netdev_err(ndev, "device not ready\n");
+ return -ENODEV;
+ }
+
+ netdev_dbg(ndev, "MAC OPEN[%p]\n", ndev);
+
+ ret = wilc_init_host_int(ndev);
+ if (ret)
+ return ret;
+
+ ret = wilc_wlan_initialize(ndev, vif);
+ if (ret) {
+ wilc_deinit_host_int(ndev);
+ return ret;
+ }
+
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype,
+ vif->idx);
+ wilc_get_mac_address(vif, mac_add);
+ netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
+ ether_addr_copy(ndev->dev_addr, mac_add);
+
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ netdev_err(ndev, "Wrong MAC address\n");
+ wilc_deinit_host_int(ndev);
+ wilc_wlan_deinitialize(ndev);
+ return -EINVAL;
+ }
+
+ wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
+ vif->ndev->ieee80211_ptr,
+ vif->frame_reg[0].type,
+ vif->frame_reg[0].reg);
+ wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
+ vif->ndev->ieee80211_ptr,
+ vif->frame_reg[1].type,
+ vif->frame_reg[1].reg);
+ netif_wake_queue(ndev);
+ wl->open_ifcs++;
+ vif->mac_opened = 1;
+ return 0;
+}
+
+static struct net_device_stats *mac_stats(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+
+ return &vif->netstats;
+}
+
+static void wilc_set_multicast_list(struct net_device *dev)
+{
+ struct netdev_hw_addr *ha;
+ struct wilc_vif *vif = netdev_priv(dev);
+ int i;
+ u8 *mc_list;
+ u8 *cur_mc;
+
+ if (dev->flags & IFF_PROMISC)
+ return;
+
+ if (dev->flags & IFF_ALLMULTI ||
+ dev->mc.count > WILC_MULTICAST_TABLE_SIZE) {
+ wilc_setup_multicast_filter(vif, 0, 0, NULL);
+ return;
+ }
+
+ if (dev->mc.count == 0) {
+ wilc_setup_multicast_filter(vif, 1, 0, NULL);
+ return;
+ }
+
+ mc_list = kmalloc_array(dev->mc.count, ETH_ALEN, GFP_ATOMIC);
+ if (!mc_list)
+ return;
+
+ cur_mc = mc_list;
+ i = 0;
+ netdev_for_each_mc_addr(ha, dev) {
+ memcpy(cur_mc, ha->addr, ETH_ALEN);
+ netdev_dbg(dev, "Entry[%d]: %pM\n", i, cur_mc);
+ i++;
+ cur_mc += ETH_ALEN;
+ }
+
+ if (wilc_setup_multicast_filter(vif, 1, dev->mc.count, mc_list))
+ kfree(mc_list);
+}
+
+static void wilc_tx_complete(void *priv, int status)
+{
+ struct tx_complete_data *pv_data = priv;
+
+ dev_kfree_skb(pv_data->skb);
+ kfree(pv_data);
+}
+
+netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct wilc_vif *vif = netdev_priv(ndev);
+ struct wilc *wilc = vif->wilc;
+ struct tx_complete_data *tx_data = NULL;
+ int queue_count;
+
+ if (skb->dev != ndev) {
+ netdev_err(ndev, "Packet not destined to this device\n");
+ return 0;
+ }
+
+ tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
+ if (!tx_data) {
+ dev_kfree_skb(skb);
+ netif_wake_queue(ndev);
+ return 0;
+ }
+
+ tx_data->buff = skb->data;
+ tx_data->size = skb->len;
+ tx_data->skb = skb;
+
+ vif->netstats.tx_packets++;
+ vif->netstats.tx_bytes += tx_data->size;
+ queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
+ tx_data->buff, tx_data->size,
+ wilc_tx_complete);
+
+ if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
+ int srcu_idx;
+ struct wilc_vif *vif;
+
+ srcu_idx = srcu_read_lock(&wilc->srcu);
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ if (vif->mac_opened)
+ netif_stop_queue(vif->ndev);
+ }
+ srcu_read_unlock(&wilc->srcu, srcu_idx);
+ }
+
+ return 0;
+}
+
+static int wilc_mac_close(struct net_device *ndev)
+{
+ struct wilc_vif *vif = netdev_priv(ndev);
+ struct wilc *wl = vif->wilc;
+
+ netdev_dbg(ndev, "Mac close\n");
+
+ if (wl->open_ifcs > 0)
+ wl->open_ifcs--;
+ else
+ return 0;
+
+ if (vif->ndev) {
+ netif_stop_queue(vif->ndev);
+
+ wilc_deinit_host_int(vif->ndev);
+ }
+
+ if (wl->open_ifcs == 0) {
+ netdev_dbg(ndev, "Deinitializing wilc1000\n");
+ wl->close = 1;
+ wilc_wlan_deinitialize(ndev);
+ }
+
+ vif->mac_opened = 0;
+
+ return 0;
+}
+
+void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size,
+ u32 pkt_offset)
+{
+ unsigned int frame_len = 0;
+ int stats;
+ unsigned char *buff_to_send = NULL;
+ struct sk_buff *skb;
+ struct net_device *wilc_netdev;
+ struct wilc_vif *vif;
+
+ if (!wilc)
+ return;
+
+ wilc_netdev = get_if_handler(wilc, buff);
+ if (!wilc_netdev)
+ return;
+
+ buff += pkt_offset;
+ vif = netdev_priv(wilc_netdev);
+
+ if (size > 0) {
+ frame_len = size;
+ buff_to_send = buff;
+
+ skb = dev_alloc_skb(frame_len);
+ if (!skb)
+ return;
+
+ skb->dev = wilc_netdev;
+
+ skb_put_data(skb, buff_to_send, frame_len);
+
+ skb->protocol = eth_type_trans(skb, wilc_netdev);
+ vif->netstats.rx_packets++;
+ vif->netstats.rx_bytes += frame_len;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ stats = netif_rx(skb);
+ netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats);
+ }
+}
+
+void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
+{
+ int srcu_idx;
+ struct wilc_vif *vif;
+
+ srcu_idx = srcu_read_lock(&wilc->srcu);
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ u16 type = le16_to_cpup((__le16 *)buff);
+
+ if (vif->priv.p2p_listen_state &&
+ ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
+ (type == vif->frame_reg[1].type && vif->frame_reg[1].reg)))
+ wilc_wfi_p2p_rx(vif, buff, size);
+
+ if (vif->monitor_flag)
+ wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size);
+ }
+ srcu_read_unlock(&wilc->srcu, srcu_idx);
+}
+
+static const struct net_device_ops wilc_netdev_ops = {
+ .ndo_init = mac_init_fn,
+ .ndo_open = wilc_mac_open,
+ .ndo_stop = wilc_mac_close,
+ .ndo_start_xmit = wilc_mac_xmit,
+ .ndo_get_stats = mac_stats,
+ .ndo_set_rx_mode = wilc_set_multicast_list,
+};
+
+void wilc_netdev_cleanup(struct wilc *wilc)
+{
+ struct wilc_vif *vif;
+ int srcu_idx, ifc_cnt = 0;
+
+ if (!wilc)
+ return;
+
+ if (wilc->firmware) {
+ release_firmware(wilc->firmware);
+ wilc->firmware = NULL;
+ }
+
+ srcu_idx = srcu_read_lock(&wilc->srcu);
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ if (vif->ndev)
+ unregister_netdev(vif->ndev);
+ }
+ srcu_read_unlock(&wilc->srcu, srcu_idx);
+
+ wilc_wfi_deinit_mon_interface(wilc, false);
+ flush_workqueue(wilc->hif_workqueue);
+ destroy_workqueue(wilc->hif_workqueue);
+
+ while (ifc_cnt < WILC_NUM_CONCURRENT_IFC) {
+ mutex_lock(&wilc->vif_mutex);
+ if (wilc->vif_num <= 0) {
+ mutex_unlock(&wilc->vif_mutex);
+ break;
+ }
+ vif = wilc_get_wl_to_vif(wilc);
+ if (!IS_ERR(vif))
+ list_del_rcu(&vif->list);
+
+ wilc->vif_num--;
+ mutex_unlock(&wilc->vif_mutex);
+ synchronize_srcu(&wilc->srcu);
+ ifc_cnt++;
+ }
+
+ wilc_wlan_cfg_deinit(wilc);
+ wlan_deinit_locks(wilc);
+ kfree(wilc->bus_data);
+ wiphy_unregister(wilc->wiphy);
+ wiphy_free(wilc->wiphy);
+}
+EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
+
+static u8 wilc_get_available_idx(struct wilc *wl)
+{
+ int idx = 0;
+ struct wilc_vif *vif;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ list_for_each_entry_rcu(vif, &wl->vif_list, list) {
+ if (vif->idx == 0)
+ idx = 1;
+ else
+ idx = 0;
+ }
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return idx;
+}
+
+struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
+ int vif_type, enum nl80211_iftype type,
+ bool rtnl_locked)
+{
+ struct net_device *ndev;
+ struct wilc_vif *vif;
+ int ret;
+
+ ndev = alloc_etherdev(sizeof(*vif));
+ if (!ndev)
+ return ERR_PTR(-ENOMEM);
+
+ vif = netdev_priv(ndev);
+ ndev->ieee80211_ptr = &vif->priv.wdev;
+ strcpy(ndev->name, name);
+ vif->wilc = wl;
+ vif->ndev = ndev;
+ ndev->ml_priv = vif;
+
+ ndev->netdev_ops = &wilc_netdev_ops;
+
+ SET_NETDEV_DEV(ndev, wiphy_dev(wl->wiphy));
+
+ vif->priv.wdev.wiphy = wl->wiphy;
+ vif->priv.wdev.netdev = ndev;
+ vif->priv.wdev.iftype = type;
+ vif->priv.dev = ndev;
+
+ if (rtnl_locked)
+ ret = register_netdevice(ndev);
+ else
+ ret = register_netdev(ndev);
+
+ if (ret) {
+ free_netdev(ndev);
+ return ERR_PTR(-EFAULT);
+ }
+
+ ndev->needs_free_netdev = true;
+ vif->iftype = vif_type;
+ vif->idx = wilc_get_available_idx(wl);
+ vif->mac_opened = 0;
+ mutex_lock(&wl->vif_mutex);
+ list_add_tail_rcu(&vif->list, &wl->vif_list);
+ wl->vif_num += 1;
+ mutex_unlock(&wl->vif_mutex);
+ synchronize_srcu(&wl->srcu);
+
+ return vif;
+}
+
+MODULE_LICENSE("GPL");
--
2.24.0

2020-03-02 16:36:33

by Ajay Singh

[permalink] [raw]
Subject: [PATCH v4 17/18] dt: bindings: net: add microchip,wilc1000,spi.yaml

From: Ajay Singh <[email protected]>

Moved '/drivers/staging/wilc1000//microchip,wilc1000,spi.yaml' to
'Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml'.

Signed-off-by: Ajay Singh <[email protected]>
---
.../net/wireless/microchip,wilc1000,spi.yaml | 61 +++++++++++++++++++
1 file changed, 61 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml

diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml
new file mode 100644
index 000000000000..cc8ed64ce627
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/wireless/microchip,wilc1000,spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip WILC wireless SPI devicetree bindings
+
+maintainers:
+ - Adham Abozaeid <[email protected]>
+ - Ajay Singh <[email protected]>
+
+description:
+ The wilc1000 chips can be connected via SPI. This document describes
+ the binding for the SPI connected module.
+
+properties:
+ compatible:
+ const: microchip,wilc1000-spi
+
+ spi-max-frequency:
+ description: Maximum SPI clocking speed of device in Hz.
+ maxItems: 1
+
+ reg:
+ description: Chip select address of device.
+ maxItems: 1
+
+ irq-gpios:
+ description: The GPIO phandle connect to a host IRQ.
+ maxItems: 1
+
+ clocks:
+ description: phandle to the clock connected on rtc clock line.
+ maxItems: 1
+
+required:
+ - compatible
+ - spi-max-frequency
+ - reg
+ - irq-gpios
+
+examples:
+ - |
+ spi1: spi@fc018000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cs-gpios = <&pioB 21 0>;
+ status = "okay";
+ wilc_spi@0 {
+ compatible = "microchip,wilc1000-spi";
+ spi-max-frequency = <48000000>;
+ reg = <0>;
+ irq-gpios = <&pioC 27 0>;
+ clocks = <&pck1>;
+ clock-names = "rtc_clk";
+ assigned-clocks = <&pck1>;
+ assigned-clock-rates = <32768>;
+ status = "okay";
+ };
+ };
--
2.24.0

2020-03-03 01:56:47

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v4 16/18] dt: bindings: net: add microchip,wilc1000,sdio.yaml

On Mon, Mar 02, 2020 at 04:34:40PM +0000, [email protected] wrote:
> From: Ajay Singh <[email protected]>
>
> Moved '/drivers/staging/wilc1000/microchip,wilc1000,sdio.yaml' to
> 'Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml'.
>
> Signed-off-by: Ajay Singh <[email protected]>
> ---
> .../net/wireless/microchip,wilc1000,sdio.yaml | 68 +++++++++++++++++++
> 1 file changed, 68 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml
>
> diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml
> new file mode 100644
> index 000000000000..b338f569f7e2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml
> @@ -0,0 +1,68 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/wireless/microchip,wilc1000,sdio.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Microchip WILC wireless SDIO devicetree bindings
> +
> +maintainers:
> + - Adham Abozaeid <[email protected]>
> + - Ajay Singh <[email protected]>
> +
> +description:
> + The wilc1000 chips can be connected via SDIO. The node is used to
> + specify child node to the SDIO controller that connects the device
> + to the system.
> +
> +properties:
> + compatible:
> + const: microchip,wilc1000-sdio
> +
> + irq-gpios:

Unless you need GPIO control of the line, use 'interrupts' instead.

> + description: The GPIO phandle connect to a host IRQ.
> + maxItems: 1
> +
> + reg:
> + description: Slot ID used in the controller.

No, it's the function number. But you can just drop this.

> + maxItems: 1
> +
> + clocks:
> + description: phandle to the clock connected on rtc clock line.
> + maxItems: 1
> +
> + bus-width:

I believe this is defined to go in the parent node.

> + description: The number of data lines wired up the slot.
> + allOf:
> + - $ref: /schemas/types.yaml#/definitions/uint32
> + - enum: [1, 4, 8]
> + - default: 1
> +
> +required:
> + - compatible
> + - irq-gpios
> + - reg
> +
> +examples:
> + - |
> + mmc1: mmc@fc000000 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3>;
> + non-removable;
> + vmmc-supply = <&vcc_mmc1_reg>;
> + vqmmc-supply = <&vcc_3v3_reg>;
> + status = "okay";

Don't show 'status' in examples.

> + wilc_sdio@0 {

wifi@0

> + compatible = "microchip,wilc1000-sdio";
> + irq-gpios = <&pioC 27 0>;
> + reg = <0>;
> + clocks = <&pck1>;
> + clock-names = "rtc_clk";
> + assigned-clocks = <&pck1>;
> + assigned-clock-rates = <32768>;
> + status = "okay";
> + bus-width = <4>;
> + };
> + };
> --
> 2.24.0

2020-03-03 02:03:09

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v4 17/18] dt: bindings: net: add microchip,wilc1000,spi.yaml

On Mon, Mar 02, 2020 at 04:34:40PM +0000, [email protected] wrote:
> From: Ajay Singh <[email protected]>
>
> Moved '/drivers/staging/wilc1000//microchip,wilc1000,spi.yaml' to
> 'Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml'.

Not a useful changelog.

I think this should be combined with the SDIO version. Details below.

>
> Signed-off-by: Ajay Singh <[email protected]>
> ---
> .../net/wireless/microchip,wilc1000,spi.yaml | 61 +++++++++++++++++++
> 1 file changed, 61 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml
>
> diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml
> new file mode 100644
> index 000000000000..cc8ed64ce627
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml
> @@ -0,0 +1,61 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/wireless/microchip,wilc1000,spi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Microchip WILC wireless SPI devicetree bindings
> +
> +maintainers:
> + - Adham Abozaeid <[email protected]>
> + - Ajay Singh <[email protected]>
> +
> +description:
> + The wilc1000 chips can be connected via SPI. This document describes
> + the binding for the SPI connected module.
> +
> +properties:
> + compatible:
> + const: microchip,wilc1000-spi

You can drop '-spi' (and '-sdio'). They don't need to be different
because they already sit on different buses.

> +
> + spi-max-frequency:
> + description: Maximum SPI clocking speed of device in Hz.
> + maxItems: 1
> +
> + reg:
> + description: Chip select address of device.
> + maxItems: 1
> +
> + irq-gpios:
> + description: The GPIO phandle connect to a host IRQ.
> + maxItems: 1
> +
> + clocks:
> + description: phandle to the clock connected on rtc clock line.
> + maxItems: 1
> +
> +required:
> + - compatible
> + - spi-max-frequency

This should not be required.

> + - reg
> + - irq-gpios
> +
> +examples:
> + - |
> + spi1: spi@fc018000 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + cs-gpios = <&pioB 21 0>;
> + status = "okay";
> + wilc_spi@0 {
> + compatible = "microchip,wilc1000-spi";
> + spi-max-frequency = <48000000>;
> + reg = <0>;
> + irq-gpios = <&pioC 27 0>;
> + clocks = <&pck1>;
> + clock-names = "rtc_clk";

Not documented. '_clk' is redundant.

> + assigned-clocks = <&pck1>;
> + assigned-clock-rates = <32768>;

Not documented.

> + status = "okay";
> + };
> + };
> --
> 2.24.0

2020-03-03 12:58:25

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH v4 16/18] dt: bindings: net: add microchip,wilc1000,sdio.yaml

Hi Rob,

Thanks for reviewing.

On 03/03/20 7:25 am, Rob Herring wrote:
>
> On Mon, Mar 02, 2020 at 04:34:40PM +0000, [email protected] wrote:
>> From: Ajay Singh <[email protected]>
>>
>> Moved '/drivers/staging/wilc1000/microchip,wilc1000,sdio.yaml' to
>> 'Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml'.
>>
>> Signed-off-by: Ajay Singh <[email protected]>
>> ---
>> .../net/wireless/microchip,wilc1000,sdio.yaml | 68 +++++++++++++++++++
>> 1 file changed, 68 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml
>> new file mode 100644
>> index 000000000000..b338f569f7e2
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.yaml
>> @@ -0,0 +1,68 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/net/wireless/microchip,wilc1000,sdio.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Microchip WILC wireless SDIO devicetree bindings
>> +
>> +maintainers:
>> + - Adham Abozaeid <[email protected]>
>> + - Ajay Singh <[email protected]>
>> +
>> +description:
>> + The wilc1000 chips can be connected via SDIO. The node is used to
>> + specify child node to the SDIO controller that connects the device
>> + to the system.
>> +
>> +properties:
>> + compatible:
>> + const: microchip,wilc1000-sdio
>> +
>> + irq-gpios:
>
> Unless you need GPIO control of the line, use 'interrupts' instead.

I will check this.

>
>> + description: The GPIO phandle connect to a host IRQ.
>> + maxItems: 1
>> +
>> + reg:
>> + description: Slot ID used in the controller.
>
> No, it's the function number. But you can just drop this.
>

Ok. I will drop this description.

>> + maxItems: 1
>> +
>> + clocks:
>> + description: phandle to the clock connected on rtc clock line.
>> + maxItems: 1
>> +
>> + bus-width:
>
> I believe this is defined to go in the parent node.
>

In that case, I think we can drop this description here by moving it to
parent node. right?

>> + description: The number of data lines wired up the slot.
>> + allOf:
>> + - $ref: /schemas/types.yaml#/definitions/uint32
>> + - enum: [1, 4, 8]
>> + - default: 1
>> +
>> +required:
>> + - compatible
>> + - irq-gpios
>> + - reg
>> +
>> +examples:
>> + - |
>> + mmc1: mmc@fc000000 {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3>;
>> + non-removable;
>> + vmmc-supply = <&vcc_mmc1_reg>;
>> + vqmmc-supply = <&vcc_3v3_reg>;
>> + status = "okay";
>
> Don't show 'status' in examples.
>

OK. I will remove this.

>> + wilc_sdio@0 {
>
> wifi@0
>
>> + compatible = "microchip,wilc1000-sdio";
>> + irq-gpios = <&pioC 27 0>;
>> + reg = <0>;
>> + clocks = <&pck1>;
>> + clock-names = "rtc_clk";
>> + assigned-clocks = <&pck1>;
>> + assigned-clock-rates = <32768>;
>> + status = "okay";

I will remove 'status' here also.

>> + bus-width = <4>;

I will move this property to parent node.

>> + };
>> + };
>> --
>> 2.24.0

2020-03-03 13:09:09

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH v4 17/18] dt: bindings: net: add microchip,wilc1000,spi.yaml



On 03/03/20 7:32 am, Rob Herring wrote:
>
> On Mon, Mar 02, 2020 at 04:34:40PM +0000, [email protected] wrote:
>> From: Ajay Singh <[email protected]>
>>
>> Moved '/drivers/staging/wilc1000//microchip,wilc1000,spi.yaml' to
>> 'Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml'.
>
> Not a useful changelog.
>

Sure. I will update the changelog.

> I think this should be combined with the SDIO version. Details below.
>
>>
>> Signed-off-by: Ajay Singh <[email protected]>
>> ---
>> .../net/wireless/microchip,wilc1000,spi.yaml | 61 +++++++++++++++++++
>> 1 file changed, 61 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml
>> new file mode 100644
>> index 000000000000..cc8ed64ce627
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.yaml
>> @@ -0,0 +1,61 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/net/wireless/microchip,wilc1000,spi.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Microchip WILC wireless SPI devicetree bindings
>> +
>> +maintainers:
>> + - Adham Abozaeid <[email protected]>
>> + - Ajay Singh <[email protected]>
>> +
>> +description:
>> + The wilc1000 chips can be connected via SPI. This document describes
>> + the binding for the SPI connected module.
>> +
>> +properties:
>> + compatible:
>> + const: microchip,wilc1000-spi
>
> You can drop '-spi' (and '-sdio'). They don't need to be different
> because they already sit on different buses.
>

In that case, we should use only a single DT binding documentation and
keep both example inside the same file i.e We will have single
properties descriptions with 2 examples(sdio/spi) in a single DT binding
document. Is my understanding correct?

>> +
>> + spi-max-frequency:
>> + description: Maximum SPI clocking speed of device in Hz.
>> + maxItems: 1
>> +
>> + reg:
>> + description: Chip select address of device.
>> + maxItems: 1
>> +
>> + irq-gpios:
>> + description: The GPIO phandle connect to a host IRQ.
>> + maxItems: 1
>> +
>> + clocks:
>> + description: phandle to the clock connected on rtc clock line.
>> + maxItems: 1
>> +
>> +required:
>> + - compatible
>> + - spi-max-frequency
>
> This should not be required.
>

Ok. I will drop this.

>> + - reg
>> + - irq-gpios
>> +
>> +examples:
>> + - |
>> + spi1: spi@fc018000 {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + cs-gpios = <&pioB 21 0>;
>> + status = "okay";
>> + wilc_spi@0 {
>> + compatible = "microchip,wilc1000-spi";
>> + spi-max-frequency = <48000000>;
>> + reg = <0>;
>> + irq-gpios = <&pioC 27 0>;
>> + clocks = <&pck1>;
>> + clock-names = "rtc_clk";
>
> Not documented. '_clk' is redundant.
>

Ok. I will update the clock-names and add the description.

>> + assigned-clocks = <&pck1>;
>> + assigned-clock-rates = <32768>;
>
> Not documented.
>

Ok. I will add the description.


Regards,
Ajay