[PATCH] cfg80211: make wifi driver probe

From: Daisy Zhang251
Date: Fri Oct 16 2020 - 03:36:36 EST


From: Daisy Zhang1 <daisy.zhang1@xxxxxxxxxx>

Register a WiFi driver of IEEE80211 WLAN for the Unisoc Marlin3
chipsets. The following code is a simple architecture for probing
driver.

Signed-off-by: Daisy Zhang1 <daisy.zhang1@xxxxxxxxxx>
---
drivers/net/wireless/sprd/Kconfig | 21 +++++
drivers/net/wireless/sprd/Makefile | 15 ++++
drivers/net/wireless/sprd/core_sc2355.c | 113 +++++++++++++++++++++++
drivers/net/wireless/sprd/core_sc2355.h | 115 ++++++++++++++++++++++++
drivers/net/wireless/sprd/interface.h | 33 +++++++
drivers/net/wireless/sprd/message.h | 95 ++++++++++++++++++++
drivers/net/wireless/sprd/wireless.h | 69 ++++++++++++++
7 files changed, 461 insertions(+)
create mode 100644 drivers/net/wireless/sprd/Kconfig
create mode 100644 drivers/net/wireless/sprd/Makefile
create mode 100644 drivers/net/wireless/sprd/core_sc2355.c
create mode 100644 drivers/net/wireless/sprd/core_sc2355.h
create mode 100644 drivers/net/wireless/sprd/interface.h
create mode 100644 drivers/net/wireless/sprd/message.h
create mode 100644 drivers/net/wireless/sprd/wireless.h

