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