diff --git a/drivers/net/wireless/sprd/Kconfig b/drivers/net/wireless/sprd/Kconfig
index 000000000000..b68db761a460
--- /dev/null
+++ b/drivers/net/wireless/sprd/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# config kernel for the Unisoc Wi-Fi driver
+
+config SPRD_WLAN
+ tristate "Unisoc Wireless LAN Support"
+ depends on CFG80211
+ help
+ This is a driver of IEEE80211 WLAN for the Unisoc WiFi chipsets.
+ This driver works on Marlin3 chip, which is the 3rd WiFi chipsets
+ of the Unisoc.
+ When compiled as a module, it will be called sprdwl_ng.
+
+config SPRD_WLAN_MARLIN3
+ bool "MARLIN3"
+
+ help
+ Select this to support the Unisoc SC2355 branch, which includes
+ SDIO and PCIe interfaces to translate data and works on Marlin3
+ chips. SDIO interface and PCIe interface correspond to different
+ code logic for different customer projects.
+
+endchoice
diff --git a/drivers/net/wireless/sprd/Makefile b/drivers/net/wireless/sprd/Makefile
index 000000000000..a1eae0b4e302
--- /dev/null
+++ b/drivers/net/wireless/sprd/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Makefile for the Unisoc Wi-Fi driver
+
+#####module name ###
+obj-m += sprdwl_ng.o
+
+#######add .o file#####
+sprdwl_ng-objs += core_sc2355.o
+
+modules:
+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) $@
+clean:
+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) $@
+kernelrelease:
+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) $@
diff --git a/drivers/net/wireless/sprd/core_sc2355.c b/drivers/net/wireless/sprd/core_sc2355.c
index 000000000000..27e1c5346b4e
--- /dev/null
+++ b/drivers/net/wireless/sprd/core_sc2355.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Wi-Fi driver of the Unisoc for Marlin3 chip:
+// register a Wi-Fi driver of IEEE802.11 WLAN for the Unisoc
+//
+// Copyright(C) 2018 Unisoc,Inc
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/utsname.h>
+#include "core_sc2355.h"
+#include "interface.h"
+#include "wireless.h"
+
+static int sprdwl_ini_download_status(void)
+{
+ return 0;
+}
+
+static void sprdwl_force_exit(void *spdev)
+{
+ struct sprdwl_intf *intf = (struct sprdwl_intf *)spdev;
+
+ intf->exit = 1;
+}
+
+static int sprdwl_is_exit(void *spdev)
+{
+ struct sprdwl_intf *intf = (struct sprdwl_intf *)spdev;
+
+ return intf->exit;
+}
+
+static struct sprdwl_if_ops sprdwl_core_ops = {
+ .force_exit = sprdwl_force_exit,
+ .is_exit = sprdwl_is_exit,
+ .ini_download_status = sprdwl_ini_download_status
+};
+
+static int sprdwl_probe(struct platform_device *pdev)
+{
+ struct sprdwl_intf *intf;
+ struct sprdwl_priv *priv;
+ int ret;
+ u8 i;
+
+ intf = kzalloc(sizeof(*intf), GFP_ATOMIC);
+ if (!intf) {
+ ret = -ENOMEM;
+ dev_err(sprdwl_dev, "sc2355 sprd-wlan:%s alloc intf fail: %d\n", __func__, ret);
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, intf);
+ intf->pdev = pdev;
+ sprdwl_dev = &pdev->dev;
+
+ for (i = 0; i < MAX_LUT_NUM; i++)
+ intf->peer_entry[i].ctx_id = 0xff;
+
+ priv = sprdwl_core_create(SPRDWL_HW_SC2355_SDIO,
+ &sprdwl_core_ops);
+ if (!priv) {
+ dev_err(sprdwl_dev, "sc2355 sprd-wlan:%s core create fail\n", __func__);
+ ret = -ENXIO;
+ goto err;
+ }
+
+ ret = sprdwl_core_init(&pdev->dev, priv);
+ if (ret)
+ goto err;
+
+ return ret;
+
+err:
+ kfree(intf);
+out:
+ return ret;
+}
+
+static int sprdwl_remove(struct platform_device *pdev)
+{
+ struct sprdwl_intf *intf = platform_get_drvdata(pdev);
+ struct sprdwl_priv *priv = intf->priv;
+
+ sprdwl_core_deinit(priv);
+ sprdwl_core_free(priv);
+ kfree(intf);
+
+ return 0;
+}
+
+static const struct of_device_id sprdwl_of_match[] = {
+ {.compatible = "sprd,sc2355-wifi",},
+ {}
+};
+MODULE_DEVICE_TABLE(of, sprdwl_of_match);
+
+static struct platform_driver sprdwl_driver = {
+ .probe = sprdwl_probe,
+ .remove = sprdwl_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "sc2355",
+ .of_match_table = sprdwl_of_match
+ }
+};
+
+module_platform_driver(sprdwl_driver);
+
+MODULE_DESCRIPTION("Unisoc Wireless LAN Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/sprd/core_sc2355.h b/drivers/net/wireless/sprd/core_sc2355.h
index 000000000000..7ff1292dbef0
--- /dev/null
+++ b/drivers/net/wireless/sprd/core_sc2355.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// Wi-Fi driver of the Unisoc for the Marlin3 chip:
+// register a Wi-Fi driver of IEEE802.11 WLAN for the Unisoc
+//
+// Copyright(C) 2018 Unisoc,Inc
+
+#define SPRDWL_NORMAL_MEM 0
+#define SPRDWL_DEFRAG_MEM 1
+
+#define SPRDWL_TX_CMD_TIMEOUT 3000
+#define SPRDWL_TX_DATA_TIMEOUT 4000
+
+#define SPRDWL_TX_MSG_CMD_NUM 128
+#define SPRDWL_TX_MSG_SPECIAL_DATA_NUM 256
+#define SPRDWL_TX_QOS_POOL_SIZE 20000
+#define SPRDWL_TX_DATA_START_NUM (SPRDWL_TX_QOS_POOL_SIZE - 3)
+#define SPRDWL_RX_MSG_NUM 20000
+
+#define SPRDWL_MAX_CMD_TXLEN 1596
+#define SPRDWL_MAX_CMD_RXLEN 1092
+#define SPRDWL_MAX_DATA_TXLEN 1672
+#define SPRDWL_MAX_DATA_RXLEN 1676
+
+#define MAX_LUT_NUM 32
+
+/* struct tx_address: the tx mac address of da and sa
+ * @da: destination address
+ * @sa: source address
+ */
+struct tx_address {
+ u8 da[ETH_ALEN];
+ u8 sa[ETH_ALEN];
+};
+
+/* struct rx_address: the rx mac address of da and sa
+ * @sa: source address
+ * @da: destination address
+ */
+struct rx_address {
+ u8 sa[ETH_ALEN];
+ u8 da[ETH_ALEN];
+};
+
+/* struct sprdwl_peer_entry: the information of peer connectted
+ * @rx: rx mac address
+ * @tx: tx mac address
+ * @lut_index: lookup table index of current peer
+ * @ctx_id: wifi context index of stap mode
+ * @ht_enable: indicate current peer high thoughput enabled
+ * @vht_enable: indicate current peer very high thoughput enabled
+ * @ip_acquired: indicate current peer ip address acquired
+ * @ba_tx_done_map: indicate current peer tx ba session enabled
+ * @vowifi_enabled: indicate current peer vowifi scenario enabled
+ */
+struct sprdwl_peer_entry {
+ union {
+ struct rx_address rx;
+ struct tx_address tx;
+ };
+
+ u8 lut_index;
+ u8 ctx_id;
+ u8 cipher_type;
+ u8 pending_num;
+ u8 ht_enable;
+ u8 vht_enable;
+ u8 ip_acquired;
+ unsigned long ba_tx_done_map;
+ u8 vowifi_enabled;
+};
+
+/* struct sprdwl_priv: the information of priv definition
+ */
+struct sprdwl_priv;
+
+/* struct sprdwl_intf: the information of interface
+ * @pdev: platform device
+ * @priv: wifi private struct
+ * @exit: indicate driver exit
+ * @tx_mode: value of tx mode
+ * @rx_mode: value of rx mode
+ * @hw_intf: the hardware interface type
+ * @sprdwl_tx: pointer to tx information struct
+ * @sprdwl_rx: pointer to rx information struct
+ * @peer_entry: the information of peer connectted
+ * @skb_da: destination address of this interface
+ * @hif_offset: data offset of the hardware interface
+ * @rx_cmd_port: cmd port for rx
+ * @rx_data_port: data port for rx
+ * @tx_cmd_port: cmd port for tx
+ * @tx_data_port: data port for tx
+ * @cp_asserted: indicate cp2 asserted
+ */
+struct sprdwl_intf {
+ struct platform_device *pdev;
+ struct sprdwl_priv *priv;
+ int exit;
+ int flag;
+ int tx_mode;
+ int rx_mode;
+ void *hw_intf;
+ void *sprdwl_tx;
+ void *sprdwl_rx;
+ struct sprdwl_peer_entry peer_entry[MAX_LUT_NUM];
+ unsigned char *skb_da;
+ int hif_offset;
+ unsigned char rx_cmd_port;
+ unsigned char rx_data_port;
+ unsigned char tx_cmd_port;
+ unsigned char tx_data_port;
+ u8 cp_asserted;
+};
+
+struct device *sprdwl_dev;
diff --git a/drivers/net/wireless/sprd/interface.h b/drivers/net/wireless/sprd/interface.h
index 000000000000..3ef1351f8d59
--- /dev/null
+++ b/drivers/net/wireless/sprd/interface.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// Wi-Fi driver of the Unisoc for Marlin3 chip:
+// interface operations
+//
+// Copyright(C) 2018 Unisoc,Inc
+
+#ifndef __SPRDWL_INTF_H__
+#define __SPRDWL_INTF_H__
+
+#include "message.h"
+#include "wireless.h"
+
+/* struct sprdwl_if_ops: interface operations
+ * @get_msg_buf: get a free message buffer from list
+ * @free_msg_buf: free the message buffer to use again
+ * @tx: transmit message buffer to tx thread
+ * @force_exit: force remove driver
+ * @is_exit: indicate driver exit or not
+ * @ini_download_status: indicate ini downloaded or not
+ */
+struct sprdwl_if_ops {
+ struct sprdwl_msg_buf *(*get_msg_buf)(void *sdev,
+ enum sprdwl_head_type type,
+ enum sprdwl_mode mode,
+ u8 ctx_id);
+ void (*free_msg_buf)(void *sdev, struct sprdwl_msg_buf *msg);
+ int (*tx)(void *spdev, struct sprdwl_msg_buf *msg);
+ void (*force_exit)(void *spdev);
+ int (*is_exit)(void *spdev);
+ int (*ini_download_status)(void);
+};
+#endif
diff --git a/drivers/net/wireless/sprd/message.h b/drivers/net/wireless/sprd/message.h
index 000000000000..841ceb626483
--- /dev/null
+++ b/drivers/net/wireless/sprd/message.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// Wi-Fi driver of the Unisoc for Marlin3 chip:
+// management the message buffer
+//
+// Copyright(C) 2018 Unisoc,Inc.
+
+#ifndef __SPRDWL_MSG_H__
+#define __SPRDWL_MSG_H__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+enum sprdwl_mode {
+ SPRDWL_MODE_NONE,
+ SPRDWL_MODE_STATION,
+ SPRDWL_MODE_AP,
+
+ SPRDWL_MODE_P2P_DEVICE = 4,
+ SPRDWL_MODE_P2P_CLIENT,
+ SPRDWL_MODE_P2P_GO,
+
+ SPRDWL_MODE_IBSS,
+
+ SPRDWL_MODE_MAX
+};
+
+enum sm_state {
+ SPRDWL_UNKNOWN = 0,
+ SPRDWL_SCANNING,
+ SPRDWL_SCAN_ABORTING,
+ SPRDWL_DISCONNECTING,
+ SPRDWL_DISCONNECTED,
+ SPRDWL_CONNECTING,
+ SPRDWL_CONNECTED
+};
+
+enum sprdwl_head_type {
+ SPRDWL_TYPE_CMD,
+ SPRDWL_TYPE_EVENT,
+ SPRDWL_TYPE_DATA,
+ SPRDWL_TYPE_DATA_SPECIAL
+};
+
+/* struct sprdwl_msg_list: the list for management of command/data
+ * @freelist: list of data to be free
+ * @busylist: list of data in used
+ * @cmd_to_free: list of cmd to be free
+ * @maxnum: max number of list
+ * @ref: reference number of list
+ * @flow: data flow contrl
+ */
+struct sprdwl_msg_list {
+ struct list_head freelist;
+ struct list_head busylist;
+ struct list_head cmd_to_free;
+ int maxnum;
+ atomic_t ref;
+ atomic_t flow;
+};
+
+/* struct sprdwl_msg_buf: to manage socket buffer
+ * @list: list head of this skb belong to
+ * @skb: socket buffer
+ * @data: data of socket buffer
+ * @tran_data: data to be transferred
+ * @type: type of this buffer
+ * @mode: indicate which mode this skb data belong to
+ * @len: socket buffer length
+ * @timeout: value of data time out in list
+ * @fifo_id: identity of fifo
+ * @msglist: indicate which list the socket buffer assign to
+ * @buffer_type: type of this socket buffer
+ * @data_list: type of this socket buffer
+ * @xmit_msg_list: list to manage transmit data list
+ * @msg_type: indicate type of this buffer
+ */
+struct sprdwl_msg_buf {
+ struct list_head list;
+ struct sk_buff *skb;
+ void *data;
+ void *tran_data;
+ u8 type;
+ u8 mode;
+ u16 len;
+ unsigned long timeout;
+ unsigned int fifo_id;
+ struct sprdwl_msg_list *msglist;
+ unsigned char buffer_type;
+ struct peer_list *data_list;
+ struct sprdwl_xmit_msg_list *xmit_msg_list;
+ unsigned char msg_type;
+};
+#endif
diff --git a/drivers/net/wireless/sprd/wireless.h b/drivers/net/wireless/sprd/wireless.h
index 000000000000..152a5c231a7b
--- /dev/null
+++ b/drivers/net/wireless/sprd/wireless.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// Wi-Fi driver of the Unisoc for Marlin3 chip:
+// Unisoc's private data structure
+//
+// Copyright(C) 2018 Unisoc,Inc.
+
+#ifndef __SPRDWL_H__
+#define __SPRDWL_H__
+
+#include <net/cfg80211.h>
+#include <linux/inetdevice.h>
+#include <linux/spinlock.h>
+#include <linux/wireless.h>
+#include "interface.h"
+
+/* struct sprdwl_vif: describe the wifi virtual interface
+ * @ndev: net device
+ * @wdev: wireless device
+ * @priv: sprdwl private structure
+ * @mode: Wi-Fi working mode
+ * @vif_node: node for virtual interface list
+ * @ref: reference of virtual interface
+ * @ctx_id: wifi context index of stap mode
+ */
+struct sprdwl_vif {
+ struct net_device *ndev;
+ struct wireless_dev wdev;
+ struct sprdwl_priv *priv;
+ enum sprdwl_mode mode;
+ struct list_head vif_node;
+ int ref;
+ u8 ctx_id;
+};
+
+enum sprdwl_hw_type {
+ SPRDWL_HW_SDIO,
+ SPRDWL_HW_SIPC,
+ SPRDWL_HW_SDIO_BA,
+ SPRDWL_HW_SC2355_SDIO,
+ SPRDWL_HW_SC2355_PCIE
+};
+
+/* struct sprdwl_priv: describe the unisoc private structure
+ * @wiphy: wiphy of net device
+ * @vif_list: list of virtual interface
+ * @hw_priv: hardware private structure
+ * @hw_type: hardware type
+ * @ hw_offset: hardware data offset
+ * @if_ops: interface operations
+ */
+struct sprdwl_priv {
+ struct wiphy *wiphy;
+ struct list_head vif_list;
+ void *hw_priv;
+ enum sprdwl_hw_type hw_type;
+ int hw_offset;
+ struct sprdwl_if_ops *if_ops;
+};
+
+extern struct device *sprdwl_dev;
+
+struct sprdwl_priv *sprdwl_core_create(enum sprdwl_hw_type type,
+ struct sprdwl_if_ops *ops);
+void sprdwl_core_free(struct sprdwl_priv *priv);
+int sprdwl_core_init(struct device *dev, struct sprdwl_priv *priv);
+int sprdwl_core_deinit(struct sprdwl_priv *priv);
+#endif
+
--
2.28.0