2018-09-26 10:25:33

by Ajay Singh

[permalink] [raw]
Subject: [RFC 00/19] wilc: added driver for wilc module

This patch set contains the driver files from 'driver/staging/wilc1000'.
Renamed the driver from 'wilc1000' to 'wilc' to have generic name, as
the same driver will be used by other wilc family members.

The patch series is based on 'wireless-driver-next'.

This driver will add support for SDIO/SPI interface for wilc family.
For now only wilc1000 module support has been intergrated in this driver.


Ajay Singh (19):
wilc: add coreconfigurator.h
wilc: add coreconfigurator.c
wilc: add host_interface.h
wilc: add host_interface.c
wilc: add wilc_wlan_if.h
wilc: add wilc_wlan_cfg.h
wilc: add wilc_wlan_cfg.c
wilc: add wilc_wlan.h
wilc: add wilc_wlan.c
wilc: add wilc_wfi_netdevice.h
wilc: add wilc_wfi_cfgoperations.h
wilc: add wilc_wfi_cfgoperations.c
wilc: add linux_wlan.c
wilc: add linux_mon.c
wilc: add wilc_spi.c
wilc: add wilc_sdio.c
wilc: updated DT device binding for wilc device
wilc: add Makefile and Kconfig files for wilc compilation
wilc: added wilc module compilation in wireless Makefile & Kconfig

.../net/wireless/microchip,wilc1000,sdio.txt | 32 +
.../net/wireless/microchip,wilc1000,spi.txt | 26 +
drivers/net/wireless/Kconfig | 1 +
drivers/net/wireless/Makefile | 1 +
drivers/net/wireless/microchip/Kconfig | 14 +
drivers/net/wireless/microchip/Makefile | 1 +
drivers/net/wireless/microchip/wilc/Kconfig | 42 +
drivers/net/wireless/microchip/wilc/Makefile | 15 +
.../net/wireless/microchip/wilc/coreconfigurator.c | 287 ++
.../net/wireless/microchip/wilc/coreconfigurator.h | 81 +
.../net/wireless/microchip/wilc/host_interface.c | 3927 ++++++++++++++++++++
.../net/wireless/microchip/wilc/host_interface.h | 362 ++
drivers/net/wireless/microchip/wilc/linux_mon.c | 273 ++
drivers/net/wireless/microchip/wilc/linux_wlan.c | 1161 ++++++
drivers/net/wireless/microchip/wilc/wilc_sdio.c | 1124 ++++++
drivers/net/wireless/microchip/wilc/wilc_spi.c | 1137 ++++++
.../microchip/wilc/wilc_wfi_cfgoperations.c | 2216 +++++++++++
.../microchip/wilc/wilc_wfi_cfgoperations.h | 23 +
.../wireless/microchip/wilc/wilc_wfi_netdevice.h | 230 ++
drivers/net/wireless/microchip/wilc/wilc_wlan.c | 1350 +++++++
drivers/net/wireless/microchip/wilc/wilc_wlan.h | 297 ++
.../net/wireless/microchip/wilc/wilc_wlan_cfg.c | 497 +++
.../net/wireless/microchip/wilc/wilc_wlan_cfg.h | 54 +
drivers/net/wireless/microchip/wilc/wilc_wlan_if.h | 830 +++++
drivers/staging/wilc1000/wilc_sdio.c | 4 +-
25 files changed, 13983 insertions(+), 2 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.txt
create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.txt
create mode 100644 drivers/net/wireless/microchip/Kconfig
create mode 100644 drivers/net/wireless/microchip/Makefile
create mode 100644 drivers/net/wireless/microchip/wilc/Kconfig
create mode 100644 drivers/net/wireless/microchip/wilc/Makefile
create mode 100644 drivers/net/wireless/microchip/wilc/coreconfigurator.c
create mode 100644 drivers/net/wireless/microchip/wilc/coreconfigurator.h
create mode 100644 drivers/net/wireless/microchip/wilc/host_interface.c
create mode 100644 drivers/net/wireless/microchip/wilc/host_interface.h
create mode 100644 drivers/net/wireless/microchip/wilc/linux_mon.c
create mode 100644 drivers/net/wireless/microchip/wilc/linux_wlan.c
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_sdio.c
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_spi.c
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_wfi_cfgoperations.c
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_wfi_cfgoperations.h
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_wfi_netdevice.h
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_wlan.c
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_wlan.h
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_wlan_cfg.c
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_wlan_cfg.h
create mode 100644 drivers/net/wireless/microchip/wilc/wilc_wlan_if.h

--
2.7.4



2018-09-26 10:25:36

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 01/19] wilc: add coreconfigurator.h

Moved '/driver/staging/wilc1000/coreconfigurator.h' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/coreconfigurator.h b/drivers/net/wireless/microchip/wilc/coreconfigurator.h
new file mode 100644
index 0000000..b62acb4
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/coreconfigurator.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#ifndef CORECONFIGURATOR_H
+#define CORECONFIGURATOR_H
+
+#include "wilc_wlan_if.h"
+
+#define NUM_RSSI 5
+
+#define MAC_HDR_LEN 24
+#define FCS_LEN 4
+#define TIME_STAMP_LEN 8
+#define BEACON_INTERVAL_LEN 2
+#define CAP_INFO_LEN 2
+#define STATUS_CODE_LEN 2
+#define AID_LEN 2
+#define IE_HDR_LEN 2
+
+#define SET_CFG 0
+#define GET_CFG 1
+
+#define MAX_STRING_LEN 256
+#define MAX_ASSOC_RESP_FRAME_SIZE MAX_STRING_LEN
+
+#define MAKE_WORD16(lsb, msb) ((((u16)(msb) << 8) & 0xFF00) | (lsb))
+#define MAKE_WORD32(lsw, msw) ((((u32)(msw) << 16) & 0xFFFF0000) | (lsw))
+
+struct rssi_history_buffer {
+ bool full;
+ u8 index;
+ s8 samples[NUM_RSSI];
+};
+
+struct network_info {
+ s8 rssi;
+ u16 cap_info;
+ u8 ssid[MAX_SSID_LEN];
+ u8 ssid_len;
+ u8 bssid[6];
+ u16 beacon_period;
+ u8 dtim_period;
+ u8 ch;
+ unsigned long time_scan_cached;
+ unsigned long time_scan;
+ bool new_network;
+ u8 found;
+ u32 tsf_lo;
+ u8 *ies;
+ u16 ies_len;
+ void *join_params;
+ struct rssi_history_buffer rssi_history;
+ u64 tsf_hi;
+};
+
+struct connect_info {
+ u8 bssid[6];
+ u8 *req_ies;
+ size_t req_ies_len;
+ u8 *resp_ies;
+ u16 resp_ies_len;
+ u16 status;
+};
+
+struct disconnect_info {
+ u16 reason;
+ u8 *ie;
+ size_t ie_len;
+};
+
+s32 wilc_parse_network_info(u8 *msg_buffer,
+ struct network_info **ret_network_info);
+s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
+ struct connect_info *ret_conn_info);
+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);
+#endif
--
2.7.4


2018-09-26 10:25:39

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 02/19] wilc: add coreconfigurator.c

Moved '/driver/staging/wilc1000/coreconfigurator.c' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/coreconfigurator.c b/drivers/net/wireless/microchip/wilc/coreconfigurator.c
new file mode 100644
index 0000000..d6d3a97
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/coreconfigurator.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/ieee80211.h>
+
+#include "coreconfigurator.h"
+
+#define TAG_PARAM_OFFSET (MAC_HDR_LEN + TIME_STAMP_LEN + \
+ BEACON_INTERVAL_LEN + CAP_INFO_LEN)
+
+enum sub_frame_type {
+ ASSOC_REQ = 0x00,
+ ASSOC_RSP = 0x10,
+ REASSOC_REQ = 0x20,
+ REASSOC_RSP = 0x30,
+ PROBE_REQ = 0x40,
+ PROBE_RSP = 0x50,
+ BEACON = 0x80,
+ ATIM = 0x90,
+ DISASOC = 0xA0,
+ AUTH = 0xB0,
+ DEAUTH = 0xC0,
+ ACTION = 0xD0,
+ PS_POLL = 0xA4,
+ RTS = 0xB4,
+ CTS = 0xC4,
+ ACK = 0xD4,
+ CFEND = 0xE4,
+ CFEND_ACK = 0xF4,
+ DATA = 0x08,
+ DATA_ACK = 0x18,
+ DATA_POLL = 0x28,
+ DATA_POLL_ACK = 0x38,
+ NULL_FRAME = 0x48,
+ CFACK = 0x58,
+ CFPOLL = 0x68,
+ CFPOLL_ACK = 0x78,
+ QOS_DATA = 0x88,
+ QOS_DATA_ACK = 0x98,
+ QOS_DATA_POLL = 0xA8,
+ QOS_DATA_POLL_ACK = 0xB8,
+ QOS_NULL_FRAME = 0xC8,
+ QOS_CFPOLL = 0xE8,
+ QOS_CFPOLL_ACK = 0xF8,
+ BLOCKACK_REQ = 0x84,
+ BLOCKACK = 0x94,
+ FRAME_SUBTYPE_FORCE_32BIT = 0xFFFFFFFF
+};
+
+static inline u16 get_beacon_period(u8 *data)
+{
+ u16 bcn_per;
+
+ bcn_per = data[0];
+ bcn_per |= (data[1] << 8);
+
+ return bcn_per;
+}
+
+static inline u32 get_beacon_timestamp_lo(u8 *data)
+{
+ u32 time_stamp = 0;
+ u32 index = MAC_HDR_LEN;
+
+ time_stamp |= data[index++];
+ time_stamp |= (data[index++] << 8);
+ time_stamp |= (data[index++] << 16);
+ time_stamp |= (data[index] << 24);
+
+ return time_stamp;
+}
+
+static inline u32 get_beacon_timestamp_hi(u8 *data)
+{
+ u32 time_stamp = 0;
+ u32 index = (MAC_HDR_LEN + 4);
+
+ time_stamp |= data[index++];
+ time_stamp |= (data[index++] << 8);
+ time_stamp |= (data[index++] << 16);
+ time_stamp |= (data[index] << 24);
+
+ return time_stamp;
+}
+
+static inline enum sub_frame_type get_sub_type(u8 *header)
+{
+ return ((enum sub_frame_type)(header[0] & 0xFC));
+}
+
+static inline u8 get_to_ds(u8 *header)
+{
+ return (header[1] & 0x01);
+}
+
+static inline u8 get_from_ds(u8 *header)
+{
+ return ((header[1] & 0x02) >> 1);
+}
+
+static inline void get_address1(u8 *msa, u8 *addr)
+{
+ memcpy(addr, msa + 4, 6);
+}
+
+static inline void get_address2(u8 *msa, u8 *addr)
+{
+ memcpy(addr, msa + 10, 6);
+}
+
+static inline void get_address3(u8 *msa, u8 *addr)
+{
+ memcpy(addr, msa + 16, 6);
+}
+
+static inline void get_bssid(u8 *data, u8 *bssid)
+{
+ if (get_from_ds(data) == 1)
+ get_address2(data, bssid);
+ else if (get_to_ds(data) == 1)
+ get_address1(data, bssid);
+ else
+ get_address3(data, bssid);
+}
+
+static inline void get_ssid(u8 *data, u8 *ssid, u8 *p_ssid_len)
+{
+ u8 i, j, len;
+
+ len = data[TAG_PARAM_OFFSET + 1];
+ j = TAG_PARAM_OFFSET + 2;
+
+ if (len >= MAX_SSID_LEN)
+ len = 0;
+
+ for (i = 0; i < len; i++, j++)
+ ssid[i] = data[j];
+
+ ssid[len] = '\0';
+
+ *p_ssid_len = len;
+}
+
+static inline u16 get_cap_info(u8 *data)
+{
+ u16 cap_info = 0;
+ u16 index = MAC_HDR_LEN;
+ enum sub_frame_type st;
+
+ st = get_sub_type(data);
+
+ if (st == BEACON || st == PROBE_RSP)
+ index += TIME_STAMP_LEN + BEACON_INTERVAL_LEN;
+
+ cap_info = data[index];
+ cap_info |= (data[index + 1] << 8);
+
+ return cap_info;
+}
+
+static inline u16 get_asoc_status(u8 *data)
+{
+ u16 asoc_status;
+
+ asoc_status = data[3];
+ return (asoc_status << 8) | data[2];
+}
+
+static u8 *get_tim_elm(u8 *msa, u16 rx_len, u16 tag_param_offset)
+{
+ u16 index;
+
+ index = tag_param_offset;
+
+ while (index < (rx_len - FCS_LEN)) {
+ if (msa[index] == WLAN_EID_TIM)
+ return &msa[index];
+ index += (IE_HDR_LEN + msa[index + 1]);
+ }
+
+ return NULL;
+}
+
+static u8 get_current_channel_802_11n(u8 *msa, u16 rx_len)
+{
+ u16 index;
+
+ index = TAG_PARAM_OFFSET;
+ while (index < (rx_len - FCS_LEN)) {
+ if (msa[index] == WLAN_EID_DS_PARAMS)
+ return msa[index + 2];
+ index += msa[index + 1] + IE_HDR_LEN;
+ }
+
+ return 0;
+}
+
+s32 wilc_parse_network_info(u8 *msg_buffer,
+ struct network_info **ret_network_info)
+{
+ struct network_info *network_info;
+ u8 *wid_val, *msa, *tim_elm, *ies;
+ u32 tsf_lo, tsf_hi;
+ u16 wid_len, rx_len, ies_len;
+ u8 msg_type, index;
+
+ msg_type = msg_buffer[0];
+
+ if ('N' != msg_type)
+ return -EFAULT;
+
+ wid_len = MAKE_WORD16(msg_buffer[6], msg_buffer[7]);
+ wid_val = &msg_buffer[8];
+
+ network_info = kzalloc(sizeof(*network_info), GFP_KERNEL);
+ if (!network_info)
+ return -ENOMEM;
+
+ network_info->rssi = wid_val[0];
+
+ msa = &wid_val[1];
+
+ rx_len = wid_len - 1;
+ network_info->cap_info = get_cap_info(msa);
+ network_info->tsf_lo = get_beacon_timestamp_lo(msa);
+
+ tsf_lo = get_beacon_timestamp_lo(msa);
+ tsf_hi = get_beacon_timestamp_hi(msa);
+
+ network_info->tsf_hi = tsf_lo | ((u64)tsf_hi << 32);
+
+ get_ssid(msa, network_info->ssid, &network_info->ssid_len);
+ get_bssid(msa, network_info->bssid);
+
+ network_info->ch = get_current_channel_802_11n(msa, rx_len
+ + FCS_LEN);
+
+ index = MAC_HDR_LEN + TIME_STAMP_LEN;
+
+ network_info->beacon_period = get_beacon_period(msa + index);
+
+ index += BEACON_INTERVAL_LEN + CAP_INFO_LEN;
+
+ tim_elm = get_tim_elm(msa, rx_len + FCS_LEN, index);
+ if (tim_elm)
+ network_info->dtim_period = tim_elm[3];
+ ies = &msa[TAG_PARAM_OFFSET];
+ ies_len = rx_len - TAG_PARAM_OFFSET;
+
+ if (ies_len > 0) {
+ network_info->ies = kmemdup(ies, ies_len, GFP_KERNEL);
+ if (!network_info->ies) {
+ kfree(network_info);
+ return -ENOMEM;
+ }
+ }
+ network_info->ies_len = ies_len;
+
+ *ret_network_info = network_info;
+
+ return 0;
+}
+
+s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
+ struct connect_info *ret_conn_info)
+{
+ u8 *ies;
+ u16 ies_len;
+
+ ret_conn_info->status = get_asoc_status(buffer);
+ if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {
+ ies = &buffer[CAP_INFO_LEN + STATUS_CODE_LEN + AID_LEN];
+ ies_len = buffer_len - (CAP_INFO_LEN + STATUS_CODE_LEN +
+ AID_LEN);
+
+ ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL);
+ if (!ret_conn_info->resp_ies)
+ return -ENOMEM;
+
+ ret_conn_info->resp_ies_len = ies_len;
+ }
+
+ return 0;
+}
--
2.7.4


2018-09-26 10:25:42

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 03/19] wilc: add host_interface.h

Moved '/driver/staging/wilc1000/host_interface.h' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/host_interface.h b/drivers/net/wireless/microchip/wilc/host_interface.h
new file mode 100644
index 0000000..33fb731
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/host_interface.h
@@ -0,0 +1,362 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries
+ * All rights reserved.
+ */
+
+#ifndef HOST_INT_H
+#define HOST_INT_H
+#include <linux/ieee80211.h>
+#include "coreconfigurator.h"
+
+#define IDLE_MODE 0x00
+#define AP_MODE 0x01
+#define STATION_MODE 0x02
+#define GO_MODE 0x03
+#define CLIENT_MODE 0x04
+#define ACTION 0xD0
+#define PROBE_REQ 0x40
+#define PROBE_RESP 0x50
+
+#define ACTION_FRM_IDX 0
+#define PROBE_REQ_IDX 1
+#define MAX_NUM_STA 9
+#define ACTIVE_SCAN_TIME 10
+#define PASSIVE_SCAN_TIME 1200
+#define MIN_SCAN_TIME 10
+#define MAX_SCAN_TIME 1200
+#define DEFAULT_SCAN 0
+#define USER_SCAN BIT(0)
+#define OBSS_PERIODIC_SCAN BIT(1)
+#define OBSS_ONETIME_SCAN BIT(2)
+#define GTK_RX_KEY_BUFF_LEN 24
+#define ADDKEY 0x1
+#define REMOVEKEY 0x2
+#define DEFAULTKEY 0x4
+#define ADDKEY_AP 0x8
+#define MAX_NUM_SCANNED_NETWORKS 100
+#define MAX_NUM_SCANNED_NETWORKS_SHADOW 130
+#define MAX_NUM_PROBED_SSID 10
+#define CHANNEL_SCAN_TIME 250
+
+#define TX_MIC_KEY_LEN 8
+#define RX_MIC_KEY_LEN 8
+#define PTK_KEY_LEN 16
+
+#define TX_MIC_KEY_MSG_LEN 26
+#define RX_MIC_KEY_MSG_LEN 48
+#define PTK_KEY_MSG_LEN 39
+
+#define PMKSA_KEY_LEN 22
+#define ETH_ALEN 6
+#define PMKID_LEN 16
+#define WILC_MAX_NUM_PMKIDS 16
+#define WILC_ADD_STA_LENGTH 40
+#define NUM_CONCURRENT_IFC 2
+#define DRV_HANDLER_SIZE 5
+#define DRV_HANDLER_MASK 0x000000FF
+
+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 host_if_pmkid {
+ u8 bssid[ETH_ALEN];
+ u8 pmkid[PMKID_LEN];
+};
+
+struct host_if_pmkid_attr {
+ u8 numpmkid;
+ struct host_if_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS];
+};
+
+enum current_tx_rate {
+ AUTORATE = 0,
+ MBPS_1 = 1,
+ MBPS_2 = 2,
+ MBPS_5_5 = 5,
+ MBPS_11 = 11,
+ MBPS_6 = 6,
+ MBPS_9 = 9,
+ MBPS_12 = 12,
+ MBPS_18 = 18,
+ MBPS_24 = 24,
+ MBPS_36 = 36,
+ MBPS_48 = 48,
+ MBPS_54 = 54
+};
+
+struct cfg_param_attr {
+ u32 flag;
+ u8 ht_enable;
+ u8 bss_type;
+ u8 auth_type;
+ u16 auth_timeout;
+ u8 power_mgmt_mode;
+ u16 short_retry_limit;
+ u16 long_retry_limit;
+ u16 frag_threshold;
+ u16 rts_threshold;
+ u16 preamble_type;
+ u8 short_slot_allowed;
+ u8 txop_prot_disabled;
+ u16 beacon_interval;
+ u16 dtim_period;
+ enum site_survey site_survey_enabled;
+ u16 site_survey_scan_time;
+ u8 scan_source;
+ u16 active_scan_time;
+ u16 passive_scan_time;
+ enum current_tx_rate curr_tx_rate;
+
+};
+
+enum cfg_param {
+ RETRY_SHORT = BIT(0),
+ RETRY_LONG = BIT(1),
+ FRAG_THRESHOLD = BIT(2),
+ RTS_THRESHOLD = BIT(3),
+ BSS_TYPE = BIT(4),
+ AUTH_TYPE = BIT(5),
+ AUTHEN_TIMEOUT = BIT(6),
+ POWER_MANAGEMENT = BIT(7),
+ PREAMBLE = BIT(8),
+ SHORT_SLOT_ALLOWED = BIT(9),
+ TXOP_PROT_DISABLE = BIT(10),
+ BEACON_INTERVAL = BIT(11),
+ DTIM_PERIOD = BIT(12),
+ SITE_SURVEY = BIT(13),
+ SITE_SURVEY_SCAN_TIME = BIT(14),
+ ACTIVE_SCANTIME = BIT(15),
+ PASSIVE_SCANTIME = BIT(16),
+ CURRENT_TX_RATE = BIT(17),
+ HT_ENABLE = BIT(18),
+};
+
+struct found_net_info {
+ u8 bssid[6];
+ s8 rssi;
+};
+
+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 KEY_TYPE {
+ WEP,
+ WPA_RX_GTK,
+ WPA_PTK,
+ PMKSA,
+};
+
+typedef void (*wilc_scan_result)(enum scan_event, struct network_info *,
+ void *, void *);
+
+typedef void (*wilc_connect_result)(enum conn_event,
+ struct connect_info *,
+ u8,
+ struct disconnect_info *,
+ void *);
+
+typedef void (*wilc_remain_on_chan_expired)(void *, u32);
+typedef void (*wilc_remain_on_chan_ready)(void *);
+
+struct rcvd_net_info {
+ u8 *buffer;
+ u32 len;
+};
+
+struct hidden_net_info {
+ u8 *ssid;
+ u8 ssid_len;
+};
+
+struct hidden_network {
+ struct hidden_net_info *net_info;
+ u8 n_ssids;
+};
+
+struct user_scan_req {
+ wilc_scan_result scan_result;
+ void *arg;
+ u32 ch_cnt;
+ struct found_net_info net_info[MAX_NUM_SCANNED_NETWORKS];
+};
+
+struct user_conn_req {
+ u8 *bssid;
+ u8 *ssid;
+ u8 security;
+ enum authtype auth_type;
+ size_t ssid_len;
+ u8 *ies;
+ size_t ies_len;
+ wilc_connect_result conn_result;
+ bool ht_capable;
+ void *arg;
+};
+
+struct drv_handler {
+ u32 handler;
+ u8 mode;
+ u8 name;
+};
+
+struct op_mode {
+ u32 mode;
+};
+
+struct get_mac_addr {
+ u8 *mac_addr;
+};
+
+struct ba_session_info {
+ u8 bssid[ETH_ALEN];
+ u8 tid;
+ u16 buf_size;
+ u16 time_out;
+};
+
+struct remain_ch {
+ u16 ch;
+ u32 duration;
+ wilc_remain_on_chan_expired expired;
+ wilc_remain_on_chan_ready ready;
+ void *arg;
+ u32 id;
+};
+
+struct reg_frame {
+ bool reg;
+ u16 frame_type;
+ u8 reg_id;
+};
+
+struct wilc;
+struct host_if_drv {
+ struct user_scan_req usr_scan_req;
+ struct user_conn_req usr_conn_req;
+ struct remain_ch remain_on_ch;
+ u8 remain_on_ch_pending;
+ u64 p2p_timeout;
+ u8 p2p_connect;
+
+ enum host_if_state hif_state;
+
+ u8 assoc_bssid[ETH_ALEN];
+ struct cfg_param_attr cfg_values;
+ /*lock to protect concurrent setting of cfg params*/
+ struct mutex cfg_values_lock;
+
+ 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;
+ int driver_handler_id;
+ u8 assoc_resp[MAX_ASSOC_RESP_FRAME_SIZE];
+};
+
+struct add_sta_param {
+ u8 bssid[ETH_ALEN];
+ u16 aid;
+ u8 rates_len;
+ const u8 *rates;
+ bool ht_supported;
+ struct ieee80211_ht_cap ht_capa;
+ u16 flags_mask;
+ u16 flags_set;
+};
+
+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 host_if_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 *ssid,
+ size_t ssid_len, const u8 *ies, size_t ies_len,
+ wilc_connect_result connect_result, void *user_arg,
+ u8 security, enum authtype auth_type,
+ u8 channel, void *join_params);
+int wilc_disconnect(struct wilc_vif *vif, u16 reason_code);
+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, const u8 *ies,
+ size_t ies_len, wilc_scan_result scan_result, void *user_arg,
+ struct hidden_network *hidden_network);
+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,
+ u32 head_len, u8 *head, u32 tail_len, u8 *tail);
+int wilc_del_beacon(struct wilc_vif *vif);
+int wilc_add_station(struct wilc_vif *vif, struct add_sta_param *sta_param);
+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,
+ struct add_sta_param *sta_param);
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
+int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled, u32 count,
+ u8 *mc_list);
+int wilc_remain_on_channel(struct wilc_vif *vif, u32 session_id,
+ u32 duration, u16 chan,
+ wilc_remain_on_chan_expired expired,
+ wilc_remain_on_chan_ready ready,
+ void *user_arg);
+int wilc_listen_state_expired(struct wilc_vif *vif, u32 session_id);
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
+int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id, bool is_sync);
+int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode);
+int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats,
+ bool is_sync);
+void wilc_resolve_disconnect_aberration(struct wilc_vif *vif);
+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);
+
+#endif
--
2.7.4


2018-09-26 10:25:51

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 05/19] wilc: add wilc_wlan_if.h

Moved '/driver/staging/wilc1000/wilc_wlan_if.h' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_wlan_if.h b/drivers/net/wireless/microchip/wilc/wilc_wlan_if.h
new file mode 100644
index 0000000..ce2066b
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_wlan_if.h
@@ -0,0 +1,830 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#ifndef WILC_WLAN_IF_H
+#define WILC_WLAN_IF_H
+
+#include <linux/netdevice.h>
+
+/********************************************
+ *
+ * Host Interface Defines
+ *
+ ********************************************/
+
+#define HIF_SDIO (0)
+#define HIF_SPI BIT(0)
+
+/********************************************
+ *
+ * Wlan Interface Defines
+ *
+ ********************************************/
+
+struct sdio_cmd52 {
+ u32 read_write: 1;
+ u32 function: 3;
+ u32 raw: 1;
+ u32 address: 17;
+ u32 data: 8;
+};
+
+struct sdio_cmd53 {
+ u32 read_write: 1;
+ u32 function: 3;
+ u32 block_mode: 1;
+ u32 increment: 1;
+ u32 address: 17;
+ u32 count: 9;
+ u8 *buffer;
+ u32 block_size;
+};
+
+#define MAC_STATUS_INIT -1
+#define MAC_STATUS_CONNECTED 1
+#define MAC_STATUS_DISCONNECTED 0
+
+struct tx_complete_data {
+ int size;
+ void *buff;
+ u8 *bssid;
+ struct sk_buff *skb;
+};
+
+typedef void (*wilc_tx_complete_func_t)(void *, int);
+
+#define WILC_TX_ERR_NO_BUF (-2)
+
+/********************************************
+ *
+ * Wlan Configuration ID
+ *
+ ********************************************/
+#define WILC_MULTICAST_TABLE_SIZE 8
+#define MAX_SSID_LEN 33
+#define MAX_RATES_SUPPORTED 12
+
+enum bss_types {
+ INFRASTRUCTURE = 0,
+ INDEPENDENT,
+ AP,
+};
+
+enum {
+ B_ONLY_MODE = 0, /* 1, 2 M, otherwise 5, 11 M */
+ G_ONLY_MODE, /* 6,12,24 otherwise 9,18,36,48,54 */
+ G_MIXED_11B_1_MODE, /* 1,2,5.5,11 otherwise all on */
+ G_MIXED_11B_2_MODE, /* 1,2,5,11,6,12,24 otherwise all on */
+};
+
+enum {
+ G_SHORT_PREAMBLE = 0, /* Short Preamble */
+ G_LONG_PREAMBLE = 1, /* Long Preamble */
+ G_AUTO_PREAMBLE = 2, /* Auto Preamble Selection */
+};
+
+enum {
+ PASSIVE_SCAN = 0,
+ ACTIVE_SCAN = 1,
+};
+
+enum {
+ NO_POWERSAVE = 0,
+ MIN_FAST_PS = 1,
+ MAX_FAST_PS = 2,
+ MIN_PSPOLL_PS = 3,
+ MAX_PSPOLL_PS = 4
+};
+
+enum chip_ps_states {
+ CHIP_WAKEDUP = 0,
+ CHIP_SLEEPING_AUTO = 1,
+ CHIP_SLEEPING_MANUAL = 2
+};
+
+enum bus_acquire {
+ ACQUIRE_ONLY = 0,
+ ACQUIRE_AND_WAKEUP = 1,
+};
+
+enum bus_release {
+ RELEASE_ONLY = 0,
+ RELEASE_ALLOW_SLEEP = 1,
+};
+
+enum {
+ NO_SECURITY = 0,
+ WEP_40 = 0x3,
+ WEP_104 = 0x7,
+ WPA_AES = 0x29,
+ WPA_TKIP = 0x49,
+ WPA_AES_TKIP = 0x69, /* Aes or Tkip */
+ WPA2_AES = 0x31,
+ WPA2_TKIP = 0x51,
+ WPA2_AES_TKIP = 0x71, /* Aes or Tkip */
+};
+
+enum authtype {
+ OPEN_SYSTEM = 1,
+ SHARED_KEY = 2,
+ ANY = 3,
+ IEEE8021 = 5
+};
+
+enum site_survey {
+ SITE_SURVEY_1CH = 0,
+ SITE_SURVEY_ALL_CH = 1,
+ SITE_SURVEY_OFF = 2
+};
+
+enum {
+ NORMAL_ACK = 0,
+ NO_ACK,
+};
+
+enum {
+ REKEY_DISABLE = 1,
+ REKEY_TIME_BASE,
+ REKEY_PKT_BASE,
+ REKEY_TIME_PKT_BASE
+};
+
+enum {
+ FILTER_NO = 0x00,
+ FILTER_AP_ONLY = 0x01,
+ FILTER_STA_ONLY = 0x02
+};
+
+enum {
+ AUTO_PROT = 0, /* Auto */
+ NO_PROT, /* Do not use any protection */
+ ERP_PROT, /* Protect all ERP frame exchanges */
+ HT_PROT, /* Protect all HT frame exchanges */
+ GF_PROT, /* Protect all GF frame exchanges */
+};
+
+enum {
+ G_SELF_CTS_PROT,
+ G_RTS_CTS_PROT,
+};
+
+enum {
+ HT_MIXED_MODE = 1,
+ HT_ONLY_20MHZ_MODE,
+ HT_ONLY_20_40MHZ_MODE,
+};
+
+enum {
+ NO_DETECT = 0,
+ DETECT_ONLY = 1,
+ DETECT_PROTECT = 2,
+ DETECT_PROTECT_REPORT = 3,
+};
+
+enum {
+ RTS_CTS_NONHT_PROT = 0, /* RTS-CTS at non-HT rate */
+ FIRST_FRAME_NONHT_PROT, /* First frame at non-HT rate */
+ LSIG_TXOP_PROT, /* LSIG TXOP Protection */
+ FIRST_FRAME_MIXED_PROT, /* First frame at Mixed format */
+};
+
+enum {
+ STATIC_MODE = 1,
+ DYNAMIC_MODE = 2,
+ MIMO_MODE = 3, /* power save disable */
+};
+
+enum wid_type {
+ WID_CHAR = 0,
+ WID_SHORT = 1,
+ WID_INT = 2,
+ WID_STR = 3,
+ WID_BIN_DATA = 4,
+ WID_BIN = 5,
+};
+
+struct wid {
+ u16 id;
+ enum wid_type type;
+ s32 size;
+ s8 *val;
+};
+
+enum {
+ WID_NIL = 0xffff,
+
+ /*
+ * BSS Type
+ * -----------------------------------------------------------
+ * Configuration : Infrastructure Independent Access Point
+ * Values to set : 0 1 2
+ * -----------------------------------------------------------
+ */
+ WID_BSS_TYPE = 0x0000,
+
+ /*
+ * Transmit Rate
+ * -----------------------------------------------------------
+ * Configuration : 1 2 5.5 11 6 9 12 18 24 36 48 54
+ * Values to set : 1 2 5 11 6 9 12 18 24 36 48 54
+ * -----------------------------------------------------------
+ */
+ WID_CURRENT_TX_RATE = 0x0001,
+
+ /*
+ * Channel
+ * -----------------------------------------------------------
+ * Configuration(g) : 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+ * Values to set : 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+ * -----------------------------------------------------------
+ */
+ WID_CURRENT_CHANNEL = 0x0002,
+
+ /*
+ * Preamble
+ * -----------------------------------------------------------
+ * Configuration : short long Auto
+ * Values to set : 0 1 2
+ * -----------------------------------------------------------
+ */
+ WID_PREAMBLE = 0x0003,
+
+ /*
+ * 11g operating mode (ignored if 11g not present)
+ * -----------------------------------------------------------
+ * Configuration : HighPerf Compat(RSet #1) Compat(RSet #2)
+ * Values to set : 1 2 3
+ * -----------------------------------------------------------
+ */
+ WID_11G_OPERATING_MODE = 0x0004,
+
+ /*
+ * Mac status (response only)
+ * -----------------------------------------------------------
+ * Configuration : disconnect connect
+ * Values to get : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_STATUS = 0x0005,
+
+ /*
+ * Scan type
+ * -----------------------------------------------------------
+ * Configuration : Passive Scanning Active Scanning
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_SCAN_TYPE = 0x0007,
+
+ /*
+ * Key Id (WEP default key Id)
+ * -----------------------------------------------------------
+ * Configuration : Any value between 0 to 3
+ * Values to set : Same value. Default is 0
+ * -----------------------------------------------------------
+ */
+ WID_KEY_ID = 0x0009,
+
+ /*
+ * QoS Enable
+ * -----------------------------------------------------------
+ * Configuration : QoS Disable WMM Enable
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_QOS_ENABLE = 0x000A,
+
+ /*
+ * Power Management
+ * -----------------------------------------------------------
+ * Configuration : NO_POWERSAVE MIN_POWERSAVE MAX_POWERSAVE
+ * Values to set : 0 1 2
+ * -----------------------------------------------------------
+ */
+ WID_POWER_MANAGEMENT = 0x000B,
+
+ /*
+ * WEP/802 11I Configuration
+ * -----------------------------------------------------------
+ * Configuration:Disable WP40 WP104 WPA-AES WPA-TKIP RSN-AES RSN-TKIP
+ * Values (0x) : 00 03 07 29 49 31 51
+ * Configuration:WPA-AES+TKIP RSN-AES+TKIP
+ * Values (0x) : 69 71
+ * -----------------------------------------------------------
+ */
+ WID_11I_MODE = 0x000C,
+
+ /*
+ * WEP Configuration: Used in BSS STA mode only when WEP is enabled
+ * -----------------------------------------------------------
+ * Configuration : Open System Shared Key Any Type | 802.1x Auth
+ * Values (0x) : 01 02 03 | BIT2
+ * -----------------------------------------------------------
+ */
+ WID_AUTH_TYPE = 0x000D,
+
+ /*
+ * Site Survey Type
+ * -----------------------------------------------------------
+ * Configuration : Values to set
+ * Survey 1 Channel : 0
+ * survey all Channels : 1
+ * Disable Site Survey : 2
+ * -----------------------------------------------------------
+ */
+ WID_SITE_SURVEY = 0x000E,
+
+ /*
+ * Listen Interval
+ * -----------------------------------------------------------
+ * Configuration : Any value between 1 to 255
+ * Values to set : Same value. Default is 3
+ * -----------------------------------------------------------
+ */
+ WID_LISTEN_INTERVAL = 0x000F,
+
+ /*
+ * DTIM Period
+ * -----------------------------------------------------------
+ * Configuration : Any value between 1 to 255
+ * Values to set : Same value. Default is 3
+ * -----------------------------------------------------------
+ */
+ WID_DTIM_PERIOD = 0x0010,
+
+ /*
+ * ACK Policy
+ * -----------------------------------------------------------
+ * Configuration : Normal Ack No Ack
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_ACK_POLICY = 0x0011,
+
+ /*
+ * Reset MAC (Set only)
+ * -----------------------------------------------------------
+ * Configuration : Don't Reset Reset No Request
+ * Values to set : 0 1 2
+ * -----------------------------------------------------------
+ */
+ WID_RESET = 0x0012,
+
+ /*
+ * Broadcast SSID Option: Setting this will adhere to "" SSID element
+ * -----------------------------------------------------------
+ * Configuration : Enable Disable
+ * Values to set : 1 0
+ * -----------------------------------------------------------
+ */
+ WID_BCAST_SSID = 0x0015,
+
+ /*
+ * Disconnect (Station)
+ * -----------------------------------------------------------
+ * Configuration : Association ID
+ * Values to set : Association ID
+ * -----------------------------------------------------------
+ */
+ WID_DISCONNECT = 0x0016,
+
+ /*
+ * 11a Tx Power Level
+ * -----------------------------------------------------------
+ * Configuration : Sets TX Power (Higher the value greater the power)
+ * Values to set : Any value between 0 and 63 (inclusive Default 48)
+ * -----------------------------------------------------------
+ */
+ WID_TX_POWER_LEVEL_11A = 0x0018,
+
+ /*
+ * Group Key Update Policy Selection
+ * -----------------------------------------------------------
+ * Configuration : Disabled timeBased packetBased timePacketBased
+ * Values to set : 1 2 3 4
+ * -----------------------------------------------------------
+ */
+ WID_REKEY_POLICY = 0x0019,
+
+ /*
+ * Allow Short Slot
+ * -----------------------------------------------------------
+ * Configuration : Disallow Short Slot Allow Short Slot
+ * (Enable Only Long Slot) (Enable Short Slot if applicable)
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_SHORT_SLOT_ALLOWED = 0x001A,
+
+ WID_PHY_ACTIVE_REG = 0x001B,
+
+ /*
+ * 11b Tx Power Level
+ * -----------------------------------------------------------
+ * Configuration : Sets TX Power (Higher the value greater the power)
+ * Values to set : Any value between 0 and 63 (inclusive Default 48)
+ * -----------------------------------------------------------
+ */
+ WID_TX_POWER_LEVEL_11B = 0x001D,
+
+ /*
+ * Scan Request
+ * -----------------------------------------------------------
+ * Configuration : Request default scan
+ * Values to set : 0
+ * -----------------------------------------------------------
+ */
+ WID_START_SCAN_REQ = 0x001E,
+
+ /*
+ * Rssi (get only)
+ * -----------------------------------------------------------
+ * Configuration :
+ * Values to get : Rssi value
+ * -----------------------------------------------------------
+ */
+ WID_RSSI = 0x001F,
+
+ /*
+ * Join Request
+ * -----------------------------------------------------------
+ * Configuration : Request to join
+ * Values to set : index of scan result
+ * -----------------------------------------------------------
+ */
+ WID_JOIN_REQ = 0x0020,
+
+ WID_LINKSPEED = 0x0026,
+
+ /*
+ * Enable User Control of TX Power
+ * -----------------------------------------------------------
+ * Configuration : Disable Enable
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_USER_CONTROL_ON_TX_POWER = 0x0027,
+
+ WID_MEMORY_ACCESS_8BIT = 0x0029,
+
+ /*
+ * Enable Auto RX Sensitivity feature
+ * -----------------------------------------------------------
+ * Configuration : Disable Enable
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_AUTO_RX_SENSITIVITY = 0x0032,
+
+ /*
+ * Receive Buffer Based Ack
+ * -----------------------------------------------------------
+ * Configuration : Disable Enable
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_DATAFLOW_CONTROL = 0x0033,
+
+ /*
+ * Scan Filter
+ * -----------------------------------------------------------
+ * Configuration : Class No filter AP only Station Only
+ * Values to set : 0 1 2
+ * Configuration : Priority High Rssi Low Rssi Detect
+ * Values to set : 0 0x4 0x0
+ * Configuration : Channel filter off filter on
+ * Values to set : 0 0x10
+ * -----------------------------------------------------------
+ */
+ WID_SCAN_FILTER = 0x0036,
+
+ /*
+ * Link Loss Threshold (measure in the beacon period)
+ * -----------------------------------------------------------
+ * Configuration : Any value between 10 and 254(Set to 255 disable)
+ * Values to set : Same value. Default is 10
+ * -----------------------------------------------------------
+ */
+ WID_LINK_LOSS_THRESHOLD = 0x0037,
+
+ WID_ABORT_RUNNING_SCAN = 0x003E,
+
+ /* NMAC Character WID list */
+ WID_WPS_START = 0x0043,
+
+ /*
+ * Protection mode for MAC
+ * -----------------------------------------------------------
+ * Configuration : Auto No protection ERP HT GF
+ * Values to set : 0 1 2 3 4
+ * -----------------------------------------------------------
+ */
+ WID_11N_PROT_MECH = 0x0080,
+
+ /*
+ * ERP Protection type for MAC
+ * -----------------------------------------------------------
+ * Configuration : Self-CTS RTS-CTS
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_11N_ERP_PROT_TYPE = 0x0081,
+
+ /*
+ * HT Option Enable
+ * -----------------------------------------------------------
+ * Configuration : HT Enable HT Disable
+ * Values to set : 1 0
+ * -----------------------------------------------------------
+ */
+ WID_11N_ENABLE = 0x0082,
+
+ /*
+ * 11n Operating mode (Note that 11g operating mode will also be
+ * used in addition to this, if this is set to HT Mixed mode)
+ * -----------------------------------------------------------
+ * Configuration : HT Mixed HT Only-20MHz HT Only-20/40MHz
+ * Values to set : 1 2 3
+ * -----------------------------------------------------------
+ */
+ WID_11N_OPERATING_MODE = 0x0083,
+
+ /*
+ * 11n OBSS non-HT STA Detection flag
+ * -----------------------------------------------------------
+ * Configuration : Do not detect
+ * Values to set : 0
+ * Configuration : Detect, do not protect or report
+ * Values to set : 1
+ * Configuration : Detect, protect and do not report
+ * Values to set : 2
+ * Configuration : Detect, protect and report to other BSS
+ * Values to set : 3
+ * -----------------------------------------------------------
+ */
+ WID_11N_OBSS_NONHT_DETECTION = 0x0084,
+
+ /*
+ * 11n HT Protection Type
+ * -----------------------------------------------------------
+ * Configuration : RTS-CTS First Frame Exchange at non-HT-rate
+ * Values to set : 0 1
+ * Configuration : LSIG TXOP First Frame Exchange in Mixed Fmt
+ * Values to set : 2 3
+ * -----------------------------------------------------------
+ */
+ WID_11N_HT_PROT_TYPE = 0x0085,
+
+ /*
+ * 11n RIFS Protection Enable Flag
+ * -----------------------------------------------------------
+ * Configuration : Disable Enable
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_11N_RIFS_PROT_ENABLE = 0x0086,
+
+ /*
+ * SMPS Mode
+ * -----------------------------------------------------------
+ * Configuration : Static Dynamic MIMO (Power Save Disabled)
+ * Values to set : 1 2 3
+ * -----------------------------------------------------------
+ */
+ WID_11N_SMPS_MODE = 0x0087,
+
+ /*
+ * Current transmit MCS
+ * -----------------------------------------------------------
+ * Configuration : MCS Index for data rate
+ * Values to set : 0 to 7
+ * -----------------------------------------------------------
+ */
+ WID_11N_CURRENT_TX_MCS = 0x0088,
+
+ WID_11N_PRINT_STATS = 0x0089,
+
+ /*
+ * 11n Short GI Enable Flag
+ * -----------------------------------------------------------
+ * Configuration : Disable Enable
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_11N_SHORT_GI_ENABLE = 0x008D,
+
+ /*
+ * 11n RIFS Enable Flag
+ * -----------------------------------------------------------
+ * Configuration : Disable Enable
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_RIFS_MODE = 0x0094,
+
+ /*
+ * TX Abort Feature
+ * -----------------------------------------------------------
+ * Configuration : Disable Self CTS Enable Self CTS
+ * Values to set : 0 1
+ * Configuration : Disable TX Abort Enable TX Abort
+ * Values to set : 2 3
+ * Configuration : Enable HW TX Abort Enable SW TX Abort
+ * Values to set : 4 5
+ * -----------------------------------------------------------
+ */
+ WID_TX_ABORT_CONFIG = 0x00A1,
+
+ WID_REG_TSSI_11B_VALUE = 0x00A6,
+ WID_REG_TSSI_11G_VALUE = 0x00A7,
+ WID_REG_TSSI_11N_VALUE = 0x00A8,
+ WID_TX_CALIBRATION = 0x00A9,
+ WID_DSCR_TSSI_11B_VALUE = 0x00AA,
+ WID_DSCR_TSSI_11G_VALUE = 0x00AB,
+ WID_DSCR_TSSI_11N_VALUE = 0x00AC,
+
+ /*
+ * Immediate Block-Ack Support
+ * -----------------------------------------------------------
+ * Configuration : Disable Enable
+ * Values to set : 0 1
+ * -----------------------------------------------------------
+ */
+ WID_11N_IMMEDIATE_BA_ENABLED = 0x00AF,
+
+ /*
+ * TXOP Disable Flag
+ * -----------------------------------------------------------
+ * Configuration : Disable Enable
+ * Values to set : 1 0
+ * -----------------------------------------------------------
+ */
+ WID_11N_TXOP_PROT_DISABLE = 0x00B0,
+
+ WID_TX_POWER_LEVEL_11N = 0x00B1,
+
+ /* Custom Character WID list */
+ WID_PC_TEST_MODE = 0x00C8,
+ /* SCAN Complete notification WID*/
+ WID_SCAN_COMPLETE = 0x00C9,
+
+ WID_DEL_BEACON = 0x00CA,
+
+ WID_LOG_TERMINAL_SWITCH = 0x00CD,
+ WID_TX_POWER = 0x00CE,
+ /* EMAC Short WID list */
+ /* RTS Threshold */
+ /*
+ * -----------------------------------------------------------
+ * Configuration : Any value between 256 to 2347
+ * Values to set : Same value. Default is 2347
+ * -----------------------------------------------------------
+ */
+ WID_RTS_THRESHOLD = 0x1000,
+
+ /*
+ * Fragmentation Threshold
+ * -----------------------------------------------------------
+ * Configuration : Any value between 256 to 2346
+ * Values to set : Same value. Default is 2346
+ * -----------------------------------------------------------
+ */
+ WID_FRAG_THRESHOLD = 0x1001,
+
+ WID_SHORT_RETRY_LIMIT = 0x1002,
+ WID_LONG_RETRY_LIMIT = 0x1003,
+ WID_BEACON_INTERVAL = 0x1006,
+ WID_MEMORY_ACCESS_16BIT = 0x1008,
+ WID_RX_SENSE = 0x100B,
+ WID_ACTIVE_SCAN_TIME = 0x100C,
+ WID_PASSIVE_SCAN_TIME = 0x100D,
+
+ WID_SITE_SURVEY_SCAN_TIME = 0x100E,
+ WID_JOIN_START_TIMEOUT = 0x100F,
+ WID_AUTH_TIMEOUT = 0x1010,
+ WID_ASOC_TIMEOUT = 0x1011,
+ WID_11I_PROTOCOL_TIMEOUT = 0x1012,
+ WID_EAPOL_RESPONSE_TIMEOUT = 0x1013,
+
+ /* NMAC Short WID list */
+ WID_11N_SIG_QUAL_VAL = 0x1085,
+ WID_CCA_THRESHOLD = 0x1087,
+
+ /* Custom Short WID list */
+
+ /* EMAC Integer WID list */
+ WID_FAILED_COUNT = 0x2000,
+ WID_RETRY_COUNT = 0x2001,
+ WID_MULTIPLE_RETRY_COUNT = 0x2002,
+ WID_FRAME_DUPLICATE_COUNT = 0x2003,
+ WID_ACK_FAILURE_COUNT = 0x2004,
+ WID_RECEIVED_FRAGMENT_COUNT = 0x2005,
+ WID_MCAST_RECEIVED_FRAME_COUNT = 0x2006,
+ WID_FCS_ERROR_COUNT = 0x2007,
+ WID_SUCCESS_FRAME_COUNT = 0x2008,
+ WID_HUT_TX_COUNT = 0x200A,
+ WID_TX_FRAGMENT_COUNT = 0x200B,
+ WID_TX_MULTICAST_FRAME_COUNT = 0x200C,
+ WID_RTS_SUCCESS_COUNT = 0x200D,
+ WID_RTS_FAILURE_COUNT = 0x200E,
+ WID_WEP_UNDECRYPTABLE_COUNT = 0x200F,
+ WID_REKEY_PERIOD = 0x2010,
+ WID_REKEY_PACKET_COUNT = 0x2011,
+ WID_1X_SERV_ADDR = 0x2012,
+ WID_STACK_IP_ADDR = 0x2013,
+ WID_STACK_NETMASK_ADDR = 0x2014,
+ WID_HW_RX_COUNT = 0x2015,
+ WID_MEMORY_ADDRESS = 0x201E,
+ WID_MEMORY_ACCESS_32BIT = 0x201F,
+ WID_RF_REG_VAL = 0x2021,
+
+ /* NMAC Integer WID list */
+ WID_11N_PHY_ACTIVE_REG_VAL = 0x2080,
+
+ /* Custom Integer WID list */
+ WID_GET_INACTIVE_TIME = 0x2084,
+ WID_SET_OPERATION_MODE = 0X2086,
+ /* EMAC String WID list */
+ WID_SSID = 0x3000,
+ WID_FIRMWARE_VERSION = 0x3001,
+ WID_OPERATIONAL_RATE_SET = 0x3002,
+ WID_BSSID = 0x3003,
+ WID_WEP_KEY_VALUE = 0x3004,
+ WID_11I_PSK = 0x3008,
+ WID_11E_P_ACTION_REQ = 0x3009,
+ WID_1X_KEY = 0x300A,
+ WID_HARDWARE_VERSION = 0x300B,
+ WID_MAC_ADDR = 0x300C,
+ WID_HUT_DEST_ADDR = 0x300D,
+ WID_PHY_VERSION = 0x300F,
+ WID_SUPP_USERNAME = 0x3010,
+ WID_SUPP_PASSWORD = 0x3011,
+ WID_SITE_SURVEY_RESULTS = 0x3012,
+ WID_RX_POWER_LEVEL = 0x3013,
+ WID_DEL_ALL_RX_BA = 0x3014,
+ WID_SET_STA_MAC_INACTIVE_TIME = 0x3017,
+ WID_ADD_WEP_KEY = 0x3019,
+ WID_REMOVE_WEP_KEY = 0x301A,
+ WID_ADD_PTK = 0x301B,
+ WID_ADD_RX_GTK = 0x301C,
+ WID_ADD_TX_GTK = 0x301D,
+ WID_REMOVE_KEY = 0x301E,
+ WID_ASSOC_REQ_INFO = 0x301F,
+ WID_ASSOC_RES_INFO = 0x3020,
+ WID_MANUFACTURER = 0x3026, /*Added for CAPI tool */
+ WID_MODEL_NAME = 0x3027, /*Added for CAPI tool */
+ WID_MODEL_NUM = 0x3028, /*Added for CAPI tool */
+ WID_DEVICE_NAME = 0x3029, /*Added for CAPI tool */
+ WID_SET_DRV_HANDLER = 0x3079,
+
+ /* NMAC String WID list */
+ WID_11N_P_ACTION_REQ = 0x3080,
+ WID_HUT_TEST_ID = 0x3081,
+ WID_PMKID_INFO = 0x3082,
+ WID_FIRMWARE_INFO = 0x3083,
+ WID_REGISTER_FRAME = 0x3084,
+ WID_DEL_ALL_STA = 0x3085,
+ WID_REMAIN_ON_CHAN = 0x3996,
+ WID_SSID_PROBE_REQ = 0x3997,
+ WID_JOIN_REQ_EXTENDED = 0x3998,
+
+ WID_IP_ADDRESS = 0x3999,
+
+ /* Custom String WID list */
+
+ /* EMAC Binary WID list */
+ WID_UAPSD_CONFIG = 0x4001,
+ WID_UAPSD_STATUS = 0x4002,
+ WID_WMM_AP_AC_PARAMS = 0x4003,
+ WID_WMM_STA_AC_PARAMS = 0x4004,
+ WID_NETWORK_INFO = 0x4005,
+ WID_STA_JOIN_INFO = 0x4006,
+ WID_CONNECTED_STA_LIST = 0x4007,
+
+ /* NMAC Binary WID list */
+ WID_11N_AUTORATE_TABLE = 0x4080,
+
+ WID_SCAN_CHANNEL_LIST = 0x4084,
+
+ WID_INFO_ELEMENT_PROBE = 0x4085,
+ WID_INFO_ELEMENT_ASSOCIATE = 0x4086,
+ WID_ADD_STA = 0X4087,
+ WID_REMOVE_STA = 0X4088,
+ WID_EDIT_STA = 0X4089,
+ WID_ADD_BEACON = 0x408a,
+
+ WID_SETUP_MULTICAST_FILTER = 0x408b,
+
+ /* Miscellaneous WIDs */
+ WID_ALL = 0x7FFE,
+ WID_MAX = 0xFFFF
+};
+
+struct wilc;
+int wilc_wlan_init(struct net_device *dev);
+u32 wilc_get_chipid(struct wilc *wilc, bool update);
+
+#endif
--
2.7.4


2018-09-26 10:25:50

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 04/19] wilc: add host_interface.c

Moved '/driver/staging/wilc1000/host_interface.c' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/host_interface.c b/drivers/net/wireless/microchip/wilc/host_interface.c
new file mode 100644
index 0000000..01db899
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/host_interface.c
@@ -0,0 +1,3927 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "wilc_wfi_netdevice.h"
+
+#define HOST_IF_SCAN_TIMEOUT 4000
+#define HOST_IF_CONNECT_TIMEOUT 9500
+
+#define FALSE_FRMWR_CHANNEL 100
+
+#define REAL_JOIN_REQ 0
+
+struct host_if_wpa_attr {
+ u8 *key;
+ const u8 *mac_addr;
+ u8 *seq;
+ u8 seq_len;
+ u8 index;
+ u8 key_len;
+ u8 mode;
+};
+
+struct host_if_wep_attr {
+ u8 *key;
+ u8 key_len;
+ u8 index;
+ u8 mode;
+ enum authtype auth_type;
+};
+
+union host_if_key_attr {
+ struct host_if_wep_attr wep;
+ struct host_if_wpa_attr wpa;
+ struct host_if_pmkid_attr pmkid;
+};
+
+struct key_attr {
+ enum KEY_TYPE type;
+ u8 action;
+ union host_if_key_attr attr;
+};
+
+struct scan_attr {
+ u8 src;
+ u8 type;
+ u8 *ch_freq_list;
+ u8 ch_list_len;
+ u8 *ies;
+ size_t ies_len;
+ wilc_scan_result result;
+ void *arg;
+ struct hidden_network hidden_network;
+};
+
+struct connect_attr {
+ u8 *bssid;
+ u8 *ssid;
+ size_t ssid_len;
+ u8 *ies;
+ size_t ies_len;
+ u8 security;
+ wilc_connect_result result;
+ void *arg;
+ enum authtype auth_type;
+ u8 ch;
+ void *params;
+};
+
+struct rcvd_async_info {
+ u8 *buffer;
+ u32 len;
+};
+
+struct channel_attr {
+ u8 set_ch;
+};
+
+struct beacon_attr {
+ u32 interval;
+ u32 dtim_period;
+ u32 head_len;
+ u8 *head;
+ u32 tail_len;
+ u8 *tail;
+};
+
+struct set_multicast {
+ bool enabled;
+ u32 cnt;
+ u8 *mc_list;
+};
+
+struct del_all_sta {
+ u8 del_all_sta[MAX_NUM_STA][ETH_ALEN];
+ u8 assoc_sta;
+};
+
+struct del_sta {
+ u8 mac_addr[ETH_ALEN];
+};
+
+struct power_mgmt_param {
+ bool enabled;
+ u32 timeout;
+};
+
+struct set_ip_addr {
+ u8 *ip_addr;
+ u8 idx;
+};
+
+struct sta_inactive_t {
+ u32 inactive_time;
+ u8 mac[6];
+};
+
+struct tx_power {
+ u8 tx_pwr;
+};
+
+union message_body {
+ struct scan_attr scan_info;
+ struct connect_attr con_info;
+ struct rcvd_net_info net_info;
+ struct rcvd_async_info async_info;
+ struct key_attr key_info;
+ struct cfg_param_attr cfg_info;
+ struct channel_attr channel_info;
+ struct beacon_attr beacon_info;
+ struct add_sta_param add_sta_info;
+ struct del_sta del_sta_info;
+ struct add_sta_param edit_sta_info;
+ struct power_mgmt_param pwr_mgmt_info;
+ struct sta_inactive_t mac_info;
+ struct set_ip_addr ip_info;
+ struct drv_handler drv;
+ struct set_multicast multicast_info;
+ struct op_mode mode;
+ struct get_mac_addr get_mac_info;
+ struct ba_session_info session_info;
+ struct remain_ch remain_on_ch;
+ struct reg_frame reg_frame;
+ char *data;
+ struct del_all_sta del_all_sta_info;
+ struct tx_power tx_power;
+};
+
+struct host_if_msg {
+ union message_body body;
+ struct wilc_vif *vif;
+ struct work_struct work;
+ void (*fn)(struct work_struct *ws);
+ struct completion work_comp;
+ bool is_sync;
+};
+
+struct join_bss_param {
+ enum bss_types bss_type;
+ u8 dtim_period;
+ u16 beacon_period;
+ u16 cap_info;
+ u8 bssid[6];
+ char ssid[MAX_SSID_LEN];
+ u8 ssid_len;
+ u8 supp_rates[MAX_RATES_SUPPORTED + 1];
+ u8 ht_capable;
+ u8 wmm_cap;
+ u8 uapsd_cap;
+ bool rsn_found;
+ u8 rsn_grp_policy;
+ u8 mode_802_11i;
+ u8 rsn_pcip_policy[3];
+ u8 rsn_auth_policy[3];
+ u8 rsn_cap[2];
+ u32 tsf;
+ u8 noa_enabled;
+ u8 opp_enabled;
+ u8 ct_window;
+ u8 cnt;
+ u8 idx;
+ u8 duration[4];
+ u8 interval[4];
+ u8 start_time[4];
+};
+
+static struct host_if_drv *terminated_handle;
+static struct mutex hif_deinit_lock;
+
+/* 'msg' should be free by the caller for syc */
+static struct host_if_msg*
+wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *),
+ bool is_sync)
+{
+ struct host_if_msg *msg;
+
+ if (!work_fun)
+ return ERR_PTR(-EINVAL);
+
+ msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
+ if (!msg)
+ return ERR_PTR(-ENOMEM);
+ msg->fn = work_fun;
+ msg->vif = vif;
+ msg->is_sync = is_sync;
+ if (is_sync)
+ init_completion(&msg->work_comp);
+
+ return msg;
+}
+
+static int wilc_enqueue_work(struct host_if_msg *msg)
+{
+ INIT_WORK(&msg->work, msg->fn);
+
+ if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue)
+ return -EINVAL;
+
+ if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work))
+ return -EINVAL;
+
+ return 0;
+}
+
+/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as
+ * special purpose in wilc device, so we add 1 to the index to starts from 1.
+ * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC.
+ */
+int wilc_get_vif_idx(struct wilc_vif *vif)
+{
+ return vif->idx + 1;
+}
+
+/* We need to minus 1 from idx which is from wilc device to get real index
+ * of wilc->vif[], because we add 1 when pass to wilc device in the function
+ * wilc_get_vif_idx.
+ * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1).
+ */
+static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx)
+{
+ int index = idx - 1;
+
+ if (index < 0 || index >= NUM_CONCURRENT_IFC)
+ return NULL;
+
+ return wilc->vif[index];
+}
+
+static void handle_set_channel(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct channel_attr *hif_set_ch = &msg->body.channel_info;
+ int ret;
+ struct wid wid;
+
+ wid.id = WID_CURRENT_CHANNEL;
+ wid.type = WID_CHAR;
+ wid.val = (char *)&hif_set_ch->set_ch;
+ wid.size = sizeof(char);
+
+ ret = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+
+ if (ret)
+ netdev_err(vif->ndev, "Failed to set channel\n");
+ kfree(msg);
+}
+
+static void handle_set_wfi_drv_handler(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct drv_handler *hif_drv_handler = &msg->body.drv;
+ int ret;
+ struct wid wid;
+ u8 *currbyte, *buffer;
+ struct host_if_drv *hif_drv;
+
+ if (!vif->hif_drv || !hif_drv_handler)
+ goto free_msg;
+
+ hif_drv = vif->hif_drv;
+
+ buffer = kzalloc(DRV_HANDLER_SIZE, GFP_KERNEL);
+ if (!buffer)
+ goto free_msg;
+
+ currbyte = buffer;
+ *currbyte = hif_drv->driver_handler_id & DRV_HANDLER_MASK;
+ currbyte++;
+ *currbyte = (u32)0 & DRV_HANDLER_MASK;
+ currbyte++;
+ *currbyte = (u32)0 & DRV_HANDLER_MASK;
+ currbyte++;
+ *currbyte = (u32)0 & DRV_HANDLER_MASK;
+ currbyte++;
+ *currbyte = (hif_drv_handler->name | (hif_drv_handler->mode << 1));
+
+ wid.id = WID_SET_DRV_HANDLER;
+ wid.type = WID_STR;
+ wid.val = (s8 *)buffer;
+ wid.size = DRV_HANDLER_SIZE;
+
+ ret = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ hif_drv->driver_handler_id);
+ if (ret)
+ netdev_err(vif->ndev, "Failed to set driver handler\n");
+
+ kfree(buffer);
+
+free_msg:
+ if (msg->is_sync)
+ complete(&msg->work_comp);
+
+ kfree(msg);
+}
+
+static void handle_set_operation_mode(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct op_mode *hif_op_mode = &msg->body.mode;
+ int ret;
+ struct wid wid;
+
+ wid.id = WID_SET_OPERATION_MODE;
+ wid.type = WID_INT;
+ wid.val = (s8 *)&hif_op_mode->mode;
+ wid.size = sizeof(u32);
+
+ ret = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+
+ if (ret)
+ netdev_err(vif->ndev, "Failed to set operation mode\n");
+
+ kfree(msg);
+}
+
+static void handle_get_mac_address(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct get_mac_addr *get_mac_addr = &msg->body.get_mac_info;
+ int ret;
+ struct wid wid;
+
+ wid.id = WID_MAC_ADDR;
+ wid.type = WID_STR;
+ wid.val = get_mac_addr->mac_addr;
+ wid.size = ETH_ALEN;
+
+ ret = wilc_send_config_pkt(vif, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+
+ if (ret)
+ netdev_err(vif->ndev, "Failed to get mac address\n");
+ complete(&msg->work_comp);
+ /* free 'msg' data later, in caller */
+}
+
+static void handle_cfg_param(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct cfg_param_attr *param = &msg->body.cfg_info;
+ int ret;
+ struct wid wid_list[32];
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ int i = 0;
+
+ mutex_lock(&hif_drv->cfg_values_lock);
+
+ if (param->flag & BSS_TYPE) {
+ u8 bss_type = param->bss_type;
+
+ if (bss_type < 6) {
+ wid_list[i].id = WID_BSS_TYPE;
+ wid_list[i].val = (s8 *)&param->bss_type;
+ wid_list[i].type = WID_CHAR;
+ wid_list[i].size = sizeof(char);
+ hif_drv->cfg_values.bss_type = bss_type;
+ } else {
+ netdev_err(vif->ndev, "check value 6 over\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & AUTH_TYPE) {
+ u8 auth_type = param->auth_type;
+
+ if (auth_type == 1 || auth_type == 2 || auth_type == 5) {
+ wid_list[i].id = WID_AUTH_TYPE;
+ wid_list[i].val = (s8 *)&param->auth_type;
+ wid_list[i].type = WID_CHAR;
+ wid_list[i].size = sizeof(char);
+ hif_drv->cfg_values.auth_type = auth_type;
+ } else {
+ netdev_err(vif->ndev, "Impossible value\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & AUTHEN_TIMEOUT) {
+ if (param->auth_timeout > 0) {
+ wid_list[i].id = WID_AUTH_TIMEOUT;
+ wid_list[i].val = (s8 *)&param->auth_timeout;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.auth_timeout = param->auth_timeout;
+ } else {
+ netdev_err(vif->ndev, "Range(1 ~ 65535) over\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & POWER_MANAGEMENT) {
+ u8 pm_mode = param->power_mgmt_mode;
+
+ if (pm_mode < 5) {
+ wid_list[i].id = WID_POWER_MANAGEMENT;
+ wid_list[i].val = (s8 *)&param->power_mgmt_mode;
+ wid_list[i].type = WID_CHAR;
+ wid_list[i].size = sizeof(char);
+ hif_drv->cfg_values.power_mgmt_mode = pm_mode;
+ } else {
+ netdev_err(vif->ndev, "Invalid power mode\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & RETRY_SHORT) {
+ u16 retry_limit = param->short_retry_limit;
+
+ if (retry_limit > 0 && retry_limit < 256) {
+ wid_list[i].id = WID_SHORT_RETRY_LIMIT;
+ wid_list[i].val = (s8 *)&param->short_retry_limit;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.short_retry_limit = retry_limit;
+ } else {
+ netdev_err(vif->ndev, "Range(1~256) over\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & RETRY_LONG) {
+ u16 limit = param->long_retry_limit;
+
+ if (limit > 0 && limit < 256) {
+ wid_list[i].id = WID_LONG_RETRY_LIMIT;
+ wid_list[i].val = (s8 *)&param->long_retry_limit;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.long_retry_limit = limit;
+ } else {
+ netdev_err(vif->ndev, "Range(1~256) over\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & FRAG_THRESHOLD) {
+ u16 frag_th = param->frag_threshold;
+
+ if (frag_th > 255 && frag_th < 7937) {
+ wid_list[i].id = WID_FRAG_THRESHOLD;
+ wid_list[i].val = (s8 *)&param->frag_threshold;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.frag_threshold = frag_th;
+ } else {
+ netdev_err(vif->ndev, "Threshold Range fail\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & RTS_THRESHOLD) {
+ u16 rts_th = param->rts_threshold;
+
+ if (rts_th > 255) {
+ wid_list[i].id = WID_RTS_THRESHOLD;
+ wid_list[i].val = (s8 *)&param->rts_threshold;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.rts_threshold = rts_th;
+ } else {
+ netdev_err(vif->ndev, "Threshold Range fail\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & PREAMBLE) {
+ u16 preamble_type = param->preamble_type;
+
+ if (param->preamble_type < 3) {
+ wid_list[i].id = WID_PREAMBLE;
+ wid_list[i].val = (s8 *)&param->preamble_type;
+ wid_list[i].type = WID_CHAR;
+ wid_list[i].size = sizeof(char);
+ hif_drv->cfg_values.preamble_type = preamble_type;
+ } else {
+ netdev_err(vif->ndev, "Preamble Range(0~2) over\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & SHORT_SLOT_ALLOWED) {
+ u8 slot_allowed = param->short_slot_allowed;
+
+ if (slot_allowed < 2) {
+ wid_list[i].id = WID_SHORT_SLOT_ALLOWED;
+ wid_list[i].val = (s8 *)&param->short_slot_allowed;
+ wid_list[i].type = WID_CHAR;
+ wid_list[i].size = sizeof(char);
+ hif_drv->cfg_values.short_slot_allowed = slot_allowed;
+ } else {
+ netdev_err(vif->ndev, "Short slot(2) over\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & TXOP_PROT_DISABLE) {
+ u8 prot_disabled = param->txop_prot_disabled;
+
+ if (param->txop_prot_disabled < 2) {
+ wid_list[i].id = WID_11N_TXOP_PROT_DISABLE;
+ wid_list[i].val = (s8 *)&param->txop_prot_disabled;
+ wid_list[i].type = WID_CHAR;
+ wid_list[i].size = sizeof(char);
+ hif_drv->cfg_values.txop_prot_disabled = prot_disabled;
+ } else {
+ netdev_err(vif->ndev, "TXOP prot disable\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & BEACON_INTERVAL) {
+ u16 beacon_interval = param->beacon_interval;
+
+ if (beacon_interval > 0) {
+ wid_list[i].id = WID_BEACON_INTERVAL;
+ wid_list[i].val = (s8 *)&param->beacon_interval;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.beacon_interval = beacon_interval;
+ } else {
+ netdev_err(vif->ndev, "Beacon interval(1~65535)fail\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & DTIM_PERIOD) {
+ if (param->dtim_period > 0 && param->dtim_period < 256) {
+ wid_list[i].id = WID_DTIM_PERIOD;
+ wid_list[i].val = (s8 *)&param->dtim_period;
+ wid_list[i].type = WID_CHAR;
+ wid_list[i].size = sizeof(char);
+ hif_drv->cfg_values.dtim_period = param->dtim_period;
+ } else {
+ netdev_err(vif->ndev, "DTIM range(1~255) fail\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & SITE_SURVEY) {
+ enum site_survey enabled = param->site_survey_enabled;
+
+ if (enabled < 3) {
+ wid_list[i].id = WID_SITE_SURVEY;
+ wid_list[i].val = (s8 *)&param->site_survey_enabled;
+ wid_list[i].type = WID_CHAR;
+ wid_list[i].size = sizeof(char);
+ hif_drv->cfg_values.site_survey_enabled = enabled;
+ } else {
+ netdev_err(vif->ndev, "Site survey disable\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & SITE_SURVEY_SCAN_TIME) {
+ u16 scan_time = param->site_survey_scan_time;
+
+ if (scan_time > 0) {
+ wid_list[i].id = WID_SITE_SURVEY_SCAN_TIME;
+ wid_list[i].val = (s8 *)&param->site_survey_scan_time;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.site_survey_scan_time = scan_time;
+ } else {
+ netdev_err(vif->ndev, "Site scan time(1~65535) over\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & ACTIVE_SCANTIME) {
+ u16 active_scan_time = param->active_scan_time;
+
+ if (active_scan_time > 0) {
+ wid_list[i].id = WID_ACTIVE_SCAN_TIME;
+ wid_list[i].val = (s8 *)&param->active_scan_time;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.active_scan_time = active_scan_time;
+ } else {
+ netdev_err(vif->ndev, "Active time(1~65535) over\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & PASSIVE_SCANTIME) {
+ u16 time = param->passive_scan_time;
+
+ if (time > 0) {
+ wid_list[i].id = WID_PASSIVE_SCAN_TIME;
+ wid_list[i].val = (s8 *)&param->passive_scan_time;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.passive_scan_time = time;
+ } else {
+ netdev_err(vif->ndev, "Passive time(1~65535) over\n");
+ goto unlock;
+ }
+ i++;
+ }
+ if (param->flag & CURRENT_TX_RATE) {
+ enum current_tx_rate curr_tx_rate = param->curr_tx_rate;
+
+ if (curr_tx_rate == AUTORATE || curr_tx_rate == MBPS_1 ||
+ curr_tx_rate == MBPS_2 || curr_tx_rate == MBPS_5_5 ||
+ curr_tx_rate == MBPS_11 || curr_tx_rate == MBPS_6 ||
+ curr_tx_rate == MBPS_9 || curr_tx_rate == MBPS_12 ||
+ curr_tx_rate == MBPS_18 || curr_tx_rate == MBPS_24 ||
+ curr_tx_rate == MBPS_36 || curr_tx_rate == MBPS_48 ||
+ curr_tx_rate == MBPS_54) {
+ wid_list[i].id = WID_CURRENT_TX_RATE;
+ wid_list[i].val = (s8 *)&curr_tx_rate;
+ wid_list[i].type = WID_SHORT;
+ wid_list[i].size = sizeof(u16);
+ hif_drv->cfg_values.curr_tx_rate = (u8)curr_tx_rate;
+ } else {
+ netdev_err(vif->ndev, "out of TX rate\n");
+ goto unlock;
+ }
+ i++;
+ }
+
+ ret = wilc_send_config_pkt(vif, SET_CFG, wid_list,
+ i, wilc_get_vif_idx(vif));
+
+ if (ret)
+ netdev_err(vif->ndev, "Error in setting CFG params\n");
+
+unlock:
+ mutex_unlock(&hif_drv->cfg_values_lock);
+ kfree(msg);
+}
+
+static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt)
+{
+ int result = 0;
+ u8 abort_running_scan;
+ struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct user_scan_req *scan_req;
+
+ if (evt == SCAN_EVENT_ABORTED) {
+ abort_running_scan = 1;
+ wid.id = WID_ABORT_RUNNING_SCAN;
+ wid.type = WID_CHAR;
+ wid.val = (s8 *)&abort_running_scan;
+ wid.size = sizeof(char);
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+
+ if (result) {
+ netdev_err(vif->ndev, "Failed to set abort running\n");
+ result = -EFAULT;
+ }
+ }
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+ return result;
+ }
+
+ scan_req = &hif_drv->usr_scan_req;
+ if (scan_req->scan_result) {
+ scan_req->scan_result(evt, NULL, scan_req->arg, NULL);
+ scan_req->scan_result = NULL;
+ }
+
+ return result;
+}
+
+static void handle_scan(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct scan_attr *scan_info = &msg->body.scan_info;
+ int result = 0;
+ struct wid wid_list[5];
+ u32 index = 0;
+ u32 i;
+ u8 *buffer;
+ u8 valuesize = 0;
+ u8 *hdn_ntwk_wid_val = NULL;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct hidden_network *hidden_net = &scan_info->hidden_network;
+
+ hif_drv->usr_scan_req.scan_result = scan_info->result;
+ hif_drv->usr_scan_req.arg = scan_info->arg;
+
+ if (hif_drv->hif_state >= HOST_IF_SCANNING &&
+ hif_drv->hif_state < HOST_IF_CONNECTED) {
+ netdev_err(vif->ndev, "Already scan\n");
+ result = -EBUSY;
+ goto error;
+ }
+
+ if (vif->obtaining_ip || vif->connecting) {
+ netdev_err(vif->ndev, "Don't do obss scan\n");
+ result = -EBUSY;
+ goto error;
+ }
+
+ hif_drv->usr_scan_req.ch_cnt = 0;
+
+ wid_list[index].id = WID_SSID_PROBE_REQ;
+ wid_list[index].type = WID_STR;
+
+ for (i = 0; i < hidden_net->n_ssids; i++)
+ valuesize += ((hidden_net->net_info[i].ssid_len) + 1);
+ hdn_ntwk_wid_val = kmalloc(valuesize + 1, GFP_KERNEL);
+ wid_list[index].val = hdn_ntwk_wid_val;
+ if (wid_list[index].val) {
+ buffer = wid_list[index].val;
+
+ *buffer++ = hidden_net->n_ssids;
+
+ for (i = 0; i < hidden_net->n_ssids; i++) {
+ *buffer++ = hidden_net->net_info[i].ssid_len;
+ memcpy(buffer, hidden_net->net_info[i].ssid,
+ hidden_net->net_info[i].ssid_len);
+ buffer += hidden_net->net_info[i].ssid_len;
+ }
+
+ wid_list[index].size = (s32)(valuesize + 1);
+ index++;
+ }
+
+ wid_list[index].id = WID_INFO_ELEMENT_PROBE;
+ wid_list[index].type = WID_BIN_DATA;
+ wid_list[index].val = scan_info->ies;
+ wid_list[index].size = scan_info->ies_len;
+ index++;
+
+ wid_list[index].id = WID_SCAN_TYPE;
+ wid_list[index].type = WID_CHAR;
+ wid_list[index].size = sizeof(char);
+ wid_list[index].val = (s8 *)&scan_info->type;
+ index++;
+
+ wid_list[index].id = WID_SCAN_CHANNEL_LIST;
+ wid_list[index].type = WID_BIN_DATA;
+
+ if (scan_info->ch_freq_list &&
+ scan_info->ch_list_len > 0) {
+ int i;
+
+ for (i = 0; i < scan_info->ch_list_len; i++) {
+ if (scan_info->ch_freq_list[i] > 0)
+ scan_info->ch_freq_list[i] -= 1;
+ }
+ }
+
+ wid_list[index].val = scan_info->ch_freq_list;
+ wid_list[index].size = scan_info->ch_list_len;
+ index++;
+
+ wid_list[index].id = WID_START_SCAN_REQ;
+ wid_list[index].type = WID_CHAR;
+ wid_list[index].size = sizeof(char);
+ wid_list[index].val = (s8 *)&scan_info->src;
+ index++;
+
+ result = wilc_send_config_pkt(vif, SET_CFG, wid_list,
+ index,
+ wilc_get_vif_idx(vif));
+
+ if (result)
+ netdev_err(vif->ndev, "Failed to send scan parameters\n");
+
+error:
+ if (result) {
+ del_timer(&hif_drv->scan_timer);
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
+ }
+
+ kfree(scan_info->ch_freq_list);
+ scan_info->ch_freq_list = NULL;
+
+ kfree(scan_info->ies);
+ scan_info->ies = NULL;
+ kfree(scan_info->hidden_network.net_info);
+ scan_info->hidden_network.net_info = NULL;
+
+ kfree(hdn_ntwk_wid_val);
+
+ kfree(msg);
+}
+
+static void handle_connect(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct connect_attr *conn_attr = &msg->body.con_info;
+ int result = 0;
+ struct wid wid_list[8];
+ u32 wid_cnt = 0, dummyval = 0;
+ u8 *cur_byte = NULL;
+ struct join_bss_param *bss_param;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (msg->vif->hif_drv->usr_scan_req.scan_result) {
+ result = wilc_enqueue_work(msg);
+ if (result)
+ goto error;
+
+ usleep_range(2 * 1000, 2 * 1000);
+ return;
+ }
+
+ bss_param = conn_attr->params;
+ if (!bss_param) {
+ netdev_err(vif->ndev, "Required BSSID not found\n");
+ result = -ENOENT;
+ goto error;
+ }
+
+ if (conn_attr->bssid) {
+ hif_drv->usr_conn_req.bssid = kmemdup(conn_attr->bssid, 6,
+ GFP_KERNEL);
+ if (!hif_drv->usr_conn_req.bssid) {
+ result = -ENOMEM;
+ goto error;
+ }
+ }
+
+ hif_drv->usr_conn_req.ssid_len = conn_attr->ssid_len;
+ if (conn_attr->ssid) {
+ hif_drv->usr_conn_req.ssid = kmalloc(conn_attr->ssid_len + 1,
+ GFP_KERNEL);
+ if (!hif_drv->usr_conn_req.ssid) {
+ result = -ENOMEM;
+ goto error;
+ }
+ memcpy(hif_drv->usr_conn_req.ssid,
+ conn_attr->ssid,
+ conn_attr->ssid_len);
+ hif_drv->usr_conn_req.ssid[conn_attr->ssid_len] = '\0';
+ }
+
+ hif_drv->usr_conn_req.ies_len = conn_attr->ies_len;
+ if (conn_attr->ies) {
+ hif_drv->usr_conn_req.ies = kmemdup(conn_attr->ies,
+ conn_attr->ies_len,
+ GFP_KERNEL);
+ if (!hif_drv->usr_conn_req.ies) {
+ result = -ENOMEM;
+ goto error;
+ }
+ }
+
+ hif_drv->usr_conn_req.security = conn_attr->security;
+ hif_drv->usr_conn_req.auth_type = conn_attr->auth_type;
+ hif_drv->usr_conn_req.conn_result = conn_attr->result;
+ hif_drv->usr_conn_req.arg = conn_attr->arg;
+
+ wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)(&(dummyval));
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)(&(dummyval));
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_FAILED_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)(&(dummyval));
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
+ wid_list[wid_cnt].type = WID_BIN_DATA;
+ wid_list[wid_cnt].val = hif_drv->usr_conn_req.ies;
+ wid_list[wid_cnt].size = hif_drv->usr_conn_req.ies_len;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_11I_MODE;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&hif_drv->usr_conn_req.security;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_AUTH_TYPE;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&hif_drv->usr_conn_req.auth_type;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED;
+ wid_list[wid_cnt].type = WID_STR;
+ wid_list[wid_cnt].size = 112;
+ wid_list[wid_cnt].val = kmalloc(wid_list[wid_cnt].size, GFP_KERNEL);
+
+ if (!wid_list[wid_cnt].val) {
+ result = -EFAULT;
+ goto error;
+ }
+
+ cur_byte = wid_list[wid_cnt].val;
+
+ if (conn_attr->ssid) {
+ memcpy(cur_byte, conn_attr->ssid, conn_attr->ssid_len);
+ cur_byte[conn_attr->ssid_len] = '\0';
+ }
+ cur_byte += MAX_SSID_LEN;
+ *(cur_byte++) = INFRASTRUCTURE;
+
+ if (conn_attr->ch >= 1 && conn_attr->ch <= 14) {
+ *(cur_byte++) = conn_attr->ch;
+ } else {
+ netdev_err(vif->ndev, "Channel out of range\n");
+ *(cur_byte++) = 0xFF;
+ }
+ *(cur_byte++) = (bss_param->cap_info) & 0xFF;
+ *(cur_byte++) = ((bss_param->cap_info) >> 8) & 0xFF;
+
+ if (conn_attr->bssid)
+ memcpy(cur_byte, conn_attr->bssid, 6);
+ cur_byte += 6;
+
+ if (conn_attr->bssid)
+ memcpy(cur_byte, conn_attr->bssid, 6);
+ cur_byte += 6;
+
+ *(cur_byte++) = (bss_param->beacon_period) & 0xFF;
+ *(cur_byte++) = ((bss_param->beacon_period) >> 8) & 0xFF;
+ *(cur_byte++) = bss_param->dtim_period;
+
+ memcpy(cur_byte, bss_param->supp_rates, MAX_RATES_SUPPORTED + 1);
+ cur_byte += (MAX_RATES_SUPPORTED + 1);
+
+ *(cur_byte++) = bss_param->wmm_cap;
+ *(cur_byte++) = bss_param->uapsd_cap;
+
+ *(cur_byte++) = bss_param->ht_capable;
+ hif_drv->usr_conn_req.ht_capable = bss_param->ht_capable;
+
+ *(cur_byte++) = bss_param->rsn_found;
+ *(cur_byte++) = bss_param->rsn_grp_policy;
+ *(cur_byte++) = bss_param->mode_802_11i;
+
+ memcpy(cur_byte, bss_param->rsn_pcip_policy,
+ sizeof(bss_param->rsn_pcip_policy));
+ cur_byte += sizeof(bss_param->rsn_pcip_policy);
+
+ memcpy(cur_byte, bss_param->rsn_auth_policy,
+ sizeof(bss_param->rsn_auth_policy));
+ cur_byte += sizeof(bss_param->rsn_auth_policy);
+
+ memcpy(cur_byte, bss_param->rsn_cap, sizeof(bss_param->rsn_cap));
+ cur_byte += sizeof(bss_param->rsn_cap);
+
+ *(cur_byte++) = REAL_JOIN_REQ;
+ *(cur_byte++) = bss_param->noa_enabled;
+
+ if (bss_param->noa_enabled) {
+ *(cur_byte++) = (bss_param->tsf) & 0xFF;
+ *(cur_byte++) = ((bss_param->tsf) >> 8) & 0xFF;
+ *(cur_byte++) = ((bss_param->tsf) >> 16) & 0xFF;
+ *(cur_byte++) = ((bss_param->tsf) >> 24) & 0xFF;
+
+ *(cur_byte++) = bss_param->opp_enabled;
+ *(cur_byte++) = bss_param->idx;
+
+ if (bss_param->opp_enabled)
+ *(cur_byte++) = bss_param->ct_window;
+
+ *(cur_byte++) = bss_param->cnt;
+
+ memcpy(cur_byte, bss_param->duration,
+ sizeof(bss_param->duration));
+ cur_byte += sizeof(bss_param->duration);
+
+ memcpy(cur_byte, bss_param->interval,
+ sizeof(bss_param->interval));
+ cur_byte += sizeof(bss_param->interval);
+
+ memcpy(cur_byte, bss_param->start_time,
+ sizeof(bss_param->start_time));
+ cur_byte += sizeof(bss_param->start_time);
+ }
+
+ cur_byte = wid_list[wid_cnt].val;
+ wid_cnt++;
+
+ result = wilc_send_config_pkt(vif, SET_CFG, wid_list,
+ wid_cnt,
+ wilc_get_vif_idx(vif));
+ if (result) {
+ netdev_err(vif->ndev, "failed to send config packet\n");
+ result = -EFAULT;
+ goto error;
+ } else {
+ hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
+ }
+
+error:
+ if (result) {
+ struct connect_info conn_info;
+
+ del_timer(&hif_drv->connect_timer);
+
+ memset(&conn_info, 0, sizeof(struct connect_info));
+
+ if (conn_attr->result) {
+ if (conn_attr->bssid)
+ memcpy(conn_info.bssid, conn_attr->bssid, 6);
+
+ if (conn_attr->ies) {
+ conn_info.req_ies_len = conn_attr->ies_len;
+ conn_info.req_ies = kmalloc(conn_attr->ies_len,
+ GFP_KERNEL);
+ memcpy(conn_info.req_ies,
+ conn_attr->ies,
+ conn_attr->ies_len);
+ }
+
+ conn_attr->result(CONN_DISCONN_EVENT_CONN_RESP,
+ &conn_info, MAC_STATUS_DISCONNECTED,
+ NULL, conn_attr->arg);
+ hif_drv->hif_state = HOST_IF_IDLE;
+ kfree(conn_info.req_ies);
+ conn_info.req_ies = NULL;
+
+ } else {
+ netdev_err(vif->ndev, "Connect callback is NULL\n");
+ }
+ }
+
+ kfree(conn_attr->bssid);
+ conn_attr->bssid = NULL;
+
+ kfree(conn_attr->ssid);
+ conn_attr->ssid = NULL;
+
+ kfree(conn_attr->ies);
+ conn_attr->ies = NULL;
+
+ kfree(cur_byte);
+ kfree(msg);
+}
+
+static void handle_connect_timeout(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ int result;
+ struct connect_info info;
+ struct wid wid;
+ u16 dummy_reason_code = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+ goto out;
+ }
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+
+ memset(&info, 0, sizeof(struct connect_info));
+
+ if (hif_drv->usr_conn_req.conn_result) {
+ if (hif_drv->usr_conn_req.bssid) {
+ memcpy(info.bssid,
+ hif_drv->usr_conn_req.bssid, 6);
+ }
+
+ if (hif_drv->usr_conn_req.ies) {
+ info.req_ies_len = hif_drv->usr_conn_req.ies_len;
+ info.req_ies = kmemdup(hif_drv->usr_conn_req.ies,
+ hif_drv->usr_conn_req.ies_len,
+ GFP_KERNEL);
+ if (!info.req_ies)
+ goto out;
+ }
+
+ hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
+ &info,
+ MAC_STATUS_DISCONNECTED,
+ NULL,
+ hif_drv->usr_conn_req.arg);
+
+ kfree(info.req_ies);
+ info.req_ies = NULL;
+ } else {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ }
+
+ wid.id = WID_DISCONNECT;
+ wid.type = WID_CHAR;
+ wid.val = (s8 *)&dummy_reason_code;
+ wid.size = sizeof(char);
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result)
+ netdev_err(vif->ndev, "Failed to send disconnect\n");
+
+ hif_drv->usr_conn_req.ssid_len = 0;
+ kfree(hif_drv->usr_conn_req.ssid);
+ hif_drv->usr_conn_req.ssid = NULL;
+ kfree(hif_drv->usr_conn_req.bssid);
+ hif_drv->usr_conn_req.bssid = NULL;
+ hif_drv->usr_conn_req.ies_len = 0;
+ kfree(hif_drv->usr_conn_req.ies);
+ hif_drv->usr_conn_req.ies = NULL;
+
+out:
+ kfree(msg);
+}
+
+static void host_int_fill_join_bss_param(struct join_bss_param *param, u8 *ies,
+ u16 *out_index, u8 *pcipher_tc,
+ u8 *auth_total_cnt, u32 tsf_lo,
+ u8 *rates_no)
+{
+ u8 ext_rates_no;
+ u16 offset;
+ u8 pcipher_cnt;
+ u8 auth_cnt;
+ u8 i, j;
+ u16 index = *out_index;
+
+ if (ies[index] == WLAN_EID_SUPP_RATES) {
+ *rates_no = ies[index + 1];
+ param->supp_rates[0] = *rates_no;
+ index += 2;
+
+ for (i = 0; i < *rates_no; i++)
+ param->supp_rates[i + 1] = ies[index + i];
+
+ index += *rates_no;
+ } else if (ies[index] == WLAN_EID_EXT_SUPP_RATES) {
+ ext_rates_no = ies[index + 1];
+ if (ext_rates_no > (MAX_RATES_SUPPORTED - *rates_no))
+ param->supp_rates[0] = MAX_RATES_SUPPORTED;
+ else
+ param->supp_rates[0] += ext_rates_no;
+ index += 2;
+ for (i = 0; i < (param->supp_rates[0] - *rates_no); i++)
+ param->supp_rates[*rates_no + i + 1] = ies[index + i];
+
+ index += ext_rates_no;
+ } else if (ies[index] == WLAN_EID_HT_CAPABILITY) {
+ param->ht_capable = true;
+ index += ies[index + 1] + 2;
+ } else if ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) &&
+ (ies[index + 2] == 0x00) && (ies[index + 3] == 0x50) &&
+ (ies[index + 4] == 0xF2) && (ies[index + 5] == 0x02) &&
+ ((ies[index + 6] == 0x00) || (ies[index + 6] == 0x01)) &&
+ (ies[index + 7] == 0x01)) {
+ param->wmm_cap = true;
+
+ if (ies[index + 8] & BIT(7))
+ param->uapsd_cap = true;
+ index += ies[index + 1] + 2;
+ } else if ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) &&
+ (ies[index + 2] == 0x50) && (ies[index + 3] == 0x6f) &&
+ (ies[index + 4] == 0x9a) &&
+ (ies[index + 5] == 0x09) && (ies[index + 6] == 0x0c)) {
+ u16 p2p_cnt;
+
+ param->tsf = tsf_lo;
+ param->noa_enabled = 1;
+ param->idx = ies[index + 9];
+
+ if (ies[index + 10] & BIT(7)) {
+ param->opp_enabled = 1;
+ param->ct_window = ies[index + 10];
+ } else {
+ param->opp_enabled = 0;
+ }
+
+ param->cnt = ies[index + 11];
+ p2p_cnt = index + 12;
+
+ memcpy(param->duration, ies + p2p_cnt, 4);
+ p2p_cnt += 4;
+
+ memcpy(param->interval, ies + p2p_cnt, 4);
+ p2p_cnt += 4;
+
+ memcpy(param->start_time, ies + p2p_cnt, 4);
+
+ index += ies[index + 1] + 2;
+ } else if ((ies[index] == WLAN_EID_RSN) ||
+ ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) &&
+ (ies[index + 2] == 0x00) &&
+ (ies[index + 3] == 0x50) && (ies[index + 4] == 0xF2) &&
+ (ies[index + 5] == 0x01))) {
+ u16 rsn_idx = index;
+
+ if (ies[rsn_idx] == WLAN_EID_RSN) {
+ param->mode_802_11i = 2;
+ } else {
+ if (param->mode_802_11i == 0)
+ param->mode_802_11i = 1;
+ rsn_idx += 4;
+ }
+
+ rsn_idx += 7;
+ param->rsn_grp_policy = ies[rsn_idx];
+ rsn_idx++;
+ offset = ies[rsn_idx] * 4;
+ pcipher_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
+ rsn_idx += 2;
+
+ i = *pcipher_tc;
+ j = 0;
+ for (; i < (pcipher_cnt + *pcipher_tc) && i < 3; i++, j++) {
+ u8 *policy = &param->rsn_pcip_policy[i];
+
+ *policy = ies[rsn_idx + ((j + 1) * 4) - 1];
+ }
+
+ *pcipher_tc += pcipher_cnt;
+ rsn_idx += offset;
+
+ offset = ies[rsn_idx] * 4;
+
+ auth_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
+ rsn_idx += 2;
+ i = *auth_total_cnt;
+ j = 0;
+ for (; i < (*auth_total_cnt + auth_cnt); i++, j++) {
+ u8 *policy = &param->rsn_auth_policy[i];
+
+ *policy = ies[rsn_idx + ((j + 1) * 4) - 1];
+ }
+
+ *auth_total_cnt += auth_cnt;
+ rsn_idx += offset;
+
+ if (ies[index] == WLAN_EID_RSN) {
+ param->rsn_cap[0] = ies[rsn_idx];
+ param->rsn_cap[1] = ies[rsn_idx + 1];
+ rsn_idx += 2;
+ }
+ param->rsn_found = true;
+ index += ies[index + 1] + 2;
+ } else {
+ index += ies[index + 1] + 2;
+ }
+
+ *out_index = index;
+}
+
+static void *host_int_parse_join_bss_param(struct network_info *info)
+{
+ struct join_bss_param *param;
+ u16 index = 0;
+ u8 rates_no = 0;
+ u8 pcipher_total_cnt = 0;
+ u8 auth_total_cnt = 0;
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param)
+ return NULL;
+
+ param->dtim_period = info->dtim_period;
+ param->beacon_period = info->beacon_period;
+ param->cap_info = info->cap_info;
+ memcpy(param->bssid, info->bssid, 6);
+ memcpy((u8 *)param->ssid, info->ssid, info->ssid_len + 1);
+ param->ssid_len = info->ssid_len;
+ memset(param->rsn_pcip_policy, 0xFF, 3);
+ memset(param->rsn_auth_policy, 0xFF, 3);
+
+ while (index < info->ies_len)
+ host_int_fill_join_bss_param(param, info->ies, &index,
+ &pcipher_total_cnt,
+ &auth_total_cnt, info->tsf_lo,
+ &rates_no);
+
+ return (void *)param;
+}
+
+static void handle_rcvd_ntwrk_info(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct rcvd_net_info *rcvd_info = &msg->body.net_info;
+ u32 i;
+ bool found;
+ struct network_info *info = NULL;
+ void *params;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct user_scan_req *scan_req = &hif_drv->usr_scan_req;
+
+ found = true;
+
+ if (!scan_req->scan_result)
+ goto done;
+
+ wilc_parse_network_info(rcvd_info->buffer, &info);
+ if (!info || !scan_req->scan_result) {
+ netdev_err(vif->ndev, "%s: info or scan result NULL\n",
+ __func__);
+ goto done;
+ }
+
+ for (i = 0; i < scan_req->ch_cnt; i++) {
+ if (memcmp(scan_req->net_info[i].bssid, info->bssid, 6) == 0) {
+ if (info->rssi <= scan_req->net_info[i].rssi) {
+ goto done;
+ } else {
+ scan_req->net_info[i].rssi = info->rssi;
+ found = false;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ if (scan_req->ch_cnt < MAX_NUM_SCANNED_NETWORKS) {
+ scan_req->net_info[scan_req->ch_cnt].rssi = info->rssi;
+
+ memcpy(scan_req->net_info[scan_req->ch_cnt].bssid,
+ info->bssid, 6);
+
+ scan_req->ch_cnt++;
+
+ info->new_network = true;
+ params = host_int_parse_join_bss_param(info);
+
+ scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info,
+ scan_req->arg, params);
+ }
+ } else {
+ info->new_network = false;
+ scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info,
+ scan_req->arg, NULL);
+ }
+
+done:
+ kfree(rcvd_info->buffer);
+ rcvd_info->buffer = NULL;
+
+ if (info) {
+ kfree(info->ies);
+ kfree(info);
+ }
+
+ kfree(msg);
+}
+
+static void host_int_get_assoc_res_info(struct wilc_vif *vif,
+ u8 *assoc_resp_info,
+ u32 max_assoc_resp_info_len,
+ u32 *rcvd_assoc_resp_info_len)
+{
+ int result;
+ struct wid wid;
+
+ wid.id = WID_ASSOC_RES_INFO;
+ wid.type = WID_STR;
+ wid.val = assoc_resp_info;
+ wid.size = max_assoc_resp_info_len;
+
+ result = wilc_send_config_pkt(vif, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result) {
+ *rcvd_assoc_resp_info_len = 0;
+ netdev_err(vif->ndev, "Failed to send association response\n");
+ return;
+ }
+
+ *rcvd_assoc_resp_info_len = wid.size;
+}
+
+static inline void host_int_free_user_conn_req(struct host_if_drv *hif_drv)
+{
+ hif_drv->usr_conn_req.ssid_len = 0;
+ kfree(hif_drv->usr_conn_req.ssid);
+ hif_drv->usr_conn_req.ssid = NULL;
+ kfree(hif_drv->usr_conn_req.bssid);
+ hif_drv->usr_conn_req.bssid = NULL;
+ hif_drv->usr_conn_req.ies_len = 0;
+ kfree(hif_drv->usr_conn_req.ies);
+ hif_drv->usr_conn_req.ies = NULL;
+}
+
+static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
+ u8 mac_status)
+{
+ struct connect_info conn_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ memset(&conn_info, 0, sizeof(struct connect_info));
+
+ if (mac_status == MAC_STATUS_CONNECTED) {
+ u32 assoc_resp_info_len;
+
+ memset(hif_drv->assoc_resp, 0, MAX_ASSOC_RESP_FRAME_SIZE);
+
+ host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,
+ MAX_ASSOC_RESP_FRAME_SIZE,
+ &assoc_resp_info_len);
+
+ if (assoc_resp_info_len != 0) {
+ s32 err = 0;
+
+ err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp,
+ assoc_resp_info_len,
+ &conn_info);
+ if (err)
+ netdev_err(vif->ndev,
+ "wilc_parse_assoc_resp_info() returned error %d\n",
+ err);
+ }
+ }
+
+ if (hif_drv->usr_conn_req.bssid) {
+ memcpy(conn_info.bssid, hif_drv->usr_conn_req.bssid, 6);
+
+ if (mac_status == MAC_STATUS_CONNECTED &&
+ conn_info.status == WLAN_STATUS_SUCCESS) {
+ memcpy(hif_drv->assoc_bssid,
+ hif_drv->usr_conn_req.bssid, ETH_ALEN);
+ }
+ }
+
+ if (hif_drv->usr_conn_req.ies) {
+ conn_info.req_ies = kmemdup(hif_drv->usr_conn_req.ies,
+ hif_drv->usr_conn_req.ies_len,
+ GFP_KERNEL);
+ if (conn_info.req_ies)
+ conn_info.req_ies_len = hif_drv->usr_conn_req.ies_len;
+ }
+
+ del_timer(&hif_drv->connect_timer);
+ hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
+ &conn_info, mac_status, NULL,
+ hif_drv->usr_conn_req.arg);
+
+ if (mac_status == MAC_STATUS_CONNECTED &&
+ conn_info.status == WLAN_STATUS_SUCCESS) {
+ wilc_set_power_mgmt(vif, 0, 0);
+
+ hif_drv->hif_state = HOST_IF_CONNECTED;
+
+ vif->obtaining_ip = true;
+ mod_timer(&vif->during_ip_timer,
+ jiffies + msecs_to_jiffies(10000));
+ } else {
+ hif_drv->hif_state = HOST_IF_IDLE;
+ }
+
+ kfree(conn_info.resp_ies);
+ conn_info.resp_ies = NULL;
+
+ kfree(conn_info.req_ies);
+ conn_info.req_ies = NULL;
+ host_int_free_user_conn_req(hif_drv);
+}
+
+static inline void host_int_handle_disconnect(struct wilc_vif *vif)
+{
+ struct disconnect_info disconn_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ wilc_connect_result conn_result = hif_drv->usr_conn_req.conn_result;
+
+ memset(&disconn_info, 0, sizeof(struct disconnect_info));
+
+ if (hif_drv->usr_scan_req.scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
+ }
+
+ disconn_info.reason = 0;
+ disconn_info.ie = NULL;
+ disconn_info.ie_len = 0;
+
+ if (conn_result) {
+ vif->obtaining_ip = false;
+ wilc_set_power_mgmt(vif, 0, 0);
+
+ conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL, 0,
+ &disconn_info, hif_drv->usr_conn_req.arg);
+ } else {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ }
+
+ eth_zero_addr(hif_drv->assoc_bssid);
+
+ host_int_free_user_conn_req(hif_drv);
+ hif_drv->hif_state = HOST_IF_IDLE;
+}
+
+static void handle_rcvd_gnrl_async_info(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct rcvd_async_info *rcvd_info = &msg->body.async_info;
+ u8 msg_type;
+ u8 mac_status;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!rcvd_info->buffer) {
+ netdev_err(vif->ndev, "%s: buffer is NULL\n", __func__);
+ goto free_msg;
+ }
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+ goto free_rcvd_info;
+ }
+
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
+ hif_drv->hif_state == HOST_IF_CONNECTED ||
+ hif_drv->usr_scan_req.scan_result) {
+ if (!hif_drv->usr_conn_req.conn_result) {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n",
+ __func__);
+ goto free_rcvd_info;
+ }
+
+ msg_type = rcvd_info->buffer[0];
+
+ if ('I' != msg_type) {
+ netdev_err(vif->ndev, "Received Message incorrect.\n");
+ goto free_rcvd_info;
+ }
+
+ mac_status = rcvd_info->buffer[7];
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
+ host_int_parse_assoc_resp_info(vif, mac_status);
+ } else if ((mac_status == MAC_STATUS_DISCONNECTED) &&
+ (hif_drv->hif_state == HOST_IF_CONNECTED)) {
+ host_int_handle_disconnect(vif);
+ } else if ((mac_status == MAC_STATUS_DISCONNECTED) &&
+ (hif_drv->usr_scan_req.scan_result)) {
+ del_timer(&hif_drv->scan_timer);
+ if (hif_drv->usr_scan_req.scan_result)
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
+ }
+ }
+
+free_rcvd_info:
+ kfree(rcvd_info->buffer);
+ rcvd_info->buffer = NULL;
+
+free_msg:
+ kfree(msg);
+}
+
+static int wilc_pmksa_key_copy(struct wilc_vif *vif, struct key_attr *hif_key)
+{
+ int i;
+ int ret;
+ struct wid wid;
+ u8 *key_buf;
+
+ key_buf = kmalloc((hif_key->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1,
+ GFP_KERNEL);
+ if (!key_buf)
+ return -ENOMEM;
+
+ key_buf[0] = hif_key->attr.pmkid.numpmkid;
+
+ for (i = 0; i < hif_key->attr.pmkid.numpmkid; i++) {
+ memcpy(key_buf + ((PMKSA_KEY_LEN * i) + 1),
+ hif_key->attr.pmkid.pmkidlist[i].bssid, ETH_ALEN);
+ memcpy(key_buf + ((PMKSA_KEY_LEN * i) + ETH_ALEN + 1),
+ hif_key->attr.pmkid.pmkidlist[i].pmkid, PMKID_LEN);
+ }
+
+ wid.id = WID_PMKID_INFO;
+ wid.type = WID_STR;
+ wid.val = (s8 *)key_buf;
+ wid.size = (hif_key->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1;
+
+ ret = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+
+ kfree(key_buf);
+
+ return ret;
+}
+
+static void handle_key(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct key_attr *hif_key = &msg->body.key_info;
+ int result = 0;
+ struct wid wid;
+ struct wid wid_list[5];
+ u8 *key_buf;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ switch (hif_key->type) {
+ case WEP:
+
+ if (hif_key->action & ADDKEY_AP) {
+ wid_list[0].id = WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&hif_key->attr.wep.mode;
+
+ wid_list[1].id = WID_AUTH_TYPE;
+ wid_list[1].type = WID_CHAR;
+ wid_list[1].size = sizeof(char);
+ wid_list[1].val = (s8 *)&hif_key->attr.wep.auth_type;
+
+ key_buf = kmalloc(hif_key->attr.wep.key_len + 2,
+ GFP_KERNEL);
+ if (!key_buf) {
+ result = -ENOMEM;
+ goto out_wep;
+ }
+
+ key_buf[0] = hif_key->attr.wep.index;
+ key_buf[1] = hif_key->attr.wep.key_len;
+
+ memcpy(&key_buf[2], hif_key->attr.wep.key,
+ hif_key->attr.wep.key_len);
+
+ wid_list[2].id = WID_WEP_KEY_VALUE;
+ wid_list[2].type = WID_STR;
+ wid_list[2].size = hif_key->attr.wep.key_len + 2;
+ wid_list[2].val = (s8 *)key_buf;
+
+ result = wilc_send_config_pkt(vif, SET_CFG,
+ wid_list, 3,
+ wilc_get_vif_idx(vif));
+ kfree(key_buf);
+ } else if (hif_key->action & ADDKEY) {
+ key_buf = kmalloc(hif_key->attr.wep.key_len + 2,
+ GFP_KERNEL);
+ if (!key_buf) {
+ result = -ENOMEM;
+ goto out_wep;
+ }
+ key_buf[0] = hif_key->attr.wep.index;
+ memcpy(key_buf + 1, &hif_key->attr.wep.key_len, 1);
+ memcpy(key_buf + 2, hif_key->attr.wep.key,
+ hif_key->attr.wep.key_len);
+
+ wid.id = WID_ADD_WEP_KEY;
+ wid.type = WID_STR;
+ wid.val = (s8 *)key_buf;
+ wid.size = hif_key->attr.wep.key_len + 2;
+
+ result = wilc_send_config_pkt(vif, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
+ kfree(key_buf);
+ } else if (hif_key->action & REMOVEKEY) {
+ wid.id = WID_REMOVE_WEP_KEY;
+ wid.type = WID_STR;
+
+ wid.val = (s8 *)&hif_key->attr.wep.index;
+ wid.size = 1;
+
+ result = wilc_send_config_pkt(vif, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
+ } else if (hif_key->action & DEFAULTKEY) {
+ wid.id = WID_KEY_ID;
+ wid.type = WID_CHAR;
+ wid.val = (s8 *)&hif_key->attr.wep.index;
+ wid.size = sizeof(char);
+
+ result = wilc_send_config_pkt(vif, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
+ }
+out_wep:
+ complete(&msg->work_comp);
+ break;
+
+ case WPA_RX_GTK:
+ if (hif_key->action & ADDKEY_AP) {
+ key_buf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL);
+ if (!key_buf) {
+ result = -ENOMEM;
+ goto out_wpa_rx_gtk;
+ }
+
+ if (hif_key->attr.wpa.seq)
+ memcpy(key_buf + 6, hif_key->attr.wpa.seq, 8);
+
+ memcpy(key_buf + 14, &hif_key->attr.wpa.index, 1);
+ memcpy(key_buf + 15, &hif_key->attr.wpa.key_len, 1);
+ memcpy(key_buf + 16, hif_key->attr.wpa.key,
+ hif_key->attr.wpa.key_len);
+
+ wid_list[0].id = WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&hif_key->attr.wpa.mode;
+
+ wid_list[1].id = WID_ADD_RX_GTK;
+ wid_list[1].type = WID_STR;
+ wid_list[1].val = (s8 *)key_buf;
+ wid_list[1].size = RX_MIC_KEY_MSG_LEN;
+
+ result = wilc_send_config_pkt(vif, SET_CFG,
+ wid_list, 2,
+ wilc_get_vif_idx(vif));
+
+ kfree(key_buf);
+ } else if (hif_key->action & ADDKEY) {
+ key_buf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL);
+ if (!key_buf) {
+ result = -ENOMEM;
+ goto out_wpa_rx_gtk;
+ }
+
+ if (hif_drv->hif_state == HOST_IF_CONNECTED)
+ memcpy(key_buf, hif_drv->assoc_bssid, ETH_ALEN);
+ else
+ netdev_err(vif->ndev, "Couldn't handle\n");
+
+ memcpy(key_buf + 6, hif_key->attr.wpa.seq, 8);
+ memcpy(key_buf + 14, &hif_key->attr.wpa.index, 1);
+ memcpy(key_buf + 15, &hif_key->attr.wpa.key_len, 1);
+ memcpy(key_buf + 16, hif_key->attr.wpa.key,
+ hif_key->attr.wpa.key_len);
+
+ wid.id = WID_ADD_RX_GTK;
+ wid.type = WID_STR;
+ wid.val = (s8 *)key_buf;
+ wid.size = RX_MIC_KEY_MSG_LEN;
+
+ result = wilc_send_config_pkt(vif, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
+
+ kfree(key_buf);
+ }
+out_wpa_rx_gtk:
+ complete(&msg->work_comp);
+ break;
+
+ case WPA_PTK:
+ if (hif_key->action & ADDKEY_AP) {
+ key_buf = kmalloc(PTK_KEY_MSG_LEN + 1, GFP_KERNEL);
+ if (!key_buf) {
+ result = -ENOMEM;
+ goto out_wpa_ptk;
+ }
+
+ memcpy(key_buf, hif_key->attr.wpa.mac_addr, 6);
+ memcpy(key_buf + 6, &hif_key->attr.wpa.index, 1);
+ memcpy(key_buf + 7, &hif_key->attr.wpa.key_len, 1);
+ memcpy(key_buf + 8, hif_key->attr.wpa.key,
+ hif_key->attr.wpa.key_len);
+
+ wid_list[0].id = WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&hif_key->attr.wpa.mode;
+
+ wid_list[1].id = WID_ADD_PTK;
+ wid_list[1].type = WID_STR;
+ wid_list[1].val = (s8 *)key_buf;
+ wid_list[1].size = PTK_KEY_MSG_LEN + 1;
+
+ result = wilc_send_config_pkt(vif, SET_CFG,
+ wid_list, 2,
+ wilc_get_vif_idx(vif));
+ kfree(key_buf);
+ } else if (hif_key->action & ADDKEY) {
+ key_buf = kmalloc(PTK_KEY_MSG_LEN, GFP_KERNEL);
+ if (!key_buf) {
+ result = -ENOMEM;
+ goto out_wpa_ptk;
+ }
+
+ memcpy(key_buf, hif_key->attr.wpa.mac_addr, 6);
+ memcpy(key_buf + 6, &hif_key->attr.wpa.key_len, 1);
+ memcpy(key_buf + 7, hif_key->attr.wpa.key,
+ hif_key->attr.wpa.key_len);
+
+ wid.id = WID_ADD_PTK;
+ wid.type = WID_STR;
+ wid.val = (s8 *)key_buf;
+ wid.size = PTK_KEY_MSG_LEN;
+
+ result = wilc_send_config_pkt(vif, SET_CFG,
+ &wid, 1,
+ wilc_get_vif_idx(vif));
+ kfree(key_buf);
+ }
+
+out_wpa_ptk:
+ complete(&msg->work_comp);
+ break;
+
+ case PMKSA:
+ result = wilc_pmksa_key_copy(vif, hif_key);
+ /*free 'msg', this case it not a sync call*/
+ kfree(msg);
+ break;
+ }
+
+ if (result)
+ netdev_err(vif->ndev, "Failed to send key config packet\n");
+
+ /* free 'msg' data in caller sync call */
+}
+
+static void handle_disconnect(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct disconnect_info disconn_info;
+ struct user_scan_req *scan_req;
+ struct user_conn_req *conn_req;
+ int result;
+ u16 dummy_reason_code = 0;
+
+ wid.id = WID_DISCONNECT;
+ wid.type = WID_CHAR;
+ wid.val = (s8 *)&dummy_reason_code;
+ wid.size = sizeof(char);
+
+ vif->obtaining_ip = false;
+ wilc_set_power_mgmt(vif, 0, 0);
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+
+ if (result) {
+ netdev_err(vif->ndev, "Failed to send dissconect\n");
+ goto out;
+ }
+
+ memset(&disconn_info, 0, sizeof(struct disconnect_info));
+
+ disconn_info.reason = 0;
+ disconn_info.ie = NULL;
+ disconn_info.ie_len = 0;
+ scan_req = &hif_drv->usr_scan_req;
+ conn_req = &hif_drv->usr_conn_req;
+
+ if (scan_req->scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg,
+ NULL);
+ scan_req->scan_result = NULL;
+ }
+
+ if (conn_req->conn_result) {
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
+ del_timer(&hif_drv->connect_timer);
+
+ conn_req->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL,
+ 0, &disconn_info, conn_req->arg);
+ } else {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ }
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+
+ eth_zero_addr(hif_drv->assoc_bssid);
+
+ conn_req->ssid_len = 0;
+ kfree(conn_req->ssid);
+ conn_req->ssid = NULL;
+ kfree(conn_req->bssid);
+ conn_req->bssid = NULL;
+ conn_req->ies_len = 0;
+ kfree(conn_req->ies);
+ conn_req->ies = NULL;
+
+out:
+
+ complete(&msg->work_comp);
+ /* free 'msg' in caller after receiving completion */
+}
+
+void wilc_resolve_disconnect_aberration(struct wilc_vif *vif)
+{
+ if (!vif->hif_drv)
+ return;
+ if (vif->hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
+ vif->hif_drv->hif_state == HOST_IF_CONNECTING)
+ wilc_disconnect(vif, 1);
+}
+
+static void handle_get_rssi(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ int result;
+ struct wid wid;
+
+ wid.id = WID_RSSI;
+ wid.type = WID_CHAR;
+ wid.val = msg->body.data;
+ wid.size = sizeof(char);
+
+ result = wilc_send_config_pkt(vif, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result)
+ netdev_err(vif->ndev, "Failed to get RSSI value\n");
+
+ complete(&msg->work_comp);
+ /* free 'msg' data in caller */
+}
+
+static void handle_get_statistics(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct wid wid_list[5];
+ u32 wid_cnt = 0, result;
+ struct rf_info *stats = (struct rf_info *)msg->body.data;
+
+ wid_list[wid_cnt].id = WID_LINKSPEED;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&stats->link_speed;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_RSSI;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&stats->rssi;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_FAILED_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt;
+ wid_cnt++;
+
+ result = wilc_send_config_pkt(vif, GET_CFG, wid_list,
+ wid_cnt,
+ wilc_get_vif_idx(vif));
+
+ if (result)
+ netdev_err(vif->ndev, "Failed to send scan parameters\n");
+
+ 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);
+
+ /* free 'msg' for async command, for sync caller will free it */
+ if (msg->is_sync)
+ complete(&msg->work_comp);
+ else
+ kfree(msg);
+}
+
+static void handle_get_inactive_time(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct sta_inactive_t *hif_sta_inactive = &msg->body.mac_info;
+ int result;
+ struct wid wid;
+
+ wid.id = WID_SET_STA_MAC_INACTIVE_TIME;
+ wid.type = WID_STR;
+ wid.size = ETH_ALEN;
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ goto out;
+
+ ether_addr_copy(wid.val, hif_sta_inactive->mac);
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ kfree(wid.val);
+
+ if (result) {
+ netdev_err(vif->ndev, "Failed to set inactive mac\n");
+ goto out;
+ }
+
+ wid.id = WID_GET_INACTIVE_TIME;
+ wid.type = WID_INT;
+ wid.val = (s8 *)&hif_sta_inactive->inactive_time;
+ wid.size = sizeof(u32);
+
+ result = wilc_send_config_pkt(vif, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+
+ if (result)
+ netdev_err(vif->ndev, "Failed to get inactive time\n");
+
+out:
+ /* free 'msg' data in caller */
+ complete(&msg->work_comp);
+}
+
+static void handle_add_beacon(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct beacon_attr *param = &msg->body.beacon_info;
+ int result;
+ struct wid wid;
+ u8 *cur_byte;
+
+ wid.id = WID_ADD_BEACON;
+ wid.type = WID_BIN;
+ wid.size = param->head_len + param->tail_len + 16;
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ goto error;
+
+ cur_byte = wid.val;
+ *cur_byte++ = (param->interval & 0xFF);
+ *cur_byte++ = ((param->interval >> 8) & 0xFF);
+ *cur_byte++ = ((param->interval >> 16) & 0xFF);
+ *cur_byte++ = ((param->interval >> 24) & 0xFF);
+
+ *cur_byte++ = (param->dtim_period & 0xFF);
+ *cur_byte++ = ((param->dtim_period >> 8) & 0xFF);
+ *cur_byte++ = ((param->dtim_period >> 16) & 0xFF);
+ *cur_byte++ = ((param->dtim_period >> 24) & 0xFF);
+
+ *cur_byte++ = (param->head_len & 0xFF);
+ *cur_byte++ = ((param->head_len >> 8) & 0xFF);
+ *cur_byte++ = ((param->head_len >> 16) & 0xFF);
+ *cur_byte++ = ((param->head_len >> 24) & 0xFF);
+
+ memcpy(cur_byte, param->head, param->head_len);
+ cur_byte += param->head_len;
+
+ *cur_byte++ = (param->tail_len & 0xFF);
+ *cur_byte++ = ((param->tail_len >> 8) & 0xFF);
+ *cur_byte++ = ((param->tail_len >> 16) & 0xFF);
+ *cur_byte++ = ((param->tail_len >> 24) & 0xFF);
+
+ if (param->tail)
+ memcpy(cur_byte, param->tail, param->tail_len);
+ cur_byte += param->tail_len;
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result)
+ netdev_err(vif->ndev, "Failed to send add beacon\n");
+
+error:
+ kfree(wid.val);
+ kfree(param->head);
+ kfree(param->tail);
+ kfree(msg);
+}
+
+static void handle_del_beacon(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ int result;
+ struct wid wid;
+ u8 del_beacon = 0;
+
+ wid.id = WID_DEL_BEACON;
+ wid.type = WID_CHAR;
+ wid.size = sizeof(char);
+ wid.val = &del_beacon;
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result)
+ netdev_err(vif->ndev, "Failed to send delete beacon\n");
+ kfree(msg);
+}
+
+static u32 wilc_hif_pack_sta_param(u8 *buff, struct add_sta_param *param)
+{
+ u8 *cur_byte;
+
+ cur_byte = buff;
+
+ memcpy(cur_byte, param->bssid, ETH_ALEN);
+ cur_byte += ETH_ALEN;
+
+ *cur_byte++ = param->aid & 0xFF;
+ *cur_byte++ = (param->aid >> 8) & 0xFF;
+
+ *cur_byte++ = param->rates_len;
+ if (param->rates_len > 0)
+ memcpy(cur_byte, param->rates, param->rates_len);
+ cur_byte += param->rates_len;
+
+ *cur_byte++ = param->ht_supported;
+ memcpy(cur_byte, &param->ht_capa, sizeof(struct ieee80211_ht_cap));
+ cur_byte += sizeof(struct ieee80211_ht_cap);
+
+ *cur_byte++ = param->flags_mask & 0xFF;
+ *cur_byte++ = (param->flags_mask >> 8) & 0xFF;
+
+ *cur_byte++ = param->flags_set & 0xFF;
+ *cur_byte++ = (param->flags_set >> 8) & 0xFF;
+
+ return cur_byte - buff;
+}
+
+static void handle_add_station(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct add_sta_param *param = &msg->body.add_sta_info;
+ int result;
+ struct wid wid;
+ u8 *cur_byte;
+
+ wid.id = WID_ADD_STA;
+ wid.type = WID_BIN;
+ wid.size = WILC_ADD_STA_LENGTH + param->rates_len;
+
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ goto error;
+
+ cur_byte = wid.val;
+ cur_byte += wilc_hif_pack_sta_param(cur_byte, param);
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result != 0)
+ netdev_err(vif->ndev, "Failed to send add station\n");
+
+error:
+ kfree(param->rates);
+ kfree(wid.val);
+ kfree(msg);
+}
+
+static void handle_del_all_sta(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct del_all_sta *param = &msg->body.del_all_sta_info;
+ int result;
+ struct wid wid;
+ u8 *curr_byte;
+ u8 i;
+ u8 zero_buff[6] = {0};
+
+ wid.id = WID_DEL_ALL_STA;
+ wid.type = WID_STR;
+ wid.size = (param->assoc_sta * ETH_ALEN) + 1;
+
+ wid.val = kmalloc((param->assoc_sta * ETH_ALEN) + 1, GFP_KERNEL);
+ if (!wid.val)
+ goto error;
+
+ curr_byte = wid.val;
+
+ *(curr_byte++) = param->assoc_sta;
+
+ for (i = 0; i < MAX_NUM_STA; i++) {
+ if (memcmp(param->del_all_sta[i], zero_buff, ETH_ALEN))
+ memcpy(curr_byte, param->del_all_sta[i], ETH_ALEN);
+ else
+ continue;
+
+ curr_byte += ETH_ALEN;
+ }
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result)
+ netdev_err(vif->ndev, "Failed to send delete all station\n");
+
+error:
+ kfree(wid.val);
+
+ /* free 'msg' data in caller */
+ complete(&msg->work_comp);
+}
+
+static void handle_del_station(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct del_sta *param = &msg->body.del_sta_info;
+ int result;
+ struct wid wid;
+
+ wid.id = WID_REMOVE_STA;
+ wid.type = WID_BIN;
+ wid.size = ETH_ALEN;
+
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ goto error;
+
+ ether_addr_copy(wid.val, param->mac_addr);
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result)
+ netdev_err(vif->ndev, "Failed to del station\n");
+
+error:
+ kfree(wid.val);
+ kfree(msg);
+}
+
+static void handle_edit_station(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct add_sta_param *param = &msg->body.edit_sta_info;
+ int result;
+ struct wid wid;
+ u8 *cur_byte;
+
+ wid.id = WID_EDIT_STA;
+ wid.type = WID_BIN;
+ wid.size = WILC_ADD_STA_LENGTH + param->rates_len;
+
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ goto error;
+
+ cur_byte = wid.val;
+ cur_byte += wilc_hif_pack_sta_param(cur_byte, param);
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result)
+ netdev_err(vif->ndev, "Failed to send edit station\n");
+
+error:
+ kfree(param->rates);
+ kfree(wid.val);
+ kfree(msg);
+}
+
+static int handle_remain_on_chan(struct wilc_vif *vif,
+ struct remain_ch *hif_remain_ch)
+{
+ int result;
+ u8 remain_on_chan_flag;
+ struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv->remain_on_ch_pending) {
+ hif_drv->remain_on_ch.arg = hif_remain_ch->arg;
+ hif_drv->remain_on_ch.expired = hif_remain_ch->expired;
+ hif_drv->remain_on_ch.ready = hif_remain_ch->ready;
+ hif_drv->remain_on_ch.ch = hif_remain_ch->ch;
+ hif_drv->remain_on_ch.id = hif_remain_ch->id;
+ } else {
+ hif_remain_ch->ch = hif_drv->remain_on_ch.ch;
+ }
+
+ if (hif_drv->usr_scan_req.scan_result) {
+ hif_drv->remain_on_ch_pending = 1;
+ result = -EBUSY;
+ goto error;
+ }
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
+ result = -EBUSY;
+ goto error;
+ }
+
+ if (vif->obtaining_ip || vif->connecting) {
+ result = -EBUSY;
+ goto error;
+ }
+
+ remain_on_chan_flag = true;
+ wid.id = WID_REMAIN_ON_CHAN;
+ wid.type = WID_STR;
+ wid.size = 2;
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val) {
+ result = -ENOMEM;
+ goto error;
+ }
+
+ wid.val[0] = remain_on_chan_flag;
+ wid.val[1] = (s8)hif_remain_ch->ch;
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ kfree(wid.val);
+ if (result != 0)
+ netdev_err(vif->ndev, "Failed to set remain on channel\n");
+
+error:
+ hif_drv->remain_on_ch_timer_vif = vif;
+ mod_timer(&hif_drv->remain_on_ch_timer,
+ jiffies + msecs_to_jiffies(hif_remain_ch->duration));
+
+ if (hif_drv->remain_on_ch.ready)
+ hif_drv->remain_on_ch.ready(hif_drv->remain_on_ch.arg);
+
+ if (hif_drv->remain_on_ch_pending)
+ hif_drv->remain_on_ch_pending = 0;
+
+ return result;
+}
+
+static void handle_register_frame(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct reg_frame *hif_reg_frame = &msg->body.reg_frame;
+ int result;
+ struct wid wid;
+ u8 *cur_byte;
+
+ wid.id = WID_REGISTER_FRAME;
+ wid.type = WID_STR;
+ wid.val = kmalloc(sizeof(u16) + 2, GFP_KERNEL);
+ if (!wid.val)
+ goto out;
+
+ cur_byte = wid.val;
+
+ *cur_byte++ = hif_reg_frame->reg;
+ *cur_byte++ = hif_reg_frame->reg_id;
+ memcpy(cur_byte, &hif_reg_frame->frame_type, sizeof(u16));
+
+ wid.size = sizeof(u16) + 2;
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ kfree(wid.val);
+ if (result)
+ netdev_err(vif->ndev, "Failed to frame register\n");
+
+out:
+ kfree(msg);
+}
+
+static void handle_listen_state_expired(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct remain_ch *hif_remain_ch = &msg->body.remain_on_ch;
+ u8 remain_on_chan_flag;
+ struct wid wid;
+ int result;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
+
+ if (priv->p2p_listen_state) {
+ remain_on_chan_flag = false;
+ wid.id = WID_REMAIN_ON_CHAN;
+ wid.type = WID_STR;
+ wid.size = 2;
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+
+ if (!wid.val)
+ goto free_msg;
+
+ wid.val[0] = remain_on_chan_flag;
+ wid.val[1] = FALSE_FRMWR_CHANNEL;
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ kfree(wid.val);
+ if (result != 0) {
+ netdev_err(vif->ndev, "Failed to set remain channel\n");
+ goto free_msg;
+ }
+
+ if (hif_drv->remain_on_ch.expired) {
+ hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
+ hif_remain_ch->id);
+ }
+ } else {
+ netdev_dbg(vif->ndev, "Not in listen state\n");
+ }
+
+free_msg:
+ kfree(msg);
+}
+
+static void listen_timer_cb(struct timer_list *t)
+{
+ struct host_if_drv *hif_drv = from_timer(hif_drv, t,
+ remain_on_ch_timer);
+ struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif;
+ int result;
+ struct host_if_msg *msg;
+
+ del_timer(&vif->hif_drv->remain_on_ch_timer);
+
+ msg = wilc_alloc_work(vif, handle_listen_state_expired, false);
+ if (IS_ERR(msg))
+ return;
+
+ msg->body.remain_on_ch.id = vif->hif_drv->remain_on_ch.id;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+}
+
+static void handle_power_management(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct power_mgmt_param *pm_param = &msg->body.pwr_mgmt_info;
+ int result;
+ struct wid wid;
+ s8 power_mode;
+
+ wid.id = WID_POWER_MANAGEMENT;
+
+ if (pm_param->enabled)
+ power_mode = MIN_FAST_PS;
+ else
+ power_mode = NO_POWERSAVE;
+
+ wid.val = &power_mode;
+ wid.size = sizeof(char);
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result)
+ netdev_err(vif->ndev, "Failed to send power management\n");
+ kfree(msg);
+}
+
+static void handle_set_mcast_filter(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ struct set_multicast *hif_set_mc = &msg->body.multicast_info;
+ int result;
+ struct wid wid;
+ u8 *cur_byte;
+
+ wid.id = WID_SETUP_MULTICAST_FILTER;
+ wid.type = WID_BIN;
+ wid.size = sizeof(struct set_multicast) + (hif_set_mc->cnt * ETH_ALEN);
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ goto error;
+
+ cur_byte = wid.val;
+ *cur_byte++ = (hif_set_mc->enabled & 0xFF);
+ *cur_byte++ = 0;
+ *cur_byte++ = 0;
+ *cur_byte++ = 0;
+
+ *cur_byte++ = (hif_set_mc->cnt & 0xFF);
+ *cur_byte++ = ((hif_set_mc->cnt >> 8) & 0xFF);
+ *cur_byte++ = ((hif_set_mc->cnt >> 16) & 0xFF);
+ *cur_byte++ = ((hif_set_mc->cnt >> 24) & 0xFF);
+
+ if (hif_set_mc->cnt > 0 && hif_set_mc->mc_list)
+ memcpy(cur_byte, hif_set_mc->mc_list,
+ ((hif_set_mc->cnt) * ETH_ALEN));
+
+ result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (result)
+ netdev_err(vif->ndev, "Failed to send setup multicast\n");
+
+error:
+ kfree(hif_set_mc->mc_list);
+ kfree(wid.val);
+ kfree(msg);
+}
+
+static void handle_set_tx_pwr(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ u8 tx_pwr = msg->body.tx_power.tx_pwr;
+ int ret;
+ struct wid wid;
+
+ wid.id = WID_TX_POWER;
+ wid.type = WID_CHAR;
+ wid.val = &tx_pwr;
+ wid.size = sizeof(char);
+
+ ret = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (ret)
+ netdev_err(vif->ndev, "Failed to set TX PWR\n");
+ kfree(msg);
+}
+
+/* Note: 'msg' will be free after using data */
+static void handle_get_tx_pwr(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc_vif *vif = msg->vif;
+ u8 *tx_pwr = &msg->body.tx_power.tx_pwr;
+ int ret;
+ struct wid wid;
+
+ wid.id = WID_TX_POWER;
+ wid.type = WID_CHAR;
+ wid.val = (s8 *)tx_pwr;
+ wid.size = sizeof(char);
+
+ ret = wilc_send_config_pkt(vif, GET_CFG, &wid, 1,
+ wilc_get_vif_idx(vif));
+ if (ret)
+ netdev_err(vif->ndev, "Failed to get TX PWR\n");
+
+ complete(&msg->work_comp);
+}
+
+static void handle_scan_timer(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+
+ handle_scan_done(msg->vif, SCAN_EVENT_ABORTED);
+ kfree(msg);
+}
+
+static void handle_remain_on_chan_work(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+
+ handle_remain_on_chan(msg->vif, &msg->body.remain_on_ch);
+ kfree(msg);
+}
+
+static void handle_scan_complete(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+ struct wilc *wilc = msg->vif->wilc;
+
+ del_timer(&msg->vif->hif_drv->scan_timer);
+
+ if (!wilc_wlan_get_num_conn_ifcs(wilc))
+ wilc_chip_sleep_manually(wilc);
+
+ handle_scan_done(msg->vif, SCAN_EVENT_DONE);
+
+ if (msg->vif->hif_drv->remain_on_ch_pending)
+ handle_remain_on_chan(msg->vif, &msg->body.remain_on_ch);
+ kfree(msg);
+}
+
+static void timer_scan_cb(struct timer_list *t)
+{
+ struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer);
+ struct wilc_vif *vif = hif_drv->scan_timer_vif;
+ struct host_if_msg *msg;
+ int result;
+
+ msg = wilc_alloc_work(vif, handle_scan_timer, false);
+ if (IS_ERR(msg))
+ return;
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ kfree(msg);
+}
+
+static void timer_connect_cb(struct timer_list *t)
+{
+ struct host_if_drv *hif_drv = from_timer(hif_drv, t,
+ connect_timer);
+ struct wilc_vif *vif = hif_drv->connect_timer_vif;
+ struct host_if_msg *msg;
+ int result;
+
+ msg = wilc_alloc_work(vif, handle_connect_timeout, false);
+ if (IS_ERR(msg))
+ return;
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ kfree(msg);
+}
+
+int wilc_remove_wep_key(struct wilc_vif *vif, u8 index)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ result = -EFAULT;
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return result;
+ }
+
+ msg = wilc_alloc_work(vif, handle_key, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.key_info.type = WEP;
+ msg->body.key_info.action = REMOVEKEY;
+ msg->body.key_info.attr.wep.index = index;
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ else
+ wait_for_completion(&msg->work_comp);
+
+ kfree(msg);
+ return result;
+}
+
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ result = -EFAULT;
+ netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+ return result;
+ }
+
+ msg = wilc_alloc_work(vif, handle_key, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.key_info.type = WEP;
+ msg->body.key_info.action = DEFAULTKEY;
+ msg->body.key_info.attr.wep.index = index;
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ else
+ wait_for_completion(&msg->work_comp);
+
+ kfree(msg);
+ return result;
+}
+
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ msg = wilc_alloc_work(vif, handle_key, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.key_info.type = WEP;
+ msg->body.key_info.action = ADDKEY;
+ msg->body.key_info.attr.wep.key = kmemdup(key, len, GFP_KERNEL);
+ if (!msg->body.key_info.attr.wep.key) {
+ result = -ENOMEM;
+ goto free_msg;
+ }
+
+ msg->body.key_info.attr.wep.key_len = len;
+ msg->body.key_info.attr.wep.index = index;
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ goto free_key;
+
+ wait_for_completion(&msg->work_comp);
+
+free_key:
+ kfree(msg->body.key_info.attr.wep.key);
+
+free_msg:
+ kfree(msg);
+ return result;
+}
+
+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 result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+ return -EFAULT;
+ }
+
+ msg = wilc_alloc_work(vif, handle_key, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.key_info.type = WEP;
+ msg->body.key_info.action = ADDKEY_AP;
+ msg->body.key_info.attr.wep.key = kmemdup(key, len, GFP_KERNEL);
+ if (!msg->body.key_info.attr.wep.key) {
+ result = -ENOMEM;
+ goto free_msg;
+ }
+
+ msg->body.key_info.attr.wep.key_len = len;
+ msg->body.key_info.attr.wep.index = index;
+ msg->body.key_info.attr.wep.mode = mode;
+ msg->body.key_info.attr.wep.auth_type = auth_type;
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ goto free_key;
+
+ wait_for_completion(&msg->work_comp);
+
+free_key:
+ kfree(msg->body.key_info.attr.wep.key);
+
+free_msg:
+ kfree(msg);
+ return result;
+}
+
+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)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ u8 key_len = ptk_key_len;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ if (rx_mic)
+ key_len += RX_MIC_KEY_LEN;
+
+ if (tx_mic)
+ key_len += TX_MIC_KEY_LEN;
+
+ msg = wilc_alloc_work(vif, handle_key, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.key_info.type = WPA_PTK;
+ if (mode == AP_MODE) {
+ msg->body.key_info.action = ADDKEY_AP;
+ msg->body.key_info.attr.wpa.index = index;
+ }
+ if (mode == STATION_MODE)
+ msg->body.key_info.action = ADDKEY;
+
+ msg->body.key_info.attr.wpa.key = kmemdup(ptk, ptk_key_len, GFP_KERNEL);
+ if (!msg->body.key_info.attr.wpa.key) {
+ result = -ENOMEM;
+ goto free_msg;
+ }
+
+ if (rx_mic)
+ memcpy(msg->body.key_info.attr.wpa.key + 16, rx_mic,
+ RX_MIC_KEY_LEN);
+
+ if (tx_mic)
+ memcpy(msg->body.key_info.attr.wpa.key + 24, tx_mic,
+ TX_MIC_KEY_LEN);
+
+ msg->body.key_info.attr.wpa.key_len = key_len;
+ msg->body.key_info.attr.wpa.mac_addr = mac_addr;
+ msg->body.key_info.attr.wpa.mode = cipher_mode;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ goto free_key;
+ }
+
+ wait_for_completion(&msg->work_comp);
+
+free_key:
+ kfree(msg->body.key_info.attr.wpa.key);
+
+free_msg:
+ kfree(msg);
+ return result;
+}
+
+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 result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ u8 key_len = gtk_key_len;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ msg = wilc_alloc_work(vif, handle_key, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ if (rx_mic)
+ key_len += RX_MIC_KEY_LEN;
+
+ if (tx_mic)
+ key_len += TX_MIC_KEY_LEN;
+
+ if (key_rsc) {
+ msg->body.key_info.attr.wpa.seq = kmemdup(key_rsc,
+ key_rsc_len,
+ GFP_KERNEL);
+ if (!msg->body.key_info.attr.wpa.seq) {
+ result = -ENOMEM;
+ goto free_msg;
+ }
+ }
+
+ msg->body.key_info.type = WPA_RX_GTK;
+
+ if (mode == AP_MODE) {
+ msg->body.key_info.action = ADDKEY_AP;
+ msg->body.key_info.attr.wpa.mode = cipher_mode;
+ }
+ if (mode == STATION_MODE)
+ msg->body.key_info.action = ADDKEY;
+
+ msg->body.key_info.attr.wpa.key = kmemdup(rx_gtk, key_len, GFP_KERNEL);
+ if (!msg->body.key_info.attr.wpa.key) {
+ result = -ENOMEM;
+ goto free_seq;
+ }
+
+ if (rx_mic)
+ memcpy(msg->body.key_info.attr.wpa.key + 16, rx_mic,
+ RX_MIC_KEY_LEN);
+
+ if (tx_mic)
+ memcpy(msg->body.key_info.attr.wpa.key + 24, tx_mic,
+ TX_MIC_KEY_LEN);
+
+ msg->body.key_info.attr.wpa.index = index;
+ msg->body.key_info.attr.wpa.key_len = key_len;
+ msg->body.key_info.attr.wpa.seq_len = key_rsc_len;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ goto free_key;
+ }
+
+ wait_for_completion(&msg->work_comp);
+
+free_key:
+ kfree(msg->body.key_info.attr.wpa.key);
+
+free_seq:
+ kfree(msg->body.key_info.attr.wpa.seq);
+
+free_msg:
+ kfree(msg);
+ return result;
+}
+
+int wilc_set_pmkid_info(struct wilc_vif *vif,
+ struct host_if_pmkid_attr *pmkid)
+{
+ int result;
+ struct host_if_msg *msg;
+ int i;
+
+ msg = wilc_alloc_work(vif, handle_key, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.key_info.type = PMKSA;
+ msg->body.key_info.action = ADDKEY;
+
+ for (i = 0; i < pmkid->numpmkid; i++) {
+ memcpy(msg->body.key_info.attr.pmkid.pmkidlist[i].bssid,
+ &pmkid->pmkidlist[i].bssid, ETH_ALEN);
+ memcpy(msg->body.key_info.attr.pmkid.pmkidlist[i].pmkid,
+ &pmkid->pmkidlist[i].pmkid, PMKID_LEN);
+ }
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+
+ return result;
+}
+
+int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_get_mac_address, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.get_mac_info.mac_addr = mac_addr;
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ else
+ wait_for_completion(&msg->work_comp);
+
+ kfree(msg);
+
+ return result;
+}
+
+int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ssid,
+ size_t ssid_len, const u8 *ies, size_t ies_len,
+ wilc_connect_result connect_result, void *user_arg,
+ u8 security, enum authtype auth_type,
+ u8 channel, void *join_params)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv || !connect_result) {
+ netdev_err(vif->ndev,
+ "%s: hif driver or connect result is NULL",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (!join_params) {
+ netdev_err(vif->ndev, "%s: joinparams is NULL\n", __func__);
+ return -EFAULT;
+ }
+
+ msg = wilc_alloc_work(vif, handle_connect, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.con_info.security = security;
+ msg->body.con_info.auth_type = auth_type;
+ msg->body.con_info.ch = channel;
+ msg->body.con_info.result = connect_result;
+ msg->body.con_info.arg = user_arg;
+ msg->body.con_info.params = join_params;
+
+ if (bssid) {
+ msg->body.con_info.bssid = kmemdup(bssid, 6, GFP_KERNEL);
+ if (!msg->body.con_info.bssid) {
+ result = -ENOMEM;
+ goto free_msg;
+ }
+ }
+
+ if (ssid) {
+ msg->body.con_info.ssid_len = ssid_len;
+ msg->body.con_info.ssid = kmemdup(ssid, ssid_len, GFP_KERNEL);
+ if (!msg->body.con_info.ssid) {
+ result = -ENOMEM;
+ goto free_bssid;
+ }
+ }
+
+ if (ies) {
+ msg->body.con_info.ies_len = ies_len;
+ msg->body.con_info.ies = kmemdup(ies, ies_len, GFP_KERNEL);
+ if (!msg->body.con_info.ies) {
+ result = -ENOMEM;
+ goto free_ssid;
+ }
+ }
+ if (hif_drv->hif_state < HOST_IF_CONNECTING)
+ hif_drv->hif_state = HOST_IF_CONNECTING;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ goto free_ies;
+ }
+
+ hif_drv->connect_timer_vif = vif;
+ mod_timer(&hif_drv->connect_timer,
+ jiffies + msecs_to_jiffies(HOST_IF_CONNECT_TIMEOUT));
+
+ return 0;
+
+free_ies:
+ kfree(msg->body.con_info.ies);
+
+free_ssid:
+ kfree(msg->body.con_info.ssid);
+
+free_bssid:
+ kfree(msg->body.con_info.bssid);
+
+free_msg:
+ kfree(msg);
+ return result;
+}
+
+int wilc_disconnect(struct wilc_vif *vif, u16 reason_code)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ msg = wilc_alloc_work(vif, handle_disconnect, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ else
+ wait_for_completion(&msg->work_comp);
+
+ kfree(msg);
+ return result;
+}
+
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_set_channel, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.channel_info.set_ch = channel;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+
+ return result;
+}
+
+int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id, bool is_sync)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_set_wfi_drv_handler, is_sync);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.drv.handler = index;
+ msg->body.drv.mode = mode;
+ msg->body.drv.name = ifc_id;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ return result;
+ }
+
+ if (is_sync)
+ wait_for_completion(&msg->work_comp);
+
+ return result;
+}
+
+int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_set_operation_mode, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.mode.mode = mode;
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+
+ return result;
+}
+
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
+ u32 *out_val)
+{
+ s32 result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ msg = wilc_alloc_work(vif, handle_get_inactive_time, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ memcpy(msg->body.mac_info.mac, mac, ETH_ALEN);
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ else
+ wait_for_completion(&msg->work_comp);
+
+ *out_val = msg->body.mac_info.inactive_time;
+ kfree(msg);
+
+ return result;
+}
+
+int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ if (!rssi_level) {
+ netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__);
+ return -EFAULT;
+ }
+
+ msg = wilc_alloc_work(vif, handle_get_rssi, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.data = kzalloc(sizeof(s8), GFP_KERNEL);
+ if (!msg->body.data) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ } else {
+ wait_for_completion(&msg->work_comp);
+ *rssi_level = *msg->body.data;
+ }
+
+ kfree(msg->body.data);
+ kfree(msg);
+
+ return result;
+}
+
+int
+wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats, bool is_sync)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_get_statistics, is_sync);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.data = (char *)stats;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ return result;
+ }
+
+ if (is_sync) {
+ wait_for_completion(&msg->work_comp);
+ kfree(msg);
+ }
+
+ return result;
+}
+
+int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
+ u8 *ch_freq_list, u8 ch_list_len, const u8 *ies,
+ size_t ies_len, wilc_scan_result scan_result, void *user_arg,
+ struct hidden_network *hidden_network)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct scan_attr *scan_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv || !scan_result) {
+ netdev_err(vif->ndev, "hif_drv or scan_result = NULL\n");
+ return -EFAULT;
+ }
+
+ msg = wilc_alloc_work(vif, handle_scan, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ scan_info = &msg->body.scan_info;
+
+ if (hidden_network) {
+ scan_info->hidden_network.net_info = hidden_network->net_info;
+ scan_info->hidden_network.n_ssids = hidden_network->n_ssids;
+ }
+
+ scan_info->src = scan_source;
+ scan_info->type = scan_type;
+ scan_info->result = scan_result;
+ scan_info->arg = user_arg;
+
+ scan_info->ch_list_len = ch_list_len;
+ scan_info->ch_freq_list = kmemdup(ch_freq_list,
+ ch_list_len,
+ GFP_KERNEL);
+ if (!scan_info->ch_freq_list) {
+ result = -ENOMEM;
+ goto free_msg;
+ }
+
+ scan_info->ies_len = ies_len;
+ scan_info->ies = kmemdup(ies, ies_len, GFP_KERNEL);
+ if (!scan_info->ies) {
+ result = -ENOMEM;
+ goto free_freq_list;
+ }
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ goto free_ies;
+ }
+
+ hif_drv->scan_timer_vif = vif;
+ mod_timer(&hif_drv->scan_timer,
+ jiffies + msecs_to_jiffies(HOST_IF_SCAN_TIMEOUT));
+
+ return 0;
+
+free_ies:
+ kfree(scan_info->ies);
+
+free_freq_list:
+ kfree(scan_info->ch_freq_list);
+
+free_msg:
+ kfree(msg);
+ return result;
+}
+
+int wilc_hif_set_cfg(struct wilc_vif *vif,
+ struct cfg_param_attr *cfg_param)
+{
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ int result;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ msg = wilc_alloc_work(vif, handle_cfg_param, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.cfg_info = *cfg_param;
+ result = wilc_enqueue_work(msg);
+ if (result)
+ kfree(msg);
+
+ return result;
+}
+
+static void get_periodic_rssi(struct timer_list *t)
+{
+ struct wilc_vif *vif = from_timer(vif, t, periodic_rssi);
+
+ if (!vif->hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return;
+ }
+
+ if (vif->hif_drv->hif_state == HOST_IF_CONNECTED)
+ wilc_get_statistics(vif, &vif->periodic_stat, false);
+
+ mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
+}
+
+int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
+{
+ struct host_if_drv *hif_drv;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+ int i;
+
+ hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL);
+ if (!hif_drv)
+ return -ENOMEM;
+
+ *hif_drv_handler = hif_drv;
+ for (i = 0; i < wilc->vif_num; i++)
+ if (dev == wilc->vif[i]->ndev) {
+ wilc->vif[i]->hif_drv = hif_drv;
+ hif_drv->driver_handler_id = i + 1;
+ break;
+ }
+
+ vif->obtaining_ip = false;
+
+ if (wilc->clients_count == 0)
+ mutex_init(&hif_deinit_lock);
+
+ timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0);
+ mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
+
+ timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0);
+ timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0);
+ timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0);
+
+ mutex_init(&hif_drv->cfg_values_lock);
+ mutex_lock(&hif_drv->cfg_values_lock);
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+ hif_drv->cfg_values.site_survey_enabled = SITE_SURVEY_OFF;
+ hif_drv->cfg_values.scan_source = DEFAULT_SCAN;
+ hif_drv->cfg_values.active_scan_time = ACTIVE_SCAN_TIME;
+ hif_drv->cfg_values.passive_scan_time = PASSIVE_SCAN_TIME;
+ hif_drv->cfg_values.curr_tx_rate = AUTORATE;
+
+ hif_drv->p2p_timeout = 0;
+
+ mutex_unlock(&hif_drv->cfg_values_lock);
+
+ wilc->clients_count++;
+
+ return 0;
+}
+
+int wilc_deinit(struct wilc_vif *vif)
+{
+ int result = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ mutex_lock(&hif_deinit_lock);
+
+ terminated_handle = hif_drv;
+
+ del_timer_sync(&hif_drv->scan_timer);
+ del_timer_sync(&hif_drv->connect_timer);
+ del_timer_sync(&vif->periodic_rssi);
+ del_timer_sync(&hif_drv->remain_on_ch_timer);
+
+ wilc_set_wfi_drv_handler(vif, 0, 0, 0, true);
+
+ if (hif_drv->usr_scan_req.scan_result) {
+ hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
+ hif_drv->usr_scan_req.arg,
+ NULL);
+ hif_drv->usr_scan_req.scan_result = NULL;
+ }
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+
+ kfree(hif_drv);
+
+ vif->wilc->clients_count--;
+ terminated_handle = NULL;
+ mutex_unlock(&hif_deinit_lock);
+ return result;
+}
+
+void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length)
+{
+ int result;
+ struct host_if_msg *msg;
+ int id;
+ struct host_if_drv *hif_drv;
+ struct wilc_vif *vif;
+
+ id = buffer[length - 4];
+ id |= (buffer[length - 3] << 8);
+ id |= (buffer[length - 2] << 16);
+ id |= (buffer[length - 1] << 24);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif)
+ return;
+ hif_drv = vif->hif_drv;
+
+ if (!hif_drv || hif_drv == terminated_handle) {
+ netdev_err(vif->ndev, "driver not init[%p]\n", hif_drv);
+ return;
+ }
+
+ msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false);
+ if (IS_ERR(msg))
+ return;
+
+ msg->body.net_info.len = length;
+ msg->body.net_info.buffer = kmemdup(buffer, length, GFP_KERNEL);
+ if (!msg->body.net_info.buffer) {
+ kfree(msg);
+ return;
+ }
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg->body.net_info.buffer);
+ kfree(msg);
+ }
+}
+
+void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length)
+{
+ int result;
+ struct host_if_msg *msg;
+ int id;
+ struct host_if_drv *hif_drv;
+ struct wilc_vif *vif;
+
+ mutex_lock(&hif_deinit_lock);
+
+ id = buffer[length - 4];
+ id |= (buffer[length - 3] << 8);
+ id |= (buffer[length - 2] << 16);
+ id |= (buffer[length - 1] << 24);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif) {
+ mutex_unlock(&hif_deinit_lock);
+ return;
+ }
+
+ hif_drv = vif->hif_drv;
+
+ if (!hif_drv || hif_drv == terminated_handle) {
+ mutex_unlock(&hif_deinit_lock);
+ return;
+ }
+
+ if (!hif_drv->usr_conn_req.conn_result) {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ mutex_unlock(&hif_deinit_lock);
+ return;
+ }
+
+ msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false);
+ if (IS_ERR(msg)) {
+ mutex_unlock(&hif_deinit_lock);
+ return;
+ }
+
+ msg->body.async_info.len = length;
+ msg->body.async_info.buffer = kmemdup(buffer, length, GFP_KERNEL);
+ if (!msg->body.async_info.buffer) {
+ kfree(msg);
+ mutex_unlock(&hif_deinit_lock);
+ return;
+ }
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg->body.async_info.buffer);
+ kfree(msg);
+ }
+
+ mutex_unlock(&hif_deinit_lock);
+}
+
+void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length)
+{
+ int result;
+ int id;
+ struct host_if_drv *hif_drv;
+ struct wilc_vif *vif;
+
+ id = buffer[length - 4];
+ id |= buffer[length - 3] << 8;
+ id |= buffer[length - 2] << 16;
+ id |= buffer[length - 1] << 24;
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif)
+ return;
+ hif_drv = vif->hif_drv;
+
+ if (!hif_drv || hif_drv == terminated_handle)
+ return;
+
+ if (hif_drv->usr_scan_req.scan_result) {
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_scan_complete, false);
+ if (IS_ERR(msg))
+ return;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n",
+ __func__);
+ kfree(msg);
+ }
+ }
+}
+
+int wilc_remain_on_channel(struct wilc_vif *vif, u32 session_id,
+ u32 duration, u16 chan,
+ wilc_remain_on_chan_expired expired,
+ wilc_remain_on_chan_ready ready,
+ void *user_arg)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_remain_on_chan_work, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.remain_on_ch.ch = chan;
+ msg->body.remain_on_ch.expired = expired;
+ msg->body.remain_on_ch.ready = ready;
+ msg->body.remain_on_ch.arg = user_arg;
+ msg->body.remain_on_ch.duration = duration;
+ msg->body.remain_on_ch.id = session_id;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+
+ return result;
+}
+
+int wilc_listen_state_expired(struct wilc_vif *vif, u32 session_id)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ del_timer(&hif_drv->remain_on_ch_timer);
+
+ msg = wilc_alloc_work(vif, handle_listen_state_expired, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.remain_on_ch.id = session_id;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+
+ return result;
+}
+
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_register_frame, false);
+ if (IS_ERR(msg))
+ return;
+
+ switch (frame_type) {
+ case ACTION:
+ msg->body.reg_frame.reg_id = ACTION_FRM_IDX;
+ break;
+
+ case PROBE_REQ:
+ msg->body.reg_frame.reg_id = PROBE_REQ_IDX;
+ break;
+
+ default:
+ break;
+ }
+ msg->body.reg_frame.frame_type = frame_type;
+ msg->body.reg_frame.reg = reg;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+}
+
+int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
+ u32 head_len, u8 *head, u32 tail_len, u8 *tail)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct beacon_attr *beacon_info;
+
+ msg = wilc_alloc_work(vif, handle_add_beacon, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ beacon_info = &msg->body.beacon_info;
+ beacon_info->interval = interval;
+ beacon_info->dtim_period = dtim_period;
+ beacon_info->head_len = head_len;
+ beacon_info->head = kmemdup(head, head_len, GFP_KERNEL);
+ if (!beacon_info->head) {
+ result = -ENOMEM;
+ goto error;
+ }
+ beacon_info->tail_len = tail_len;
+
+ if (tail_len > 0) {
+ beacon_info->tail = kmemdup(tail, tail_len, GFP_KERNEL);
+ if (!beacon_info->tail) {
+ result = -ENOMEM;
+ goto error;
+ }
+ } else {
+ beacon_info->tail = NULL;
+ }
+
+ result = wilc_enqueue_work(msg);
+ if (result)
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+
+error:
+ if (result) {
+ kfree(beacon_info->head);
+ kfree(beacon_info->tail);
+ kfree(msg);
+ }
+
+ return result;
+}
+
+int wilc_del_beacon(struct wilc_vif *vif)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_del_beacon, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+
+ return result;
+}
+
+int wilc_add_station(struct wilc_vif *vif, struct add_sta_param *sta_param)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct add_sta_param *add_sta_info;
+
+ msg = wilc_alloc_work(vif, handle_add_station, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ add_sta_info = &msg->body.add_sta_info;
+ memcpy(add_sta_info, sta_param, sizeof(struct add_sta_param));
+ if (add_sta_info->rates_len > 0) {
+ add_sta_info->rates = kmemdup(sta_param->rates,
+ add_sta_info->rates_len,
+ GFP_KERNEL);
+ if (!add_sta_info->rates) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+ }
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(add_sta_info->rates);
+ kfree(msg);
+ }
+ return result;
+}
+
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct del_sta *del_sta_info;
+
+ msg = wilc_alloc_work(vif, handle_del_station, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ del_sta_info = &msg->body.del_sta_info;
+
+ if (!mac_addr)
+ eth_broadcast_addr(del_sta_info->mac_addr);
+ else
+ memcpy(del_sta_info->mac_addr, mac_addr, ETH_ALEN);
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+ return result;
+}
+
+int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])
+{
+ int result;
+ struct host_if_msg *msg;
+ struct del_all_sta *del_all_sta_info;
+ u8 zero_addr[ETH_ALEN] = {0};
+ int i;
+ u8 assoc_sta = 0;
+
+ msg = wilc_alloc_work(vif, handle_del_all_sta, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ del_all_sta_info = &msg->body.del_all_sta_info;
+
+ for (i = 0; i < MAX_NUM_STA; i++) {
+ if (memcmp(mac_addr[i], zero_addr, ETH_ALEN)) {
+ memcpy(del_all_sta_info->del_all_sta[i], mac_addr[i],
+ ETH_ALEN);
+ assoc_sta++;
+ }
+ }
+ if (!assoc_sta) {
+ kfree(msg);
+ return 0;
+ }
+
+ del_all_sta_info->assoc_sta = assoc_sta;
+ result = wilc_enqueue_work(msg);
+
+ if (result)
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ else
+ wait_for_completion(&msg->work_comp);
+
+ kfree(msg);
+
+ return result;
+}
+
+int wilc_edit_station(struct wilc_vif *vif,
+ struct add_sta_param *sta_param)
+{
+ int result;
+ struct host_if_msg *msg;
+ struct add_sta_param *add_sta_info;
+
+ msg = wilc_alloc_work(vif, handle_edit_station, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ add_sta_info = &msg->body.add_sta_info;
+ memcpy(add_sta_info, sta_param, sizeof(*add_sta_info));
+ if (add_sta_info->rates_len > 0) {
+ add_sta_info->rates = kmemdup(sta_param->rates,
+ add_sta_info->rates_len,
+ GFP_KERNEL);
+ if (!add_sta_info->rates) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+ }
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(add_sta_info->rates);
+ kfree(msg);
+ }
+
+ return result;
+}
+
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ if (wilc_wlan_get_num_conn_ifcs(vif->wilc) == 2 && enabled)
+ return 0;
+
+ msg = wilc_alloc_work(vif, handle_power_management, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.pwr_mgmt_info.enabled = enabled;
+ msg->body.pwr_mgmt_info.timeout = timeout;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+ return result;
+}
+
+int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled, u32 count,
+ u8 *mc_list)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_set_mcast_filter, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.multicast_info.enabled = enabled;
+ msg->body.multicast_info.cnt = count;
+ msg->body.multicast_info.mc_list = mc_list;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+ return result;
+}
+
+int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power)
+{
+ int ret;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_set_tx_pwr, false);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->body.tx_power.tx_pwr = tx_power;
+
+ ret = wilc_enqueue_work(msg);
+ if (ret) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+
+ return ret;
+}
+
+int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
+{
+ int ret;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_get_tx_pwr, true);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ ret = wilc_enqueue_work(msg);
+ if (ret) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ } else {
+ wait_for_completion(&msg->work_comp);
+ *tx_power = msg->body.tx_power.tx_pwr;
+ }
+
+ /* free 'msg' after copying data */
+ kfree(msg);
+ return ret;
+}
--
2.7.4


2018-09-26 10:25:53

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 06/19] wilc: add wilc_wlan_cfg.h

Moved '/driver/staging/wilc1000/wilc_wlan_cfg.h' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_wlan_cfg.h b/drivers/net/wireless/microchip/wilc/wilc_wlan_cfg.h
new file mode 100644
index 0000000..e5ca6ce
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_wlan_cfg.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#ifndef WILC_WLAN_CFG_H
+#define WILC_WLAN_CFG_H
+
+struct wilc_cfg_byte {
+ u16 id;
+ u8 val;
+};
+
+struct wilc_cfg_hword {
+ u16 id;
+ u16 val;
+};
+
+struct wilc_cfg_word {
+ u16 id;
+ u32 val;
+};
+
+struct wilc_cfg_str {
+ u16 id;
+ u8 *str;
+};
+
+struct wilc_cfg_str_vals {
+ u8 mac_address[7];
+ u8 firmware_version[129];
+ u8 assoc_rsp[256];
+};
+
+struct wilc_cfg {
+ struct wilc_cfg_byte *b;
+ struct wilc_cfg_hword *hw;
+ struct wilc_cfg_word *w;
+ struct wilc_cfg_str *s;
+ struct wilc_cfg_str_vals *str_vals;
+};
+
+struct wilc;
+int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size);
+int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id);
+int wilc_wlan_cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer,
+ u32 buffer_size);
+void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
+ struct wilc_cfg_rsp *rsp);
+int wilc_wlan_cfg_init(struct wilc *wl);
+void wilc_wlan_cfg_deinit(struct wilc *wl);
+
+#endif
--
2.7.4


2018-09-26 10:25:57

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 07/19] wilc: add wilc_wlan_cfg.c

Moved '/driver/staging/wilc1000/wilc_wlan_cfg.c' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_wlan_cfg.c b/drivers/net/wireless/microchip/wilc/wilc_wlan_cfg.c
new file mode 100644
index 0000000..930a389
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_wlan_cfg.c
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "wilc_wlan_if.h"
+#include "wilc_wlan.h"
+#include "wilc_wlan_cfg.h"
+#include "coreconfigurator.h"
+#include "wilc_wfi_netdevice.h"
+
+enum cfg_cmd_type {
+ CFG_BYTE_CMD = 0,
+ CFG_HWORD_CMD = 1,
+ CFG_WORD_CMD = 2,
+ CFG_STR_CMD = 3,
+ CFG_BIN_CMD = 4
+};
+
+static const struct wilc_cfg_byte g_cfg_byte[] = {
+ {WID_STATUS, 0},
+ {WID_RSSI, 0},
+ {WID_LINKSPEED, 0},
+ {WID_NIL, 0}
+};
+
+static const struct wilc_cfg_hword g_cfg_hword[] = {
+ {WID_NIL, 0}
+};
+
+static const struct wilc_cfg_word g_cfg_word[] = {
+ {WID_FAILED_COUNT, 0},
+ {WID_RECEIVED_FRAGMENT_COUNT, 0},
+ {WID_SUCCESS_FRAME_COUNT, 0},
+ {WID_GET_INACTIVE_TIME, 0},
+ {WID_NIL, 0}
+
+};
+
+static const struct wilc_cfg_str g_cfg_str[] = {
+ {WID_FIRMWARE_VERSION, NULL},
+ {WID_MAC_ADDR, NULL},
+ {WID_ASSOC_RES_INFO, NULL},
+ {WID_NIL, NULL}
+};
+
+/********************************************
+ *
+ * Configuration Functions
+ *
+ ********************************************/
+
+static int wilc_wlan_cfg_set_byte(u8 *frame, u32 offset, u16 id, u8 val8)
+{
+ u8 *buf;
+
+ if ((offset + 4) >= MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ buf = &frame[offset];
+
+ buf[0] = (u8)id;
+ buf[1] = (u8)(id >> 8);
+ buf[2] = 1;
+ buf[3] = 0;
+ buf[4] = val8;
+ return 5;
+}
+
+static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16)
+{
+ u8 *buf;
+
+ if ((offset + 5) >= MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ buf = &frame[offset];
+
+ buf[0] = (u8)id;
+ buf[1] = (u8)(id >> 8);
+ buf[2] = 2;
+ buf[3] = 0;
+ buf[4] = (u8)val16;
+ buf[5] = (u8)(val16 >> 8);
+
+ return 6;
+}
+
+static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
+{
+ u8 *buf;
+
+ if ((offset + 7) >= MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ buf = &frame[offset];
+
+ buf[0] = (u8)id;
+ buf[1] = (u8)(id >> 8);
+ buf[2] = 4;
+ buf[3] = 0;
+ buf[4] = (u8)val32;
+ buf[5] = (u8)(val32 >> 8);
+ buf[6] = (u8)(val32 >> 16);
+ buf[7] = (u8)(val32 >> 24);
+
+ return 8;
+}
+
+static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str,
+ u32 size)
+{
+ u8 *buf;
+
+ if ((offset + size + 4) >= MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ buf = &frame[offset];
+
+ buf[0] = (u8)id;
+ buf[1] = (u8)(id >> 8);
+ buf[2] = (u8)size;
+ buf[3] = (u8)(size >> 8);
+
+ if (str && size != 0)
+ memcpy(&buf[4], str, size);
+
+ return (size + 4);
+}
+
+static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size)
+{
+ u8 *buf;
+ u32 i;
+ u8 checksum = 0;
+
+ if ((offset + size + 5) >= MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ buf = &frame[offset];
+ buf[0] = (u8)id;
+ buf[1] = (u8)(id >> 8);
+ buf[2] = (u8)size;
+ buf[3] = (u8)(size >> 8);
+
+ if ((b) && size != 0) {
+ memcpy(&buf[4], b, size);
+ for (i = 0; i < size; i++)
+ checksum += buf[i + 4];
+ }
+
+ buf[size + 4] = checksum;
+
+ return (size + 5);
+}
+
+/********************************************
+ *
+ * Configuration Response Functions
+ *
+ ********************************************/
+
+#define GET_WID_TYPE(wid) (((wid) >> 12) & 0x7)
+static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size)
+{
+ u16 wid;
+ u32 len = 0, i = 0;
+
+ while (size > 0) {
+ i = 0;
+ wid = info[0] | (info[1] << 8);
+
+ switch (GET_WID_TYPE(wid)) {
+ case WID_CHAR:
+ do {
+ if (wl->cfg.b[i].id == WID_NIL)
+ break;
+
+ if (wl->cfg.b[i].id == wid) {
+ wl->cfg.b[i].val = info[4];
+ break;
+ }
+ i++;
+ } while (1);
+ len = 3;
+ break;
+
+ case WID_SHORT:
+ do {
+ if (wl->cfg.hw[i].id == WID_NIL)
+ break;
+
+ if (wl->cfg.hw[i].id == wid) {
+ wl->cfg.hw[i].val = (info[4] |
+ (info[5] << 8));
+ break;
+ }
+ i++;
+ } while (1);
+ len = 4;
+ break;
+
+ case WID_INT:
+ do {
+ if (wl->cfg.w[i].id == WID_NIL)
+ break;
+
+ if (wl->cfg.w[i].id == wid) {
+ wl->cfg.w[i].val = (info[4] |
+ (info[5] << 8) |
+ (info[6] << 16) |
+ (info[7] << 24));
+ break;
+ }
+ i++;
+ } while (1);
+ len = 6;
+ break;
+
+ case WID_STR:
+ do {
+ if (wl->cfg.s[i].id == WID_NIL)
+ break;
+
+ if (wl->cfg.s[i].id == wid) {
+ memcpy(wl->cfg.s[i].str, &info[2],
+ (info[2] + 2));
+ break;
+ }
+ i++;
+ } while (1);
+ len = 2 + info[2];
+ break;
+
+ default:
+ break;
+ }
+ size -= (2 + len);
+ info += (2 + len);
+ }
+}
+
+static void wilc_wlan_parse_info_frame(struct wilc *wl, u8 *info)
+{
+ u32 wid, len;
+
+ wid = info[0] | (info[1] << 8);
+
+ len = info[2];
+
+ if (len == 1 && wid == WID_STATUS) {
+ int i = 0;
+
+ do {
+ if (wl->cfg.b[i].id == WID_NIL)
+ break;
+
+ if (wl->cfg.b[i].id == wid) {
+ wl->cfg.b[i].val = info[3];
+ break;
+ }
+ i++;
+ } while (1);
+ }
+}
+
+/********************************************
+ *
+ * Configuration Exported Functions
+ *
+ ********************************************/
+
+int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size)
+{
+ u8 type = (id >> 12) & 0xf;
+ int ret = 0;
+
+ switch (type) {
+ case CFG_BYTE_CMD:
+ if (size >= 1)
+ ret = wilc_wlan_cfg_set_byte(frame, offset, id, *buf);
+ break;
+
+ case CFG_HWORD_CMD:
+ if (size >= 2)
+ ret = wilc_wlan_cfg_set_hword(frame, offset, id,
+ *((u16 *)buf));
+ break;
+
+ case CFG_WORD_CMD:
+ if (size >= 4)
+ ret = wilc_wlan_cfg_set_word(frame, offset, id,
+ *((u32 *)buf));
+ break;
+
+ case CFG_STR_CMD:
+ ret = wilc_wlan_cfg_set_str(frame, offset, id, buf, size);
+ break;
+
+ case CFG_BIN_CMD:
+ ret = wilc_wlan_cfg_set_bin(frame, offset, id, buf, size);
+ break;
+ }
+
+ return ret;
+}
+
+int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id)
+{
+ u8 *buf;
+
+ if ((offset + 2) >= MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ buf = &frame[offset];
+
+ buf[0] = (u8)id;
+ buf[1] = (u8)(id >> 8);
+
+ return 2;
+}
+
+int wilc_wlan_cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer,
+ u32 buffer_size)
+{
+ u32 type = (wid >> 12) & 0xf;
+ int i, ret = 0;
+
+ i = 0;
+ if (type == CFG_BYTE_CMD) {
+ do {
+ if (wl->cfg.b[i].id == WID_NIL)
+ break;
+
+ if (wl->cfg.b[i].id == wid) {
+ memcpy(buffer, &wl->cfg.b[i].val, 1);
+ ret = 1;
+ break;
+ }
+ i++;
+ } while (1);
+ } else if (type == CFG_HWORD_CMD) {
+ do {
+ if (wl->cfg.hw[i].id == WID_NIL)
+ break;
+
+ if (wl->cfg.hw[i].id == wid) {
+ memcpy(buffer, &wl->cfg.hw[i].val, 2);
+ ret = 2;
+ break;
+ }
+ i++;
+ } while (1);
+ } else if (type == CFG_WORD_CMD) {
+ do {
+ if (wl->cfg.w[i].id == WID_NIL)
+ break;
+
+ if (wl->cfg.w[i].id == wid) {
+ memcpy(buffer, &wl->cfg.w[i].val, 4);
+ ret = 4;
+ break;
+ }
+ i++;
+ } while (1);
+ } else if (type == CFG_STR_CMD) {
+ do {
+ u32 id = wl->cfg.s[i].id;
+
+ if (id == WID_NIL)
+ break;
+
+ if (id == wid) {
+ u32 size = (wl->cfg.s[i].str[0] |
+ (wl->cfg.s[i].str[1] << 8));
+
+ if (buffer_size >= size) {
+ memcpy(buffer, &wl->cfg.s[i].str[2],
+ size);
+ ret = size;
+ }
+ break;
+ }
+ i++;
+ } while (1);
+ }
+ return ret;
+}
+
+void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
+ struct wilc_cfg_rsp *rsp)
+{
+ u8 msg_type;
+ u8 msg_id;
+
+ msg_type = frame[0];
+ msg_id = frame[1]; /* seq no */
+ frame += 4;
+ size -= 4;
+ rsp->type = 0;
+
+ /*
+ * The valid types of response messages are
+ * 'R' (Response),
+ * 'I' (Information), and
+ * 'N' (Network Information)
+ */
+
+ switch (msg_type) {
+ case 'R':
+ wilc_wlan_parse_response_frame(wilc, frame, size);
+ rsp->type = WILC_CFG_RSP;
+ rsp->seq_no = msg_id;
+ break;
+
+ case 'I':
+ wilc_wlan_parse_info_frame(wilc, frame);
+ rsp->type = WILC_CFG_RSP_STATUS;
+ rsp->seq_no = msg_id;
+ /*call host interface info parse as well*/
+ wilc_gnrl_async_info_received(wilc, frame - 4, size + 4);
+ break;
+
+ case 'N':
+ wilc_network_info_received(wilc, frame - 4, size + 4);
+ break;
+
+ case 'S':
+ wilc_scan_complete_received(wilc, frame - 4, size + 4);
+ break;
+
+ default:
+ rsp->seq_no = msg_id;
+ break;
+ }
+}
+
+int wilc_wlan_cfg_init(struct wilc *wl)
+{
+ struct wilc_cfg_str_vals *str_vals;
+ int i = 0;
+
+ wl->cfg.b = kmemdup(g_cfg_byte, sizeof(g_cfg_byte), GFP_KERNEL);
+ if (!wl->cfg.b)
+ return -ENOMEM;
+
+ wl->cfg.hw = kmemdup(g_cfg_hword, sizeof(g_cfg_hword), GFP_KERNEL);
+ if (!wl->cfg.hw)
+ goto out_b;
+
+ wl->cfg.w = kmemdup(g_cfg_word, sizeof(g_cfg_word), GFP_KERNEL);
+ if (!wl->cfg.w)
+ goto out_hw;
+
+ wl->cfg.s = kmemdup(g_cfg_str, sizeof(g_cfg_str), GFP_KERNEL);
+ if (!wl->cfg.s)
+ goto out_w;
+
+ str_vals = kzalloc(sizeof(str_vals), GFP_KERNEL);
+ if (!str_vals)
+ goto out_s;
+
+ wl->cfg.str_vals = str_vals;
+ /* store the string cfg parameters */
+ wl->cfg.s[i].id = WID_FIRMWARE_VERSION;
+ wl->cfg.s[i].str = str_vals->firmware_version;
+ i++;
+ wl->cfg.s[i].id = WID_MAC_ADDR;
+ wl->cfg.s[i].str = str_vals->mac_address;
+ i++;
+ wl->cfg.s[i].id = WID_ASSOC_RES_INFO;
+ wl->cfg.s[i].str = str_vals->assoc_rsp;
+ i++;
+ wl->cfg.s[i].id = WID_NIL;
+ wl->cfg.s[i].str = NULL;
+ return 0;
+
+out_s:
+ kfree(wl->cfg.s);
+out_w:
+ kfree(wl->cfg.w);
+out_hw:
+ kfree(wl->cfg.hw);
+out_b:
+ kfree(wl->cfg.b);
+ return -ENOMEM;
+}
+
+void wilc_wlan_cfg_deinit(struct wilc *wl)
+{
+ kfree(wl->cfg.b);
+ kfree(wl->cfg.hw);
+ kfree(wl->cfg.w);
+ kfree(wl->cfg.s);
+ kfree(wl->cfg.str_vals);
+}
--
2.7.4


2018-09-26 10:26:08

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 10/19] wilc: add wilc_wfi_netdevice.h

Moved '/driver/staging/wilc1000/wilc_wfi_netdevice.h' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_wfi_netdevice.h b/drivers/net/wireless/microchip/wilc/wilc_wfi_netdevice.h
new file mode 100644
index 0000000..4f05a16
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_wfi_netdevice.h
@@ -0,0 +1,230 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#ifndef WILC_WFI_NETDEVICE
+#define WILC_WFI_NETDEVICE
+
+#include <linux/tcp.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include <net/ieee80211_radiotap.h>
+#include <linux/if_arp.h>
+#include <linux/gpio/consumer.h>
+
+#include "host_interface.h"
+#include "wilc_wlan.h"
+#include "wilc_wlan_cfg.h"
+
+#define FLOW_CONTROL_LOWER_THRESHOLD 128
+#define FLOW_CONTROL_UPPER_THRESHOLD 256
+
+#define WILC_MAX_NUM_PMKIDS 16
+#define PMKID_LEN 16
+#define PMKID_FOUND 1
+#define NUM_STA_ASSOCIATED 8
+
+#define NUM_REG_FRAME 2
+
+#define TCP_ACK_FILTER_LINK_SPEED_THRESH 54
+#define DEFAULT_LINK_SPEED 72
+
+#define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
+
+struct wilc_wfi_stats {
+ unsigned long rx_packets;
+ unsigned long tx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+ u64 rx_time;
+ u64 tx_time;
+
+};
+
+struct wilc_wfi_key {
+ u8 *key;
+ u8 *seq;
+ int key_len;
+ int seq_len;
+ u32 cipher;
+};
+
+struct wilc_wfi_wep_key {
+ u8 *key;
+ u8 key_len;
+ u8 key_idx;
+};
+
+struct sta_info {
+ u8 sta_associated_bss[MAX_NUM_STA][ETH_ALEN];
+};
+
+/*Parameters needed for host interface for remaining on channel*/
+struct wilc_wfi_p2p_listen_params {
+ struct ieee80211_channel *listen_ch;
+ u32 listen_duration;
+ u64 listen_cookie;
+ u32 listen_session_id;
+};
+
+struct wilc_p2p_var {
+ u8 local_random;
+ u8 recv_random;
+ bool is_wilc_ie;
+};
+
+struct wilc_priv {
+ struct wireless_dev *wdev;
+ struct cfg80211_scan_request *scan_req;
+
+ struct wilc_wfi_p2p_listen_params remain_on_ch_params;
+ u64 tx_cookie;
+
+ bool cfg_scanning;
+ u32 rcvd_ch_cnt;
+
+ u8 associated_bss[ETH_ALEN];
+ struct sta_info assoc_stainfo;
+ struct sk_buff *skb;
+ struct net_device *dev;
+ struct host_if_drv *hif_drv;
+ struct host_if_pmkid_attr pmkid_list;
+ u8 wep_key[4][WLAN_KEY_LEN_WEP104];
+ u8 wep_key_len[4];
+ /* The real interface that the monitor is on */
+ struct net_device *real_ndev;
+ struct wilc_wfi_key *wilc_gtk[MAX_NUM_STA];
+ struct wilc_wfi_key *wilc_ptk[MAX_NUM_STA];
+ u8 wilc_groupkey;
+ /* mutexes */
+ struct mutex scan_req_lock;
+ bool p2p_listen_state;
+ struct timer_list aging_timer;
+ struct network_info scanned_shadow[MAX_NUM_SCANNED_NETWORKS_SHADOW];
+ int scanned_cnt;
+ struct wilc_p2p_var p2p;
+};
+
+struct frame_reg {
+ u16 type;
+ bool reg;
+};
+
+#define MAX_TCP_SESSION 25
+#define MAX_PENDING_ACKS 256
+
+struct ack_session_info {
+ u32 seq_num;
+ u32 bigger_ack_num;
+ u16 src_port;
+ u16 dst_port;
+ u16 status;
+};
+
+struct pending_acks {
+ u32 ack_num;
+ u32 session_index;
+ struct txq_entry_t *txqe;
+};
+
+struct tcp_ack_filter {
+ struct ack_session_info ack_session_info[2 * MAX_TCP_SESSION];
+ struct pending_acks pending_acks[MAX_PENDING_ACKS];
+ u32 pending_base;
+ u32 tcp_session;
+ u32 pending_acks_idx;
+ bool enabled;
+};
+
+struct wilc_vif {
+ u8 idx;
+ u8 iftype;
+ int monitor_flag;
+ int mac_opened;
+ struct frame_reg frame_reg[NUM_REG_FRAME];
+ struct net_device_stats netstats;
+ struct wilc *wilc;
+ u8 src_addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ struct host_if_drv *hif_drv;
+ struct net_device *ndev;
+ u8 mode;
+ u8 ifc_id;
+ struct timer_list during_ip_timer;
+ bool obtaining_ip;
+ struct timer_list periodic_rssi;
+ struct rf_info periodic_stat;
+ struct tcp_ack_filter ack_filter;
+ bool connecting;
+};
+
+struct wilc {
+ const struct wilc_hif_func *hif_func;
+ int io_type;
+ s8 mac_status;
+ struct gpio_desc *gpio_irq;
+ bool initialized;
+ int dev_irq_num;
+ int close;
+ u8 vif_num;
+ struct wilc_vif *vif[NUM_CONCURRENT_IFC];
+ u8 open_ifcs;
+ /*protect head of transmit queue*/
+ struct mutex txq_add_to_head_cs;
+ /*protect txq_entry_t transmit queue*/
+ spinlock_t txq_spinlock;
+ /*protect rxq_entry_t receiver queue*/
+ struct mutex rxq_cs;
+ /* lock to protect hif access */
+ struct mutex hif_cs;
+
+ struct completion cfg_event;
+ struct completion sync_event;
+ struct completion txq_event;
+ struct completion txq_thread_started;
+
+ struct task_struct *txq_thread;
+
+ int quit;
+ int cfg_frame_in_use;
+ struct wilc_cfg_frame cfg_frame;
+ u32 cfg_frame_offset;
+ int cfg_seq_no;
+
+ u8 *rx_buffer;
+ u32 rx_buffer_offset;
+ u8 *tx_buffer;
+
+ struct txq_entry_t txq_head;
+ int txq_entries;
+
+ struct rxq_entry_t rxq_head;
+
+ const struct firmware *firmware;
+
+ struct device *dev;
+ bool suspend_event;
+
+ bool enable_ps;
+ int clients_count;
+ struct workqueue_struct *hif_workqueue;
+ enum chip_ps_states chip_ps_state;
+ struct wilc_cfg cfg;
+ void *bus_data;
+};
+
+struct wilc_wfi_mon_priv {
+ struct net_device *real_ndev;
+};
+
+void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset);
+void wilc_mac_indicate(struct wilc *wilc);
+void wilc_netdev_cleanup(struct wilc *wilc);
+int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
+ const struct wilc_hif_func *ops);
+void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size);
+void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode);
+
+#endif
--
2.7.4


2018-09-26 10:26:10

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 11/19] wilc: add wilc_wfi_cfgoperations.h

Moved '/driver/staging/wilc1000/wilc_wfi_cfgoperations.h' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_wfi_cfgoperations.h b/drivers/net/wireless/microchip/wilc/wilc_wfi_cfgoperations.h
new file mode 100644
index 0000000..4812c8e
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_wfi_cfgoperations.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#ifndef NM_WFI_CFGOPERATIONS
+#define NM_WFI_CFGOPERATIONS
+#include "wilc_wfi_netdevice.h"
+
+struct wireless_dev *wilc_create_wiphy(struct net_device *net,
+ struct device *dev);
+void wilc_free_wiphy(struct net_device *net);
+void wilc_deinit_host_int(struct net_device *net);
+int wilc_init_host_int(struct net_device *net);
+void wilc_wfi_monitor_rx(u8 *buff, u32 size);
+void wilc_wfi_deinit_mon_interface(void);
+struct net_device *wilc_wfi_init_mon_interface(const char *name,
+ struct net_device *real_dev);
+void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
+ u16 frame_type, bool reg);
+
+#endif
--
2.7.4


2018-09-26 10:26:15

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 12/19] wilc: add wilc_wfi_cfgoperations.c

Moved '/driver/staging/wilc1000/wilc_wfi_cfgoperations.c' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_wfi_cfgoperations.c b/drivers/net/wireless/microchip/wilc/wilc_wfi_cfgoperations.c
new file mode 100644
index 0000000..4fbbbbd
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_wfi_cfgoperations.c
@@ -0,0 +1,2216 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "wilc_wfi_cfgoperations.h"
+
+#define NO_ENCRYPT 0
+#define ENCRYPT_ENABLED BIT(0)
+#define WEP BIT(1)
+#define WEP_EXTENDED BIT(2)
+#define WPA BIT(3)
+#define WPA2 BIT(4)
+#define AES BIT(5)
+#define TKIP BIT(6)
+
+#define FRAME_TYPE_ID 0
+#define ACTION_CAT_ID 24
+#define ACTION_SUBTYPE_ID 25
+#define P2P_PUB_ACTION_SUBTYPE 30
+
+#define ACTION_FRAME 0xd0
+#define GO_INTENT_ATTR_ID 0x04
+#define CHANLIST_ATTR_ID 0x0b
+#define OPERCHAN_ATTR_ID 0x11
+#define PUB_ACTION_ATTR_ID 0x04
+#define P2PELEM_ATTR_ID 0xdd
+
+#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 PUBLIC_ACT_VENDORSPEC 0x09
+#define GAS_INITIAL_REQ 0x0a
+#define GAS_INITIAL_RSP 0x0b
+
+#define INVALID_CHANNEL 0
+
+#define nl80211_SCAN_RESULT_EXPIRE (3 * HZ)
+#define SCAN_RESULT_EXPIRE (40 * HZ)
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC,
+};
+
+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
+};
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = NL80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+static struct ieee80211_channel ieee80211_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0),
+};
+
+#define RATETAB_ENT(_rate, _hw_value, _flags) { \
+ .bitrate = (_rate), \
+ .hw_value = (_hw_value), \
+ .flags = (_flags), \
+}
+
+static struct ieee80211_rate ieee80211_bitrates[] = {
+ RATETAB_ENT(10, 0, 0),
+ RATETAB_ENT(20, 1, 0),
+ RATETAB_ENT(55, 2, 0),
+ RATETAB_ENT(110, 3, 0),
+ RATETAB_ENT(60, 9, 0),
+ RATETAB_ENT(90, 6, 0),
+ RATETAB_ENT(120, 7, 0),
+ RATETAB_ENT(180, 8, 0),
+ RATETAB_ENT(240, 9, 0),
+ RATETAB_ENT(360, 10, 0),
+ RATETAB_ENT(480, 11, 0),
+ RATETAB_ENT(540, 12, 0),
+};
+
+struct p2p_mgmt_data {
+ int size;
+ u8 *buff;
+};
+
+static u8 wlan_channel = INVALID_CHANNEL;
+static u8 curr_channel;
+static u8 p2p_oui[] = {0x50, 0x6f, 0x9A, 0x09};
+static u8 p2p_vendor_spec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03};
+
+static struct ieee80211_supported_band wilc_band_2ghz = {
+ .channels = ieee80211_2ghz_channels,
+ .n_channels = ARRAY_SIZE(ieee80211_2ghz_channels),
+ .bitrates = ieee80211_bitrates,
+ .n_bitrates = ARRAY_SIZE(ieee80211_bitrates),
+};
+
+#define AGING_TIME (9 * 1000)
+#define DURING_IP_TIME_OUT 15000
+
+static void clear_shadow_scan(struct wilc_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ kfree(priv->scanned_shadow[i].ies);
+ priv->scanned_shadow[i].ies = NULL;
+
+ kfree(priv->scanned_shadow[i].join_params);
+ priv->scanned_shadow[i].join_params = NULL;
+ }
+ priv->scanned_cnt = 0;
+}
+
+static u32 get_rssi_avg(struct network_info *network_info)
+{
+ u8 i;
+ int rssi_v = 0;
+ u8 num_rssi = (network_info->rssi_history.full) ?
+ NUM_RSSI : (network_info->rssi_history.index);
+
+ for (i = 0; i < num_rssi; i++)
+ rssi_v += network_info->rssi_history.samples[i];
+
+ rssi_v /= num_rssi;
+ return rssi_v;
+}
+
+static void refresh_scan(struct wilc_priv *priv, bool direct_scan)
+{
+ struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy;
+ int i;
+
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ struct network_info *network_info;
+ s32 freq;
+ struct ieee80211_channel *channel;
+ int rssi;
+ struct cfg80211_bss *bss;
+
+ network_info = &priv->scanned_shadow[i];
+
+ if (!memcmp("DIRECT-", network_info->ssid, 7) && !direct_scan)
+ continue;
+
+ freq = ieee80211_channel_to_frequency((s32)network_info->ch,
+ NL80211_BAND_2GHZ);
+ channel = ieee80211_get_channel(wiphy, freq);
+ rssi = get_rssi_avg(network_info);
+ bss = cfg80211_inform_bss(wiphy,
+ channel,
+ CFG80211_BSS_FTYPE_UNKNOWN,
+ network_info->bssid,
+ network_info->tsf_hi,
+ network_info->cap_info,
+ network_info->beacon_period,
+ (const u8 *)network_info->ies,
+ (size_t)network_info->ies_len,
+ (s32)rssi * 100,
+ GFP_KERNEL);
+ cfg80211_put_bss(wiphy, bss);
+ }
+}
+
+static void reset_shadow_found(struct wilc_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->scanned_cnt; i++)
+ priv->scanned_shadow[i].found = 0;
+}
+
+static void update_scan_time(struct wilc_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->scanned_cnt; i++)
+ priv->scanned_shadow[i].time_scan = jiffies;
+}
+
+static void remove_network_from_shadow(struct timer_list *t)
+{
+ struct wilc_priv *priv = from_timer(priv, t, aging_timer);
+ unsigned long now = jiffies;
+ int i, j;
+
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ if (!time_after(now, priv->scanned_shadow[i].time_scan +
+ (unsigned long)(SCAN_RESULT_EXPIRE)))
+ continue;
+ kfree(priv->scanned_shadow[i].ies);
+ priv->scanned_shadow[i].ies = NULL;
+
+ kfree(priv->scanned_shadow[i].join_params);
+
+ for (j = i; (j < priv->scanned_cnt - 1); j++)
+ priv->scanned_shadow[j] = priv->scanned_shadow[j + 1];
+
+ priv->scanned_cnt--;
+ }
+
+ if (priv->scanned_cnt != 0)
+ mod_timer(&priv->aging_timer,
+ jiffies + msecs_to_jiffies(AGING_TIME));
+}
+
+static void clear_during_ip(struct timer_list *t)
+{
+ struct wilc_vif *vif = from_timer(vif, t, during_ip_timer);
+
+ vif->obtaining_ip = false;
+}
+
+static int is_network_in_shadow(struct network_info *nw_info,
+ struct wilc_priv *priv)
+{
+ int state = -1;
+ int i;
+
+ if (priv->scanned_cnt == 0) {
+ mod_timer(&priv->aging_timer,
+ jiffies + msecs_to_jiffies(AGING_TIME));
+ state = -1;
+ } else {
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ if (memcmp(priv->scanned_shadow[i].bssid,
+ nw_info->bssid, 6) == 0) {
+ state = i;
+ break;
+ }
+ }
+ }
+ return state;
+}
+
+static void add_network_to_shadow(struct network_info *nw_info,
+ struct wilc_priv *priv, void *join_params)
+{
+ int ap_found = is_network_in_shadow(nw_info, priv);
+ u32 ap_index = 0;
+ u8 rssi_index = 0;
+ struct network_info *shadow_nw_info;
+
+ if (priv->scanned_cnt >= MAX_NUM_SCANNED_NETWORKS_SHADOW)
+ return;
+
+ if (ap_found == -1) {
+ ap_index = priv->scanned_cnt;
+ priv->scanned_cnt++;
+ } else {
+ ap_index = ap_found;
+ }
+ shadow_nw_info = &priv->scanned_shadow[ap_index];
+ rssi_index = shadow_nw_info->rssi_history.index;
+ shadow_nw_info->rssi_history.samples[rssi_index++] = nw_info->rssi;
+ if (rssi_index == NUM_RSSI) {
+ rssi_index = 0;
+ shadow_nw_info->rssi_history.full = true;
+ }
+ shadow_nw_info->rssi_history.index = rssi_index;
+ shadow_nw_info->rssi = nw_info->rssi;
+ shadow_nw_info->cap_info = nw_info->cap_info;
+ shadow_nw_info->ssid_len = nw_info->ssid_len;
+ memcpy(shadow_nw_info->ssid, nw_info->ssid, nw_info->ssid_len);
+ memcpy(shadow_nw_info->bssid, nw_info->bssid, ETH_ALEN);
+ shadow_nw_info->beacon_period = nw_info->beacon_period;
+ shadow_nw_info->dtim_period = nw_info->dtim_period;
+ shadow_nw_info->ch = nw_info->ch;
+ shadow_nw_info->tsf_hi = nw_info->tsf_hi;
+ if (ap_found != -1)
+ kfree(shadow_nw_info->ies);
+ shadow_nw_info->ies = kmemdup(nw_info->ies, nw_info->ies_len,
+ GFP_KERNEL);
+ if (shadow_nw_info->ies)
+ shadow_nw_info->ies_len = nw_info->ies_len;
+ else
+ shadow_nw_info->ies_len = 0;
+ shadow_nw_info->time_scan = jiffies;
+ shadow_nw_info->time_scan_cached = jiffies;
+ shadow_nw_info->found = 1;
+ if (ap_found != -1)
+ kfree(shadow_nw_info->join_params);
+ shadow_nw_info->join_params = join_params;
+}
+
+static void cfg_scan_result(enum scan_event scan_event,
+ struct network_info *network_info,
+ void *user_void, void *join_params)
+{
+ struct wilc_priv *priv;
+ struct wiphy *wiphy;
+ s32 freq;
+ struct ieee80211_channel *channel;
+ struct cfg80211_bss *bss = NULL;
+
+ priv = user_void;
+ if (!priv->cfg_scanning)
+ return;
+
+ if (scan_event == SCAN_EVENT_NETWORK_FOUND) {
+ wiphy = priv->dev->ieee80211_ptr->wiphy;
+
+ if (!wiphy || !network_info)
+ return;
+
+ if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
+ (((s32)network_info->rssi * 100) < 0 ||
+ ((s32)network_info->rssi * 100) > 100))
+ return;
+
+ freq = ieee80211_channel_to_frequency((s32)network_info->ch,
+ NL80211_BAND_2GHZ);
+ channel = ieee80211_get_channel(wiphy, freq);
+
+ if (!channel)
+ return;
+
+ if (network_info->new_network) {
+ if (priv->rcvd_ch_cnt >= MAX_NUM_SCANNED_NETWORKS)
+ return;
+
+ priv->rcvd_ch_cnt++;
+
+ add_network_to_shadow(network_info, priv, join_params);
+
+ if (memcmp("DIRECT-", network_info->ssid, 7))
+ return;
+
+ bss = cfg80211_inform_bss(wiphy,
+ channel,
+ CFG80211_BSS_FTYPE_UNKNOWN,
+ network_info->bssid,
+ network_info->tsf_hi,
+ network_info->cap_info,
+ network_info->beacon_period,
+ (const u8 *)network_info->ies,
+ (size_t)network_info->ies_len,
+ (s32)network_info->rssi * 100,
+ GFP_KERNEL);
+ cfg80211_put_bss(wiphy, bss);
+ } else {
+ u32 i;
+
+ for (i = 0; i < priv->rcvd_ch_cnt; i++) {
+ if (memcmp(priv->scanned_shadow[i].bssid,
+ network_info->bssid, 6) == 0)
+ break;
+ }
+
+ if (i >= priv->rcvd_ch_cnt)
+ return;
+
+ priv->scanned_shadow[i].rssi = network_info->rssi;
+ priv->scanned_shadow[i].time_scan = jiffies;
+ }
+ } else if (scan_event == SCAN_EVENT_DONE) {
+ refresh_scan(priv, false);
+
+ 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->rcvd_ch_cnt = 0;
+ 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,
+ };
+
+ update_scan_time(priv);
+ refresh_scan(priv, false);
+
+ cfg80211_scan_done(priv->scan_req, &info);
+ priv->cfg_scanning = false;
+ priv->scan_req = NULL;
+ }
+ mutex_unlock(&priv->scan_req_lock);
+ }
+}
+
+static inline bool wilc_cfg_scan_time_expired(struct wilc_priv *priv, int i)
+{
+ unsigned long now = jiffies;
+
+ if (time_after(now, priv->scanned_shadow[i].time_scan_cached +
+ (unsigned long)(nl80211_SCAN_RESULT_EXPIRE - (1 * HZ))))
+ return true;
+ else
+ return false;
+}
+
+static void cfg_connect_result(enum conn_event conn_disconn_evt,
+ struct connect_info *conn_info,
+ u8 mac_status,
+ struct disconnect_info *disconn_info,
+ 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;
+ u8 null_bssid[ETH_ALEN] = {0};
+
+ vif->connecting = false;
+
+ if (conn_disconn_evt == CONN_DISCONN_EVENT_CONN_RESP) {
+ u16 connect_status;
+
+ connect_status = conn_info->status;
+
+ if (mac_status == MAC_STATUS_DISCONNECTED &&
+ conn_info->status == WLAN_STATUS_SUCCESS) {
+ connect_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wilc_wlan_set_bssid(priv->dev, null_bssid,
+ STATION_MODE);
+
+ if (!wfi_drv->p2p_connect)
+ wlan_channel = INVALID_CHANNEL;
+
+ netdev_err(dev, "Unspecified failure\n");
+ }
+
+ if (connect_status == WLAN_STATUS_SUCCESS) {
+ bool scan_refresh = false;
+ u32 i;
+
+ memcpy(priv->associated_bss, conn_info->bssid,
+ ETH_ALEN);
+
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ if (memcmp(priv->scanned_shadow[i].bssid,
+ conn_info->bssid,
+ ETH_ALEN) == 0) {
+ if (wilc_cfg_scan_time_expired(priv, i))
+ scan_refresh = true;
+
+ break;
+ }
+ }
+
+ if (scan_refresh)
+ refresh_scan(priv, true);
+ }
+
+ cfg80211_connect_result(dev, conn_info->bssid,
+ conn_info->req_ies,
+ conn_info->req_ies_len,
+ conn_info->resp_ies,
+ conn_info->resp_ies_len, connect_status,
+ GFP_KERNEL);
+ } else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) {
+ vif->obtaining_ip = false;
+ priv->p2p.local_random = 0x01;
+ priv->p2p.recv_random = 0x00;
+ priv->p2p.is_wilc_ie = false;
+ eth_zero_addr(priv->associated_bss);
+ wilc_wlan_set_bssid(priv->dev, null_bssid, STATION_MODE);
+
+ if (!wfi_drv->p2p_connect)
+ wlan_channel = INVALID_CHANNEL;
+ if (wfi_drv->ifc_up && dev == wl->vif[1]->ndev)
+ disconn_info->reason = 3;
+ else if (!wfi_drv->ifc_up && dev == wl->vif[1]->ndev)
+ disconn_info->reason = 1;
+
+ cfg80211_disconnected(dev, disconn_info->reason,
+ disconn_info->ie, disconn_info->ie_len,
+ false, GFP_KERNEL);
+ }
+}
+
+static int set_channel(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef)
+{
+ u32 channelnum = 0;
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+ int result = 0;
+
+ channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq);
+
+ curr_channel = channelnum;
+ result = wilc_set_mac_chnl_num(vif, channelnum);
+
+ if (result != 0)
+ netdev_err(priv->dev, "Error in setting channel\n");
+
+ return result;
+}
+
+static inline int
+wilc_wfi_cfg_alloc_fill_ssid(struct cfg80211_scan_request *request,
+ struct hidden_network *ntwk)
+{
+ int i;
+ int slot_id = 0;
+
+ ntwk->net_info = kcalloc(request->n_ssids, sizeof(*ntwk->net_info),
+ GFP_KERNEL);
+ if (!ntwk->net_info)
+ goto out;
+
+ ntwk->n_ssids = request->n_ssids;
+
+ for (i = 0; i < request->n_ssids; i++) {
+ if (request->ssids[i].ssid_len > 0) {
+ struct hidden_net_info *info = &ntwk->net_info[slot_id];
+
+ info->ssid = kmemdup(request->ssids[i].ssid,
+ request->ssids[i].ssid_len,
+ GFP_KERNEL);
+ if (!info->ssid)
+ goto out_free;
+
+ info->ssid_len = request->ssids[i].ssid_len;
+ slot_id++;
+ } else {
+ ntwk->n_ssids -= 1;
+ }
+ }
+ return 0;
+
+out_free:
+
+ for (i = 0; i < slot_id; i++)
+ kfree(ntwk->net_info[i].ssid);
+
+ kfree(ntwk->net_info);
+out:
+
+ return -ENOMEM;
+}
+
+static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+ u32 i;
+ int ret = 0;
+ u8 scan_ch_list[MAX_NUM_SCANNED_NETWORKS];
+ struct hidden_network hidden_ntwk;
+
+ priv->scan_req = request;
+
+ priv->rcvd_ch_cnt = 0;
+
+ reset_shadow_found(priv);
+
+ priv->cfg_scanning = true;
+ if (request->n_channels <= MAX_NUM_SCANNED_NETWORKS) {
+ 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 >= 1) {
+ if (wilc_wfi_cfg_alloc_fill_ssid(request,
+ &hidden_ntwk))
+ return -ENOMEM;
+
+ ret = wilc_scan(vif, USER_SCAN, ACTIVE_SCAN,
+ scan_ch_list,
+ request->n_channels,
+ (const u8 *)request->ie,
+ request->ie_len, cfg_scan_result,
+ (void *)priv, &hidden_ntwk);
+ } else {
+ ret = wilc_scan(vif, USER_SCAN, ACTIVE_SCAN,
+ scan_ch_list,
+ request->n_channels,
+ (const u8 *)request->ie,
+ request->ie_len, cfg_scan_result,
+ (void *)priv, NULL);
+ }
+ } else {
+ netdev_err(priv->dev, "Requested scanned channels over\n");
+ }
+
+ if (ret != 0)
+ ret = -EBUSY;
+
+ return ret;
+}
+
+static int connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ struct network_info *nw_info;
+ int ret;
+ u32 i;
+ u32 sel_bssi_idx = UINT_MAX;
+ u8 security = NO_ENCRYPT;
+ enum authtype auth_type = ANY;
+ u32 cipher_group;
+
+ vif->connecting = true;
+
+ if (!(strncmp(sme->ssid, "DIRECT-", 7)))
+ wfi_drv->p2p_connect = 1;
+ else
+ wfi_drv->p2p_connect = 0;
+
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ if (sme->ssid_len == priv->scanned_shadow[i].ssid_len &&
+ memcmp(priv->scanned_shadow[i].ssid,
+ sme->ssid,
+ sme->ssid_len) == 0) {
+ if (!sme->bssid) {
+ if (sel_bssi_idx == UINT_MAX ||
+ priv->scanned_shadow[i].rssi >
+ priv->scanned_shadow[sel_bssi_idx].rssi)
+ sel_bssi_idx = i;
+ } else {
+ if (memcmp(priv->scanned_shadow[i].bssid,
+ sme->bssid,
+ ETH_ALEN) == 0) {
+ sel_bssi_idx = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (sel_bssi_idx < priv->scanned_cnt) {
+ nw_info = &priv->scanned_shadow[sel_bssi_idx];
+ } else {
+ ret = -ENOENT;
+ goto out_error;
+ }
+
+ if (ether_addr_equal_unaligned(vif->bssid, nw_info->bssid)) {
+ ret = -EALREADY;
+ goto out_error;
+ }
+
+ 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 != NO_ENCRYPT) {
+ if (cipher_group == WLAN_CIPHER_SUITE_WEP40) {
+ security = ENCRYPT_ENABLED | 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 = ENCRYPT_ENABLED | WEP | 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 = ENCRYPT_ENABLED | WPA2 | TKIP;
+ else
+ security = ENCRYPT_ENABLED | WPA2 | AES;
+ } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) {
+ if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
+ security = ENCRYPT_ENABLED | WPA | TKIP;
+ else
+ security = ENCRYPT_ENABLED | 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 = security | TKIP;
+ else
+ security = security | AES;
+ }
+ }
+
+ switch (sme->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ auth_type = OPEN_SYSTEM;
+ break;
+
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ auth_type = SHARED_KEY;
+ break;
+
+ default:
+ break;
+ }
+
+ if (sme->crypto.n_akm_suites) {
+ if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X)
+ auth_type = IEEE8021;
+ }
+
+ curr_channel = nw_info->ch;
+
+ if (!wfi_drv->p2p_connect)
+ wlan_channel = nw_info->ch;
+
+ wilc_wlan_set_bssid(dev, nw_info->bssid, STATION_MODE);
+
+ ret = wilc_set_join_req(vif, nw_info->bssid, sme->ssid,
+ sme->ssid_len, sme->ie, sme->ie_len,
+ cfg_connect_result, (void *)priv,
+ security, auth_type,
+ nw_info->ch,
+ nw_info->join_params);
+ if (ret) {
+ u8 null_bssid[ETH_ALEN] = {0};
+
+ netdev_err(dev, "wilc_set_join_req(): Error\n");
+ ret = -ENOENT;
+ wilc_wlan_set_bssid(dev, null_bssid, STATION_MODE);
+ goto out_error;
+ }
+ return 0;
+
+out_error:
+ vif->connecting = false;
+ return ret;
+}
+
+static int disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc *wilc = vif->wilc;
+ struct host_if_drv *wfi_drv;
+ int ret;
+ u8 null_bssid[ETH_ALEN] = {0};
+
+ vif->connecting = false;
+
+ if (!wilc)
+ return -EIO;
+
+ if (wilc->close) {
+ /* already disconnected done */
+ cfg80211_disconnected(dev, 0, NULL, 0, true, GFP_KERNEL);
+ return 0;
+ }
+
+ wfi_drv = (struct host_if_drv *)priv->hif_drv;
+ if (!wfi_drv->p2p_connect)
+ wlan_channel = INVALID_CHANNEL;
+ wilc_wlan_set_bssid(priv->dev, null_bssid, STATION_MODE);
+
+ priv->p2p.local_random = 0x01;
+ priv->p2p.recv_random = 0x00;
+ priv->p2p.is_wilc_ie = false;
+ wfi_drv->p2p_timeout = 0;
+
+ ret = wilc_disconnect(vif, reason_code);
+ if (ret != 0) {
+ netdev_err(priv->dev, "Error in disconnecting\n");
+ ret = -EINVAL;
+ }
+
+ 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;
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ const u8 *rx_mic = NULL;
+ const u8 *tx_mic = NULL;
+ u8 mode = NO_ENCRYPT;
+ u8 op_mode;
+ struct wilc_vif *vif = netdev_priv(netdev);
+
+ 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 = ENCRYPT_ENABLED | WEP;
+ else
+ mode = ENCRYPT_ENABLED | WEP | WEP_EXTENDED;
+
+ ret = wilc_add_wep_key_bss_ap(vif, params->key,
+ params->key_len,
+ key_index, mode,
+ 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 = ENCRYPT_ENABLED | WPA | TKIP;
+ else
+ mode = ENCRYPT_ENABLED | WPA2 | AES;
+
+ priv->wilc_groupkey = mode;
+
+ key = priv->wilc_gtk[key_index];
+ } else {
+ if (params->cipher == WLAN_CIPHER_SUITE_TKIP)
+ mode = ENCRYPT_ENABLED | WPA | TKIP;
+ else
+ mode = priv->wilc_groupkey | AES;
+
+ key = priv->wilc_ptk[key_index];
+ }
+ ret = wilc_wfi_cfg_copy_wpa_info(key, params);
+ if (ret)
+ return -ENOMEM;
+
+ op_mode = 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 = 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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc *wl = vif->wilc;
+
+ if (netdev == wl->vif[0]->ndev) {
+ 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_priv *priv = wiphy_priv(wiphy);
+ 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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ 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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(dev);
+ u32 i = 0;
+ u32 associatedsta = ~0;
+ u32 inactive_time = 0;
+
+ if (vif->iftype == AP_MODE || vif->iftype == 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 == STATION_MODE) {
+ struct rf_info stats;
+
+ wilc_get_statistics(vif, &stats, true);
+
+ 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;
+ struct cfg_param_attr cfg_param_val;
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ cfg_param_val.flag = 0;
+
+ if (changed & WIPHY_PARAM_RETRY_SHORT) {
+ cfg_param_val.flag |= RETRY_SHORT;
+ cfg_param_val.short_retry_limit = wiphy->retry_short;
+ }
+ if (changed & WIPHY_PARAM_RETRY_LONG) {
+ cfg_param_val.flag |= RETRY_LONG;
+ cfg_param_val.long_retry_limit = wiphy->retry_long;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ cfg_param_val.flag |= FRAG_THRESHOLD;
+ cfg_param_val.frag_threshold = wiphy->frag_threshold;
+ }
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ cfg_param_val.flag |= RTS_THRESHOLD;
+ cfg_param_val.rts_threshold = wiphy->rts_threshold;
+ }
+
+ ret = wilc_hif_set_cfg(vif, &cfg_param_val);
+ if (ret)
+ netdev_err(priv->dev, "Error in setting WIPHY PARAMS\n");
+
+ return ret;
+}
+
+static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+ 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,
+ 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;
+ int ret = 0;
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+
+ 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 host_if_pmkid));
+ break;
+ }
+ }
+
+ if (i < priv->pmkid_list.numpmkid && priv->pmkid_list.numpmkid > 0) {
+ 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,
+ PMKID_LEN);
+ }
+ priv->pmkid_list.numpmkid--;
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+
+ memset(&priv->pmkid_list, 0, sizeof(struct host_if_pmkid_attr));
+
+ return 0;
+}
+
+static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u8 ch_list_attr_idx,
+ u8 op_ch_attr_idx)
+{
+ int i = 0;
+ int j = 0;
+
+ if (ch_list_attr_idx) {
+ u8 limit = ch_list_attr_idx + 3 + buf[ch_list_attr_idx + 1];
+
+ for (i = ch_list_attr_idx + 3; i < limit; i++) {
+ if (buf[i] == 0x51) {
+ for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++)
+ buf[j] = wlan_channel;
+ break;
+ }
+ }
+ }
+
+ if (op_ch_attr_idx) {
+ buf[op_ch_attr_idx + 6] = 0x51;
+ buf[op_ch_attr_idx + 7] = wlan_channel;
+ }
+}
+
+static void wilc_wfi_cfg_parse_rx_action(u8 *buf, u32 len)
+{
+ u32 index = 0;
+ u8 op_channel_attr_index = 0;
+ u8 channel_list_attr_index = 0;
+
+ while (index < len) {
+ if (buf[index] == GO_INTENT_ATTR_ID)
+ buf[index + 3] = (buf[index + 3] & 0x01) | (0x00 << 1);
+
+ if (buf[index] == CHANLIST_ATTR_ID)
+ channel_list_attr_index = index;
+ else if (buf[index] == OPERCHAN_ATTR_ID)
+ op_channel_attr_index = index;
+ index += buf[index + 1] + 3;
+ }
+ if (wlan_channel != INVALID_CHANNEL)
+ wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
+ op_channel_attr_index);
+}
+
+static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch,
+ u8 iftype)
+{
+ u32 index = 0;
+ u8 op_channel_attr_index = 0;
+ u8 channel_list_attr_index = 0;
+
+ while (index < len) {
+ if (buf[index] == GO_INTENT_ATTR_ID) {
+ buf[index + 3] = (buf[index + 3] & 0x01) | (0x0f << 1);
+
+ break;
+ }
+
+ if (buf[index] == CHANLIST_ATTR_ID)
+ channel_list_attr_index = index;
+ else if (buf[index] == OPERCHAN_ATTR_ID)
+ op_channel_attr_index = index;
+ index += buf[index + 1] + 3;
+ }
+ if (wlan_channel != INVALID_CHANNEL && oper_ch)
+ wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
+ op_channel_attr_index);
+}
+
+static void wilc_wfi_cfg_parse_rx_vendor_spec(struct wilc_priv *priv, u8 *buff,
+ u32 size)
+{
+ int i;
+ u8 subtype;
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ subtype = buff[P2P_PUB_ACTION_SUBTYPE];
+ if ((subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) &&
+ !priv->p2p.is_wilc_ie) {
+ for (i = P2P_PUB_ACTION_SUBTYPE; i < size; i++) {
+ if (!memcmp(p2p_vendor_spec, &buff[i], 6)) {
+ priv->p2p.recv_random = buff[i + 6];
+ priv->p2p.is_wilc_ie = true;
+ break;
+ }
+ }
+ }
+
+ if (priv->p2p.local_random <= priv->p2p.recv_random) {
+ netdev_dbg(vif->ndev,
+ "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n",
+ priv->p2p.local_random, priv->p2p.recv_random);
+ return;
+ }
+
+ if (subtype == GO_NEG_REQ || subtype == GO_NEG_RSP ||
+ subtype == P2P_INV_REQ || subtype == P2P_INV_RSP) {
+ for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < size; i++) {
+ if (buff[i] == P2PELEM_ATTR_ID &&
+ !(memcmp(p2p_oui, &buff[i + 2], 4))) {
+ wilc_wfi_cfg_parse_rx_action(&buff[i + 6],
+ size - (i + 6));
+ break;
+ }
+ }
+ }
+}
+
+void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
+{
+ struct wilc_priv *priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ u32 header, pkt_offset;
+ s32 freq;
+ __le16 fc;
+
+ memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
+ le32_to_cpus(&header);
+ pkt_offset = GET_PKT_OFFSET(header);
+
+ if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
+ bool ack = false;
+
+ if (buff[FRAME_TYPE_ID] == IEEE80211_STYPE_PROBE_RESP ||
+ 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(curr_channel, NL80211_BAND_2GHZ);
+
+ fc = ((struct ieee80211_hdr *)buff)->frame_control;
+ if (!ieee80211_is_action(fc)) {
+ cfg80211_rx_mgmt(priv->wdev, freq, 0, buff, size, 0);
+ return;
+ }
+
+ if (priv->cfg_scanning &&
+ time_after_eq(jiffies, (unsigned long)wfi_drv->p2p_timeout)) {
+ netdev_dbg(dev, "Receiving action wrong ch\n");
+ return;
+ }
+ if (buff[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) {
+ u8 subtype = buff[P2P_PUB_ACTION_SUBTYPE];
+
+ switch (buff[ACTION_SUBTYPE_ID]) {
+ case GAS_INITIAL_REQ:
+ case GAS_INITIAL_RSP:
+ break;
+
+ case PUBLIC_ACT_VENDORSPEC:
+ if (!memcmp(p2p_oui, &buff[ACTION_SUBTYPE_ID + 1], 4))
+ wilc_wfi_cfg_parse_rx_vendor_spec(priv, buff,
+ size);
+
+ if ((subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) &&
+ priv->p2p.is_wilc_ie)
+ size -= 7;
+
+ break;
+
+ default:
+ netdev_dbg(dev,
+ "%s: Not handled action frame type:%x\n",
+ __func__, buff[ACTION_SUBTYPE_ID]);
+ break;
+ }
+ }
+
+ cfg80211_rx_mgmt(priv->wdev, freq, 0, buff, size, 0);
+}
+
+static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
+{
+ struct p2p_mgmt_data *pv_data = priv;
+
+ kfree(pv_data->buff);
+ kfree(pv_data);
+}
+
+static void wilc_wfi_remain_on_channel_ready(void *priv_data)
+{
+ struct wilc_priv *priv;
+
+ priv = priv_data;
+
+ priv->p2p_listen_state = true;
+
+ cfg80211_ready_on_channel(priv->wdev,
+ priv->remain_on_ch_params.listen_cookie,
+ priv->remain_on_ch_params.listen_ch,
+ priv->remain_on_ch_params.listen_duration,
+ GFP_KERNEL);
+}
+
+static void wilc_wfi_remain_on_channel_expired(void *data, u32 session_id)
+{
+ struct wilc_priv *priv = data;
+ struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params;
+
+ if (session_id != params->listen_session_id)
+ 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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ if (wdev->iftype == NL80211_IFTYPE_AP) {
+ netdev_dbg(vif->ndev, "Required while in AP mode\n");
+ return ret;
+ }
+
+ curr_channel = chan->hw_value;
+
+ priv->remain_on_ch_params.listen_ch = chan;
+ priv->remain_on_ch_params.listen_cookie = *cookie;
+ priv->remain_on_ch_params.listen_duration = duration;
+ priv->remain_on_ch_params.listen_session_id++;
+
+ return wilc_remain_on_channel(vif,
+ priv->remain_on_ch_params.listen_session_id,
+ duration, chan->hw_value,
+ wilc_wfi_remain_on_channel_expired,
+ wilc_wfi_remain_on_channel_ready, (void *)priv);
+}
+
+static int cancel_remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u64 cookie)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ return wilc_listen_state_expired(vif,
+ priv->remain_on_ch_params.listen_session_id);
+}
+
+static void wilc_wfi_cfg_tx_vendor_spec(struct wilc_priv *priv,
+ struct p2p_mgmt_data *mgmt_tx,
+ struct cfg80211_mgmt_tx_params *params,
+ u8 iftype, u32 buf_len)
+{
+ const u8 *buf = params->buf;
+ size_t len = params->len;
+ u32 i;
+ u8 subtype = buf[P2P_PUB_ACTION_SUBTYPE];
+
+ if (subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) {
+ if (priv->p2p.local_random == 1 &&
+ priv->p2p.recv_random < priv->p2p.local_random) {
+ get_random_bytes(&priv->p2p.local_random, 1);
+ priv->p2p.local_random++;
+ }
+ }
+
+ if (priv->p2p.local_random <= priv->p2p.recv_random ||
+ !(subtype == GO_NEG_REQ || subtype == GO_NEG_RSP ||
+ subtype == P2P_INV_REQ || subtype == P2P_INV_RSP))
+ return;
+
+ for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < len; i++) {
+ if (buf[i] == P2PELEM_ATTR_ID &&
+ !memcmp(p2p_oui, &buf[i + 2], 4)) {
+ bool oper_ch = false;
+ u8 *tx_buff = &mgmt_tx->buff[i + 6];
+
+ if (subtype == P2P_INV_REQ || subtype == P2P_INV_RSP)
+ oper_ch = true;
+
+ wilc_wfi_cfg_parse_tx_action(tx_buff, len - (i + 6),
+ oper_ch, iftype);
+
+ break;
+ }
+ }
+
+ if (subtype != P2P_INV_REQ && subtype != P2P_INV_RSP) {
+ int vendor_spec_len = sizeof(p2p_vendor_spec);
+
+ memcpy(&mgmt_tx->buff[len], p2p_vendor_spec,
+ vendor_spec_len);
+ mgmt_tx->buff[len + vendor_spec_len] = priv->p2p.local_random;
+ mgmt_tx->size = buf_len;
+ }
+}
+
+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 p2p_mgmt_data *mgmt_tx;
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ u32 buf_len = len + sizeof(p2p_vendor_spec) + sizeof(priv->p2p.local_random);
+ int ret = 0;
+
+ *cookie = (unsigned long)buf;
+ 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(buf_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);
+ curr_channel = chan->hw_value;
+ goto out_txq_add_pkt;
+ }
+
+ if (!ieee80211_is_action(mgmt->frame_control))
+ goto out_txq_add_pkt;
+
+ if (buf[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) {
+ if (buf[ACTION_SUBTYPE_ID] != PUBLIC_ACT_VENDORSPEC ||
+ buf[P2P_PUB_ACTION_SUBTYPE] != GO_NEG_CONF) {
+ wilc_set_mac_chnl_num(vif, chan->hw_value);
+ curr_channel = chan->hw_value;
+ }
+ switch (buf[ACTION_SUBTYPE_ID]) {
+ case GAS_INITIAL_REQ:
+ case GAS_INITIAL_RSP:
+ break;
+
+ case PUBLIC_ACT_VENDORSPEC:
+ if (!memcmp(p2p_oui, &buf[ACTION_SUBTYPE_ID + 1], 4))
+ wilc_wfi_cfg_tx_vendor_spec(priv, mgmt_tx,
+ params, vif->iftype,
+ buf_len);
+ else
+ netdev_dbg(vif->ndev,
+ "Not a P2P public action frame\n");
+
+ break;
+
+ default:
+ netdev_dbg(vif->ndev,
+ "%s: Not handled action frame type:%x\n",
+ __func__, buf[ACTION_SUBTYPE_ID]);
+ break;
+ }
+ }
+
+ 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_priv *priv = wiphy_priv(wiphy);
+ 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(priv->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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->wdev->netdev);
+ struct wilc *wl = vif->wilc;
+
+ if (!frame_type)
+ return;
+
+ switch (frame_type) {
+ case PROBE_REQ:
+ vif->frame_reg[0].type = frame_type;
+ vif->frame_reg[0].reg = reg;
+ break;
+
+ case 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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ if (idx != 0)
+ return -ENOENT;
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
+
+ wilc_get_rssi(vif, &sinfo->signal);
+
+ memcpy(mac, 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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ if (!priv->hif_drv)
+ return -EIO;
+
+ if (vif->wilc->enable_ps)
+ 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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+
+ priv->p2p.local_random = 0x01;
+ priv->p2p.recv_random = 0x00;
+ priv->p2p.is_wilc_ie = false;
+ vif->obtaining_ip = false;
+ del_timer(&vif->during_ip_timer);
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ vif->connecting = false;
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev->iftype = type;
+ vif->monitor_flag = 0;
+ vif->iftype = STATION_MODE;
+ wilc_set_operation_mode(vif, STATION_MODE);
+
+ memset(priv->assoc_stainfo.sta_associated_bss, 0,
+ MAX_NUM_STA * ETH_ALEN);
+
+ wl->enable_ps = true;
+ wilc_set_power_mgmt(vif, 1, 0);
+ break;
+
+ case NL80211_IFTYPE_P2P_CLIENT:
+ vif->connecting = false;
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev->iftype = type;
+ vif->monitor_flag = 0;
+ vif->iftype = CLIENT_MODE;
+ wilc_set_operation_mode(vif, STATION_MODE);
+
+ wl->enable_ps = false;
+ wilc_set_power_mgmt(vif, 0, 0);
+ break;
+
+ case NL80211_IFTYPE_AP:
+ wl->enable_ps = false;
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev->iftype = type;
+ vif->iftype = AP_MODE;
+
+ if (wl->initialized) {
+ wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
+ 0, vif->ifc_id, false);
+ wilc_set_operation_mode(vif, AP_MODE);
+ wilc_set_power_mgmt(vif, 0, 0);
+ }
+ break;
+
+ case NL80211_IFTYPE_P2P_GO:
+ vif->obtaining_ip = true;
+ mod_timer(&vif->during_ip_timer,
+ jiffies + msecs_to_jiffies(DURING_IP_TIME_OUT));
+ wilc_set_operation_mode(vif, AP_MODE);
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev->iftype = type;
+ vif->iftype = GO_MODE;
+
+ wl->enable_ps = false;
+ wilc_set_power_mgmt(vif, 0, 0);
+ 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);
+ struct wilc *wl = vif->wilc;
+ struct cfg80211_beacon_data *beacon = &settings->beacon;
+ int ret;
+
+ ret = set_channel(wiphy, &settings->chandef);
+
+ if (ret != 0)
+ netdev_err(dev, "Error in setting channel\n");
+
+ wilc_wlan_set_bssid(dev, wl->vif[vif->idx]->src_addr, AP_MODE);
+ wilc_set_power_mgmt(vif, 0, 0);
+
+ return wilc_add_beacon(vif, settings->beacon_interval,
+ settings->dtim_period, beacon->head_len,
+ (u8 *)beacon->head, beacon->tail_len,
+ (u8 *)beacon->tail);
+}
+
+static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_beacon_data *beacon)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ return wilc_add_beacon(vif, 0, 0, beacon->head_len,
+ (u8 *)beacon->head, beacon->tail_len,
+ (u8 *)beacon->tail);
+}
+
+static int stop_ap(struct wiphy *wiphy, struct net_device *dev)
+{
+ int ret;
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+ u8 null_bssid[ETH_ALEN] = {0};
+
+ wilc_wlan_set_bssid(dev, null_bssid, 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_priv *priv = wiphy_priv(wiphy);
+ struct add_sta_param sta_params = { {0} };
+ struct wilc_vif *vif = netdev_priv(dev);
+
+ if (vif->iftype == AP_MODE || vif->iftype == GO_MODE) {
+ memcpy(sta_params.bssid, mac, ETH_ALEN);
+ memcpy(priv->assoc_stainfo.sta_associated_bss[params->aid], mac,
+ ETH_ALEN);
+ sta_params.aid = params->aid;
+ sta_params.rates_len = params->supported_rates_len;
+ sta_params.rates = params->supported_rates;
+
+ if (!params->ht_capa) {
+ sta_params.ht_supported = false;
+ } else {
+ sta_params.ht_supported = true;
+ sta_params.ht_capa = *params->ht_capa;
+ }
+
+ sta_params.flags_mask = params->sta_flags_mask;
+ sta_params.flags_set = params->sta_flags_set;
+
+ ret = wilc_add_station(vif, &sta_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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct sta_info *info;
+
+ if (!(vif->iftype == AP_MODE || vif->iftype == 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 add_sta_param sta_params = { {0} };
+ struct wilc_vif *vif = netdev_priv(dev);
+
+ if (vif->iftype == AP_MODE || vif->iftype == GO_MODE) {
+ memcpy(sta_params.bssid, mac, ETH_ALEN);
+ sta_params.aid = params->aid;
+ sta_params.rates_len = params->supported_rates_len;
+ sta_params.rates = params->supported_rates;
+
+ if (!params->ht_capa) {
+ sta_params.ht_supported = false;
+ } else {
+ sta_params.ht_supported = true;
+ sta_params.ht_capa = *params->ht_capa;
+ }
+
+ sta_params.flags_mask = params->sta_flags_mask;
+ sta_params.flags_set = params->sta_flags_set;
+
+ ret = wilc_edit_station(vif, &sta_params);
+ if (ret)
+ netdev_err(dev, "Host edit station fail\n");
+ }
+ return ret;
+}
+
+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_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->wdev->netdev);
+ struct net_device *new_ifc;
+
+ if (type == NL80211_IFTYPE_MONITOR) {
+ new_ifc = wilc_wfi_init_mon_interface(name, vif->ndev);
+ if (new_ifc) {
+ vif = netdev_priv(priv->wdev->netdev);
+ vif->monitor_flag = 1;
+ }
+ }
+ return priv->wdev;
+}
+
+static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ return 0;
+}
+
+static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ if (!wow && wilc_wlan_get_num_conn_ifcs(vif->wilc))
+ vif->wilc->suspend_event = true;
+ else
+ vif->wilc->suspend_event = false;
+
+ return 0;
+}
+
+static int wilc_resume(struct wiphy *wiphy)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ netdev_info(vif->ndev, "cfg resume\n");
+ return 0;
+}
+
+static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled)
+{
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled);
+}
+
+static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, int mbm)
+{
+ int ret;
+ s32 tx_power = MBM_TO_DBM(mbm);
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ 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");
+
+ return ret;
+}
+
+static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ int *dbm)
+{
+ int ret;
+ struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+ 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 struct wireless_dev *wilc_wfi_cfg_alloc(void)
+{
+ struct wireless_dev *wdev;
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (!wdev)
+ goto out;
+
+ wdev->wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(struct wilc_priv));
+ if (!wdev->wiphy)
+ goto free_mem;
+
+ wilc_band_2ghz.ht_cap.ht_supported = 1;
+ wilc_band_2ghz.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+ wilc_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+ wilc_band_2ghz.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
+ wilc_band_2ghz.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
+
+ wdev->wiphy->bands[NL80211_BAND_2GHZ] = &wilc_band_2ghz;
+
+ return wdev;
+
+free_mem:
+ kfree(wdev);
+out:
+ return NULL;
+}
+
+struct wireless_dev *wilc_create_wiphy(struct net_device *net,
+ struct device *dev)
+{
+ struct wilc_priv *priv;
+ struct wireless_dev *wdev;
+ int ret;
+
+ wdev = wilc_wfi_cfg_alloc();
+ if (!wdev) {
+ netdev_err(net, "wiphy new allocate failed\n");
+ return NULL;
+ }
+
+ priv = wdev_priv(wdev);
+ priv->wdev = wdev;
+ wdev->wiphy->max_scan_ssids = MAX_NUM_PROBED_SSID;
+#ifdef CONFIG_PM
+ wdev->wiphy->wowlan = &wowlan_support;
+#endif
+ wdev->wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
+ wdev->wiphy->max_scan_ie_len = 1000;
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+ wdev->wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
+
+ wdev->wiphy->max_remain_on_channel_duration = 500;
+ wdev->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);
+ wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ wdev->iftype = NL80211_IFTYPE_STATION;
+
+ set_wiphy_dev(wdev->wiphy, dev);
+
+ ret = wiphy_register(wdev->wiphy);
+ if (ret) {
+ netdev_err(net, "Cannot register wiphy device\n");
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ return NULL;
+ }
+
+ priv->dev = net;
+ return wdev;
+}
+
+int wilc_init_host_int(struct net_device *net)
+{
+ int ret;
+ struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ timer_setup(&priv->aging_timer, remove_network_from_shadow, 0);
+ timer_setup(&vif->during_ip_timer, clear_during_ip, 0);
+
+ 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_priv *priv = wdev_priv(net->ieee80211_ptr);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ priv->p2p_listen_state = false;
+
+ mutex_destroy(&priv->scan_req_lock);
+ ret = wilc_deinit(vif);
+
+ del_timer_sync(&priv->aging_timer);
+ clear_shadow_scan(priv);
+ del_timer_sync(&vif->during_ip_timer);
+
+ if (ret)
+ netdev_err(net, "Error while deinitializing host interface\n");
+}
+
+void wilc_free_wiphy(struct net_device *net)
+{
+ if (!net)
+ return;
+
+ if (!net->ieee80211_ptr)
+ return;
+
+ if (!net->ieee80211_ptr->wiphy)
+ return;
+
+ wiphy_unregister(net->ieee80211_ptr->wiphy);
+
+ wiphy_free(net->ieee80211_ptr->wiphy);
+ kfree(net->ieee80211_ptr);
+}
--
2.7.4


2018-09-26 10:26:18

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 13/19] wilc: add linux_wlan.c

Moved '/driver/staging/wilc1000/linux_wlan.c' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/linux_wlan.c b/drivers/net/wireless/microchip/wilc/linux_wlan.c
new file mode 100644
index 0000000..76c9012
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/linux_wlan.c
@@ -0,0 +1,1161 @@
+// 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 "wilc_wfi_cfgoperations.h"
+
+static int dev_state_ev_handler(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct in_ifaddr *dev_iface = ptr;
+ struct wilc_priv *priv;
+ struct host_if_drv *hif_drv;
+ struct net_device *dev;
+ u8 *ip_addr_buf;
+ struct wilc_vif *vif;
+ u8 null_ip[4] = {0};
+ char wlan_dev_name[5] = "wlan0";
+
+ if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev)
+ return NOTIFY_DONE;
+
+ if (memcmp(dev_iface->ifa_label, "wlan0", 5) &&
+ memcmp(dev_iface->ifa_label, "p2p0", 4))
+ return NOTIFY_DONE;
+
+ dev = (struct net_device *)dev_iface->ifa_dev->dev;
+ if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
+ return NOTIFY_DONE;
+
+ priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
+ if (!priv)
+ return NOTIFY_DONE;
+
+ hif_drv = (struct host_if_drv *)priv->hif_drv;
+ vif = netdev_priv(dev);
+ if (!vif || !hif_drv)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_UP:
+ if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
+ hif_drv->ifc_up = 1;
+ vif->obtaining_ip = false;
+ del_timer(&vif->during_ip_timer);
+ }
+
+ if (vif->wilc->enable_ps)
+ wilc_set_power_mgmt(vif, 1, 0);
+
+ netdev_dbg(dev, "[%s] Up IP\n", dev_iface->ifa_label);
+
+ ip_addr_buf = (char *)&dev_iface->ifa_address;
+ netdev_dbg(dev, "IP add=%d:%d:%d:%d\n",
+ ip_addr_buf[0], ip_addr_buf[1],
+ ip_addr_buf[2], ip_addr_buf[3]);
+
+ break;
+
+ case NETDEV_DOWN:
+ if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
+ hif_drv->ifc_up = 0;
+ vif->obtaining_ip = false;
+ }
+
+ if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0)
+ wilc_set_power_mgmt(vif, 0, 0);
+
+ wilc_resolve_disconnect_aberration(vif);
+
+ netdev_dbg(dev, "[%s] Down IP\n", dev_iface->ifa_label);
+
+ ip_addr_buf = null_ip;
+ netdev_dbg(dev, "IP add=%d:%d:%d:%d\n",
+ ip_addr_buf[0], ip_addr_buf[1],
+ ip_addr_buf[2], ip_addr_buf[3]);
+
+ break;
+
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+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_LOW | 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 == 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)
+{
+ u8 *bssid, *bssid1;
+ int i = 0;
+
+ bssid = mac_header + 10;
+ bssid1 = mac_header + 4;
+
+ for (i = 0; i < wilc->vif_num; i++) {
+ if (wilc->vif[i]->mode == STATION_MODE)
+ if (ether_addr_equal_unaligned(bssid,
+ wilc->vif[i]->bssid))
+ return wilc->vif[i]->ndev;
+ if (wilc->vif[i]->mode == AP_MODE)
+ if (ether_addr_equal_unaligned(bssid1,
+ wilc->vif[i]->bssid))
+ return wilc->vif[i]->ndev;
+ }
+
+ return NULL;
+}
+
+void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
+{
+ struct wilc_vif *vif = netdev_priv(wilc_netdev);
+
+ memcpy(vif->bssid, bssid, 6);
+ vif->mode = mode;
+}
+
+int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
+{
+ u8 i = 0;
+ u8 null_bssid[6] = {0};
+ u8 ret_val = 0;
+
+ for (i = 0; i < wilc->vif_num; i++)
+ if (memcmp(wilc->vif[i]->bssid, null_bssid, 6))
+ ret_val++;
+
+ return ret_val;
+}
+
+static int linux_wlan_txq_task(void *vp)
+{
+ int ret;
+ u32 txq_count;
+ struct net_device *dev = vp;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+
+ 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(dev, &txq_count);
+ if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
+ if (netif_queue_stopped(wl->vif[0]->ndev))
+ netif_wake_queue(wl->vif[0]->ndev);
+ if (netif_queue_stopped(wl->vif[1]->ndev))
+ netif_wake_queue(wl->vif[1]->ndev);
+ }
+ } while (ret == WILC_TX_ERR_NO_BUF && !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, ret = 0;
+ 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);
+ ret = -1;
+ goto fail;
+ }
+ wilc->firmware = wilc_firmware;
+
+fail:
+
+ return ret;
+}
+
+static int linux_wlan_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 < 0)
+ 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 < 0)
+ return ret;
+
+ release_firmware(wilc->firmware);
+ wilc->firmware = NULL;
+
+ netdev_dbg(dev, "Download Succeeded\n");
+
+ return 0;
+}
+
+static int linux_wlan_init_test_config(struct net_device *dev,
+ struct wilc_vif *vif)
+{
+ unsigned char c_val[64];
+ struct wilc *wilc = vif->wilc;
+ struct wilc_priv *priv;
+ struct host_if_drv *hif_drv;
+
+ netdev_dbg(dev, "Start configuring Firmware\n");
+ priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
+ hif_drv = (struct host_if_drv *)priv->hif_drv;
+ netdev_dbg(dev, "Host = %p\n", hif_drv);
+ wilc_get_chipid(wilc, false);
+
+ *(int *)c_val = 1;
+
+ if (!wilc_wlan_cfg_set(vif, 1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0))
+ goto fail;
+
+ c_val[0] = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_PC_TEST_MODE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = INFRASTRUCTURE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = AUTORATE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = G_MIXED_11B_2_MODE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, c_val, 1, 0,
+ 0))
+ goto fail;
+
+ c_val[0] = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = G_SHORT_PREAMBLE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = AUTO_PROT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = ACTIVE_SCAN;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = SITE_SURVEY_OFF;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, c_val, 1, 0, 0))
+ goto fail;
+
+ *((int *)c_val) = 0xffff;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, c_val, 2, 0, 0))
+ goto fail;
+
+ *((int *)c_val) = 2346;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0))
+ goto fail;
+
+ c_val[0] = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = NO_POWERSAVE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = NO_SECURITY; /* NO_ENCRYPT, 0x79 */
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = OPEN_SYSTEM;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, c_val, 1, 0, 0))
+ goto fail;
+
+ strcpy(c_val, "123456790abcdef1234567890");
+ if (!wilc_wlan_cfg_set(vif, 0, WID_WEP_KEY_VALUE, c_val,
+ (strlen(c_val) + 1), 0, 0))
+ goto fail;
+
+ strcpy(c_val, "12345678");
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11I_PSK, c_val, (strlen(c_val)), 0,
+ 0))
+ goto fail;
+
+ strcpy(c_val, "password");
+ if (!wilc_wlan_cfg_set(vif, 0, WID_1X_KEY, c_val, (strlen(c_val) + 1),
+ 0, 0))
+ goto fail;
+
+ c_val[0] = 192;
+ c_val[1] = 168;
+ c_val[2] = 1;
+ c_val[3] = 112;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_1X_SERV_ADDR, c_val, 4, 0, 0))
+ goto fail;
+
+ c_val[0] = 3;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = 3;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = NORMAL_ACK;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1,
+ 0, 0))
+ goto fail;
+
+ c_val[0] = 48;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0,
+ 0))
+ goto fail;
+
+ c_val[0] = 28;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0,
+ 0))
+ goto fail;
+
+ *((int *)c_val) = 100;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, c_val, 2, 0, 0))
+ goto fail;
+
+ c_val[0] = REKEY_DISABLE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, c_val, 1, 0, 0))
+ goto fail;
+
+ *((int *)c_val) = 84600;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, c_val, 4, 0, 0))
+ goto fail;
+
+ *((int *)c_val) = 500;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, c_val, 4, 0,
+ 0))
+ goto fail;
+
+ c_val[0] = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0,
+ 0))
+ goto fail;
+
+ c_val[0] = G_SELF_CTS_PROT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = HT_MIXED_MODE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, c_val, 1, 0,
+ 0))
+ goto fail;
+
+ c_val[0] = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0,
+ 0))
+ goto fail;
+
+ c_val[0] = DETECT_PROTECT_REPORT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1,
+ 0, 0))
+ goto fail;
+
+ c_val[0] = RTS_CTS_NONHT_PROT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0,
+ 0))
+ goto fail;
+
+ c_val[0] = MIMO_MODE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_SMPS_MODE, c_val, 1, 0, 0))
+ goto fail;
+
+ c_val[0] = 7;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0,
+ 0))
+ goto fail;
+
+ c_val[0] = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1,
+ 1, 1))
+ goto fail;
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+static void wlan_deinit_locks(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ mutex_destroy(&wilc->hif_cs);
+ mutex_destroy(&wilc->rxq_cs);
+ mutex_destroy(&wilc->txq_add_to_head_cs);
+}
+
+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);
+ wilc_wlan_cleanup(dev);
+ wlan_deinit_locks(dev);
+
+ wl->initialized = false;
+
+ netdev_dbg(dev, "wilc1000 deinitialization Done\n");
+ } else {
+ netdev_dbg(dev, "wilc1000 is not initialized\n");
+ }
+}
+
+static void wlan_init_locks(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+
+ mutex_init(&wl->hif_cs);
+ mutex_init(&wl->rxq_cs);
+
+ 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);
+}
+
+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(linux_wlan_txq_task, (void *)dev,
+ "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 = MAC_STATUS_INIT;
+ wl->close = 0;
+
+ wlan_init_locks(dev);
+
+ ret = wilc_wlan_init(dev);
+ if (ret < 0) {
+ ret = -EIO;
+ goto fail_locks;
+ }
+
+ if (wl->gpio_irq && init_irq(dev)) {
+ ret = -EIO;
+ goto fail_locks;
+ }
+
+ ret = wlan_initialize_threads(dev);
+ if (ret < 0) {
+ ret = -EIO;
+ goto fail_wilc_wlan;
+ }
+
+ if (!wl->dev_irq_num &&
+ wl->hif_func->enable_interrupt &&
+ wl->hif_func->enable_interrupt(wl)) {
+ ret = -EIO;
+ goto fail_irq_init;
+ }
+
+ if (wilc_wlan_get_firmware(dev)) {
+ ret = -EIO;
+ goto fail_irq_enable;
+ }
+
+ ret = wilc1000_firmware_download(dev);
+ if (ret < 0) {
+ ret = -EIO;
+ goto fail_irq_enable;
+ }
+
+ ret = linux_wlan_start_firmware(dev);
+ if (ret < 0) {
+ ret = -EIO;
+ 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 = linux_wlan_init_test_config(dev, vif);
+
+ if (ret < 0) {
+ netdev_err(dev, "Failed to configure firmware\n");
+ ret = -EIO;
+ goto fail_fw_start;
+ }
+
+ wl->initialized = true;
+ return 0;
+
+fail_fw_start:
+ wilc_wlan_stop(wl);
+
+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);
+
+ wlan_deinitialize_threads(dev);
+fail_wilc_wlan:
+ wilc_wlan_cleanup(dev);
+fail_locks:
+ wlan_deinit_locks(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;
+ struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
+ unsigned char mac_add[ETH_ALEN] = {0};
+ int ret = 0;
+ int i = 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 < 0)
+ return ret;
+
+ ret = wilc_wlan_initialize(ndev, vif);
+ if (ret < 0) {
+ wilc_deinit_host_int(ndev);
+ return ret;
+ }
+
+ for (i = 0; i < wl->vif_num; i++) {
+ if (ndev == wl->vif[i]->ndev) {
+ wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
+ vif->iftype, vif->ifc_id,
+ false);
+ wilc_set_operation_mode(vif, vif->iftype);
+ break;
+ }
+ }
+
+ wilc_get_mac_address(vif, mac_add);
+ netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
+ memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN);
+ memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN);
+
+ 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++;
+ priv->p2p.local_random = 0x01;
+ 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, false, 0, NULL);
+ return;
+ }
+
+ if (dev->mc.count == 0) {
+ wilc_setup_multicast_filter(vif, true, 0, NULL);
+ return;
+ }
+
+ mc_list = kmalloc_array(dev->mc.count, ETH_ALEN, GFP_KERNEL);
+ 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, true, dev->mc.count, mc_list))
+ kfree(mc_list);
+}
+
+static void linux_wlan_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;
+ char *udp_buf;
+ struct iphdr *ih;
+ struct ethhdr *eth_h;
+
+ 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;
+
+ eth_h = (struct ethhdr *)(skb->data);
+ if (eth_h->h_proto == cpu_to_be16(0x8e88))
+ netdev_dbg(ndev, "EAPOL transmitted\n");
+
+ ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
+
+ udp_buf = (char *)ih + sizeof(struct iphdr);
+ if ((udp_buf[1] == 68 && udp_buf[3] == 67) ||
+ (udp_buf[1] == 67 && udp_buf[3] == 68))
+ netdev_dbg(ndev, "DHCP Message transmitted, type:%x %x %x\n",
+ udp_buf[248], udp_buf[249], udp_buf[250]);
+
+ vif->netstats.tx_packets++;
+ vif->netstats.tx_bytes += tx_data->size;
+ tx_data->bssid = wilc->vif[vif->idx]->bssid;
+ queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
+ tx_data->buff, tx_data->size,
+ linux_wlan_tx_complete);
+
+ if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
+ netif_stop_queue(wilc->vif[0]->ndev);
+ netif_stop_queue(wilc->vif[1]->ndev);
+ }
+
+ return 0;
+}
+
+static int wilc_mac_close(struct net_device *ndev)
+{
+ struct wilc_priv *priv;
+ struct wilc_vif *vif = netdev_priv(ndev);
+ struct host_if_drv *hif_drv;
+ struct wilc *wl;
+
+ if (!vif || !vif->ndev || !vif->ndev->ieee80211_ptr ||
+ !vif->ndev->ieee80211_ptr->wiphy)
+ return 0;
+
+ priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
+ wl = vif->wilc;
+
+ if (!priv)
+ return 0;
+
+ hif_drv = (struct host_if_drv *)priv->hif_drv;
+
+ netdev_dbg(ndev, "Mac close\n");
+
+ if (!wl)
+ return 0;
+
+ if (!hif_drv)
+ return 0;
+
+ 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);
+ wilc_wfi_deinit_mon_interface();
+ }
+
+ vif->mac_opened = 0;
+
+ return 0;
+}
+
+void wilc_frmw_to_linux(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 i = 0;
+ struct wilc_vif *vif;
+
+ for (i = 0; i < wilc->vif_num; i++) {
+ vif = netdev_priv(wilc->vif[i]->ndev);
+ if (vif->monitor_flag) {
+ wilc_wfi_monitor_rx(buff, size);
+ return;
+ }
+ }
+
+ vif = netdev_priv(wilc->vif[1]->ndev);
+ if ((buff[0] == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
+ (buff[0] == vif->frame_reg[1].type && vif->frame_reg[1].reg))
+ wilc_wfi_p2p_rx(wilc->vif[1]->ndev, buff, size);
+}
+
+static struct notifier_block g_dev_notifier = {
+ .notifier_call = dev_state_ev_handler
+};
+
+void wilc_netdev_cleanup(struct wilc *wilc)
+{
+ int i;
+
+ if (!wilc)
+ return;
+
+ if (wilc->vif[0]->ndev || wilc->vif[1]->ndev)
+ unregister_inetaddr_notifier(&g_dev_notifier);
+
+ if (wilc->firmware) {
+ release_firmware(wilc->firmware);
+ wilc->firmware = NULL;
+ }
+
+ if (wilc->vif[0]->ndev || wilc->vif[1]->ndev) {
+ for (i = 0; i < NUM_CONCURRENT_IFC; i++)
+ if (wilc->vif[i]->ndev)
+ if (wilc->vif[i]->mac_opened)
+ wilc_mac_close(wilc->vif[i]->ndev);
+
+ for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
+ unregister_netdev(wilc->vif[i]->ndev);
+ wilc_free_wiphy(wilc->vif[i]->ndev);
+ free_netdev(wilc->vif[i]->ndev);
+ }
+ }
+
+ flush_workqueue(wilc->hif_workqueue);
+ destroy_workqueue(wilc->hif_workqueue);
+ wilc_wlan_cfg_deinit(wilc);
+ kfree(wilc->bus_data);
+ kfree(wilc);
+}
+EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
+
+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,
+};
+
+int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
+ const struct wilc_hif_func *ops)
+{
+ int i, ret;
+ struct wilc_vif *vif;
+ struct net_device *ndev;
+ struct wilc *wl;
+
+ wl = kzalloc(sizeof(*wl), GFP_KERNEL);
+ if (!wl)
+ return -ENOMEM;
+
+ ret = wilc_wlan_cfg_init(wl);
+ if (ret)
+ goto free_wl;
+
+ *wilc = wl;
+ wl->io_type = io_type;
+ wl->hif_func = ops;
+ wl->enable_ps = true;
+ wl->chip_ps_state = CHIP_WAKEDUP;
+ INIT_LIST_HEAD(&wl->txq_head.list);
+ INIT_LIST_HEAD(&wl->rxq_head.list);
+
+ wl->hif_workqueue = create_singlethread_workqueue("WILC_wq");
+ if (!wl->hif_workqueue) {
+ ret = -ENOMEM;
+ goto free_cfg;
+ }
+
+ register_inetaddr_notifier(&g_dev_notifier);
+
+ for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
+ struct wireless_dev *wdev;
+
+ ndev = alloc_etherdev(sizeof(struct wilc_vif));
+ if (!ndev) {
+ ret = -ENOMEM;
+ goto free_ndev;
+ }
+
+ vif = netdev_priv(ndev);
+ memset(vif, 0, sizeof(struct wilc_vif));
+
+ if (i == 0) {
+ strcpy(ndev->name, "wlan%d");
+ vif->ifc_id = 1;
+ } else {
+ strcpy(ndev->name, "p2p%d");
+ vif->ifc_id = 0;
+ }
+ vif->wilc = *wilc;
+ vif->ndev = ndev;
+ wl->vif[i] = vif;
+ wl->vif_num = i;
+ vif->idx = wl->vif_num;
+
+ ndev->netdev_ops = &wilc_netdev_ops;
+
+ wdev = wilc_create_wiphy(ndev, dev);
+ if (!wdev) {
+ netdev_err(ndev, "Can't register WILC Wiphy\n");
+ ret = -ENOMEM;
+ goto free_ndev;
+ }
+
+ SET_NETDEV_DEV(ndev, dev);
+
+ vif->ndev->ieee80211_ptr = wdev;
+ vif->ndev->ml_priv = vif;
+ wdev->netdev = vif->ndev;
+ vif->netstats.rx_packets = 0;
+ vif->netstats.tx_packets = 0;
+ vif->netstats.rx_bytes = 0;
+ vif->netstats.tx_bytes = 0;
+
+ ret = register_netdev(ndev);
+ if (ret)
+ goto free_ndev;
+
+ vif->iftype = STATION_MODE;
+ vif->mac_opened = 0;
+ }
+
+ return 0;
+
+free_ndev:
+ for (; i >= 0; i--) {
+ if (wl->vif[i]) {
+ if (wl->vif[i]->iftype == STATION_MODE)
+ unregister_netdev(wl->vif[i]->ndev);
+
+ if (wl->vif[i]->ndev) {
+ wilc_free_wiphy(wl->vif[i]->ndev);
+ free_netdev(wl->vif[i]->ndev);
+ }
+ }
+ }
+ unregister_inetaddr_notifier(&g_dev_notifier);
+ destroy_workqueue(wl->hif_workqueue);
+free_cfg:
+ wilc_wlan_cfg_deinit(wl);
+free_wl:
+ kfree(wl);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wilc_netdev_init);
+
+MODULE_LICENSE("GPL");
--
2.7.4


2018-09-26 10:26:21

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 14/19] wilc: add linux_mon.c

Moved '/driver/staging/wilc1000/linux_mon.c' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/linux_mon.c b/drivers/net/wireless/microchip/wilc/linux_mon.c
new file mode 100644
index 0000000..a634468
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/linux_mon.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "wilc_wfi_cfgoperations.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;
+
+static struct net_device *wilc_wfi_mon; /* global monitor netdev */
+
+static u8 srcadd[6];
+static u8 bssid[6];
+
+#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive*/
+
+#define TX_RADIOTAP_PRESENT ((1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_TX_FLAGS))
+
+void wilc_wfi_monitor_rx(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 (!wilc_wfi_mon)
+ return;
+
+ if (!netif_running(wilc_wfi_mon))
+ return;
+
+ /* Get WILC header */
+ memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET);
+ le32_to_cpus(&header);
+ /*
+ * The packet offset field contain info about what type of management
+ * the frame we are dealing with and ack status
+ */
+ pkt_offset = GET_PKT_OFFSET(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 = wilc_wfi_mon;
+ 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;
+
+ if (!wilc_wfi_mon)
+ return -EFAULT;
+
+ mon_priv = netdev_priv(wilc_wfi_mon);
+ 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 = wilc_wfi_mon;
+ 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;
+
+ memcpy(srcadd, &skb->data[10], 6);
+ memcpy(bssid, &skb->data[16], 6);
+ /*
+ * 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(const char *name,
+ struct net_device *real_dev)
+{
+ struct wilc_wfi_mon_priv *priv;
+
+ /*If monitor interface is already initialized, return it*/
+ if (wilc_wfi_mon)
+ return wilc_wfi_mon;
+
+ wilc_wfi_mon = alloc_etherdev(sizeof(struct wilc_wfi_mon_priv));
+ if (!wilc_wfi_mon)
+ return NULL;
+ wilc_wfi_mon->type = ARPHRD_IEEE80211_RADIOTAP;
+ strncpy(wilc_wfi_mon->name, name, IFNAMSIZ);
+ wilc_wfi_mon->name[IFNAMSIZ - 1] = 0;
+ wilc_wfi_mon->netdev_ops = &wilc_wfi_netdev_ops;
+
+ if (register_netdevice(wilc_wfi_mon)) {
+ netdev_err(real_dev, "register_netdevice failed\n");
+ return NULL;
+ }
+ priv = netdev_priv(wilc_wfi_mon);
+ if (!priv)
+ return NULL;
+
+ priv->real_ndev = real_dev;
+
+ return wilc_wfi_mon;
+}
+
+void wilc_wfi_deinit_mon_interface(void)
+{
+ bool rollback_lock = false;
+
+ if (wilc_wfi_mon) {
+ if (rtnl_is_locked()) {
+ rtnl_unlock();
+ rollback_lock = true;
+ }
+ unregister_netdev(wilc_wfi_mon);
+
+ if (rollback_lock) {
+ rtnl_lock();
+ rollback_lock = false;
+ }
+ wilc_wfi_mon = NULL;
+ }
+}
--
2.7.4


2018-09-26 10:26:24

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 15/19] wilc: add wilc_spi.c

Moved '/driver/staging/wilc1000/wilc_spi.c' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_spi.c b/drivers/net/wireless/microchip/wilc/wilc_spi.c
new file mode 100644
index 0000000..cef127b
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_spi.c
@@ -0,0 +1,1137 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/spi/spi.h>
+
+#include "wilc_wfi_netdevice.h"
+
+struct wilc_spi {
+ int crc_off;
+ int nint;
+ int has_thrpt_enh;
+};
+
+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;
+}
+
+/********************************************
+ *
+ * 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 N_OK 1
+#define N_FAIL 0
+#define N_RESET -1
+#define N_RETRY -2
+
+#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
+
+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_netdev_init(&wilc, NULL, 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;
+
+ 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);
+ 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_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
+ u8 clockless)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ u8 wb[32], rb[32];
+ u8 wix, rix;
+ u32 len2;
+ u8 rsp;
+ int len = 0;
+ int result = N_OK;
+ int retry;
+ u8 crc[2];
+
+ wb[0] = cmd;
+ switch (cmd) {
+ case CMD_SINGLE_READ: /* single word (4 bytes) read */
+ wb[1] = (u8)(adr >> 16);
+ wb[2] = (u8)(adr >> 8);
+ wb[3] = (u8)adr;
+ len = 5;
+ break;
+
+ case CMD_INTERNAL_READ: /* internal register read */
+ wb[1] = (u8)(adr >> 8);
+ if (clockless == 1)
+ wb[1] |= BIT(7);
+ wb[2] = (u8)adr;
+ wb[3] = 0x00;
+ len = 5;
+ break;
+
+ case CMD_TERMINATE:
+ wb[1] = 0x00;
+ wb[2] = 0x00;
+ wb[3] = 0x00;
+ len = 5;
+ break;
+
+ case CMD_REPEAT:
+ wb[1] = 0x00;
+ wb[2] = 0x00;
+ wb[3] = 0x00;
+ len = 5;
+ break;
+
+ case CMD_RESET:
+ wb[1] = 0xff;
+ wb[2] = 0xff;
+ wb[3] = 0xff;
+ len = 5;
+ break;
+
+ case CMD_DMA_WRITE: /* dma write */
+ case CMD_DMA_READ: /* dma read */
+ wb[1] = (u8)(adr >> 16);
+ wb[2] = (u8)(adr >> 8);
+ wb[3] = (u8)adr;
+ wb[4] = (u8)(sz >> 8);
+ wb[5] = (u8)(sz);
+ len = 7;
+ break;
+
+ case CMD_DMA_EXT_WRITE: /* dma extended write */
+ case CMD_DMA_EXT_READ: /* dma extended read */
+ wb[1] = (u8)(adr >> 16);
+ wb[2] = (u8)(adr >> 8);
+ wb[3] = (u8)adr;
+ wb[4] = (u8)(sz >> 16);
+ wb[5] = (u8)(sz >> 8);
+ wb[6] = (u8)(sz);
+ len = 8;
+ break;
+
+ case CMD_INTERNAL_WRITE: /* internal register write */
+ wb[1] = (u8)(adr >> 8);
+ if (clockless == 1)
+ wb[1] |= BIT(7);
+ wb[2] = (u8)(adr);
+ wb[3] = b[3];
+ wb[4] = b[2];
+ wb[5] = b[1];
+ wb[6] = b[0];
+ len = 8;
+ break;
+
+ case CMD_SINGLE_WRITE: /* single word write */
+ wb[1] = (u8)(adr >> 16);
+ wb[2] = (u8)(adr >> 8);
+ wb[3] = (u8)(adr);
+ wb[4] = b[3];
+ wb[5] = b[2];
+ wb[6] = b[1];
+ wb[7] = b[0];
+ len = 9;
+ break;
+
+ default:
+ result = N_FAIL;
+ break;
+ }
+
+ if (result != N_OK)
+ return result;
+
+ if (!spi_priv->crc_off)
+ wb[len - 1] = (crc7(0x7f, (const u8 *)&wb[0], len - 1)) << 1;
+ else
+ len -= 1;
+
+#define NUM_SKIP_BYTES (1)
+#define NUM_RSP_BYTES (2)
+#define NUM_DATA_HDR_BYTES (1)
+#define NUM_DATA_BYTES (4)
+#define NUM_CRC_BYTES (2)
+#define NUM_DUMMY_BYTES (3)
+ if (cmd == CMD_RESET ||
+ cmd == CMD_TERMINATE ||
+ cmd == CMD_REPEAT) {
+ len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES);
+ } else if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
+ int tmp = NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES
+ + NUM_DUMMY_BYTES;
+ if (!spi_priv->crc_off)
+ len2 = len + tmp + NUM_CRC_BYTES;
+ else
+ len2 = len + tmp;
+ } else {
+ len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES);
+ }
+#undef NUM_DUMMY_BYTES
+
+ if (len2 > ARRAY_SIZE(wb)) {
+ dev_err(&spi->dev, "spi buffer size too small (%d) (%zu)\n",
+ len2, ARRAY_SIZE(wb));
+ return N_FAIL;
+ }
+ /* zero spi write buffers. */
+ for (wix = len; wix < len2; wix++)
+ wb[wix] = 0;
+ rix = len;
+
+ if (wilc_spi_tx_rx(wilc, wb, rb, len2)) {
+ dev_err(&spi->dev, "Failed cmd write, bus error...\n");
+ return N_FAIL;
+ }
+
+ /*
+ * Command/Control response
+ */
+ if (cmd == CMD_RESET || cmd == CMD_TERMINATE || cmd == CMD_REPEAT)
+ rix++; /* skip 1 byte */
+
+ rsp = rb[rix++];
+
+ if (rsp != cmd) {
+ dev_err(&spi->dev,
+ "Failed cmd response, cmd (%02x), resp (%02x)\n",
+ cmd, rsp);
+ return N_FAIL;
+ }
+
+ /*
+ * State response
+ */
+ rsp = rb[rix++];
+ if (rsp != 0x00) {
+ dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
+ rsp);
+ return N_FAIL;
+ }
+
+ if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ ||
+ cmd == CMD_DMA_READ || cmd == CMD_DMA_EXT_READ) {
+ /*
+ * Data Respnose header
+ */
+ retry = 100;
+ do {
+ /*
+ * ensure there is room in buffer later
+ * to read data and crc
+ */
+ if (rix < len2) {
+ rsp = rb[rix++];
+ } else {
+ retry = 0;
+ break;
+ }
+ if (((rsp >> 4) & 0xf) == 0xf)
+ break;
+ } while (retry--);
+
+ if (retry <= 0) {
+ dev_err(&spi->dev,
+ "Error, data read response (%02x)\n", rsp);
+ return N_RESET;
+ }
+ }
+
+ if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
+ /*
+ * Read bytes
+ */
+ if ((rix + 3) < len2) {
+ b[0] = rb[rix++];
+ b[1] = rb[rix++];
+ b[2] = rb[rix++];
+ b[3] = rb[rix++];
+ } else {
+ dev_err(&spi->dev,
+ "buffer overrun when reading data.\n");
+ return N_FAIL;
+ }
+
+ if (!spi_priv->crc_off) {
+ /*
+ * Read Crc
+ */
+ if ((rix + 1) < len2) {
+ crc[0] = rb[rix++];
+ crc[1] = rb[rix++];
+ } else {
+ dev_err(&spi->dev,
+ "buffer overrun when reading crc.\n");
+ return N_FAIL;
+ }
+ }
+ } else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) {
+ int ix;
+
+ /* some data may be read in response to dummy bytes. */
+ for (ix = 0; (rix < len2) && (ix < sz); )
+ b[ix++] = rb[rix++];
+
+ sz -= ix;
+
+ if (sz > 0) {
+ int nbytes;
+
+ if (sz <= (DATA_PKT_SZ - ix))
+ nbytes = sz;
+ else
+ nbytes = DATA_PKT_SZ - ix;
+
+ /*
+ * Read bytes
+ */
+ if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev,
+ "Failed block read, bus err\n");
+ return N_FAIL;
+ }
+
+ /*
+ * 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 N_FAIL;
+ }
+
+ ix += nbytes;
+ sz -= nbytes;
+ }
+
+ /*
+ * if any data in left unread,
+ * then read the rest using normal DMA code.
+ */
+ while (sz > 0) {
+ int nbytes;
+
+ if (sz <= DATA_PKT_SZ)
+ nbytes = sz;
+ else
+ nbytes = DATA_PKT_SZ;
+
+ /*
+ * read data response only on the next DMA cycles not
+ * the first DMA since data response header is already
+ * handled above for the first DMA.
+ */
+ /*
+ * Data Respnose header
+ */
+ retry = 10;
+ do {
+ if (wilc_spi_rx(wilc, &rsp, 1)) {
+ dev_err(&spi->dev,
+ "Failed resp read, bus err\n");
+ result = N_FAIL;
+ break;
+ }
+ if (((rsp >> 4) & 0xf) == 0xf)
+ break;
+ } while (retry--);
+
+ if (result == N_FAIL)
+ break;
+
+ /*
+ * Read bytes
+ */
+ if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev,
+ "Failed block read, bus err\n");
+ result = N_FAIL;
+ break;
+ }
+
+ /*
+ * Read Crc
+ */
+ if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) {
+ dev_err(&spi->dev,
+ "Failed block crc read, bus err\n");
+ result = N_FAIL;
+ break;
+ }
+
+ ix += nbytes;
+ sz -= nbytes;
+ }
+ }
+ return result;
+}
+
+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 = 1;
+ 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 = N_FAIL;
+ break;
+ }
+
+ /*
+ * Write data
+ */
+ if (wilc_spi_tx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev,
+ "Failed data block write, bus error...\n");
+ result = N_FAIL;
+ 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 = N_FAIL;
+ break;
+ }
+ }
+
+ /*
+ * No need to wait for response
+ */
+ ix += nbytes;
+ sz -= nbytes;
+ } while (sz);
+
+ return result;
+}
+
+/********************************************
+ *
+ * Spi Internal Read/Write Function
+ *
+ ********************************************/
+
+static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result;
+
+ cpu_to_le32s(&dat);
+ result = spi_cmd_complete(wilc, CMD_INTERNAL_WRITE, adr, (u8 *)&dat, 4,
+ 0);
+ if (result != N_OK)
+ dev_err(&spi->dev, "Failed internal write cmd...\n");
+
+ return result;
+}
+
+static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result;
+
+ result = spi_cmd_complete(wilc, CMD_INTERNAL_READ, adr, (u8 *)data, 4,
+ 0);
+ if (result != N_OK) {
+ dev_err(&spi->dev, "Failed internal read cmd...\n");
+ return 0;
+ }
+
+ le32_to_cpus(data);
+
+ return 1;
+}
+
+/********************************************
+ *
+ * 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 = N_OK;
+ u8 cmd = CMD_SINGLE_WRITE;
+ u8 clockless = 0;
+
+ cpu_to_le32s(&data);
+ if (addr < 0x30) {
+ /* Clockless register */
+ cmd = CMD_INTERNAL_WRITE;
+ clockless = 1;
+ }
+
+ result = spi_cmd_complete(wilc, cmd, addr, (u8 *)&data, 4, clockless);
+ if (result != N_OK)
+ dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr);
+
+ return result;
+}
+
+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 0;
+
+ result = spi_cmd_complete(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size, 0);
+ if (result != N_OK) {
+ dev_err(&spi->dev,
+ "Failed cmd, write block (%08x)...\n", addr);
+ return 0;
+ }
+
+ /*
+ * Data
+ */
+ result = spi_data_write(wilc, buf, size);
+ if (result != N_OK)
+ dev_err(&spi->dev, "Failed block data write...\n");
+
+ return 1;
+}
+
+static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result = N_OK;
+ u8 cmd = CMD_SINGLE_READ;
+ u8 clockless = 0;
+
+ if (addr < 0x30) {
+ /* Clockless register */
+ cmd = CMD_INTERNAL_READ;
+ clockless = 1;
+ }
+
+ result = spi_cmd_complete(wilc, cmd, addr, (u8 *)data, 4, clockless);
+ if (result != N_OK) {
+ dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr);
+ return 0;
+ }
+
+ le32_to_cpus(data);
+
+ return 1;
+}
+
+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 0;
+
+ result = spi_cmd_complete(wilc, CMD_DMA_EXT_READ, addr, buf, size, 0);
+ if (result != N_OK) {
+ dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr);
+ return 0;
+ }
+
+ return 1;
+}
+
+/********************************************
+ *
+ * Bus interfaces
+ *
+ ********************************************/
+
+static int _wilc_spi_deinit(struct wilc *wilc)
+{
+ /*
+ * TODO:
+ */
+ return 1;
+}
+
+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;
+
+ if (isinit) {
+ if (!wilc_spi_read_reg(wilc, 0x1000, &chipid)) {
+ dev_err(&spi->dev, "Fail cmd read chip id...\n");
+ return 0;
+ }
+ return 1;
+ }
+
+ /*
+ * configure protocol
+ */
+
+ /*
+ * TODO: We can remove the CRC trials if there is a definite
+ * way to reset
+ */
+ /* the SPI to it's initial value. */
+ if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg)) {
+ /*
+ * 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");
+ if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg)) {
+ /*
+ * Read failed with both CRC on and off,
+ * something went bad
+ */
+ dev_err(&spi->dev, "Failed internal read protocol\n");
+ return 0;
+ }
+ }
+ if (spi_priv->crc_off == 0) {
+ reg &= ~0xc; /* disable crc checking */
+ reg &= ~0x70;
+ reg |= (0x5 << 4);
+ if (!spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg)) {
+ dev_err(&spi->dev,
+ "[wilc spi %d]: Failed internal write reg\n",
+ __LINE__);
+ return 0;
+ }
+ spi_priv->crc_off = 1;
+ }
+
+ /*
+ * make sure can read back chip id correctly
+ */
+ if (!wilc_spi_read_reg(wilc, 0x1000, &chipid)) {
+ dev_err(&spi->dev, "Fail cmd read chip id...\n");
+ return 0;
+ }
+
+ spi_priv->has_thrpt_enh = 1;
+
+ isinit = 1;
+
+ return 1;
+}
+
+static int wilc_spi_read_size(struct wilc *wilc, u32 *size)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ int ret;
+
+ if (spi_priv->has_thrpt_enh) {
+ ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
+ size);
+ *size = *size & IRQ_DMA_WD_CNT_MASK;
+ } else {
+ u32 tmp;
+ u32 byte_cnt;
+
+ ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE,
+ &byte_cnt);
+ if (!ret) {
+ dev_err(&spi->dev,
+ "Failed read WILC_VMM_TO_HOST_SIZE ...\n");
+ return ret;
+ }
+ tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK;
+ *size = tmp;
+ }
+
+ return ret;
+}
+
+static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ int ret;
+ u32 tmp;
+ u32 byte_cnt;
+ int happened, j;
+ u32 unknown_mask;
+ u32 irq_flags;
+ int k = IRG_FLAGS_OFFSET + 5;
+
+ if (spi_priv->has_thrpt_enh) {
+ ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
+ int_status);
+ return ret;
+ }
+ ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE, &byte_cnt);
+ if (!ret) {
+ dev_err(&spi->dev,
+ "Failed read WILC_VMM_TO_HOST_SIZE ...\n");
+ return ret;
+ }
+ tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK;
+
+ j = 0;
+ do {
+ happened = 0;
+
+ wilc_spi_read_reg(wilc, 0x1a90, &irq_flags);
+ tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET);
+
+ if (spi_priv->nint > 5) {
+ wilc_spi_read_reg(wilc, 0x1a94, &irq_flags);
+ tmp |= (((irq_flags >> 0) & 0x7) << k);
+ }
+
+ unknown_mask = ~((1ul << spi_priv->nint) - 1);
+
+ if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) {
+ dev_err(&spi->dev,
+ "Unexpected interrupt(2):j=%d,tmp=%x,mask=%x\n",
+ j, tmp, unknown_mask);
+ happened = 1;
+ }
+
+ j++;
+ } while (happened);
+
+ *int_status = tmp;
+
+ return ret;
+}
+
+static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ int ret;
+ u32 flags;
+ u32 tbl_ctl;
+
+ if (spi_priv->has_thrpt_enh) {
+ ret = spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE,
+ val);
+ return ret;
+ }
+
+ flags = val & (BIT(MAX_NUM_INT) - 1);
+ if (flags) {
+ int i;
+
+ ret = 1;
+ for (i = 0; i < spi_priv->nint; i++) {
+ /*
+ * No matter what you write 1 or 0,
+ * it will clear interrupt.
+ */
+ if (flags & 1)
+ ret = wilc_spi_write_reg(wilc,
+ 0x10c8 + i * 4, 1);
+ if (!ret)
+ break;
+ flags >>= 1;
+ }
+ if (!ret) {
+ dev_err(&spi->dev,
+ "Failed wilc_spi_write_reg, set reg %x ...\n",
+ 0x10c8 + i * 4);
+ return ret;
+ }
+ for (i = spi_priv->nint; i < MAX_NUM_INT; i++) {
+ if (flags & 1)
+ dev_err(&spi->dev,
+ "Unexpected interrupt cleared %d...\n",
+ i);
+ flags >>= 1;
+ }
+ }
+
+ tbl_ctl = 0;
+ /* select VMM table 0 */
+ if (val & SEL_VMM_TBL0)
+ tbl_ctl |= BIT(0);
+ /* select VMM table 1 */
+ if (val & SEL_VMM_TBL1)
+ tbl_ctl |= BIT(1);
+
+ ret = wilc_spi_write_reg(wilc, WILC_VMM_TBL_CTL, tbl_ctl);
+ if (!ret) {
+ dev_err(&spi->dev, "fail write reg vmm_tbl_ctl...\n");
+ return ret;
+ }
+
+ if (val & EN_VMM) {
+ /*
+ * enable vmm transfer.
+ */
+ ret = wilc_spi_write_reg(wilc, WILC_VMM_CORE_CTL, 1);
+ if (!ret) {
+ dev_err(&spi->dev, "fail write reg vmm_core_ctl...\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ u32 reg;
+ int ret, i;
+
+ if (nint > MAX_NUM_INT) {
+ dev_err(&spi->dev, "Too many interrupts (%d)...\n", nint);
+ return 0;
+ }
+
+ spi_priv->nint = nint;
+
+ /*
+ * 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 0;
+ }
+ 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 0;
+ }
+
+ /*
+ * 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 0;
+ }
+
+ 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 0;
+ }
+ 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 0;
+ }
+
+ 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 0;
+ }
+ }
+
+ return 1;
+}
+
+/* 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.7.4


2018-09-26 10:26:25

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 09/19] wilc: add wilc_wlan.c

Moved '/driver/staging/wilc1000/wilc_wlan.c' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_wlan.c b/drivers/net/wireless/microchip/wilc/wilc_wlan.c
new file mode 100644
index 0000000..a48c906
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_wlan.c
@@ -0,0 +1,1350 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include "wilc_wfi_netdevice.h"
+#include "wilc_wlan_cfg.h"
+
+static inline bool is_wilc1000(u32 id)
+{
+ return ((id & 0xfffff000) == 0x100000 ? true : false);
+}
+
+static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
+{
+ mutex_lock(&wilc->hif_cs);
+ if (acquire == ACQUIRE_AND_WAKEUP)
+ chip_wakeup(wilc);
+}
+
+static inline void release_bus(struct wilc *wilc, enum bus_release release)
+{
+ if (release == RELEASE_ALLOW_SLEEP)
+ chip_allow_sleep(wilc);
+ mutex_unlock(&wilc->hif_cs);
+}
+
+static void wilc_wlan_txq_remove(struct wilc *wilc, struct txq_entry_t *tqe)
+{
+ list_del(&tqe->list);
+ wilc->txq_entries -= 1;
+}
+
+static struct txq_entry_t *
+wilc_wlan_txq_remove_from_head(struct net_device *dev)
+{
+ struct txq_entry_t *tqe = NULL;
+ unsigned long flags;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
+
+ if (!list_empty(&wilc->txq_head.list)) {
+ tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t,
+ list);
+ list_del(&tqe->list);
+ wilc->txq_entries -= 1;
+ }
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
+ return tqe;
+}
+
+static void wilc_wlan_txq_add_to_tail(struct net_device *dev,
+ struct txq_entry_t *tqe)
+{
+ unsigned long flags;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
+
+ list_add_tail(&tqe->list, &wilc->txq_head.list);
+ wilc->txq_entries += 1;
+
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
+
+ complete(&wilc->txq_event);
+}
+
+static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif,
+ struct txq_entry_t *tqe)
+{
+ unsigned long flags;
+ struct wilc *wilc = vif->wilc;
+
+ mutex_lock(&wilc->txq_add_to_head_cs);
+
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
+
+ list_add(&tqe->list, &wilc->txq_head.list);
+ wilc->txq_entries += 1;
+
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
+ mutex_unlock(&wilc->txq_add_to_head_cs);
+ complete(&wilc->txq_event);
+}
+
+#define NOT_TCP_ACK (-1)
+
+static inline void add_tcp_session(struct wilc_vif *vif, u32 src_prt,
+ u32 dst_prt, u32 seq)
+{
+ struct tcp_ack_filter *f = &vif->ack_filter;
+
+ if (f->tcp_session < 2 * MAX_TCP_SESSION) {
+ f->ack_session_info[f->tcp_session].seq_num = seq;
+ f->ack_session_info[f->tcp_session].bigger_ack_num = 0;
+ f->ack_session_info[f->tcp_session].src_port = src_prt;
+ f->ack_session_info[f->tcp_session].dst_port = dst_prt;
+ f->tcp_session++;
+ }
+}
+
+static inline void update_tcp_session(struct wilc_vif *vif, u32 index, u32 ack)
+{
+ struct tcp_ack_filter *f = &vif->ack_filter;
+
+ if (index < 2 * MAX_TCP_SESSION &&
+ ack > f->ack_session_info[index].bigger_ack_num)
+ f->ack_session_info[index].bigger_ack_num = ack;
+}
+
+static inline void add_tcp_pending_ack(struct wilc_vif *vif, u32 ack,
+ u32 session_index,
+ struct txq_entry_t *txqe)
+{
+ struct tcp_ack_filter *f = &vif->ack_filter;
+ u32 i = f->pending_base + f->pending_acks_idx;
+
+ if (i < MAX_PENDING_ACKS) {
+ f->pending_acks[i].ack_num = ack;
+ f->pending_acks[i].txqe = txqe;
+ f->pending_acks[i].session_index = session_index;
+ txqe->ack_idx = i;
+ f->pending_acks_idx++;
+ }
+}
+
+static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
+{
+ void *buffer = tqe->buffer;
+ const struct ethhdr *eth_hdr_ptr = buffer;
+ int i;
+ unsigned long flags;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+ struct tcp_ack_filter *f = &vif->ack_filter;
+ const struct iphdr *ip_hdr_ptr;
+ const struct tcphdr *tcp_hdr_ptr;
+ u32 ihl, total_length, data_offset;
+
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
+
+ if (eth_hdr_ptr->h_proto != htons(ETH_P_IP))
+ goto out;
+
+ ip_hdr_ptr = buffer + ETH_HLEN;
+
+ if (ip_hdr_ptr->protocol != IPPROTO_TCP)
+ goto out;
+
+ ihl = ip_hdr_ptr->ihl << 2;
+ tcp_hdr_ptr = buffer + ETH_HLEN + ihl;
+ total_length = ntohs(ip_hdr_ptr->tot_len);
+
+ data_offset = tcp_hdr_ptr->doff << 2;
+ if (total_length == (ihl + data_offset)) {
+ u32 seq_no, ack_no;
+
+ seq_no = ntohl(tcp_hdr_ptr->seq);
+ ack_no = ntohl(tcp_hdr_ptr->ack_seq);
+ for (i = 0; i < f->tcp_session; i++) {
+ u32 j = f->ack_session_info[i].seq_num;
+
+ if (i < 2 * MAX_TCP_SESSION &&
+ j == seq_no) {
+ update_tcp_session(vif, i, ack_no);
+ break;
+ }
+ }
+ if (i == f->tcp_session)
+ add_tcp_session(vif, 0, 0, seq_no);
+
+ add_tcp_pending_ack(vif, ack_no, i, tqe);
+ }
+
+out:
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
+}
+
+static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+ struct tcp_ack_filter *f = &vif->ack_filter;
+ u32 i = 0;
+ u32 dropped = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
+ for (i = f->pending_base;
+ i < (f->pending_base + f->pending_acks_idx); i++) {
+ u32 index;
+ u32 bigger_ack_num;
+
+ if (i >= MAX_PENDING_ACKS)
+ break;
+
+ index = f->pending_acks[i].session_index;
+
+ if (index >= 2 * MAX_TCP_SESSION)
+ break;
+
+ bigger_ack_num = f->ack_session_info[index].bigger_ack_num;
+
+ if (f->pending_acks[i].ack_num < bigger_ack_num) {
+ struct txq_entry_t *tqe;
+
+ tqe = f->pending_acks[i].txqe;
+ if (tqe) {
+ wilc_wlan_txq_remove(wilc, tqe);
+ tqe->status = 1;
+ if (tqe->tx_complete_func)
+ tqe->tx_complete_func(tqe->priv,
+ tqe->status);
+ kfree(tqe);
+ dropped++;
+ }
+ }
+ }
+ f->pending_acks_idx = 0;
+ f->tcp_session = 0;
+
+ if (f->pending_base == 0)
+ f->pending_base = MAX_TCP_SESSION;
+ else
+ f->pending_base = 0;
+
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
+
+ while (dropped > 0) {
+ wait_for_completion_timeout(&wilc->txq_event,
+ msecs_to_jiffies(1));
+ dropped--;
+ }
+}
+
+void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value)
+{
+ vif->ack_filter.enabled = value;
+}
+
+static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,
+ u32 buffer_size)
+{
+ struct txq_entry_t *tqe;
+ struct wilc *wilc = vif->wilc;
+
+ netdev_dbg(vif->ndev, "Adding config packet ...\n");
+ if (wilc->quit) {
+ netdev_dbg(vif->ndev, "Return due to clear function\n");
+ complete(&wilc->cfg_event);
+ return 0;
+ }
+
+ tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
+ if (!tqe)
+ return 0;
+
+ tqe->type = WILC_CFG_PKT;
+ tqe->buffer = buffer;
+ tqe->buffer_size = buffer_size;
+ tqe->tx_complete_func = NULL;
+ tqe->priv = NULL;
+ tqe->ack_idx = NOT_TCP_ACK;
+
+ wilc_wlan_txq_add_to_head(vif, tqe);
+
+ return 1;
+}
+
+int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
+ u32 buffer_size, wilc_tx_complete_func_t func)
+{
+ struct txq_entry_t *tqe;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc;
+
+ wilc = vif->wilc;
+
+ if (wilc->quit)
+ return 0;
+
+ tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
+
+ if (!tqe)
+ return 0;
+ tqe->type = WILC_NET_PKT;
+ tqe->buffer = buffer;
+ tqe->buffer_size = buffer_size;
+ tqe->tx_complete_func = func;
+ tqe->priv = priv;
+
+ tqe->ack_idx = NOT_TCP_ACK;
+ if (vif->ack_filter.enabled)
+ tcp_process(dev, tqe);
+ wilc_wlan_txq_add_to_tail(dev, tqe);
+ return wilc->txq_entries;
+}
+
+int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
+ u32 buffer_size, wilc_tx_complete_func_t func)
+{
+ struct txq_entry_t *tqe;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc;
+
+ wilc = vif->wilc;
+
+ if (wilc->quit)
+ return 0;
+
+ tqe = kmalloc(sizeof(*tqe), GFP_KERNEL);
+
+ if (!tqe)
+ return 0;
+ tqe->type = WILC_MGMT_PKT;
+ tqe->buffer = buffer;
+ tqe->buffer_size = buffer_size;
+ tqe->tx_complete_func = func;
+ tqe->priv = priv;
+ tqe->ack_idx = NOT_TCP_ACK;
+ wilc_wlan_txq_add_to_tail(dev, tqe);
+ return 1;
+}
+
+static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc)
+{
+ struct txq_entry_t *tqe = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
+
+ if (!list_empty(&wilc->txq_head.list))
+ tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t,
+ list);
+
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
+
+ return tqe;
+}
+
+static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
+ struct txq_entry_t *tqe)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wilc->txq_spinlock, flags);
+
+ if (!list_is_last(&tqe->list, &wilc->txq_head.list))
+ tqe = list_next_entry(tqe, list);
+ else
+ tqe = NULL;
+ spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
+
+ return tqe;
+}
+
+static void wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)
+{
+ if (wilc->quit)
+ return;
+
+ mutex_lock(&wilc->rxq_cs);
+ list_add_tail(&rqe->list, &wilc->rxq_head.list);
+ mutex_unlock(&wilc->rxq_cs);
+}
+
+static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
+{
+ struct rxq_entry_t *rqe = NULL;
+
+ mutex_lock(&wilc->rxq_cs);
+ if (!list_empty(&wilc->rxq_head.list)) {
+ rqe = list_first_entry(&wilc->rxq_head.list, struct rxq_entry_t,
+ list);
+ list_del(&rqe->list);
+ }
+ mutex_unlock(&wilc->rxq_cs);
+ return rqe;
+}
+
+void chip_allow_sleep(struct wilc *wilc)
+{
+ u32 reg = 0;
+
+ wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
+
+ wilc->hif_func->hif_write_reg(wilc, 0xf0, reg & ~BIT(0));
+ wilc->hif_func->hif_write_reg(wilc, 0xfa, 0);
+}
+EXPORT_SYMBOL_GPL(chip_allow_sleep);
+
+void chip_wakeup(struct wilc *wilc)
+{
+ u32 reg, clk_status_reg;
+
+ if ((wilc->io_type & 0x1) == HIF_SPI) {
+ do {
+ wilc->hif_func->hif_read_reg(wilc, 1, &reg);
+ wilc->hif_func->hif_write_reg(wilc, 1, reg | BIT(1));
+ wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1));
+
+ do {
+ usleep_range(2 * 1000, 2 * 1000);
+ wilc_get_chipid(wilc, true);
+ } while (wilc_get_chipid(wilc, true) == 0);
+ } while (wilc_get_chipid(wilc, true) == 0);
+ } else if ((wilc->io_type & 0x1) == HIF_SDIO) {
+ wilc->hif_func->hif_write_reg(wilc, 0xfa, 1);
+ usleep_range(200, 400);
+ wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
+ do {
+ wilc->hif_func->hif_write_reg(wilc, 0xf0,
+ reg | BIT(0));
+ wilc->hif_func->hif_read_reg(wilc, 0xf1,
+ &clk_status_reg);
+
+ while ((clk_status_reg & 0x1) == 0) {
+ usleep_range(2 * 1000, 2 * 1000);
+
+ wilc->hif_func->hif_read_reg(wilc, 0xf1,
+ &clk_status_reg);
+ }
+ if ((clk_status_reg & 0x1) == 0) {
+ wilc->hif_func->hif_write_reg(wilc, 0xf0,
+ reg & (~BIT(0)));
+ }
+ } while ((clk_status_reg & 0x1) == 0);
+ }
+
+ if (wilc->chip_ps_state == CHIP_SLEEPING_MANUAL) {
+ if (wilc_get_chipid(wilc, false) < 0x1002b0) {
+ u32 val32;
+
+ wilc->hif_func->hif_read_reg(wilc, 0x1e1c, &val32);
+ val32 |= BIT(6);
+ wilc->hif_func->hif_write_reg(wilc, 0x1e1c, val32);
+
+ wilc->hif_func->hif_read_reg(wilc, 0x1e9c, &val32);
+ val32 |= BIT(6);
+ wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32);
+ }
+ }
+ wilc->chip_ps_state = CHIP_WAKEDUP;
+}
+EXPORT_SYMBOL_GPL(chip_wakeup);
+
+void wilc_chip_sleep_manually(struct wilc *wilc)
+{
+ if (wilc->chip_ps_state != CHIP_WAKEDUP)
+ return;
+ acquire_bus(wilc, ACQUIRE_ONLY);
+
+ chip_allow_sleep(wilc);
+ wilc->hif_func->hif_write_reg(wilc, 0x10a8, 1);
+
+ wilc->chip_ps_state = CHIP_SLEEPING_MANUAL;
+ release_bus(wilc, RELEASE_ONLY);
+}
+EXPORT_SYMBOL_GPL(wilc_chip_sleep_manually);
+
+void host_wakeup_notify(struct wilc *wilc)
+{
+ acquire_bus(wilc, ACQUIRE_ONLY);
+ wilc->hif_func->hif_write_reg(wilc, 0x10b0, 1);
+ release_bus(wilc, RELEASE_ONLY);
+}
+EXPORT_SYMBOL_GPL(host_wakeup_notify);
+
+void host_sleep_notify(struct wilc *wilc)
+{
+ acquire_bus(wilc, ACQUIRE_ONLY);
+ wilc->hif_func->hif_write_reg(wilc, 0x10ac, 1);
+ release_bus(wilc, RELEASE_ONLY);
+}
+EXPORT_SYMBOL_GPL(host_sleep_notify);
+
+int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
+{
+ int i, entries = 0;
+ u32 sum;
+ u32 reg;
+ u32 offset = 0;
+ int vmm_sz = 0;
+ struct txq_entry_t *tqe;
+ int ret = 0;
+ int counter;
+ int timeout;
+ u32 vmm_table[WILC_VMM_TBL_SIZE];
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+ const struct wilc_hif_func *func;
+ u8 *txb = wilc->tx_buffer;
+
+ if (wilc->quit)
+ goto out;
+
+ mutex_lock(&wilc->txq_add_to_head_cs);
+ wilc_wlan_txq_filter_dup_tcp_ack(dev);
+ tqe = wilc_wlan_txq_get_first(wilc);
+ i = 0;
+ sum = 0;
+ do {
+ if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) {
+ if (tqe->type == WILC_CFG_PKT)
+ vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
+
+ else if (tqe->type == WILC_NET_PKT)
+ vmm_sz = ETH_ETHERNET_HDR_OFFSET;
+
+ else
+ vmm_sz = HOST_HDR_OFFSET;
+
+ vmm_sz += tqe->buffer_size;
+
+ if (vmm_sz & 0x3)
+ vmm_sz = (vmm_sz + 4) & ~0x3;
+
+ if ((sum + vmm_sz) > LINUX_TX_SIZE)
+ break;
+
+ vmm_table[i] = vmm_sz / 4;
+ if (tqe->type == WILC_CFG_PKT)
+ vmm_table[i] |= BIT(10);
+ cpu_to_le32s(&vmm_table[i]);
+
+ i++;
+ sum += vmm_sz;
+ tqe = wilc_wlan_txq_get_next(wilc, tqe);
+ } else {
+ break;
+ }
+ } while (1);
+
+ if (i == 0)
+ goto out;
+ vmm_table[i] = 0x0;
+
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
+ counter = 0;
+ func = wilc->hif_func;
+ do {
+ ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
+ if (!ret)
+ break;
+
+ if ((reg & 0x1) == 0)
+ break;
+
+ counter++;
+ if (counter > 200) {
+ counter = 0;
+ ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0);
+ break;
+ }
+ } while (!wilc->quit);
+
+ if (!ret)
+ goto out_release_bus;
+
+ timeout = 200;
+ do {
+ ret = func->hif_block_tx(wilc,
+ WILC_VMM_TBL_RX_SHADOW_BASE,
+ (u8 *)vmm_table,
+ ((i + 1) * 4));
+ if (!ret)
+ break;
+
+ ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);
+ if (!ret)
+ break;
+
+ do {
+ ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
+ if (!ret)
+ break;
+ if ((reg >> 2) & 0x1) {
+ entries = ((reg >> 3) & 0x3f);
+ break;
+ }
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+ } while (--timeout);
+ if (timeout <= 0) {
+ ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
+ break;
+ }
+
+ if (!ret)
+ break;
+
+ if (entries == 0) {
+ ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
+ if (!ret)
+ break;
+ reg &= ~BIT(0);
+ ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
+ if (!ret)
+ break;
+ break;
+ }
+ break;
+ } while (1);
+
+ if (!ret)
+ goto out_release_bus;
+
+ if (entries == 0) {
+ ret = WILC_TX_ERR_NO_BUF;
+ goto out_release_bus;
+ }
+
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+
+ offset = 0;
+ i = 0;
+ do {
+ u32 header, buffer_offset;
+ char *bssid;
+
+ tqe = wilc_wlan_txq_remove_from_head(dev);
+ if (!tqe)
+ break;
+
+ if (vmm_table[i] == 0)
+ break;
+
+ le32_to_cpus(&vmm_table[i]);
+ vmm_sz = (vmm_table[i] & 0x3ff);
+ vmm_sz *= 4;
+ header = (tqe->type << 31) |
+ (tqe->buffer_size << 15) |
+ vmm_sz;
+ if (tqe->type == WILC_MGMT_PKT)
+ header |= BIT(30);
+ else
+ header &= ~BIT(30);
+
+ cpu_to_le32s(&header);
+ memcpy(&txb[offset], &header, 4);
+ if (tqe->type == WILC_CFG_PKT) {
+ buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
+ } else if (tqe->type == WILC_NET_PKT) {
+ bssid = ((struct tx_complete_data *)(tqe->priv))->bssid;
+
+ buffer_offset = ETH_ETHERNET_HDR_OFFSET;
+ memcpy(&txb[offset + 8], bssid, 6);
+ } else {
+ buffer_offset = HOST_HDR_OFFSET;
+ }
+
+ memcpy(&txb[offset + buffer_offset],
+ tqe->buffer, tqe->buffer_size);
+ offset += vmm_sz;
+ i++;
+ tqe->status = 1;
+ if (tqe->tx_complete_func)
+ tqe->tx_complete_func(tqe->priv, tqe->status);
+ if (tqe->ack_idx != NOT_TCP_ACK &&
+ tqe->ack_idx < MAX_PENDING_ACKS)
+ vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL;
+ kfree(tqe);
+ } while (--entries);
+
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
+
+ ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
+ if (!ret)
+ goto out_release_bus;
+
+ ret = func->hif_block_tx_ext(wilc, 0, txb, offset);
+
+out_release_bus:
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+
+out:
+ mutex_unlock(&wilc->txq_add_to_head_cs);
+
+ *txq_count = wilc->txq_entries;
+ return ret;
+}
+
+static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
+{
+ int offset = 0;
+ u32 header;
+ u32 pkt_len, pkt_offset, tp_len;
+ int is_cfg_packet;
+ u8 *buff_ptr;
+
+ do {
+ buff_ptr = buffer + offset;
+ memcpy(&header, buff_ptr, 4);
+ le32_to_cpus(&header);
+
+ is_cfg_packet = (header >> 31) & 0x1;
+ pkt_offset = (header >> 22) & 0x1ff;
+ tp_len = (header >> 11) & 0x7ff;
+ pkt_len = header & 0x7ff;
+
+ if (pkt_len == 0 || tp_len == 0)
+ break;
+
+ if (pkt_offset & IS_MANAGMEMENT) {
+ pkt_offset &= ~(IS_MANAGMEMENT |
+ IS_MANAGMEMENT_CALLBACK |
+ IS_MGMT_STATUS_SUCCES);
+ buff_ptr += HOST_HDR_OFFSET;
+ wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len);
+ } else {
+ if (!is_cfg_packet) {
+ if (pkt_len > 0) {
+ wilc_frmw_to_linux(wilc, buff_ptr,
+ pkt_len,
+ pkt_offset);
+ }
+ } else {
+ struct wilc_cfg_rsp rsp;
+
+ buff_ptr += pkt_offset;
+
+ wilc_wlan_cfg_indicate_rx(wilc, buff_ptr,
+ pkt_len,
+ &rsp);
+ if (rsp.type == WILC_CFG_RSP) {
+ if (wilc->cfg_seq_no == rsp.seq_no)
+ complete(&wilc->cfg_event);
+ } else if (rsp.type == WILC_CFG_RSP_STATUS) {
+ wilc_mac_indicate(wilc);
+ }
+ }
+ }
+ offset += tp_len;
+ if (offset >= size)
+ break;
+ } while (1);
+}
+
+static void wilc_wlan_handle_rxq(struct wilc *wilc)
+{
+ int size;
+ u8 *buffer;
+ struct rxq_entry_t *rqe;
+
+ do {
+ if (wilc->quit) {
+ complete(&wilc->cfg_event);
+ break;
+ }
+ rqe = wilc_wlan_rxq_remove(wilc);
+ if (!rqe)
+ break;
+
+ buffer = rqe->buffer;
+ size = rqe->buffer_size;
+ wilc_wlan_handle_rx_buff(wilc, buffer, size);
+
+ kfree(rqe);
+ } while (1);
+}
+
+static void wilc_unknown_isr_ext(struct wilc *wilc)
+{
+ wilc->hif_func->hif_clear_int_ext(wilc, 0);
+}
+
+static void wilc_pllupdate_isr_ext(struct wilc *wilc, u32 int_stats)
+{
+ int trials = 10;
+
+ wilc->hif_func->hif_clear_int_ext(wilc, PLL_INT_CLR);
+
+ if (wilc->io_type == HIF_SDIO)
+ mdelay(WILC_PLL_TO_SDIO);
+ else
+ mdelay(WILC_PLL_TO_SPI);
+
+ while (!(is_wilc1000(wilc_get_chipid(wilc, true)) && --trials))
+ mdelay(1);
+}
+
+static void wilc_sleeptimer_isr_ext(struct wilc *wilc, u32 int_stats1)
+{
+ wilc->hif_func->hif_clear_int_ext(wilc, SLEEP_INT_CLR);
+}
+
+static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
+{
+ u32 offset = wilc->rx_buffer_offset;
+ u8 *buffer = NULL;
+ u32 size;
+ u32 retries = 0;
+ int ret = 0;
+ struct rxq_entry_t *rqe;
+
+ size = (int_status & 0x7fff) << 2;
+
+ while (!size && retries < 10) {
+ wilc->hif_func->hif_read_size(wilc, &size);
+ size = (size & 0x7fff) << 2;
+ retries++;
+ }
+
+ if (size <= 0)
+ return;
+
+ if (LINUX_RX_SIZE - offset < size)
+ offset = 0;
+
+ buffer = &wilc->rx_buffer[offset];
+
+ wilc->hif_func->hif_clear_int_ext(wilc, DATA_INT_CLR | ENABLE_RX_VMM);
+ ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size);
+ if (!ret)
+ return;
+
+ offset += size;
+ wilc->rx_buffer_offset = offset;
+ rqe = kmalloc(sizeof(*rqe), GFP_KERNEL);
+ if (!rqe)
+ return;
+
+ rqe->buffer = buffer;
+ rqe->buffer_size = size;
+ wilc_wlan_rxq_add(wilc, rqe);
+ wilc_wlan_handle_rxq(wilc);
+}
+
+void wilc_handle_isr(struct wilc *wilc)
+{
+ u32 int_status;
+
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
+ wilc->hif_func->hif_read_int(wilc, &int_status);
+
+ if (int_status & PLL_INT_EXT)
+ wilc_pllupdate_isr_ext(wilc, int_status);
+
+ if (int_status & DATA_INT_EXT)
+ wilc_wlan_handle_isr_ext(wilc, int_status);
+
+ if (int_status & SLEEP_INT_EXT)
+ wilc_sleeptimer_isr_ext(wilc, int_status);
+
+ if (!(int_status & (ALL_INT_EXT)))
+ wilc_unknown_isr_ext(wilc);
+
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+}
+EXPORT_SYMBOL_GPL(wilc_handle_isr);
+
+int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
+ u32 buffer_size)
+{
+ u32 offset;
+ u32 addr, size, size2, blksz;
+ u8 *dma_buffer;
+ int ret = 0;
+
+ blksz = BIT(12);
+
+ dma_buffer = kmalloc(blksz, GFP_KERNEL);
+ if (!dma_buffer)
+ return -EIO;
+
+ offset = 0;
+ do {
+ memcpy(&addr, &buffer[offset], 4);
+ memcpy(&size, &buffer[offset + 4], 4);
+ le32_to_cpus(&addr);
+ le32_to_cpus(&size);
+ acquire_bus(wilc, ACQUIRE_ONLY);
+ offset += 8;
+ while (((int)size) && (offset < buffer_size)) {
+ if (size <= blksz)
+ size2 = size;
+ else
+ size2 = blksz;
+
+ memcpy(dma_buffer, &buffer[offset], size2);
+ ret = wilc->hif_func->hif_block_tx(wilc, addr,
+ dma_buffer, size2);
+ if (!ret)
+ break;
+
+ addr += size2;
+ offset += size2;
+ size -= size2;
+ }
+ release_bus(wilc, RELEASE_ONLY);
+
+ if (!ret) {
+ ret = -EIO;
+ goto fail;
+ }
+ } while (offset < buffer_size);
+
+fail:
+
+ kfree(dma_buffer);
+
+ return (ret < 0) ? ret : 0;
+}
+
+int wilc_wlan_start(struct wilc *wilc)
+{
+ u32 reg = 0;
+ int ret;
+ u32 chipid;
+
+ if (wilc->io_type == HIF_SDIO) {
+ reg = 0;
+ reg |= BIT(3);
+ } else if (wilc->io_type == HIF_SPI) {
+ reg = 1;
+ }
+ acquire_bus(wilc, ACQUIRE_ONLY);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);
+ if (!ret) {
+ release_bus(wilc, RELEASE_ONLY);
+ return -EIO;
+ }
+ reg = 0;
+ if (wilc->io_type == HIF_SDIO && wilc->dev_irq_num)
+ reg |= WILC_HAVE_SDIO_IRQ_GPIO;
+
+#ifdef WILC_DISABLE_PMU
+#else
+ reg |= WILC_HAVE_USE_PMU;
+#endif
+
+#ifdef WILC_SLEEP_CLK_SRC_XO
+ reg |= WILC_HAVE_SLEEP_CLK_SRC_XO;
+#elif defined WILC_SLEEP_CLK_SRC_RTC
+ reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC;
+#endif
+
+#ifdef WILC_EXT_PA_INV_TX_RX
+ reg |= WILC_HAVE_EXT_PA_INV_TX_RX;
+#endif
+ reg |= WILC_HAVE_USE_IRQ_AS_HOST_WAKE;
+ reg |= WILC_HAVE_LEGACY_RF_SETTINGS;
+#ifdef XTAL_24
+ reg |= WILC_HAVE_XTAL_24;
+#endif
+#ifdef DISABLE_WILC_UART
+ reg |= WILC_HAVE_DISABLE_WILC_UART;
+#endif
+
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg);
+ if (!ret) {
+ release_bus(wilc, RELEASE_ONLY);
+ return -EIO;
+ }
+
+ wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT);
+
+ ret = wilc->hif_func->hif_read_reg(wilc, 0x1000, &chipid);
+ if (!ret) {
+ release_bus(wilc, RELEASE_ONLY);
+ return -EIO;
+ }
+
+ wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
+ if ((reg & BIT(10)) == BIT(10)) {
+ reg &= ~BIT(10);
+ wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+ wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
+ }
+
+ reg |= BIT(10);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+ wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
+ release_bus(wilc, RELEASE_ONLY);
+
+ return (ret < 0) ? ret : 0;
+}
+
+int wilc_wlan_stop(struct wilc *wilc)
+{
+ u32 reg = 0;
+ int ret;
+ u8 timeout = 10;
+
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
+
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
+ if (!ret) {
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+ return ret;
+ }
+
+ reg &= ~BIT(10);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+ if (!ret) {
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+ return ret;
+ }
+
+ do {
+ ret = wilc->hif_func->hif_read_reg(wilc,
+ WILC_GLB_RESET_0, &reg);
+ if (!ret) {
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+ return ret;
+ }
+
+ if ((reg & BIT(10))) {
+ reg &= ~BIT(10);
+ ret = wilc->hif_func->hif_write_reg(wilc,
+ WILC_GLB_RESET_0,
+ reg);
+ timeout--;
+ } else {
+ ret = wilc->hif_func->hif_read_reg(wilc,
+ WILC_GLB_RESET_0,
+ &reg);
+ if (!ret) {
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+ return ret;
+ }
+ break;
+ }
+
+ } while (timeout);
+ reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) |
+ BIT(29) | BIT(30) | BIT(31));
+
+ wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+ reg = (u32)~BIT(10);
+
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+
+ return ret;
+}
+
+void wilc_wlan_cleanup(struct net_device *dev)
+{
+ struct txq_entry_t *tqe;
+ struct rxq_entry_t *rqe;
+ u32 reg = 0;
+ int ret;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ wilc->quit = 1;
+ do {
+ tqe = wilc_wlan_txq_remove_from_head(dev);
+ if (!tqe)
+ break;
+ if (tqe->tx_complete_func)
+ tqe->tx_complete_func(tqe->priv, 0);
+ kfree(tqe);
+ } while (1);
+
+ do {
+ rqe = wilc_wlan_rxq_remove(wilc);
+ if (!rqe)
+ break;
+ kfree(rqe);
+ } while (1);
+
+ kfree(wilc->rx_buffer);
+ wilc->rx_buffer = NULL;
+ kfree(wilc->tx_buffer);
+ wilc->tx_buffer = NULL;
+
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
+
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, &reg);
+ if (!ret)
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
+ (reg | ABORT_INT));
+ if (!ret)
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+ wilc->hif_func->hif_deinit(NULL);
+}
+
+static int wilc_wlan_cfg_commit(struct wilc_vif *vif, int type,
+ u32 drv_handler)
+{
+ struct wilc *wilc = vif->wilc;
+ struct wilc_cfg_frame *cfg = &wilc->cfg_frame;
+ int total_len = wilc->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE;
+ int seq_no = wilc->cfg_seq_no % 256;
+ int driver_handler = (u32)drv_handler;
+
+ if (type == WILC_CFG_SET)
+ cfg->wid_header[0] = 'W';
+ else
+ cfg->wid_header[0] = 'Q';
+ cfg->wid_header[1] = seq_no;
+ cfg->wid_header[2] = (u8)total_len;
+ cfg->wid_header[3] = (u8)(total_len >> 8);
+ cfg->wid_header[4] = (u8)driver_handler;
+ cfg->wid_header[5] = (u8)(driver_handler >> 8);
+ cfg->wid_header[6] = (u8)(driver_handler >> 16);
+ cfg->wid_header[7] = (u8)(driver_handler >> 24);
+ wilc->cfg_seq_no = seq_no;
+
+ if (!wilc_wlan_txq_add_cfg_pkt(vif, &cfg->wid_header[0], total_len))
+ return -1;
+
+ return 0;
+}
+
+int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
+ u32 buffer_size, int commit, u32 drv_handler)
+{
+ u32 offset;
+ int ret_size;
+ struct wilc *wilc = vif->wilc;
+
+ if (wilc->cfg_frame_in_use)
+ return 0;
+
+ if (start)
+ wilc->cfg_frame_offset = 0;
+
+ offset = wilc->cfg_frame_offset;
+ ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset,
+ wid, buffer, buffer_size);
+ offset += ret_size;
+ wilc->cfg_frame_offset = offset;
+
+ if (!commit)
+ return ret_size;
+
+ netdev_dbg(vif->ndev, "%s: seqno[%d]\n", __func__, wilc->cfg_seq_no);
+ wilc->cfg_frame_in_use = 1;
+
+ if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler))
+ ret_size = 0;
+
+ if (!wait_for_completion_timeout(&wilc->cfg_event,
+ msecs_to_jiffies(CFG_PKTS_TIMEOUT))) {
+ netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);
+ ret_size = 0;
+ }
+
+ wilc->cfg_frame_in_use = 0;
+ wilc->cfg_frame_offset = 0;
+ wilc->cfg_seq_no += 1;
+
+ return ret_size;
+}
+
+int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
+ u32 drv_handler)
+{
+ u32 offset;
+ int ret_size;
+ struct wilc *wilc = vif->wilc;
+
+ if (wilc->cfg_frame_in_use)
+ return 0;
+
+ if (start)
+ wilc->cfg_frame_offset = 0;
+
+ offset = wilc->cfg_frame_offset;
+ ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset, wid);
+ offset += ret_size;
+ wilc->cfg_frame_offset = offset;
+
+ if (!commit)
+ return ret_size;
+
+ wilc->cfg_frame_in_use = 1;
+
+ if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler))
+ ret_size = 0;
+
+ if (!wait_for_completion_timeout(&wilc->cfg_event,
+ msecs_to_jiffies(CFG_PKTS_TIMEOUT))) {
+ netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);
+ ret_size = 0;
+ }
+ wilc->cfg_frame_in_use = 0;
+ wilc->cfg_frame_offset = 0;
+ wilc->cfg_seq_no += 1;
+
+ return ret_size;
+}
+
+int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size)
+{
+ return wilc_wlan_cfg_get_wid_value(wl, wid, buffer, buffer_size);
+}
+
+int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
+ u32 count, u32 drv)
+{
+ int i;
+ int ret = 0;
+
+ if (mode == GET_CFG) {
+ for (i = 0; i < count; i++) {
+ if (!wilc_wlan_cfg_get(vif, !i,
+ wids[i].id,
+ (i == count - 1),
+ drv)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+ for (i = 0; i < count; i++) {
+ wids[i].size = wilc_wlan_cfg_get_val(vif->wilc,
+ wids[i].id,
+ wids[i].val,
+ wids[i].size);
+ }
+ } else if (mode == SET_CFG) {
+ for (i = 0; i < count; i++) {
+ if (!wilc_wlan_cfg_set(vif, !i,
+ wids[i].id,
+ wids[i].val,
+ wids[i].size,
+ (i == count - 1),
+ drv)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static u32 init_chip(struct net_device *dev)
+{
+ u32 chipid;
+ u32 reg, ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ acquire_bus(wilc, ACQUIRE_ONLY);
+
+ chipid = wilc_get_chipid(wilc, true);
+
+ if ((chipid & 0xfff) != 0xa0) {
+ ret = wilc->hif_func->hif_read_reg(wilc, 0x1118, &reg);
+ if (!ret) {
+ netdev_err(dev, "fail read reg 0x1118\n");
+ return ret;
+ }
+ reg |= BIT(0);
+ ret = wilc->hif_func->hif_write_reg(wilc, 0x1118, reg);
+ if (!ret) {
+ netdev_err(dev, "fail write reg 0x1118\n");
+ return ret;
+ }
+ ret = wilc->hif_func->hif_write_reg(wilc, 0xc0000, 0x71);
+ if (!ret) {
+ netdev_err(dev, "fail write reg 0xc0000\n");
+ return ret;
+ }
+ }
+
+ release_bus(wilc, RELEASE_ONLY);
+
+ return ret;
+}
+
+u32 wilc_get_chipid(struct wilc *wilc, bool update)
+{
+ static u32 chipid;
+ u32 tempchipid = 0;
+ u32 rfrevid = 0;
+
+ if (chipid == 0 || update) {
+ wilc->hif_func->hif_read_reg(wilc, 0x1000, &tempchipid);
+ wilc->hif_func->hif_read_reg(wilc, 0x13f4, &rfrevid);
+ if (!is_wilc1000(tempchipid)) {
+ chipid = 0;
+ return chipid;
+ }
+ if (tempchipid == 0x1002a0) {
+ if (rfrevid != 0x1)
+ tempchipid = 0x1002a1;
+ } else if (tempchipid == 0x1002b0) {
+ if (rfrevid == 0x4)
+ tempchipid = 0x1002b1;
+ else if (rfrevid != 0x3)
+ tempchipid = 0x1002b2;
+ }
+
+ chipid = tempchipid;
+ }
+ return chipid;
+}
+
+int wilc_wlan_init(struct net_device *dev)
+{
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc;
+
+ wilc = vif->wilc;
+
+ wilc->quit = 0;
+
+ if (!wilc->hif_func->hif_init(wilc, false)) {
+ ret = -EIO;
+ goto fail;
+ }
+
+ if (!wilc->tx_buffer)
+ wilc->tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL);
+
+ if (!wilc->tx_buffer) {
+ ret = -ENOBUFS;
+ goto fail;
+ }
+
+ if (!wilc->rx_buffer)
+ wilc->rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL);
+
+ if (!wilc->rx_buffer) {
+ ret = -ENOBUFS;
+ goto fail;
+ }
+
+ if (!init_chip(dev)) {
+ ret = -EIO;
+ goto fail;
+ }
+
+ return 1;
+
+fail:
+
+ kfree(wilc->rx_buffer);
+ wilc->rx_buffer = NULL;
+ kfree(wilc->tx_buffer);
+ wilc->tx_buffer = NULL;
+
+ return ret;
+}
--
2.7.4


2018-09-26 10:26:28

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 16/19] wilc: add wilc_sdio.c

Moved '/driver/staging/wilc1000/wilc_sdio.c' to
'drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_sdio.c b/drivers/net/wireless/microchip/wilc/wilc_sdio.c
new file mode 100644
index 0000000..ca351c9
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_sdio.c
@@ -0,0 +1,1124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/host.h>
+
+#include "wilc_wfi_netdevice.h"
+
+#define SDIO_MODALIAS "wilc1000_sdio"
+
+#define SDIO_VENDOR_ID_WILC 0x0296
+#define SDIO_DEVICE_ID_WILC 0x5347
+
+static const struct sdio_device_id wilc_sdio_ids[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) },
+ { },
+};
+
+#define WILC_SDIO_BLOCK_SIZE 512
+
+struct wilc_sdio {
+ bool irq_gpio;
+ u32 block_size;
+ int nint;
+/* Max num interrupts allowed in registers 0xf7, 0xf8 */
+#define MAX_NUN_INT_THRPT_ENH2 (5)
+ int has_thrpt_enh3;
+};
+
+static const struct wilc_hif_func wilc_hif_sdio;
+
+static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data);
+static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data);
+static int sdio_init(struct wilc *wilc, bool resume);
+
+static void wilc_sdio_interrupt(struct sdio_func *func)
+{
+ sdio_release_host(func);
+ wilc_handle_isr(sdio_get_drvdata(func));
+ sdio_claim_host(func);
+}
+
+static int wilc_sdio_cmd52(struct wilc *wilc, struct sdio_cmd52 *cmd)
+{
+ struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev);
+ int ret;
+ u8 data;
+
+ sdio_claim_host(func);
+
+ func->num = cmd->function;
+ if (cmd->read_write) { /* write */
+ if (cmd->raw) {
+ sdio_writeb(func, cmd->data, cmd->address, &ret);
+ data = sdio_readb(func, cmd->address, &ret);
+ cmd->data = data;
+ } else {
+ sdio_writeb(func, cmd->data, cmd->address, &ret);
+ }
+ } else { /* read */
+ data = sdio_readb(func, cmd->address, &ret);
+ cmd->data = data;
+ }
+
+ sdio_release_host(func);
+
+ if (ret)
+ dev_err(&func->dev, "%s..failed, err(%d)\n", __func__, ret);
+ return ret;
+}
+
+static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd)
+{
+ struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev);
+ int size, ret;
+
+ sdio_claim_host(func);
+
+ func->num = cmd->function;
+ func->cur_blksize = cmd->block_size;
+ if (cmd->block_mode)
+ size = cmd->count * cmd->block_size;
+ else
+ size = cmd->count;
+
+ if (cmd->read_write) { /* write */
+ ret = sdio_memcpy_toio(func, cmd->address,
+ (void *)cmd->buffer, size);
+ } else { /* read */
+ ret = sdio_memcpy_fromio(func, (void *)cmd->buffer,
+ cmd->address, size);
+ }
+
+ sdio_release_host(func);
+
+ if (ret)
+ dev_err(&func->dev, "%s..failed, err(%d)\n", __func__, ret);
+
+ return ret;
+}
+
+static int linux_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct wilc *wilc;
+ int ret;
+ struct gpio_desc *gpio = NULL;
+ struct wilc_sdio *sdio_priv;
+
+ sdio_priv = kzalloc(sizeof(*sdio_priv), GFP_KERNEL);
+ if (!sdio_priv)
+ return -ENOMEM;
+
+ if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) {
+ gpio = gpiod_get(&func->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(&func->dev, "failed to get irq gpio\n");
+ }
+ }
+
+ dev_dbg(&func->dev, "Initializing netdev\n");
+ ret = wilc_netdev_init(&wilc, &func->dev, HIF_SDIO, &wilc_hif_sdio);
+ if (ret) {
+ dev_err(&func->dev, "Couldn't initialize netdev\n");
+ kfree(sdio_priv);
+ return ret;
+ }
+ sdio_set_drvdata(func, wilc);
+ wilc->bus_data = sdio_priv;
+ wilc->dev = &func->dev;
+ wilc->gpio_irq = gpio;
+
+ dev_info(&func->dev, "Driver Initializing success\n");
+ return 0;
+}
+
+static void linux_sdio_remove(struct sdio_func *func)
+{
+ struct wilc *wilc = sdio_get_drvdata(func);
+
+ /* free the GPIO in module remove */
+ if (wilc->gpio_irq)
+ gpiod_put(wilc->gpio_irq);
+ wilc_netdev_cleanup(wilc);
+}
+
+static int sdio_reset(struct wilc *wilc)
+{
+ struct sdio_cmd52 cmd;
+ int ret;
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0x6;
+ cmd.data = 0x8;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Fail cmd 52, reset cmd ...\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int wilc_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct wilc *wilc = sdio_get_drvdata(func);
+ int ret;
+
+ dev_info(dev, "sdio suspend\n");
+ chip_wakeup(wilc);
+
+ if (!wilc->suspend_event) {
+ wilc_chip_sleep_manually(wilc);
+ } else {
+ host_sleep_notify(wilc);
+ chip_allow_sleep(wilc);
+ }
+
+ ret = sdio_reset(wilc);
+ if (ret) {
+ dev_err(&func->dev, "Fail reset sdio\n");
+ return ret;
+ }
+ sdio_claim_host(func);
+
+ return 0;
+}
+
+static int wilc_sdio_resume(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct wilc *wilc = sdio_get_drvdata(func);
+
+ dev_info(dev, "sdio resume\n");
+ sdio_release_host(func);
+ chip_wakeup(wilc);
+ sdio_init(wilc, true);
+
+ if (wilc->suspend_event)
+ host_wakeup_notify(wilc);
+
+ chip_allow_sleep(wilc);
+
+ return 0;
+}
+
+static const struct of_device_id wilc_of_match[] = {
+ { .compatible = "microchip,wilc1000-sdio", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, wilc_of_match);
+
+static const struct dev_pm_ops wilc_sdio_pm_ops = {
+ .suspend = wilc_sdio_suspend,
+ .resume = wilc_sdio_resume,
+};
+
+static struct sdio_driver wilc_sdio_driver = {
+ .name = SDIO_MODALIAS,
+ .id_table = wilc_sdio_ids,
+ .probe = linux_sdio_probe,
+ .remove = linux_sdio_remove,
+ .drv = {
+ .pm = &wilc_sdio_pm_ops,
+ .of_match_table = wilc_of_match,
+ }
+};
+module_driver(wilc_sdio_driver,
+ sdio_register_driver,
+ sdio_unregister_driver);
+MODULE_LICENSE("GPL");
+
+static int wilc_sdio_enable_interrupt(struct wilc *dev)
+{
+ struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev);
+ int ret = 0;
+
+ sdio_claim_host(func);
+ ret = sdio_claim_irq(func, wilc_sdio_interrupt);
+ sdio_release_host(func);
+
+ if (ret < 0) {
+ dev_err(&func->dev, "can't claim sdio_irq, err(%d)\n", ret);
+ ret = -EIO;
+ }
+ return ret;
+}
+
+static void wilc_sdio_disable_interrupt(struct wilc *dev)
+{
+ struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev);
+ int ret;
+
+ sdio_claim_host(func);
+ ret = sdio_release_irq(func);
+ if (ret < 0)
+ dev_err(&func->dev, "can't release sdio_irq, err(%d)\n", ret);
+ sdio_release_host(func);
+}
+
+/********************************************
+ *
+ * Function 0
+ *
+ ********************************************/
+
+static int sdio_set_func0_csa_address(struct wilc *wilc, u32 adr)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct sdio_cmd52 cmd;
+ int ret;
+
+ /**
+ * Review: BIG ENDIAN
+ **/
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0x10c;
+ cmd.data = (u8)adr;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x10c data...\n");
+ goto fail;
+ }
+
+ cmd.address = 0x10d;
+ cmd.data = (u8)(adr >> 8);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x10d data...\n");
+ goto fail;
+ }
+
+ cmd.address = 0x10e;
+ cmd.data = (u8)(adr >> 16);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x10e data...\n");
+ goto fail;
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+
+static int sdio_set_func0_block_size(struct wilc *wilc, u32 block_size)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct sdio_cmd52 cmd;
+ int ret;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0x10;
+ cmd.data = (u8)block_size;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x10 data...\n");
+ goto fail;
+ }
+
+ cmd.address = 0x11;
+ cmd.data = (u8)(block_size >> 8);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x11 data...\n");
+ goto fail;
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+
+/********************************************
+ *
+ * Function 1
+ *
+ ********************************************/
+
+static int sdio_set_func1_block_size(struct wilc *wilc, u32 block_size)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct sdio_cmd52 cmd;
+ int ret;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0x110;
+ cmd.data = (u8)block_size;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x110 data...\n");
+ goto fail;
+ }
+ cmd.address = 0x111;
+ cmd.data = (u8)(block_size >> 8);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed cmd52, set 0x111 data...\n");
+ goto fail;
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+
+/********************************************
+ *
+ * Sdio interfaces
+ *
+ ********************************************/
+static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ int ret;
+
+ cpu_to_le32s(&data);
+
+ if (addr >= 0xf0 && addr <= 0xff) {
+ struct sdio_cmd52 cmd;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = addr;
+ cmd.data = data;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd 52, read reg (%08x) ...\n", addr);
+ goto fail;
+ }
+ } else {
+ struct sdio_cmd53 cmd;
+
+ /**
+ * set the AHB address
+ **/
+ if (!sdio_set_func0_csa_address(wilc, addr))
+ goto fail;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.address = 0x10f;
+ cmd.block_mode = 0;
+ cmd.increment = 1;
+ cmd.count = 4;
+ cmd.buffer = (u8 *)&data;
+ cmd.block_size = sdio_priv->block_size;
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53, write reg (%08x)...\n", addr);
+ goto fail;
+ }
+ }
+
+ return 1;
+
+fail:
+
+ return 0;
+}
+
+static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ u32 block_size = sdio_priv->block_size;
+ struct sdio_cmd53 cmd;
+ int nblk, nleft, ret;
+
+ cmd.read_write = 1;
+ if (addr > 0) {
+ /**
+ * has to be word aligned...
+ **/
+ if (size & 0x3) {
+ size += 4;
+ size &= ~0x3;
+ }
+
+ /**
+ * func 0 access
+ **/
+ cmd.function = 0;
+ cmd.address = 0x10f;
+ } else {
+ /**
+ * has to be word aligned...
+ **/
+ if (size & 0x3) {
+ size += 4;
+ size &= ~0x3;
+ }
+
+ /**
+ * func 1 access
+ **/
+ cmd.function = 1;
+ cmd.address = 0;
+ }
+
+ nblk = size / block_size;
+ nleft = size % block_size;
+
+ if (nblk > 0) {
+ cmd.block_mode = 1;
+ cmd.increment = 1;
+ cmd.count = nblk;
+ cmd.buffer = buf;
+ cmd.block_size = block_size;
+ if (addr > 0) {
+ if (!sdio_set_func0_csa_address(wilc, addr))
+ goto fail;
+ }
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53 [%x], block send...\n", addr);
+ goto fail;
+ }
+ if (addr > 0)
+ addr += nblk * block_size;
+ buf += nblk * block_size;
+ }
+
+ if (nleft > 0) {
+ cmd.block_mode = 0;
+ cmd.increment = 1;
+ cmd.count = nleft;
+ cmd.buffer = buf;
+
+ cmd.block_size = block_size;
+
+ if (addr > 0) {
+ if (!sdio_set_func0_csa_address(wilc, addr))
+ goto fail;
+ }
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53 [%x], bytes send...\n", addr);
+ goto fail;
+ }
+ }
+
+ return 1;
+
+fail:
+
+ return 0;
+}
+
+static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ int ret;
+
+ if (addr >= 0xf0 && addr <= 0xff) {
+ struct sdio_cmd52 cmd;
+
+ cmd.read_write = 0;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = addr;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd 52, read reg (%08x) ...\n", addr);
+ goto fail;
+ }
+ *data = cmd.data;
+ } else {
+ struct sdio_cmd53 cmd;
+
+ if (!sdio_set_func0_csa_address(wilc, addr))
+ goto fail;
+
+ cmd.read_write = 0;
+ cmd.function = 0;
+ cmd.address = 0x10f;
+ cmd.block_mode = 0;
+ cmd.increment = 1;
+ cmd.count = 4;
+ cmd.buffer = (u8 *)data;
+
+ cmd.block_size = sdio_priv->block_size;
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53, read reg (%08x)...\n", addr);
+ goto fail;
+ }
+ }
+
+ le32_to_cpus(data);
+
+ return 1;
+
+fail:
+
+ return 0;
+}
+
+static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ u32 block_size = sdio_priv->block_size;
+ struct sdio_cmd53 cmd;
+ int nblk, nleft, ret;
+
+ cmd.read_write = 0;
+ if (addr > 0) {
+ /**
+ * has to be word aligned...
+ **/
+ if (size & 0x3) {
+ size += 4;
+ size &= ~0x3;
+ }
+
+ /**
+ * func 0 access
+ **/
+ cmd.function = 0;
+ cmd.address = 0x10f;
+ } else {
+ /**
+ * has to be word aligned...
+ **/
+ if (size & 0x3) {
+ size += 4;
+ size &= ~0x3;
+ }
+
+ /**
+ * func 1 access
+ **/
+ cmd.function = 1;
+ cmd.address = 0;
+ }
+
+ nblk = size / block_size;
+ nleft = size % block_size;
+
+ if (nblk > 0) {
+ cmd.block_mode = 1;
+ cmd.increment = 1;
+ cmd.count = nblk;
+ cmd.buffer = buf;
+ cmd.block_size = block_size;
+ if (addr > 0) {
+ if (!sdio_set_func0_csa_address(wilc, addr))
+ goto fail;
+ }
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53 [%x], block read...\n", addr);
+ goto fail;
+ }
+ if (addr > 0)
+ addr += nblk * block_size;
+ buf += nblk * block_size;
+ } /* if (nblk > 0) */
+
+ if (nleft > 0) {
+ cmd.block_mode = 0;
+ cmd.increment = 1;
+ cmd.count = nleft;
+ cmd.buffer = buf;
+
+ cmd.block_size = block_size;
+
+ if (addr > 0) {
+ if (!sdio_set_func0_csa_address(wilc, addr))
+ goto fail;
+ }
+ ret = wilc_sdio_cmd53(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd53 [%x], bytes read...\n", addr);
+ goto fail;
+ }
+ }
+
+ return 1;
+
+fail:
+
+ return 0;
+}
+
+/********************************************
+ *
+ * Bus interfaces
+ *
+ ********************************************/
+
+static int sdio_deinit(struct wilc *wilc)
+{
+ return 1;
+}
+
+static int sdio_init(struct wilc *wilc, bool resume)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ struct sdio_cmd52 cmd;
+ int loop, ret;
+ u32 chipid;
+
+ if (!resume)
+ sdio_priv->irq_gpio = wilc->dev_irq_num;
+
+ /**
+ * function 0 csa enable
+ **/
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 1;
+ cmd.address = 0x100;
+ cmd.data = 0x80;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Fail cmd 52, enable csa...\n");
+ goto fail;
+ }
+
+ /**
+ * function 0 block size
+ **/
+ if (!sdio_set_func0_block_size(wilc, WILC_SDIO_BLOCK_SIZE)) {
+ dev_err(&func->dev, "Fail cmd 52, set func 0 block size...\n");
+ goto fail;
+ }
+ sdio_priv->block_size = WILC_SDIO_BLOCK_SIZE;
+
+ /**
+ * enable func1 IO
+ **/
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 1;
+ cmd.address = 0x2;
+ cmd.data = 0x2;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Fail cmd 52, set IOE register...\n");
+ goto fail;
+ }
+
+ /**
+ * make sure func 1 is up
+ **/
+ cmd.read_write = 0;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0x3;
+ loop = 3;
+ do {
+ cmd.data = 0;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Fail cmd 52, get IOR register...\n");
+ goto fail;
+ }
+ if (cmd.data == 0x2)
+ break;
+ } while (loop--);
+
+ if (loop <= 0) {
+ dev_err(&func->dev, "Fail func 1 is not ready...\n");
+ goto fail;
+ }
+
+ /**
+ * func 1 is ready, set func 1 block size
+ **/
+ if (!sdio_set_func1_block_size(wilc, WILC_SDIO_BLOCK_SIZE)) {
+ dev_err(&func->dev, "Fail set func 1 block size...\n");
+ goto fail;
+ }
+
+ /**
+ * func 1 interrupt enable
+ **/
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 1;
+ cmd.address = 0x4;
+ cmd.data = 0x3;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Fail cmd 52, set IEN register...\n");
+ goto fail;
+ }
+
+ /**
+ * make sure can read back chip id correctly
+ **/
+ if (!resume) {
+ if (!sdio_read_reg(wilc, 0x1000, &chipid)) {
+ dev_err(&func->dev, "Fail cmd read chip id...\n");
+ goto fail;
+ }
+ dev_err(&func->dev, "chipid (%08x)\n", chipid);
+ if ((chipid & 0xfff) > 0x2a0)
+ sdio_priv->has_thrpt_enh3 = 1;
+ else
+ sdio_priv->has_thrpt_enh3 = 0;
+ dev_info(&func->dev, "has_thrpt_enh3 = %d...\n",
+ sdio_priv->has_thrpt_enh3);
+ }
+
+ return 1;
+
+fail:
+
+ return 0;
+}
+
+static int sdio_read_size(struct wilc *wilc, u32 *size)
+{
+ u32 tmp;
+ struct sdio_cmd52 cmd;
+
+ /**
+ * Read DMA count in words
+ **/
+ cmd.read_write = 0;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0xf2;
+ cmd.data = 0;
+ wilc_sdio_cmd52(wilc, &cmd);
+ tmp = cmd.data;
+
+ cmd.address = 0xf3;
+ cmd.data = 0;
+ wilc_sdio_cmd52(wilc, &cmd);
+ tmp |= (cmd.data << 8);
+
+ *size = tmp;
+ return 1;
+}
+
+static int sdio_read_int(struct wilc *wilc, u32 *int_status)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ u32 tmp;
+ struct sdio_cmd52 cmd;
+
+ sdio_read_size(wilc, &tmp);
+
+ /**
+ * Read IRQ flags
+ **/
+ if (!sdio_priv->irq_gpio) {
+ int i;
+
+ cmd.function = 1;
+ cmd.address = 0x04;
+ cmd.data = 0;
+ wilc_sdio_cmd52(wilc, &cmd);
+
+ if (cmd.data & BIT(0))
+ tmp |= INT_0;
+ if (cmd.data & BIT(2))
+ tmp |= INT_1;
+ if (cmd.data & BIT(3))
+ tmp |= INT_2;
+ if (cmd.data & BIT(4))
+ tmp |= INT_3;
+ if (cmd.data & BIT(5))
+ tmp |= INT_4;
+ if (cmd.data & BIT(6))
+ tmp |= INT_5;
+ for (i = sdio_priv->nint; i < MAX_NUM_INT; i++) {
+ if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) {
+ dev_err(&func->dev,
+ "Unexpected interrupt (1) : tmp=%x, data=%x\n",
+ tmp, cmd.data);
+ break;
+ }
+ }
+ } else {
+ u32 irq_flags;
+
+ cmd.read_write = 0;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0xf7;
+ cmd.data = 0;
+ wilc_sdio_cmd52(wilc, &cmd);
+ irq_flags = cmd.data & 0x1f;
+ tmp |= ((irq_flags >> 0) << IRG_FLAGS_OFFSET);
+ }
+
+ *int_status = tmp;
+
+ return 1;
+}
+
+static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ int ret;
+ int vmm_ctl;
+
+ if (sdio_priv->has_thrpt_enh3) {
+ u32 reg;
+
+ if (sdio_priv->irq_gpio) {
+ u32 flags;
+
+ flags = val & (BIT(MAX_NUN_INT_THRPT_ENH2) - 1);
+ reg = flags;
+ } else {
+ reg = 0;
+ }
+ /* select VMM table 0 */
+ if (val & SEL_VMM_TBL0)
+ reg |= BIT(5);
+ /* select VMM table 1 */
+ if (val & SEL_VMM_TBL1)
+ reg |= BIT(6);
+ /* enable VMM */
+ if (val & EN_VMM)
+ reg |= BIT(7);
+ if (reg) {
+ struct sdio_cmd52 cmd;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0xf8;
+ cmd.data = reg;
+
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xf8 data (%d) ...\n",
+ __LINE__);
+ goto fail;
+ }
+ }
+ return 1;
+ }
+ if (sdio_priv->irq_gpio) {
+ /* has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
+ /*
+ * Cannot clear multiple interrupts.
+ * Must clear each interrupt individually.
+ */
+ u32 flags;
+
+ flags = val & (BIT(MAX_NUM_INT) - 1);
+ if (flags) {
+ int i;
+
+ ret = 1;
+ for (i = 0; i < sdio_priv->nint; i++) {
+ if (flags & 1) {
+ struct sdio_cmd52 cmd;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0xf8;
+ cmd.data = BIT(i);
+
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xf8 data (%d) ...\n",
+ __LINE__);
+ goto fail;
+ }
+ }
+ if (!ret)
+ break;
+ flags >>= 1;
+ }
+ if (!ret)
+ goto fail;
+ for (i = sdio_priv->nint; i < MAX_NUM_INT; i++) {
+ if (flags & 1)
+ dev_err(&func->dev,
+ "Unexpected interrupt cleared %d...\n",
+ i);
+ flags >>= 1;
+ }
+ }
+ }
+
+ vmm_ctl = 0;
+ /* select VMM table 0 */
+ if (val & SEL_VMM_TBL0)
+ vmm_ctl |= BIT(0);
+ /* select VMM table 1 */
+ if (val & SEL_VMM_TBL1)
+ vmm_ctl |= BIT(1);
+ /* enable VMM */
+ if (val & EN_VMM)
+ vmm_ctl |= BIT(2);
+
+ if (vmm_ctl) {
+ struct sdio_cmd52 cmd;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0xf6;
+ cmd.data = vmm_ctl;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xf6 data (%d) ...\n",
+ __LINE__);
+ goto fail;
+ }
+ }
+ return 1;
+fail:
+ return 0;
+}
+
+static int sdio_sync_ext(struct wilc *wilc, int nint)
+{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ u32 reg;
+
+ if (nint > MAX_NUM_INT) {
+ dev_err(&func->dev, "Too many interrupts (%d)...\n", nint);
+ return 0;
+ }
+ if (nint > MAX_NUN_INT_THRPT_ENH2) {
+ dev_err(&func->dev,
+ "Cannot support more than 5 interrupts when has_thrpt_enh2=1.\n");
+ return 0;
+ }
+
+ sdio_priv->nint = nint;
+
+ /**
+ * Disable power sequencer
+ **/
+ if (!sdio_read_reg(wilc, WILC_MISC, &reg)) {
+ dev_err(&func->dev, "Failed read misc reg...\n");
+ return 0;
+ }
+
+ reg &= ~BIT(8);
+ if (!sdio_write_reg(wilc, WILC_MISC, reg)) {
+ dev_err(&func->dev, "Failed write misc reg...\n");
+ return 0;
+ }
+
+ if (sdio_priv->irq_gpio) {
+ u32 reg;
+ int ret, i;
+
+ /**
+ * interrupt pin mux select
+ **/
+ ret = sdio_read_reg(wilc, WILC_PIN_MUX_0, &reg);
+ if (!ret) {
+ dev_err(&func->dev, "Failed read reg (%08x)...\n",
+ WILC_PIN_MUX_0);
+ return 0;
+ }
+ reg |= BIT(8);
+ ret = sdio_write_reg(wilc, WILC_PIN_MUX_0, reg);
+ if (!ret) {
+ dev_err(&func->dev, "Failed write reg (%08x)...\n",
+ WILC_PIN_MUX_0);
+ return 0;
+ }
+
+ /**
+ * interrupt enable
+ **/
+ ret = sdio_read_reg(wilc, WILC_INTR_ENABLE, &reg);
+ if (!ret) {
+ dev_err(&func->dev, "Failed read reg (%08x)...\n",
+ WILC_INTR_ENABLE);
+ return 0;
+ }
+
+ for (i = 0; (i < 5) && (nint > 0); i++, nint--)
+ reg |= BIT((27 + i));
+ ret = sdio_write_reg(wilc, WILC_INTR_ENABLE, reg);
+ if (!ret) {
+ dev_err(&func->dev, "Failed write reg (%08x)...\n",
+ WILC_INTR_ENABLE);
+ return 0;
+ }
+ if (nint) {
+ ret = sdio_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
+ if (!ret) {
+ dev_err(&func->dev,
+ "Failed read reg (%08x)...\n",
+ WILC_INTR2_ENABLE);
+ return 0;
+ }
+
+ for (i = 0; (i < 3) && (nint > 0); i++, nint--)
+ reg |= BIT(i);
+
+ ret = sdio_read_reg(wilc, WILC_INTR2_ENABLE, &reg);
+ if (!ret) {
+ dev_err(&func->dev,
+ "Failed write reg (%08x)...\n",
+ WILC_INTR2_ENABLE);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/* Global sdio HIF function table */
+static const struct wilc_hif_func wilc_hif_sdio = {
+ .hif_init = sdio_init,
+ .hif_deinit = sdio_deinit,
+ .hif_read_reg = sdio_read_reg,
+ .hif_write_reg = sdio_write_reg,
+ .hif_block_rx = sdio_read,
+ .hif_block_tx = sdio_write,
+ .hif_read_int = sdio_read_int,
+ .hif_clear_int_ext = sdio_clear_int_ext,
+ .hif_read_size = sdio_read_size,
+ .hif_block_tx_ext = sdio_write,
+ .hif_block_rx_ext = sdio_read,
+ .hif_sync_ext = sdio_sync_ext,
+ .enable_interrupt = wilc_sdio_enable_interrupt,
+ .disable_interrupt = wilc_sdio_disable_interrupt,
+};
+
--
2.7.4


2018-09-26 10:26:30

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 17/19] wilc: updated DT device binding for wilc device

Added the device tree binding document from '/driver/staging/wilc1000/'
to '/Documentation/devicetree/bindings/net/wireless/' folder.

Signed-off-by: Ajay Singh <[email protected]>
---
.../net/wireless/microchip,wilc1000,sdio.txt | 32 ++++++++++++++++++++++
.../net/wireless/microchip,wilc1000,spi.txt | 26 ++++++++++++++++++
2 files changed, 58 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.txt
create mode 100644 Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.txt

diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.txt b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.txt
new file mode 100644
index 0000000..4f7d1c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,sdio.txt
@@ -0,0 +1,32 @@
+* Microchip WILC wireless SDIO device
+
+The wilc1000 chips can be connected via SDIO. The node is used to specifiy
+child node to the SDIO controller that connects the device to the system.
+
+Required properties:
+- compatible : Should be "microchip,wilc1000-spi"
+- irq-gpios : Connect to a host IRQ
+- reg : Slot ID used in the controller
+
+Optional:
+- bus-width : Number of data lines wired up the slot. Default 1 bit.
+
+
+Examples:
+mmc1: mmc@fc000000 {
+ 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>;
+ status = "okay";
+ reg = <0>;
+ bus-width = <4>;
+ }
+ };
+}
diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.txt b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.txt
new file mode 100644
index 0000000..87db87b
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000,spi.txt
@@ -0,0 +1,26 @@
+* Microchip WILC wireless SPI device
+
+The wilc1000 chips can be connected via SPI. This document describes
+the binding for the SPI connected module.
+
+Required properties:
+- compatible : Should be "microchip,wilc1000-spi"
+- spi-max-frequency : Maximum SPI clocking speed of device in Hz
+- reg : Chip select address of device
+- irq-gpios : Connect to a host IRQ
+
+
+Examples:
+
+spi1: spi@fc018000 {
+ 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>;
+ status = "okay";
+ };
+};
--
2.7.4


2018-09-26 10:26:34

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 18/19] wilc: add Makefile and Kconfig files for wilc compilation

Added the Makefile and Kconfig for compiling the wilc module.
Renaming the module as 'wilc', so modified the Kconfig and Makefile
accordingly.
Modified wilc_sdio.c file to avoid the use of wilc1000 in macro name.

Signed-off-by: Ajay Singh <[email protected]>
---
drivers/net/wireless/microchip/Kconfig | 14 ++++++++++
drivers/net/wireless/microchip/Makefile | 1 +
drivers/net/wireless/microchip/wilc/Kconfig | 42 ++++++++++++++++++++++++++++
drivers/net/wireless/microchip/wilc/Makefile | 15 ++++++++++
drivers/staging/wilc1000/wilc_sdio.c | 4 +--
5 files changed, 74 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/wireless/microchip/Kconfig
create mode 100644 drivers/net/wireless/microchip/Makefile
create mode 100644 drivers/net/wireless/microchip/wilc/Kconfig
create mode 100644 drivers/net/wireless/microchip/wilc/Makefile

diff --git a/drivers/net/wireless/microchip/Kconfig b/drivers/net/wireless/microchip/Kconfig
new file mode 100644
index 0000000..4429b3d
--- /dev/null
+++ b/drivers/net/wireless/microchip/Kconfig
@@ -0,0 +1,14 @@
+config WLAN_VENDOR_MICROCHIP
+ bool "Microchip devices"
+ default y
+ ---help---
+ If you have a wireless card belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all the
+ questions about these cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if WLAN_VENDOR_MICROCHIP
+source "drivers/net/wireless/microchip/wilc/Kconfig"
+endif # WLAN_VENDOR_MICROCHIP
diff --git a/drivers/net/wireless/microchip/Makefile b/drivers/net/wireless/microchip/Makefile
new file mode 100644
index 0000000..6c15d8f
--- /dev/null
+++ b/drivers/net/wireless/microchip/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_WILC) += wilc/
diff --git a/drivers/net/wireless/microchip/wilc/Kconfig b/drivers/net/wireless/microchip/wilc/Kconfig
new file mode 100644
index 0000000..5268165
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/Kconfig
@@ -0,0 +1,42 @@
+config WILC
+ tristate
+ ---help---
+ This module only support IEEE 802.11n WiFi.
+
+config WILC_SDIO
+ tristate "Microchip WILC SDIO (WiFi only)"
+ depends on CFG80211 && INET && MMC
+ select WILC
+ ---help---
+ This module adds support for the SDIO interface of adapters using
+ WILC chipset. The Microchip WILC SDIO is a full speed interface.
+ It meets SDIO card specification version 2.0. The interface supports
+ the 1-bit/4-bit SD transfer mode at the clock range of 0-50 MHz.
+ The host can use this interface to read and write from any register
+ within the chip as well as configure the WILC for data DMA.
+ To use this interface, pin9 (SDIO_SPI_CFG) must be grounded. Select
+ this if your platform is using the SDIO bus.
+
+config WILC_SPI
+ tristate "Microchip WILC SPI (WiFi only)"
+ depends on CFG80211 && INET && SPI
+ select WILC
+ ---help---
+ This module adds support for the SPI interface of adapters using
+ WILC chipset. The Microchip WILC has a Serial Peripheral
+ Interface (SPI) that operates as a SPI slave. This SPI interface can
+ be used for control and for serial I/O of 802.11 data. The SPI is a
+ full-duplex slave synchronous serial interface that is available
+ immediately following reset when pin 9 (SDIO_SPI_CFG) is tied to
+ VDDIO. Select this if your platform is using the SPI bus.
+
+config WILC_HW_OOB_INTR
+ bool "WILC out of band interrupt"
+ depends on WILC_SDIO
+ default n
+ ---help---
+ This option enables out-of-band interrupt support for the WILC
+ chipset. This OOB interrupt is intended to provide a faster interrupt
+ mechanism for SDIO host controllers that don't support SDIO interrupt.
+ Select this option If the SDIO host controller in your platform
+ doesn't support SDIO time devision interrupt.
diff --git a/drivers/net/wireless/microchip/wilc/Makefile b/drivers/net/wireless/microchip/wilc/Makefile
new file mode 100644
index 0000000..a98a4af
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_WILC) += wilc.o
+
+ccflags-y += -DFIRMWARE_1002=\"atmel/wilc1002_firmware.bin\" \
+ -DFIRMWARE_1003=\"atmel/wilc1003_firmware.bin\"
+
+wilc-objs := wilc_wfi_cfgoperations.o linux_wlan.o linux_mon.o \
+ coreconfigurator.o host_interface.o \
+ wilc_wlan_cfg.o wilc_wlan.o
+
+obj-$(CONFIG_WILC_SDIO) += wilc-sdio.o
+wilc-sdio-objs += wilc_sdio.o
+
+obj-$(CONFIG_WILC_SPI) += wilc-spi.o
+wilc-spi-objs += wilc_spi.o
diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c
index b2080d8..4df1da1 100644
--- a/drivers/staging/wilc1000/wilc_sdio.c
+++ b/drivers/staging/wilc1000/wilc_sdio.c
@@ -9,7 +9,7 @@

#include "wilc_wfi_netdevice.h"

-#define SDIO_MODALIAS "wilc1000_sdio"
+#define SDIO_MODALIAS "wilc_sdio"

#define SDIO_VENDOR_ID_WILC 0x0296
#define SDIO_DEVICE_ID_WILC 0x5347
@@ -110,7 +110,7 @@ static int linux_sdio_probe(struct sdio_func *func,
int ret;
struct gpio_desc *gpio = NULL;

- if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) {
+ if (IS_ENABLED(CONFIG_WILC_HW_OOB_INTR)) {
gpio = gpiod_get(&func->dev, "irq", GPIOD_IN);
if (IS_ERR(gpio)) {
/* get the GPIO descriptor from hardcode GPIO number */
--
2.7.4


2018-09-26 10:26:37

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 19/19] wilc: added wilc module compilation in wireless Makefile & Kconfig

Modified wireless Makefile and Kconfig to include the microchip/wilc
files compilation.

Signed-off-by: Ajay Singh <[email protected]>
---
drivers/net/wireless/Kconfig | 1 +
drivers/net/wireless/Makefile | 1 +
2 files changed, 2 insertions(+)

diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 166920a..2113fce 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -46,6 +46,7 @@ source "drivers/net/wireless/st/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zydas/Kconfig"
source "drivers/net/wireless/quantenna/Kconfig"
+source "drivers/net/wireless/microchip/Kconfig"

config PCMCIA_RAYCS
tristate "Aviator/Raytheon 2.4GHz wireless support"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 7fc9630..f29c7eb 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/
obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/
+obj-$(CONFIG_WLAN_VENDOR_MICROCHIP) += microchip/

# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
--
2.7.4


2018-09-26 10:26:38

by Ajay Singh

[permalink] [raw]
Subject: [PATCH 08/19] wilc: add wilc_wlan.h

Moved '/driver/staging/wilc1000/wilc_wlan.h' to '
drivers/net/wireless/microchip/wilc/'.

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

diff --git a/drivers/net/wireless/microchip/wilc/wilc_wlan.h b/drivers/net/wireless/microchip/wilc/wilc_wlan.h
new file mode 100644
index 0000000..2766713
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc/wilc_wlan.h
@@ -0,0 +1,297 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#ifndef WILC_WLAN_H
+#define WILC_WLAN_H
+
+#include <linux/types.h>
+
+/********************************************
+ *
+ * Mac eth header length
+ *
+ ********************************************/
+#define DRIVER_HANDLER_SIZE 4
+#define MAX_MAC_HDR_LEN 26 /* QOS_MAC_HDR_LEN */
+#define SUB_MSDU_HEADER_LENGTH 14
+#define SNAP_HDR_LEN 8
+#define ETHERNET_HDR_LEN 14
+#define WORD_ALIGNMENT_PAD 0
+
+#define ETH_ETHERNET_HDR_OFFSET (MAX_MAC_HDR_LEN + \
+ SUB_MSDU_HEADER_LENGTH + \
+ SNAP_HDR_LEN - \
+ ETHERNET_HDR_LEN + \
+ WORD_ALIGNMENT_PAD)
+
+#define HOST_HDR_OFFSET 4
+#define ETHERNET_HDR_LEN 14
+#define IP_HDR_LEN 20
+#define IP_HDR_OFFSET ETHERNET_HDR_LEN
+#define UDP_HDR_OFFSET (IP_HDR_LEN + IP_HDR_OFFSET)
+#define UDP_HDR_LEN 8
+#define UDP_DATA_OFFSET (UDP_HDR_OFFSET + UDP_HDR_LEN)
+#define ETH_CONFIG_PKT_HDR_LEN UDP_DATA_OFFSET
+
+#define ETH_CONFIG_PKT_HDR_OFFSET (ETH_ETHERNET_HDR_OFFSET + \
+ ETH_CONFIG_PKT_HDR_LEN)
+
+/********************************************
+ *
+ * Register Defines
+ *
+ ********************************************/
+#define WILC_PERIPH_REG_BASE 0x1000
+#define WILC_CHANGING_VIR_IF 0x108c
+#define WILC_CHIPID WILC_PERIPH_REG_BASE
+#define WILC_GLB_RESET_0 (WILC_PERIPH_REG_BASE + 0x400)
+#define WILC_PIN_MUX_0 (WILC_PERIPH_REG_BASE + 0x408)
+#define WILC_HOST_TX_CTRL (WILC_PERIPH_REG_BASE + 0x6c)
+#define WILC_HOST_RX_CTRL_0 (WILC_PERIPH_REG_BASE + 0x70)
+#define WILC_HOST_RX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x74)
+#define WILC_HOST_VMM_CTL (WILC_PERIPH_REG_BASE + 0x78)
+#define WILC_HOST_RX_CTRL (WILC_PERIPH_REG_BASE + 0x80)
+#define WILC_HOST_RX_EXTRA_SIZE (WILC_PERIPH_REG_BASE + 0x84)
+#define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88)
+#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428)
+#define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00)
+#define WILC_INTR_ENABLE WILC_INTR_REG_BASE
+#define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4)
+
+#define WILC_INTR_POLARITY (WILC_INTR_REG_BASE + 0x10)
+#define WILC_INTR_TYPE (WILC_INTR_REG_BASE + 0x20)
+#define WILC_INTR_CLEAR (WILC_INTR_REG_BASE + 0x30)
+#define WILC_INTR_STATUS (WILC_INTR_REG_BASE + 0x40)
+
+#define WILC_VMM_TBL_SIZE 64
+#define WILC_VMM_TX_TBL_BASE 0x150400
+#define WILC_VMM_RX_TBL_BASE 0x150500
+
+#define WILC_VMM_BASE 0x150000
+#define WILC_VMM_CORE_CTL WILC_VMM_BASE
+#define WILC_VMM_TBL_CTL (WILC_VMM_BASE + 0x4)
+#define WILC_VMM_TBL_ENTRY (WILC_VMM_BASE + 0x8)
+#define WILC_VMM_TBL0_SIZE (WILC_VMM_BASE + 0xc)
+#define WILC_VMM_TO_HOST_SIZE (WILC_VMM_BASE + 0x10)
+#define WILC_VMM_CORE_CFG (WILC_VMM_BASE + 0x14)
+#define WILC_VMM_TBL_ACTIVE (WILC_VMM_BASE + 040)
+#define WILC_VMM_TBL_STATUS (WILC_VMM_BASE + 0x44)
+
+#define WILC_SPI_REG_BASE 0xe800
+#define WILC_SPI_CTL WILC_SPI_REG_BASE
+#define WILC_SPI_MASTER_DMA_ADDR (WILC_SPI_REG_BASE + 0x4)
+#define WILC_SPI_MASTER_DMA_COUNT (WILC_SPI_REG_BASE + 0x8)
+#define WILC_SPI_SLAVE_DMA_ADDR (WILC_SPI_REG_BASE + 0xc)
+#define WILC_SPI_SLAVE_DMA_COUNT (WILC_SPI_REG_BASE + 0x10)
+#define WILC_SPI_TX_MODE (WILC_SPI_REG_BASE + 0x20)
+#define WILC_SPI_PROTOCOL_CONFIG (WILC_SPI_REG_BASE + 0x24)
+#define WILC_SPI_INTR_CTL (WILC_SPI_REG_BASE + 0x2c)
+
+#define WILC_SPI_PROTOCOL_OFFSET (WILC_SPI_PROTOCOL_CONFIG - \
+ WILC_SPI_REG_BASE)
+
+#define WILC_AHB_DATA_MEM_BASE 0x30000
+#define WILC_AHB_SHARE_MEM_BASE 0xd0000
+
+#define WILC_VMM_TBL_RX_SHADOW_BASE WILC_AHB_SHARE_MEM_BASE
+#define WILC_VMM_TBL_RX_SHADOW_SIZE 256
+
+#define WILC_GP_REG_0 0x149c
+#define WILC_GP_REG_1 0x14a0
+
+#define WILC_HAVE_SDIO_IRQ_GPIO BIT(0)
+#define WILC_HAVE_USE_PMU BIT(1)
+#define WILC_HAVE_SLEEP_CLK_SRC_RTC BIT(2)
+#define WILC_HAVE_SLEEP_CLK_SRC_XO BIT(3)
+#define WILC_HAVE_EXT_PA_INV_TX_RX BIT(4)
+#define WILC_HAVE_LEGACY_RF_SETTINGS BIT(5)
+#define WILC_HAVE_XTAL_24 BIT(6)
+#define WILC_HAVE_DISABLE_WILC_UART BIT(7)
+#define WILC_HAVE_USE_IRQ_AS_HOST_WAKE BIT(8)
+
+/********************************************
+ *
+ * Wlan Defines
+ *
+ ********************************************/
+#define WILC_CFG_PKT 1
+#define WILC_NET_PKT 0
+#define WILC_MGMT_PKT 2
+
+#define WILC_CFG_SET 1
+#define WILC_CFG_QUERY 0
+
+#define WILC_CFG_RSP 1
+#define WILC_CFG_RSP_STATUS 2
+#define WILC_CFG_RSP_SCAN 3
+
+#define WILC_PLL_TO_SDIO 4
+#define WILC_PLL_TO_SPI 2
+#define ABORT_INT BIT(31)
+
+#define LINUX_RX_SIZE (96 * 1024)
+#define LINUX_TX_SIZE (64 * 1024)
+
+#define MODALIAS "WILC_SPI"
+#define GPIO_NUM 0x44
+/*******************************************/
+/* E0 and later Interrupt flags. */
+/*******************************************/
+/*******************************************/
+/* E0 and later Interrupt flags. */
+/* IRQ Status word */
+/* 15:0 = DMA count in words. */
+/* 16: INT0 flag */
+/* 17: INT1 flag */
+/* 18: INT2 flag */
+/* 19: INT3 flag */
+/* 20: INT4 flag */
+/* 21: INT5 flag */
+/*******************************************/
+#define IRG_FLAGS_OFFSET 16
+#define IRQ_DMA_WD_CNT_MASK ((1ul << IRG_FLAGS_OFFSET) - 1)
+#define INT_0 BIT(IRG_FLAGS_OFFSET)
+#define INT_1 BIT(IRG_FLAGS_OFFSET + 1)
+#define INT_2 BIT(IRG_FLAGS_OFFSET + 2)
+#define INT_3 BIT(IRG_FLAGS_OFFSET + 3)
+#define INT_4 BIT(IRG_FLAGS_OFFSET + 4)
+#define INT_5 BIT(IRG_FLAGS_OFFSET + 5)
+#define MAX_NUM_INT 6
+
+/*******************************************/
+/* E0 and later Interrupt flags. */
+/* IRQ Clear word */
+/* 0: Clear INT0 */
+/* 1: Clear INT1 */
+/* 2: Clear INT2 */
+/* 3: Clear INT3 */
+/* 4: Clear INT4 */
+/* 5: Clear INT5 */
+/* 6: Select VMM table 1 */
+/* 7: Select VMM table 2 */
+/* 8: Enable VMM */
+/*******************************************/
+#define CLR_INT0 BIT(0)
+#define CLR_INT1 BIT(1)
+#define CLR_INT2 BIT(2)
+#define CLR_INT3 BIT(3)
+#define CLR_INT4 BIT(4)
+#define CLR_INT5 BIT(5)
+#define SEL_VMM_TBL0 BIT(6)
+#define SEL_VMM_TBL1 BIT(7)
+#define EN_VMM BIT(8)
+
+#define DATA_INT_EXT INT_0
+#define PLL_INT_EXT INT_1
+#define SLEEP_INT_EXT INT_2
+#define ALL_INT_EXT (DATA_INT_EXT | PLL_INT_EXT | SLEEP_INT_EXT)
+#define NUM_INT_EXT 3
+
+#define DATA_INT_CLR CLR_INT0
+#define PLL_INT_CLR CLR_INT1
+#define SLEEP_INT_CLR CLR_INT2
+
+#define ENABLE_RX_VMM (SEL_VMM_TBL1 | EN_VMM)
+#define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM)
+/*time for expiring the completion of cfg packets*/
+#define CFG_PKTS_TIMEOUT 2000
+
+#define IS_MANAGMEMENT 0x100
+#define IS_MANAGMEMENT_CALLBACK 0x080
+#define IS_MGMT_STATUS_SUCCES 0x040
+
+/********************************************
+ *
+ * Tx/Rx Queue Structure
+ *
+ ********************************************/
+
+struct txq_entry_t {
+ struct list_head list;
+ int type;
+ int ack_idx;
+ u8 *buffer;
+ int buffer_size;
+ void *priv;
+ int status;
+ void (*tx_complete_func)(void *priv, int status);
+};
+
+struct rxq_entry_t {
+ struct list_head list;
+ u8 *buffer;
+ int buffer_size;
+};
+
+/********************************************
+ *
+ * Host IF Structure
+ *
+ ********************************************/
+struct wilc;
+struct wilc_hif_func {
+ int (*hif_init)(struct wilc *wilc, bool resume);
+ int (*hif_deinit)(struct wilc *wilc);
+ int (*hif_read_reg)(struct wilc *wilc, u32 addr, u32 *data);
+ int (*hif_write_reg)(struct wilc *wilc, u32 addr, u32 data);
+ int (*hif_block_rx)(struct wilc *wilc, u32 addr, u8 *buf, u32 size);
+ int (*hif_block_tx)(struct wilc *wilc, u32 addr, u8 *buf, u32 size);
+ int (*hif_read_int)(struct wilc *wilc, u32 *int_status);
+ int (*hif_clear_int_ext)(struct wilc *wilc, u32 val);
+ int (*hif_read_size)(struct wilc *wilc, u32 *size);
+ int (*hif_block_tx_ext)(struct wilc *wilc, u32 addr, u8 *buf, u32 size);
+ int (*hif_block_rx_ext)(struct wilc *wilc, u32 addr, u8 *buf, u32 size);
+ int (*hif_sync_ext)(struct wilc *wilc, int nint);
+ int (*enable_interrupt)(struct wilc *nic);
+ void (*disable_interrupt)(struct wilc *nic);
+};
+
+#define MAX_CFG_FRAME_SIZE 1468
+
+struct wilc_cfg_frame {
+ u8 wid_header[8];
+ u8 frame[MAX_CFG_FRAME_SIZE];
+};
+
+struct wilc_cfg_rsp {
+ int type;
+ u32 seq_no;
+};
+
+struct wilc;
+struct wilc_vif;
+
+int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
+ u32 buffer_size);
+int wilc_wlan_start(struct wilc *wilc);
+int wilc_wlan_stop(struct wilc *wilc);
+int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
+ u32 buffer_size, wilc_tx_complete_func_t func);
+int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count);
+void wilc_handle_isr(struct wilc *wilc);
+void wilc_wlan_cleanup(struct net_device *dev);
+int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
+ u32 buffer_size, int commit, u32 drv_handler);
+int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
+ u32 drv_handler);
+int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer,
+ u32 buffer_size);
+int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
+ u32 buffer_size, wilc_tx_complete_func_t func);
+void wilc_chip_sleep_manually(struct wilc *wilc);
+
+void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value);
+int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc);
+netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
+
+void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size);
+void host_wakeup_notify(struct wilc *wilc);
+void host_sleep_notify(struct wilc *wilc);
+void chip_allow_sleep(struct wilc *wilc);
+void chip_wakeup(struct wilc *wilc);
+int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
+ u32 count, u32 drv);
+#endif
--
2.7.4


2018-10-06 12:45:48

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC 00/19] wilc: added driver for wilc module

Ajay Singh <[email protected]> writes:

> This patch set contains the driver files from 'driver/staging/wilc1000'.
> Renamed the driver from 'wilc1000' to 'wilc' to have generic name, as
> the same driver will be used by other wilc family members.

I'm worried that the name 'wilc' is just too generic, I liked the
original name wilc1000 much more. Quite often when we have a new
generation of wireless devices there's also a new driver, so in the long
run I'm worried that a generic name like 'wilc' could be a source of
confusion. I think it's much smaller problem if 'wilc1000' (the driver)
also supports wilc3000 (the device), people are already used to that.
And if there's ever a need for a new driver, you can call it 'wilc4000'
or whatever.

For example, I think good driver names are like 'mt76' or 'rtw88'
(currently under review).

--
Kalle Valo

2018-10-08 05:18:06

by Ajay Singh

[permalink] [raw]
Subject: Re: [RFC 00/19] wilc: added driver for wilc module

On Sat, 6 Oct 2018 15:45:41 +0300
Kalle Valo <[email protected]> wrote:

> Ajay Singh <[email protected]> writes:
>
> > This patch set contains the driver files from
> > 'driver/staging/wilc1000'. Renamed the driver from 'wilc1000' to
> > 'wilc' to have generic name, as the same driver will be used by
> > other wilc family members.
>
> I'm worried that the name 'wilc' is just too generic, I liked the
> original name wilc1000 much more. Quite often when we have a new
> generation of wireless devices there's also a new driver, so in the
> long run I'm worried that a generic name like 'wilc' could be a
> source of confusion. I think it's much smaller problem if
> 'wilc1000' (the driver) also supports wilc3000 (the device), people
> are already used to that.

I also thought about retaining the same wilc1000 name, which has be
used for quite some time now. But as we are moving this driver
to '/driver/net/wireless/' freshly so thought it’s better to change in
the first commit.

As you know, 'wilc1000' name is used for folder name as well as module
name (i.e wilc1000.ko and wilc1000-spi.ko/wilc1000-sdio.ko). WILC3000 is
going to use the same modules(.ko).

Do you think its good approach to have 'wilc1000' folder but only remove
‘wilc1000’ prefix from .ko modules names in Makefile (i.e wilc.ko and
wilc-spio.ko/wilc-sdio.ko). So these .ko becomes generic and give clear
name to be used with both wilc1000 and wilc3000 modules.

Please let know what do you think about it and based on your input I
will make the change.

Also should I submit the v2 version by retaining old name or wait for
few more comments to include in that.

Regards,
Ajay

2018-10-08 07:38:25

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC 00/19] wilc: added driver for wilc module

Ajay Singh <[email protected]> writes:

> On Sat, 6 Oct 2018 15:45:41 +0300
> Kalle Valo <[email protected]> wrote:
>
>> Ajay Singh <[email protected]> writes:
>>
>> > This patch set contains the driver files from
>> > 'driver/staging/wilc1000'. Renamed the driver from 'wilc1000' to
>> > 'wilc' to have generic name, as the same driver will be used by
>> > other wilc family members.
>>
>> I'm worried that the name 'wilc' is just too generic, I liked the
>> original name wilc1000 much more. Quite often when we have a new
>> generation of wireless devices there's also a new driver, so in the
>> long run I'm worried that a generic name like 'wilc' could be a
>> source of confusion. I think it's much smaller problem if
>> 'wilc1000' (the driver) also supports wilc3000 (the device), people
>> are already used to that.
>
> I also thought about retaining the same wilc1000 name, which has be
> used for quite some time now. But as we are moving this driver
> to '/driver/net/wireless/' freshly so thought it’s better to change in
> the first commit.
>
> As you know, 'wilc1000' name is used for folder name as well as module
> name (i.e wilc1000.ko and wilc1000-spi.ko/wilc1000-sdio.ko). WILC3000 is
> going to use the same modules(.ko).

So just to be clear, this sounds good to me.

> Do you think its good approach to have 'wilc1000' folder but only remove
> ‘wilc1000’ prefix from .ko modules names in Makefile (i.e wilc.ko and
> wilc-spio.ko/wilc-sdio.ko). So these .ko becomes generic and give clear
> name to be used with both wilc1000 and wilc3000 modules.

But this I think is confusing. The driver should use the same name
everywhere, both in folder name ('wilc1000/') and in the module name
('wilc1000-*.ko').

If I'm understanding correctly you are worried that 'wilc1000-spi.ko'
also supports wilc3000 devices, but I don't see that as a problem. I
think it's very common (not just in wireless) that the marketing names
don't always match with driver names.

> Also should I submit the v2 version by retaining old name or wait for
> few more comments to include in that.

I haven't had a chance to review the driver and apparently nobody else
either. So I recommend waiting for review comments before submitting v2.

Also I suggest that you don't make any changes from the staging version,
like you did the rename. I think it's simplest to submit the code as it
is now in staging. And once you get review comments, first submit the
changes to staging and then send v2 for new review.

--
Kalle Valo

2018-10-08 14:17:02

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 02/19] wilc: add coreconfigurator.c


> +static inline u16 get_beacon_period(u8 *data)
> +{
> + u16 bcn_per;
> +
> + bcn_per = data[0];
> + bcn_per |= (data[1] << 8);
> +
> + return bcn_per;
> +}

Remove and use get_unaligned_le16().

> +static inline u32 get_beacon_timestamp_lo(u8 *data)
> +{
> + u32 time_stamp = 0;
> + u32 index = MAC_HDR_LEN;
> +
> + time_stamp |= data[index++];
> + time_stamp |= (data[index++] << 8);
> + time_stamp |= (data[index++] << 16);
> + time_stamp |= (data[index] << 24);
> +
> + return time_stamp;
> +}

get_unaligned_le32()

> +static inline u32 get_beacon_timestamp_hi(u8 *data)
> +{
> + u32 time_stamp = 0;
> + u32 index = (MAC_HDR_LEN + 4);
> +
> + time_stamp |= data[index++];
> + time_stamp |= (data[index++] << 8);
> + time_stamp |= (data[index++] << 16);
> + time_stamp |= (data[index] << 24);
> +
> + return time_stamp;
> +}

get_unaligned_le32()

> +static inline enum sub_frame_type get_sub_type(u8 *header)
> +{
> + return ((enum sub_frame_type)(header[0] & 0xFC));
> +}

remove, use include/linux/ieee80211.h.

> +static inline u8 get_to_ds(u8 *header)
> +{
> + return (header[1] & 0x01);
> +}
> +
> +static inline u8 get_from_ds(u8 *header)
> +{
> + return ((header[1] & 0x02) >> 1);
> +}

dito

> +static inline void get_address1(u8 *msa, u8 *addr)
> +{
> + memcpy(addr, msa + 4, 6);
> +}
> +
> +static inline void get_address2(u8 *msa, u8 *addr)
> +{
> + memcpy(addr, msa + 10, 6);
> +}
> +
> +static inline void get_address3(u8 *msa, u8 *addr)

you probably shouldn't memcpy() here, that's expensive.

> +static inline void get_bssid(u8 *data, u8 *bssid)
> +{
> + if (get_from_ds(data) == 1)
> + get_address2(data, bssid);
> + else if (get_to_ds(data) == 1)
> + get_address1(data, bssid);
> + else
> + get_address3(data, bssid);
> +}

I just noticed we don't have this in ieee80211.h, but perhaps we should.

I think you should just return a pointer though, there's no point in
memcpy().

> +static inline void get_ssid(u8 *data, u8 *ssid, u8 *p_ssid_len)
> +{
> + u8 i, j, len;
> +
> + len = data[TAG_PARAM_OFFSET + 1];
> + j = TAG_PARAM_OFFSET + 2;
> +
> + if (len >= MAX_SSID_LEN)
> + len = 0;
> +
> + for (i = 0; i < len; i++, j++)
> + ssid[i] = data[j];
> +
> + ssid[len] = '\0';

SSIDs are *NOT* strings, don't pretend they are.

> + *p_ssid_len = len;
> +}

Uh, no, we have helper functions for finding elements.

Again, return something, don't just fill out parameters.

> +static inline u16 get_cap_info(u8 *data)
> +{
> + u16 cap_info = 0;
> + u16 index = MAC_HDR_LEN;
> + enum sub_frame_type st;
> +
> + st = get_sub_type(data);
> +
> + if (st == BEACON || st == PROBE_RSP)
> + index += TIME_STAMP_LEN + BEACON_INTERVAL_LEN;
> +
> + cap_info = data[index];
> + cap_info |= (data[index + 1] << 8);
> +
> + return cap_info;
> +}

Umm, no, ieee80211.h.

> +static inline u16 get_asoc_status(u8 *data)
> +{
> + u16 asoc_status;
> +
> + asoc_status = data[3];
> + return (asoc_status << 8) | data[2];
> +}

I'll just stop here - you need to replace almost all of this file with
ieee80211.h stuff instead.

johannes

2018-10-08 14:20:32

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h

On Wed, 2018-09-26 at 15:55 +0530, Ajay Singh wrote:

> +#include <linux/ieee80211.h>

you include it

> +#include "coreconfigurator.h"
> +
> +#define IDLE_MODE 0x00
> +#define AP_MODE 0x01
> +#define STATION_MODE 0x02
> +#define GO_MODE 0x03
> +#define CLIENT_MODE 0x04
> +#define ACTION 0xD0
> +#define PROBE_REQ 0x40
> +#define PROBE_RESP 0x50

please use it too.

> +#define ACTION_FRM_IDX 0
> +#define PROBE_REQ_IDX 1
> +#define MAX_NUM_STA 9
> +#define ACTIVE_SCAN_TIME 10
> +#define PASSIVE_SCAN_TIME 1200
> +#define MIN_SCAN_TIME 10
> +#define MAX_SCAN_TIME 1200
> +#define DEFAULT_SCAN 0
> +#define USER_SCAN BIT(0)
> +#define OBSS_PERIODIC_SCAN BIT(1)
> +#define OBSS_ONETIME_SCAN BIT(2)
> +#define GTK_RX_KEY_BUFF_LEN 24
> +#define ADDKEY 0x1
> +#define REMOVEKEY 0x2
> +#define DEFAULTKEY 0x4
> +#define ADDKEY_AP 0x8
> +#define MAX_NUM_SCANNED_NETWORKS 100
> +#define MAX_NUM_SCANNED_NETWORKS_SHADOW 130
> +#define MAX_NUM_PROBED_SSID 10
> +#define CHANNEL_SCAN_TIME 250
> +
> +#define TX_MIC_KEY_LEN 8
> +#define RX_MIC_KEY_LEN 8
> +#define PTK_KEY_LEN 16
> +
> +#define TX_MIC_KEY_MSG_LEN 26
> +#define RX_MIC_KEY_MSG_LEN 48
> +#define PTK_KEY_MSG_LEN 39
> +
> +#define PMKSA_KEY_LEN 22
> +#define ETH_ALEN 6

umm?

> +#define PMKID_LEN 16

??

> +#define WILC_MAX_NUM_PMKIDS 16
> +#define WILC_ADD_STA_LENGTH 40
> +#define NUM_CONCURRENT_IFC 2
> +#define DRV_HANDLER_SIZE 5
> +#define DRV_HANDLER_MASK 0x000000FF

Also this file is strangely mixing
* 802.11 constants (that you shouldn't have anyway)
* driver constants/structs
* hardware/firmware-related things (at least it seems like - e.g. the
"REMOVEKEY" constant)

Please clean that up, separate the things, and pick a better
namespace... just having "REMOVEKEY" is probably not a good idea.

> +typedef void (*wilc_remain_on_chan_expired)(void *, u32);
> +typedef void (*wilc_remain_on_chan_ready)(void *);

Please no typedefs.

> +struct rcvd_net_info {
> + u8 *buffer;
> + u32 len;
> +};
> +
> +struct hidden_net_info {
> + u8 *ssid;
> + u8 ssid_len;
> +};
> +
> +struct hidden_network {
> + struct hidden_net_info *net_info;
> + u8 n_ssids;
> +};

This seems really odd - what part doesn't cfg80211 already handle?

johannes

2018-10-08 14:31:31

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c


> + *currbyte = (u32)0 & DRV_HANDLER_MASK;

You do this a few times, not sure what it's supposed to achieve?

> + if (param->flag & RETRY_LONG) {
> + u16 limit = param->long_retry_limit;
> +
> + if (limit > 0 && limit < 256) {
> + wid_list[i].id = WID_LONG_RETRY_LIMIT;
> + wid_list[i].val = (s8 *)&param->long_retry_limit;
> + wid_list[i].type = WID_SHORT;
> + wid_list[i].size = sizeof(u16);
> + hif_drv->cfg_values.long_retry_limit = limit;
> + } else {
> + netdev_err(vif->ndev, "Range(1~256) over\n");
> + goto unlock;
> + }
> + i++;
> + }

So ... can anyone tell me why there's a complete driver-internal
messaging infrastructure in this, that even suppresses errors like here
(out of range just results in a message rather than returning an error
to wherever it originated)?

It almost *seems* like it's a to-device infrastructure, but it can't be
since it uses host pointers everywhere?

I think this code would be far better off without the "bounce in driver
to resolve host pointers" step.

> + if (conn_attr->ssid) {
> + memcpy(cur_byte, conn_attr->ssid, conn_attr->ssid_len);
> + cur_byte[conn_attr->ssid_len] = '\0';
> + }
> + cur_byte += MAX_SSID_LEN;

again, SSIDs are not 0-terminated strings

> +static void host_int_fill_join_bss_param(struct join_bss_param *param, u8 *ies,
> + u16 *out_index, u8 *pcipher_tc,
> + u8 *auth_total_cnt, u32 tsf_lo,
> + u8 *rates_no)
> +{
> + u8 ext_rates_no;
> + u16 offset;
> + u8 pcipher_cnt;
> + u8 auth_cnt;
> + u8 i, j;
> + u16 index = *out_index;
> +
> + if (ies[index] == WLAN_EID_SUPP_RATES) {
> + *rates_no = ies[index + 1];
> + param->supp_rates[0] = *rates_no;
> + index += 2;
> +
> + for (i = 0; i < *rates_no; i++)
> + param->supp_rates[i + 1] = ies[index + i];
> +
> + index += *rates_no;
> + } else if (ies[index] == WLAN_EID_EXT_SUPP_RATES) {
> + ext_rates_no = ies[index + 1];
> + if (ext_rates_no > (MAX_RATES_SUPPORTED - *rates_no))
> + param->supp_rates[0] = MAX_RATES_SUPPORTED;
> + else
> + param->supp_rates[0] += ext_rates_no;
> + index += 2;
> + for (i = 0; i < (param->supp_rates[0] - *rates_no); i++)
> + param->supp_rates[*rates_no + i + 1] = ies[index + i];
> +
> + index += ext_rates_no;
> + } else if (ies[index] == WLAN_EID_HT_CAPABILITY) {
> + param->ht_capable = true;
> + index += ies[index + 1] + 2;
> + } else if ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) &&
> + (ies[index + 2] == 0x00) && (ies[index + 3] == 0x50) &&
> + (ies[index + 4] == 0xF2) && (ies[index + 5] == 0x02) &&
> + ((ies[index + 6] == 0x00) || (ies[index + 6] == 0x01)) &&
> + (ies[index + 7] == 0x01)) {
> + param->wmm_cap = true;
> +
> + if (ies[index + 8] & BIT(7))
> + param->uapsd_cap = true;
> + index += ies[index + 1] + 2;
> + } else if ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) &&
> + (ies[index + 2] == 0x50) && (ies[index + 3] == 0x6f) &&
> + (ies[index + 4] == 0x9a) &&
> + (ies[index + 5] == 0x09) && (ies[index + 6] == 0x0c)) {
> + u16 p2p_cnt;
> +
> + param->tsf = tsf_lo;
> + param->noa_enabled = 1;
> + param->idx = ies[index + 9];
> +
> + if (ies[index + 10] & BIT(7)) {
> + param->opp_enabled = 1;
> + param->ct_window = ies[index + 10];
> + } else {
> + param->opp_enabled = 0;
> + }
> +
> + param->cnt = ies[index + 11];
> + p2p_cnt = index + 12;
> +
> + memcpy(param->duration, ies + p2p_cnt, 4);
> + p2p_cnt += 4;
> +
> + memcpy(param->interval, ies + p2p_cnt, 4);
> + p2p_cnt += 4;
> +
> + memcpy(param->start_time, ies + p2p_cnt, 4);
> +
> + index += ies[index + 1] + 2;
> + } else if ((ies[index] == WLAN_EID_RSN) ||
> + ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) &&
> + (ies[index + 2] == 0x00) &&
> + (ies[index + 3] == 0x50) && (ies[index + 4] == 0xF2) &&
> + (ies[index + 5] == 0x01))) {
> + u16 rsn_idx = index;
> +
> + if (ies[rsn_idx] == WLAN_EID_RSN) {
> + param->mode_802_11i = 2;
> + } else {
> + if (param->mode_802_11i == 0)
> + param->mode_802_11i = 1;
> + rsn_idx += 4;
> + }
> +
> + rsn_idx += 7;
> + param->rsn_grp_policy = ies[rsn_idx];
> + rsn_idx++;
> + offset = ies[rsn_idx] * 4;
> + pcipher_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
> + rsn_idx += 2;
> +
> + i = *pcipher_tc;
> + j = 0;
> + for (; i < (pcipher_cnt + *pcipher_tc) && i < 3; i++, j++) {
> + u8 *policy = &param->rsn_pcip_policy[i];
> +
> + *policy = ies[rsn_idx + ((j + 1) * 4) - 1];
> + }
> +
> + *pcipher_tc += pcipher_cnt;
> + rsn_idx += offset;
> +
> + offset = ies[rsn_idx] * 4;
> +
> + auth_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
> + rsn_idx += 2;
> + i = *auth_total_cnt;
> + j = 0;
> + for (; i < (*auth_total_cnt + auth_cnt); i++, j++) {
> + u8 *policy = &param->rsn_auth_policy[i];
> +
> + *policy = ies[rsn_idx + ((j + 1) * 4) - 1];
> + }
> +
> + *auth_total_cnt += auth_cnt;
> + rsn_idx += offset;
> +
> + if (ies[index] == WLAN_EID_RSN) {
> + param->rsn_cap[0] = ies[rsn_idx];
> + param->rsn_cap[1] = ies[rsn_idx + 1];
> + rsn_idx += 2;
> + }
> + param->rsn_found = true;
> + index += ies[index + 1] + 2;
> + } else {
> + index += ies[index + 1] + 2;
> + }
> +
> + *out_index = index;
> +}

Again, use actual kernel infrastructure for much of this.

> + cur_byte = wid.val;
> + *cur_byte++ = (param->interval & 0xFF);
> + *cur_byte++ = ((param->interval >> 8) & 0xFF);
> + *cur_byte++ = ((param->interval >> 16) & 0xFF);
> + *cur_byte++ = ((param->interval >> 24) & 0xFF);

put_unaligned_le32().

> + *cur_byte++ = param->aid & 0xFF;
> + *cur_byte++ = (param->aid >> 8) & 0xFF;

and so on

but then again, I just suggested to not have these "pack" functions to
start with, or at least not in this way, since it just means you first
pack everything into host structs, and then repack everything again into
firmware format ...


So far I guess I'd say:
* use more kernel infra, in particular {get,put}_unaligned_le{16,32}
* name your device/driver-specific constants better, rather than things
like "SET_CFG" which leave everyone wondering if it's specific to
this driver or something from elsewhere

johannes

2018-10-08 14:33:57

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 05/19] wilc: add wilc_wlan_if.h


> +#define WILC_TX_ERR_NO_BUF (-2)

Hmm? what's wrong with just e.g. -ENOBUFS? If it doesn't go to userspace
it doesn't matter, and if it does you can't use this anyway? This would
be -ENOENT which is a bad idea.

> +
> +/********************************************
> + *
> + * Wlan Configuration ID
> + *
> + ********************************************/
> +#define WILC_MULTICAST_TABLE_SIZE 8
> +#define MAX_SSID_LEN 33

Err, it's 32?

> +#define MAX_RATES_SUPPORTED 12
> +
> +enum bss_types {
> + INFRASTRUCTURE = 0,
> + INDEPENDENT,
> + AP,
> +};
> +
> +enum {
> + B_ONLY_MODE = 0, /* 1, 2 M, otherwise 5, 11 M */
> + G_ONLY_MODE, /* 6,12,24 otherwise 9,18,36,48,54 */
> + G_MIXED_11B_1_MODE, /* 1,2,5.5,11 otherwise all on */
> + G_MIXED_11B_2_MODE, /* 1,2,5,11,6,12,24 otherwise all on */
> +};
> +
> +enum {
> + G_SHORT_PREAMBLE = 0, /* Short Preamble */
> + G_LONG_PREAMBLE = 1, /* Long Preamble */
> + G_AUTO_PREAMBLE = 2, /* Auto Preamble Selection */
> +};

here we have a lot of those "constants should have some sort of prefix"
things ... it's not even clear if they're spec or not:

> +enum authtype {
> + OPEN_SYSTEM = 1,
> + SHARED_KEY = 2,
> + ANY = 3,
> + IEEE8021 = 5
> +};

These look like they're spec but aren't ... not a good idea.

johannes

2018-10-08 14:41:29

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 13/19] wilc: add linux_wlan.c

On Wed, 2018-09-26 at 15:55 +0530, Ajay Singh wrote:
> Moved '/driver/staging/wilc1000/linux_wlan.c' to
> 'drivers/net/wireless/microchip/wilc/'.
>
> Signed-off-by: Ajay Singh <[email protected]>
> ---
> drivers/net/wireless/microchip/wilc/linux_wlan.c | 1161 ++++++++++++++++++++++
> 1 file changed, 1161 insertions(+)
> create mode 100644 drivers/net/wireless/microchip/wilc/linux_wlan.c

Hmm. It's pretty obviously a linux driver, what's the point?

> diff --git a/drivers/net/wireless/microchip/wilc/linux_wlan.c b/drivers/net/wireless/microchip/wilc/linux_wlan.c
> new file mode 100644
> index 0000000..76c9012
> --- /dev/null
> +++ b/drivers/net/wireless/microchip/wilc/linux_wlan.c
> @@ -0,0 +1,1161 @@
> +// 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 "wilc_wfi_cfgoperations.h"
> +
> +static int dev_state_ev_handler(struct notifier_block *this,
> + unsigned long event, void *ptr)
> +{
> + struct in_ifaddr *dev_iface = ptr;
> + struct wilc_priv *priv;
> + struct host_if_drv *hif_drv;
> + struct net_device *dev;
> + u8 *ip_addr_buf;
> + struct wilc_vif *vif;
> + u8 null_ip[4] = {0};
> + char wlan_dev_name[5] = "wlan0";

Regardless of what you're trying to do, thta seems like a bad idea.

> + if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev)
> + return NOTIFY_DONE;
> +
> + if (memcmp(dev_iface->ifa_label, "wlan0", 5) &&
> + memcmp(dev_iface->ifa_label, "p2p0", 4))
> + return NOTIFY_DONE;

That too. What???

> + dev = (struct net_device *)dev_iface->ifa_dev->dev;
> + if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
> + return NOTIFY_DONE;
> +
> + priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
> + if (!priv)
> + return NOTIFY_DONE;
> +
> + hif_drv = (struct host_if_drv *)priv->hif_drv;
> + vif = netdev_priv(dev);
> + if (!vif || !hif_drv)
> + return NOTIFY_DONE;
> +
> + switch (event) {
> + case NETDEV_UP:
> + if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
> + hif_drv->ifc_up = 1;
> + vif->obtaining_ip = false;
> + del_timer(&vif->during_ip_timer);
> + }
> +
> + if (vif->wilc->enable_ps)
> + wilc_set_power_mgmt(vif, 1, 0);
> +
> + netdev_dbg(dev, "[%s] Up IP\n", dev_iface->ifa_label);
> +
> + ip_addr_buf = (char *)&dev_iface->ifa_address;
> + netdev_dbg(dev, "IP add=%d:%d:%d:%d\n",
> + ip_addr_buf[0], ip_addr_buf[1],
> + ip_addr_buf[2], ip_addr_buf[3]);

%pI4, I believe, but I think you should just remove it, it likely won't
have an IP address anyway, and you might have multiple, and so this is
just broken.

> + eth_h = (struct ethhdr *)(skb->data);
> + if (eth_h->h_proto == cpu_to_be16(0x8e88))
> + netdev_dbg(ndev, "EAPOL transmitted\n");

Err, no, just remove that.

> + ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));

Sure, everything is IP. You just checked that it wasn't EAPOL?

> + udp_buf = (char *)ih + sizeof(struct iphdr);
> + if ((udp_buf[1] == 68 && udp_buf[3] == 67) ||
> + (udp_buf[1] == 67 && udp_buf[3] == 68))
> + netdev_dbg(ndev, "DHCP Message transmitted, type:%x %x %x\n",
> + udp_buf[248], udp_buf[249], udp_buf[250]);

Umm... no. Just remove that too.

> + vif->netstats.tx_packets++;
> + vif->netstats.tx_bytes += tx_data->size;
> + tx_data->bssid = wilc->vif[vif->idx]->bssid;
> + queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
> + tx_data->buff, tx_data->size,
> + linux_wlan_tx_complete);
> +
> + if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
> + netif_stop_queue(wilc->vif[0]->ndev);
> + netif_stop_queue(wilc->vif[1]->ndev);
> + }

It seems like a pretty bad idea to hard-code two interfaces, we do
dynamic addition/removal these days, in *particular* for P2P.

> +static int wilc_mac_close(struct net_device *ndev)
> +{
> + struct wilc_priv *priv;
> + struct wilc_vif *vif = netdev_priv(ndev);
> + struct host_if_drv *hif_drv;
> + struct wilc *wl;
> +
> + if (!vif || !vif->ndev || !vif->ndev->ieee80211_ptr ||
> + !vif->ndev->ieee80211_ptr->wiphy)
> + return 0;

I'm not really sure why you're so paranoid, none of that can possibly
happen.

> + priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
> + wl = vif->wilc;
> +
> + if (!priv)
> + return 0;

Nor can this.

> + hif_drv = (struct host_if_drv *)priv->hif_drv;
> +
> + netdev_dbg(ndev, "Mac close\n");
> +
> + if (!wl)
> + return 0;
> +
> + if (!hif_drv)
> + return 0;

Nor these.

johannes

2018-10-08 14:44:47

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 14/19] wilc: add linux_mon.c

On Wed, 2018-09-26 at 15:55 +0530, Ajay Singh wrote:
>
> +static struct net_device *wilc_wfi_mon; /* global monitor netdev */

There might not exist platforms with multiple devices (yet), but it's
really bad practice to do this anyway.

> +static u8 srcadd[6];
> +static u8 bssid[6];
> +
> +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
> +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive*/

Uh.. we have a radiotap include file and you already use it, why?

> +void wilc_wfi_deinit_mon_interface(void)
> +{
> + bool rollback_lock = false;
> +
> + if (wilc_wfi_mon) {
> + if (rtnl_is_locked()) {
> + rtnl_unlock();
> + rollback_lock = true;
> + }
> + unregister_netdev(wilc_wfi_mon);
> +
> + if (rollback_lock) {
> + rtnl_lock();
> + rollback_lock = false;
> + }
> + wilc_wfi_mon = NULL;
> + }
> +}

Uh, no, you really cannot do conditional locking like this.

But seeing things like this pretty much destroys all of the confidence I
might have had of the code, so I'd say we cannot merge this until you
can demonstrate somebody more familiar with Linux has reviewed it, I'm
just doing a drive-by review for the stack integration aspects (and
haven't even found where that happens yet).

johannes

2018-10-08 14:57:25

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 12/19] wilc: add wilc_wfi_cfgoperations.c

On Wed, 2018-09-26 at 15:55 +0530, Ajay Singh wrote:
>
> +#define NO_ENCRYPT 0
> +#define ENCRYPT_ENABLED BIT(0)
> +#define WEP BIT(1)
> +#define WEP_EXTENDED BIT(2)
> +#define WPA BIT(3)
> +#define WPA2 BIT(4)
> +#define AES BIT(5)
> +#define TKIP BIT(6)
> +
> +#define FRAME_TYPE_ID 0
> +#define ACTION_CAT_ID 24
> +#define ACTION_SUBTYPE_ID 25
> +#define P2P_PUB_ACTION_SUBTYPE 30
> +
> +#define ACTION_FRAME 0xd0
> +#define GO_INTENT_ATTR_ID 0x04
> +#define CHANLIST_ATTR_ID 0x0b
> +#define OPERCHAN_ATTR_ID 0x11
> +#define PUB_ACTION_ATTR_ID 0x04
> +#define P2PELEM_ATTR_ID 0xdd
> +
> +#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 PUBLIC_ACT_VENDORSPEC 0x09
> +#define GAS_INITIAL_REQ 0x0a
> +#define GAS_INITIAL_RSP 0x0b
> +
> +#define INVALID_CHANNEL 0
> +
> +#define nl80211_SCAN_RESULT_EXPIRE (3 * HZ)

???

I mentioned namespacing, but you can't steal a different one :-)

> +#define AGING_TIME (9 * 1000)
> +#define DURING_IP_TIME_OUT 15000

Not clear what the units are - should be using HZ?

> +static void clear_shadow_scan(struct wilc_priv *priv)
> +{
> + int i;
> +
> + for (i = 0; i < priv->scanned_cnt; i++) {
> + kfree(priv->scanned_shadow[i].ies);
> + priv->scanned_shadow[i].ies = NULL;
> +
> + kfree(priv->scanned_shadow[i].join_params);
> + priv->scanned_shadow[i].join_params = NULL;
> + }
> + priv->scanned_cnt = 0;
> +}

This seems unlikely to be a good idea - why keep things around in the
driver?

> +static u32 get_rssi_avg(struct network_info *network_info)
> +{
> + u8 i;
> + int rssi_v = 0;
> + u8 num_rssi = (network_info->rssi_history.full) ?
> + NUM_RSSI : (network_info->rssi_history.index);
> +
> + for (i = 0; i < num_rssi; i++)
> + rssi_v += network_info->rssi_history.samples[i];
> +
> + rssi_v /= num_rssi;
> + return rssi_v;
> +}

Why do you need a "real" average rather than EWMA which we have helpers
for?

> +static void refresh_scan(struct wilc_priv *priv, bool direct_scan)
> +{
> + struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy;
> + int i;
> +
> + for (i = 0; i < priv->scanned_cnt; i++) {
> + struct network_info *network_info;
> + s32 freq;
> + struct ieee80211_channel *channel;
> + int rssi;
> + struct cfg80211_bss *bss;
> +
> + network_info = &priv->scanned_shadow[i];
> +
> + if (!memcmp("DIRECT-", network_info->ssid, 7) && !direct_scan)
> + continue;

Err, no? Don't do that? What's the point?

I don't know what you need the shadow stuff for, but you should remove
it anyway, and use the cfg80211 functionality instead. If not
sufficient, propose patches to improve it?

> + if (memcmp("DIRECT-", network_info->ssid, 7))
> + return;

same here

> +static int cancel_remain_on_channel(struct wiphy *wiphy,
> + struct wireless_dev *wdev,
> + u64 cookie)
> +{
> + struct wilc_priv *priv = wiphy_priv(wiphy);
> + struct wilc_vif *vif = netdev_priv(priv->dev);
> +
> + return wilc_listen_state_expired(vif,
> + priv->remain_on_ch_params.listen_session_id);
> +}

You really should be using the 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 p2p_mgmt_data *mgmt_tx;
> + struct wilc_priv *priv = wiphy_priv(wiphy);
> + struct host_if_drv *wfi_drv = priv->hif_drv;
> + struct wilc_vif *vif = netdev_priv(wdev->netdev);
> + u32 buf_len = len + sizeof(p2p_vendor_spec) + sizeof(priv->p2p.local_random);
> + int ret = 0;
> +
> + *cookie = (unsigned long)buf;

Don't use pointers for the cookie, it leaks valuable data about KASLR.

> +static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
> +{
> + return 0;
> +}

Uh, not a good idea. Well, a good idea would be to actually support it,
but not to pretend to.

> +static struct wireless_dev *wilc_wfi_cfg_alloc(void)
> +{
> + struct wireless_dev *wdev;
> +
> + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
> + if (!wdev)
> + goto out;
> +
> + wdev->wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(struct wilc_priv));
> + if (!wdev->wiphy)
> + goto free_mem;
> +
> + wilc_band_2ghz.ht_cap.ht_supported = 1;
> + wilc_band_2ghz.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
> + wilc_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
> + wilc_band_2ghz.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
> + wilc_band_2ghz.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;

This kind of static variable use is weird ... you're just initializing
to constant values?

If that's really the case then just put that into the initializer, if
not you need to kmemdup() to have this per device.

johannes

2018-10-08 19:19:07

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [RFC 00/19] wilc: added driver for wilc module



On 10/08/2018 12:38 AM, Kalle Valo wrote:
> Ajay Singh <[email protected]> writes:
>
>> On Sat, 6 Oct 2018 15:45:41 +0300
>> Kalle Valo <[email protected]> wrote:
>>
>>> Ajay Singh <[email protected]> writes:
>>>
>>>> This patch set contains the driver files from
>>>> 'driver/staging/wilc1000'. Renamed the driver from 'wilc1000' to
>>>> 'wilc' to have generic name, as the same driver will be used by
>>>> other wilc family members.
>>>
>>> I'm worried that the name 'wilc' is just too generic, I liked the
>>> original name wilc1000 much more. Quite often when we have a new
>>> generation of wireless devices there's also a new driver, so in the
>>> long run I'm worried that a generic name like 'wilc' could be a
>>> source of confusion. I think it's much smaller problem if
>>> 'wilc1000' (the driver) also supports wilc3000 (the device), people
>>> are already used to that.

> If I'm understanding correctly you are worried that 'wilc1000-spi.ko'
> also supports wilc3000 devices, but I don't see that as a problem. I
> think it's very common (not just in wireless) that the marketing names
> don't always match with driver names.
>

It's highly unlikely that microchip will have a new generation of wilc devices other than wilc1000 and wilc3000, since a new family is already in development.
And in case a new generation was developed, it will be best to support it in the current driver because of the similarities between wilc devices.

I'm afraid that it might be more confusing for users to use wilc1000 naming while they are using wilc3000 hardware. It's not only that the name that is different from the marketing name, but it also refers to another existing product.

Thanks,
Adham

2018-10-09 04:23:45

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 12/19] wilc: add wilc_wfi_cfgoperations.c



On 10/08/2018 07:57 AM, Johannes Berg wrote:
> On Wed, 2018-09-26 at 15:55 +0530, Ajay Singh wrote:
>>
>> +static void clear_shadow_scan(struct wilc_priv *priv)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < priv->scanned_cnt; i++) {
>> + kfree(priv->scanned_shadow[i].ies);
>> + priv->scanned_shadow[i].ies = NULL;
>> +
>> + kfree(priv->scanned_shadow[i].join_params);
>> + priv->scanned_shadow[i].join_params = NULL;
>> + }
>> + priv->scanned_cnt = 0;
>> +}
>
> This seems unlikely to be a good idea - why keep things around in the
> driver?
>
>
>> +static void refresh_scan(struct wilc_priv *priv, bool direct_scan)
>> +{
>> + struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy;
>> + int i;
>> +
>> + for (i = 0; i < priv->scanned_cnt; i++) {
>> + struct network_info *network_info;
>> + s32 freq;
>> + struct ieee80211_channel *channel;
>> + int rssi;
>> + struct cfg80211_bss *bss;
>> +
>> + network_info = &priv->scanned_shadow[i];
>> +
>> + if (!memcmp("DIRECT-", network_info->ssid, 7) && !direct_scan)
>> + continue;
>
> Err, no? Don't do that? What's the point?
>
> I don't know what you need the shadow stuff for, but you should remove
> it anyway, and use the cfg80211 functionality instead. If not
> sufficient, propose patches to improve it?

The point behind using a shadow buffer was to keep the scan results consistent between consecutive scans, and smooth out the cases where an AP isn't found momentarily during scanning.
In this implementation, APs found during scanning are added to the shadow list, and removed if not found again for a period of time.

I'm not much in favour of this implementation neither since it complicates the driver's logic, but it was serving the purpose.

>
>> + if (memcmp("DIRECT-", network_info->ssid, 7))
>> + return;
>
> same here
>
>
> johannes
>

Thanks,
Adham

2018-10-09 07:55:39

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 12/19] wilc: add wilc_wfi_cfgoperations.c

On Tue, 2018-10-09 at 04:23 +0000, [email protected] wrote:
>
> > I don't know what you need the shadow stuff for, but you should remove
> > it anyway, and use the cfg80211 functionality instead. If not
> > sufficient, propose patches to improve it?
>
> The point behind using a shadow buffer was to keep the scan results
> consistent between consecutive scans, and smooth out the cases where
> an AP isn't found momentarily during scanning.
> In this implementation, APs found during scanning are added to the
> shadow list, and removed if not found again for a period of time.
>
> I'm not much in favour of this implementation neither since it
> complicates the driver's logic, but it was serving the purpose.

You really should remove it - cfg80211 *and* wpa_s already do this if
required.

johannes

2018-10-09 09:42:43

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 02/19] wilc: add coreconfigurator.c

Hi,

Firstly, thanks alot for taking out time and reviewing our driver.
I will work on review comment and submit the updated code changes.

On 10/8/2018 7:46 PM, Johannes Berg wrote:
>> +static inline u16 get_beacon_period(u8 *data)
>> +{
>> + u16 bcn_per;
>> +
>> + bcn_per = data[0];
>> + bcn_per |= (data[1] << 8);
>> +
>> + return bcn_per;
>> +}
> Remove and use get_unaligned_le16().
>
Sure, I will change these to make use of get_unalinged_le16() API.
>> +static inline u32 get_beacon_timestamp_lo(u8 *data)
>> +{
>> + u32 time_stamp = 0;
>> + u32 index = MAC_HDR_LEN;
>> +
>> + time_stamp |= data[index++];
>> + time_stamp |= (data[index++] << 8);
>> + time_stamp |= (data[index++] << 16);
>> + time_stamp |= (data[index] << 24);
>> +
>> + return time_stamp;
>> +}
> get_unaligned_le32()
>
Ack.
>> +static inline u32 get_beacon_timestamp_hi(u8 *data)
>> +{
>> + u32 time_stamp = 0;
>> + u32 index = (MAC_HDR_LEN + 4);
>> +
>> + time_stamp |= data[index++];
>> + time_stamp |= (data[index++] << 8);
>> + time_stamp |= (data[index++] << 16);
>> + time_stamp |= (data[index] << 24);
>> +
>> + return time_stamp;
>> +}
> get_unaligned_le32()
>
Ack
>> +static inline enum sub_frame_type get_sub_type(u8 *header)
>> +{
>> + return ((enum sub_frame_type)(header[0] & 0xFC));
>> +}
> remove, use include/linux/ieee80211.h.
>
Did you mean to use '& IEEE80211_FCTL_STYPE' to get the frame sub type,
instead of adding this API.
>> +static inline u8 get_to_ds(u8 *header)
>> +{
>> + return (header[1] & 0x01);
>> +}
>> +
>> +static inline u8 get_from_ds(u8 *header)
>> +{
>> + return ((header[1] & 0x02) >> 1);
>> +}
> dito
>
Ack.  
>> +static inline void get_address1(u8 *msa, u8 *addr)
>> +{
>> + memcpy(addr, msa + 4, 6);
>> +}
>> +
>> +static inline void get_address2(u8 *msa, u8 *addr)
>> +{
>> + memcpy(addr, msa + 10, 6);
>> +}
>> +
>> +static inline void get_address3(u8 *msa, u8 *addr)
> you probably shouldn't memcpy() here, that's expensive.
>
Got your point but currently  a copy of 'network_info' is maintained for
the shadow buffer. As we have to work on removing the use of shadow
buffer so after those changes this extra memcpy can be avoided.

>> +static inline void get_bssid(u8 *data, u8 *bssid)
>> +{
>> + if (get_from_ds(data) == 1)
>> + get_address2(data, bssid);
>> + else if (get_to_ds(data) == 1)
>> + get_address1(data, bssid);
>> + else
>> + get_address3(data, bssid);
>> +}
> I just noticed we don't have this in ieee80211.h, but perhaps we should.
>
> I think you should just return a pointer though, there's no point in
> memcpy().
>
Same as above.
>> +static inline void get_ssid(u8 *data, u8 *ssid, u8 *p_ssid_len)
>> +{
>> + u8 i, j, len;
>> +
>> + len = data[TAG_PARAM_OFFSET + 1];
>> + j = TAG_PARAM_OFFSET + 2;
>> +
>> + if (len >= MAX_SSID_LEN)
>> + len = 0;
>> +
>> + for (i = 0; i < len; i++, j++)
>> + ssid[i] = data[j];
>> +
>> + ssid[len] = '\0';
> SSIDs are *NOT* strings, don't pretend they are.
>
Will check and modify to make use of ssid_len instead of using '\0' as
terminator.
>> + *p_ssid_len = len;
>> +}
> Uh, no, we have helper functions for finding elements.
>
> Again, return something, don't just fill out parameters.
>
>> +static inline u16 get_cap_info(u8 *data)
>> +{
>> + u16 cap_info = 0;
>> + u16 index = MAC_HDR_LEN;
>> + enum sub_frame_type st;
>> +
>> + st = get_sub_type(data);
>> +
>> + if (st == BEACON || st == PROBE_RSP)
>> + index += TIME_STAMP_LEN + BEACON_INTERVAL_LEN;
>> +
>> + cap_info = data[index];
>> + cap_info |= (data[index + 1] << 8);
>> +
>> + return cap_info;
>> +}
> Umm, no, ieee80211.h.
>
Ack.
>> +static inline u16 get_asoc_status(u8 *data)
>> +{
>> + u16 asoc_status;
>> +
>> + asoc_status = data[3];
>> + return (asoc_status << 8) | data[2];
>> +}
> I'll just stop here - you need to replace almost all of this file with
> ieee80211.h stuff instead.

As suggested, will modify this code to make use of ieee80211.h header.

Regards,
Ajay


2018-10-09 10:05:44

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 02/19] wilc: add coreconfigurator.c

On Tue, 2018-10-09 at 15:12 +0530, Ajay Singh wrote:

> > > +static inline enum sub_frame_type get_sub_type(u8 *header)
> > > +{
> > > + return ((enum sub_frame_type)(header[0] & 0xFC));
> > > +}
> >
> > remove, use include/linux/ieee80211.h.
> >
>
> Did you mean to use '& IEEE80211_FCTL_STYPE' to get the frame sub type,
> instead of adding this API.

Perhaps, but I suspect you can do mostly with ieee80211_is_probe_resp()
and friends.

> > > +static inline u8 get_to_ds(u8 *header)
> > > +{
> > > + return (header[1] & 0x01);
> > > +}
> > > +
> > > +static inline u8 get_from_ds(u8 *header)
> > > +{
> > > + return ((header[1] & 0x02) >> 1);
> > > +}
> >
> > dito
> >
>
> Ack.

For this you have ieee80211_has_tods()/_fromds()/_a4() instead.

johannes

2018-10-09 10:35:09

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h


On 10/8/2018 7:50 PM, Johannes Berg wrote:
> On Wed, 2018-09-26 at 15:55 +0530, Ajay Singh wrote:
>
>> +#include <linux/ieee80211.h>
> you include it
>
>> +#include "coreconfigurator.h"
>> +
>> +#define IDLE_MODE 0x00
>> +#define AP_MODE 0x01
>> +#define STATION_MODE 0x02
>> +#define GO_MODE 0x03
>> +#define CLIENT_MODE 0x04
>> +#define ACTION 0xD0
>> +#define PROBE_REQ 0x40
>> +#define PROBE_RESP 0x50
> please use it too.
>
Ack.

>> +#define ACTION_FRM_IDX 0
>> +#define PROBE_REQ_IDX 1
>> +#define MAX_NUM_STA 9
>> +#define ACTIVE_SCAN_TIME 10
>> +#define PASSIVE_SCAN_TIME 1200
>> +#define MIN_SCAN_TIME 10
>> +#define MAX_SCAN_TIME 1200
>> +#define DEFAULT_SCAN 0
>> +#define USER_SCAN BIT(0)
>> +#define OBSS_PERIODIC_SCAN BIT(1)
>> +#define OBSS_ONETIME_SCAN BIT(2)
>> +#define GTK_RX_KEY_BUFF_LEN 24
>> +#define ADDKEY 0x1
>> +#define REMOVEKEY 0x2
>> +#define DEFAULTKEY 0x4
>> +#define ADDKEY_AP 0x8
>> +#define MAX_NUM_SCANNED_NETWORKS 100
>> +#define MAX_NUM_SCANNED_NETWORKS_SHADOW 130
>> +#define MAX_NUM_PROBED_SSID 10
>> +#define CHANNEL_SCAN_TIME 250
>> +
>> +#define TX_MIC_KEY_LEN 8
>> +#define RX_MIC_KEY_LEN 8
>> +#define PTK_KEY_LEN 16
>> +
>> +#define TX_MIC_KEY_MSG_LEN 26
>> +#define RX_MIC_KEY_MSG_LEN 48
>> +#define PTK_KEY_MSG_LEN 39
>> +
>> +#define PMKSA_KEY_LEN 22
>> +#define ETH_ALEN 6
> umm?
>
>> +#define PMKID_LEN 16
> ??
>
>> +#define WILC_MAX_NUM_PMKIDS 16
>> +#define WILC_ADD_STA_LENGTH 40
>> +#define NUM_CONCURRENT_IFC 2
>> +#define DRV_HANDLER_SIZE 5
>> +#define DRV_HANDLER_MASK 0x000000FF
> Also this file is strangely mixing
> * 802.11 constants (that you shouldn't have anyway)
> * driver constants/structs
> * hardware/firmware-related things (at least it seems like - e.g. the
> "REMOVEKEY" constant)
>
> Please clean that up, separate the things, and pick a better
> namespace... just having "REMOVEKEY" is probably not a good idea.
>
Will work on this to clean it up.
>> +typedef void (*wilc_remain_on_chan_expired)(void *, u32);
>> +typedef void (*wilc_remain_on_chan_ready)(void *);
> Please no typedefs.
>
I think as per coding style the typedef for function pointer are allowed.

>> +struct rcvd_net_info {
>> + u8 *buffer;
>> + u32 len;
>> +};
>> +
>> +struct hidden_net_info {
>> + u8 *ssid;
>> + u8 ssid_len;
>> +};
>> +
>> +struct hidden_network {
>> + struct hidden_net_info *net_info;
>> + u8 n_ssids;
>> +};
> This seems really odd - what part doesn't cfg80211 already handle?

If I understood your question correctly,  you meant what extra
functionality 'hidden_network' struct is providing.
Actually this structure is just used to keeps list of SSID's requested
in cfg80211 'scan' callback which is passed to firmware. The values are
extracted from 'cfg80211_scan_request[struct cfg80211_ssid *ssids 
-----  int n_ssids] received during scan.

Regards,
Ajay


2018-10-09 10:36:33

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h

On Tue, 2018-10-09 at 16:04 +0530, Ajay Singh wrote:

> > > +typedef void (*wilc_remain_on_chan_expired)(void *, u32);
> > > +typedef void (*wilc_remain_on_chan_ready)(void *);

> I think as per coding style the typedef for function pointer are allowed.

True, I guess, but why do you need them?

> > > +struct rcvd_net_info {
> > > + u8 *buffer;
> > > + u32 len;
> > > +};
> > > +
> > > +struct hidden_net_info {
> > > + u8 *ssid;
> > > + u8 ssid_len;
> > > +};
> > > +
> > > +struct hidden_network {
> > > + struct hidden_net_info *net_info;
> > > + u8 n_ssids;
> > > +};
> >
> > This seems really odd - what part doesn't cfg80211 already handle?
>
> If I understood your question correctly, you meant what extra
> functionality 'hidden_network' struct is providing.

Pretty much. It seems like you're trying to handle hidden SSIDs in some
way, but ... that's odd.

> Actually this structure is just used to keeps list of SSID's requested
> in cfg80211 'scan' callback which is passed to firmware. The values are
> extracted from 'cfg80211_scan_request[struct cfg80211_ssid *ssids
> ----- int n_ssids] received during scan.

So then this has nothing to do with hidden SSID?

johannes

2018-10-09 11:44:51

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h


On 10/9/2018 4:06 PM, Johannes Berg wrote:
> On Tue, 2018-10-09 at 16:04 +0530, Ajay Singh wrote:
>
>>>> +typedef void (*wilc_remain_on_chan_expired)(void *, u32);
>>>> +typedef void (*wilc_remain_on_chan_ready)(void *);
>> I think as per coding style the typedef for function pointer are allowed.
> True, I guess, but why do you need them?

Actually these function pointer are used in multiple places i.e inside
the struct and also for passing as the argument for the function. So i
think its better to keep them as typedef to simplify and avoid any 'line
over 80 chars' checkpatch issue. But anyway if you suggest we can modify
to remove these typedefs .

>>>> +struct rcvd_net_info {
>>>> + u8 *buffer;
>>>> + u32 len;
>>>> +};
>>>> +
>>>> +struct hidden_net_info {
>>>> + u8 *ssid;
>>>> + u8 ssid_len;
>>>> +};
>>>> +
>>>> +struct hidden_network {
>>>> + struct hidden_net_info *net_info;
>>>> + u8 n_ssids;
>>>> +};
>>> This seems really odd - what part doesn't cfg80211 already handle?
>> If I understood your question correctly, you meant what extra
>> functionality 'hidden_network' struct is providing.
> Pretty much. It seems like you're trying to handle hidden SSIDs in some
> way, but ... that's odd.
>
>> Actually this structure is just used to keeps list of SSID's requested
>> in cfg80211 'scan' callback which is passed to firmware. The values are
>> extracted from 'cfg80211_scan_request[struct cfg80211_ssid *ssids
>> ----- int n_ssids] received during scan.
> So then this has nothing to do with hidden SSID?

Yes, its not related to hidden SSID. Suppose cfg80211 scan is called
with SSID information(active scan) then SSID info will be maintained in
this structure.

Regards,
Ajay


2018-10-09 11:46:24

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h

On Tue, 2018-10-09 at 17:14 +0530, Ajay Singh wrote:
> On 10/9/2018 4:06 PM, Johannes Berg wrote:
> > On Tue, 2018-10-09 at 16:04 +0530, Ajay Singh wrote:
> >
> > > > > +typedef void (*wilc_remain_on_chan_expired)(void *, u32);
> > > > > +typedef void (*wilc_remain_on_chan_ready)(void *);
> > >
> > > I think as per coding style the typedef for function pointer are allowed.
> >
> > True, I guess, but why do you need them?
>
> Actually these function pointer are used in multiple places i.e inside
> the struct and also for passing as the argument for the function. So i
> think its better to keep them as typedef to simplify and avoid any 'line
> over 80 chars' checkpatch issue. But anyway if you suggest we can modify
> to remove these typedefs .

I guess that must be part of the internal bounce buffer mechanism? I
guess leave them for now and see what falls out.

> > > > > +struct hidden_network {
> > > > >
> Yes, its not related to hidden SSID. Suppose cfg80211 scan is called
> with SSID information(active scan) then SSID info will be maintained in
> this structure.

so maybe rename this?

johannes

2018-10-09 12:18:59

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h


On 10/9/2018 5:16 PM, Johannes Berg wrote:
> On Tue, 2018-10-09 at 17:14 +0530, Ajay Singh wrote:
>> On 10/9/2018 4:06 PM, Johannes Berg wrote:
>>> On Tue, 2018-10-09 at 16:04 +0530, Ajay Singh wrote:
>>>
>>>>>> +typedef void (*wilc_remain_on_chan_expired)(void *, u32);
>>>>>> +typedef void (*wilc_remain_on_chan_ready)(void *);
>>>> I think as per coding style the typedef for function pointer are allowed.
>>> True, I guess, but why do you need them?
>> Actually these function pointer are used in multiple places i.e inside
>> the struct and also for passing as the argument for the function. So i
>> think its better to keep them as typedef to simplify and avoid any 'line
>> over 80 chars' checkpatch issue. But anyway if you suggest we can modify
>> to remove these typedefs .
> I guess that must be part of the internal bounce buffer mechanism? I
> guess leave them for now and see what falls out.
>
>>>>>> +struct hidden_network {
>>>>>>
>> Yes, its not related to hidden SSID. Suppose cfg80211 scan is called
>> with SSID information(active scan) then SSID info will be maintained in
>> this structure.
> so maybe rename this?
>
Yes, sure I will rename this struct.

Regards,
Ajay


2018-10-09 17:15:50

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 12/19] wilc: add wilc_wfi_cfgoperations.c



On 10/09/2018 12:55 AM, Johannes Berg wrote:
> On Tue, 2018-10-09 at 04:23 +0000, [email protected] wrote:
>>
>>> I don't know what you need the shadow stuff for, but you should remove
>>> it anyway, and use the cfg80211 functionality instead. If not
>>> sufficient, propose patches to improve it?
>>
>> The point behind using a shadow buffer was to keep the scan results
>> consistent between consecutive scans, and smooth out the cases where
>> an AP isn't found momentarily during scanning.
>> In this implementation, APs found during scanning are added to the
>> shadow list, and removed if not found again for a period of time.
>>
>> I'm not much in favour of this implementation neither since it
>> complicates the driver's logic, but it was serving the purpose.
>
> You really should remove it - cfg80211 *and* wpa_s already do this if
> required.
>
> johannes
>

Thanks Johannes for the tip. I did some research, and I believe you are
referring to using bss_expire_age and bss_expire_count.
We'll go ahead and remove that.

Thanks,
Adham

2018-10-09 18:36:18

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h



On 10/09/2018 05:18 AM, Ajay Singh wrote:
>
> On 10/9/2018 5:16 PM, Johannes Berg wrote:
>> On Tue, 2018-10-09 at 17:14 +0530, Ajay Singh wrote:
>>> On 10/9/2018 4:06 PM, Johannes Berg wrote:
>>>> On Tue, 2018-10-09 at 16:04 +0530, Ajay Singh wrote:
>>>>
>>>>>>> +typedef void (*wilc_remain_on_chan_expired)(void *, u32);
>>>>>>> +typedef void (*wilc_remain_on_chan_ready)(void *);
>>>>> I think as per coding style the typedef for function pointer are allowed.
>>>> True, I guess, but why do you need them?
>>> Actually these function pointer are used in multiple places i.e inside
>>> the struct and also for passing as the argument for the function. So i
>>> think its better to keep them as typedef to simplify and avoid any 'line
>>> over 80 chars' checkpatch issue. But anyway if you suggest we can modify
>>> to remove these typedefs .
>> I guess that must be part of the internal bounce buffer mechanism? I
>> guess leave them for now and see what falls out.
>>
>>>>>>> +struct hidden_network {
>>>>>>>
>>> Yes, its not related to hidden SSID. Suppose cfg80211 scan is called
>>> with SSID information(active scan) then SSID info will be maintained in
>>> this structure.
>> so maybe rename this?
>>
> Yes, sure I will rename this struct.
>
> Regards,
> Ajay
>

Johannes, is the cfg80211_scan_request.ssid used for something else other than specifying the hidden networks that the controller should scan for?

2018-10-09 19:14:39

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h

On Tue, 2018-10-09 at 18:36 +0000, [email protected] wrote:
>
> Johannes, is the cfg80211_scan_request.ssid used for something else
> other than specifying the hidden networks that the controller should
> scan for?

Ahh, now I understand where you're coming from.

Well, it's the SSID to include in the probe request(s), the most common
thing there is the 0-length wildcard, of course.

So while it may be required for hidden networks, it's not strictly
related to that.

johannes

2018-10-09 20:01:25

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h



On 10/09/2018 12:14 PM, Johannes Berg wrote:
> On Tue, 2018-10-09 at 18:36 +0000, [email protected] wrote:
>>
>> Johannes, is the cfg80211_scan_request.ssid used for something else
>> other than specifying the hidden networks that the controller should
>> scan for?
>
> Ahh, now I understand where you're coming from.
>
> Well, it's the SSID to include in the probe request(s), the most common
> thing there is the 0-length wildcard, of course.
>
> So while it may be required for hidden networks, it's not strictly
> related to that.
Do you mean that it can also be used for probing specific networks even if they are broadcasting their SSID?
I think this might be a possible case if the user is trying to limit the scan results to a specific network.

>
> johannes
>

2018-10-09 20:02:59

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h

On Tue, 2018-10-09 at 20:01 +0000, [email protected] wrote:
>
> Do you mean that it can also be used for probing specific networks even if they are broadcasting their SSID?

Yes.

> I think this might be a possible case if the user is trying to limit the scan results to a specific network.

No. Don't do any filtering based on this.

Basically the only thing you should do with the (list of) SSIDs is to
send a probe request containing each of them. Userspace/cfg80211 will
take care that the usual empty (wildcard) SSID is included in the list,
so don't send one with that by yourself, just iterate the list.

If you only support sending one probe request in each scan request, then
set the max # of SSIDs supported to 1, otherwise set it to the maximum
(or a reasonable limit like 20 if it's in software).

johannes

2018-10-09 20:06:58

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h



On 10/09/2018 01:02 PM, Johannes Berg wrote:
> On Tue, 2018-10-09 at 20:01 +0000, [email protected] wrote:
>>
>> Do you mean that it can also be used for probing specific networks even if they are broadcasting their SSID?
>
> Yes.
>
>> I think this might be a possible case if the user is trying to limit the scan results to a specific network.
>
> No. Don't do any filtering based on this.
>
> Basically the only thing you should do with the (list of) SSIDs is to
> send a probe request containing each of them. Userspace/cfg80211 will
> take care that the usual empty (wildcard) SSID is included in the list,
> so don't send one with that by yourself, just iterate the list.
>
> If you only support sending one probe request in each scan request, then
> set the max # of SSIDs supported to 1, otherwise set it to the maximum
> (or a reasonable limit like 20 if it's in software).
>
> johannes
>
Thanks Johannes. It's clear now.

2018-10-10 20:06:54

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c



On 10/08/2018 07:31 AM, Johannes Berg wrote:
>
>> + *currbyte = (u32)0 & DRV_HANDLER_MASK;
>
> You do this a few times, not sure what it's supposed to achieve?
>
>> + if (param->flag & RETRY_LONG) {
>> + u16 limit = param->long_retry_limit;
>> +
>> + if (limit > 0 && limit < 256) {
>> + wid_list[i].id = WID_LONG_RETRY_LIMIT;
>> + wid_list[i].val = (s8 *)&param->long_retry_limit;
>> + wid_list[i].type = WID_SHORT;
>> + wid_list[i].size = sizeof(u16);
>> + hif_drv->cfg_values.long_retry_limit = limit;
>> + } else {
>> + netdev_err(vif->ndev, "Range(1~256) over\n");
>> + goto unlock;
>> + }
>> + i++;
>> + }
>
> So ... can anyone tell me why there's a complete driver-internal
> messaging infrastructure in this, that even suppresses errors like here
> (out of range just results in a message rather than returning an error
> to wherever it originated)?
>
Agree. parameter validation can be done before scheduling the work, and hence appropriate error can be returned to caller .

> It almost *seems* like it's a to-device infrastructure, but it can't be
> since it uses host pointers everywhere?
>
> I think this code would be far better off without the "bounce in driver
> to resolve host pointers" step.
If I got your point correctly, you are referring to the lines that stores the parameters into the hif_drv->cfg_values.
I agree, the cfg_values isn't read from anywhere in the driver, so can be removed

>> + if (conn_attr->ssid) {
>> + memcpy(cur_byte, conn_attr->ssid, conn_attr->ssid_len);
>> + cur_byte[conn_attr->ssid_len] = '\0';
>> + }
>> + cur_byte += MAX_SSID_LEN;
>
> again, SSIDs are not 0-terminated strings
For this specific code, the device requires the ssid to be null terminated, since it doesn't receive the ssid_len parameter.
For other ssid references in the driver, the null termination can be removed.
>
>> +static void host_int_fill_join_bss_param(struct join_bss_param *param, u8 *ies,
>> + u16 *out_index, u8 *pcipher_tc,
>> + u8 *auth_total_cnt, u32 tsf_lo,
>> + u8 *rates_no)
>> +{
>> + u8 ext_rates_no;
>> + u16 offset;
>> + u8 pcipher_cnt;
>> + u8 auth_cnt;
>> + u8 i, j;
>> + u16 index = *out_index;
>> +
>> + if (ies[index] == WLAN_EID_SUPP_RATES) {
>> + *rates_no = ies[index + 1];
>> + param->supp_rates[0] = *rates_no;
>> + index += 2;
>> +
>> + for (i = 0; i < *rates_no; i++)
>> + param->supp_rates[i + 1] = ies[index + i];
>> +
>> + index += *rates_no;
>> + } else if (ies[index] == WLAN_EID_EXT_SUPP_RATES) {
>> + ext_rates_no = ies[index + 1];
>> + if (ext_rates_no > (MAX_RATES_SUPPORTED - *rates_no))
>> + param->supp_rates[0] = MAX_RATES_SUPPORTED;
>> + else
>> + param->supp_rates[0] += ext_rates_no;
>> + index += 2;
>> + for (i = 0; i < (param->supp_rates[0] - *rates_no); i++)
>> + param->supp_rates[*rates_no + i + 1] = ies[index + i];
>> +
>> + index += ext_rates_no;
>> + } else if (ies[index] == WLAN_EID_HT_CAPABILITY) {
>> + param->ht_capable = true;
>> + index += ies[index + 1] + 2;
>> + } else if ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) &&
>> + (ies[index + 2] == 0x00) && (ies[index + 3] == 0x50) &&
>> + (ies[index + 4] == 0xF2) && (ies[index + 5] == 0x02) &&
>> + ((ies[index + 6] == 0x00) || (ies[index + 6] == 0x01)) &&
>> + (ies[index + 7] == 0x01)) {
>> + param->wmm_cap = true;
>> +
>> + if (ies[index + 8] & BIT(7))
>> + param->uapsd_cap = true;
>> + index += ies[index + 1] + 2;
>> + } else if ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) &&
>> + (ies[index + 2] == 0x50) && (ies[index + 3] == 0x6f) &&
>> + (ies[index + 4] == 0x9a) &&
>> + (ies[index + 5] == 0x09) && (ies[index + 6] == 0x0c)) {
>> + u16 p2p_cnt;
>> +
>> + param->tsf = tsf_lo;
>> + param->noa_enabled = 1;
>> + param->idx = ies[index + 9];
>> +
>> + if (ies[index + 10] & BIT(7)) {
>> + param->opp_enabled = 1;
>> + param->ct_window = ies[index + 10];
>> + } else {
>> + param->opp_enabled = 0;
>> + }
>> +
>> + param->cnt = ies[index + 11];
>> + p2p_cnt = index + 12;
>> +
>> + memcpy(param->duration, ies + p2p_cnt, 4);
>> + p2p_cnt += 4;
>> +
>> + memcpy(param->interval, ies + p2p_cnt, 4);
>> + p2p_cnt += 4;
>> +
>> + memcpy(param->start_time, ies + p2p_cnt, 4);
>> +
>> + index += ies[index + 1] + 2;
>> + } else if ((ies[index] == WLAN_EID_RSN) ||
>> + ((ies[index] == WLAN_EID_VENDOR_SPECIFIC) &&
>> + (ies[index + 2] == 0x00) &&
>> + (ies[index + 3] == 0x50) && (ies[index + 4] == 0xF2) &&
>> + (ies[index + 5] == 0x01))) {
>> + u16 rsn_idx = index;
>> +
>> + if (ies[rsn_idx] == WLAN_EID_RSN) {
>> + param->mode_802_11i = 2;
>> + } else {
>> + if (param->mode_802_11i == 0)
>> + param->mode_802_11i = 1;
>> + rsn_idx += 4;
>> + }
>> +
>> + rsn_idx += 7;
>> + param->rsn_grp_policy = ies[rsn_idx];
>> + rsn_idx++;
>> + offset = ies[rsn_idx] * 4;
>> + pcipher_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
>> + rsn_idx += 2;
>> +
>> + i = *pcipher_tc;
>> + j = 0;
>> + for (; i < (pcipher_cnt + *pcipher_tc) && i < 3; i++, j++) {
>> + u8 *policy = &param->rsn_pcip_policy[i];
>> +
>> + *policy = ies[rsn_idx + ((j + 1) * 4) - 1];
>> + }
>> +
>> + *pcipher_tc += pcipher_cnt;
>> + rsn_idx += offset;
>> +
>> + offset = ies[rsn_idx] * 4;
>> +
>> + auth_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
>> + rsn_idx += 2;
>> + i = *auth_total_cnt;
>> + j = 0;
>> + for (; i < (*auth_total_cnt + auth_cnt); i++, j++) {
>> + u8 *policy = &param->rsn_auth_policy[i];
>> +
>> + *policy = ies[rsn_idx + ((j + 1) * 4) - 1];
>> + }
>> +
>> + *auth_total_cnt += auth_cnt;
>> + rsn_idx += offset;
>> +
>> + if (ies[index] == WLAN_EID_RSN) {
>> + param->rsn_cap[0] = ies[rsn_idx];
>> + param->rsn_cap[1] = ies[rsn_idx + 1];
>> + rsn_idx += 2;
>> + }
>> + param->rsn_found = true;
>> + index += ies[index + 1] + 2;
>> + } else {
>> + index += ies[index + 1] + 2;
>> + }
>> +
>> + *out_index = index;
>> +}
>
> Again, use actual kernel infrastructure for much of this.
>
>> + cur_byte = wid.val;
>> + *cur_byte++ = (param->interval & 0xFF);
>> + *cur_byte++ = ((param->interval >> 8) & 0xFF);
>> + *cur_byte++ = ((param->interval >> 16) & 0xFF);
>> + *cur_byte++ = ((param->interval >> 24) & 0xFF);
>
> put_unaligned_le32().
>

Agree

>> + *cur_byte++ = param->aid & 0xFF;
>> + *cur_byte++ = (param->aid >> 8) & 0xFF;
>
> and so on
>
> but then again, I just suggested to not have these "pack" functions to
> start with, or at least not in this way, since it just means you first
> pack everything into host structs, and then repack everything again into
> firmware format ...
>

Agree.
Instead of packing the parameters in host structures like struct add_sta_param, then repacking it in the device format, it can use struct station_parameters and pack them directly into the device format
>
> So far I guess I'd say:
> * use more kernel infra, in particular {get,put}_unaligned_le{16,32}
> * name your device/driver-specific constants better, rather than things
> like "SET_CFG" which leave everyone wondering if it's specific to
> this driver or something from elsewhere
>
> johannes
>

2018-10-10 20:15:02

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c

Looking at all this wid_list stuff again,

> + wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
> + wid_list[wid_cnt].type = WID_INT;
> + wid_list[wid_cnt].size = sizeof(u32);
> + wid_list[wid_cnt].val = (s8 *)(&(dummyval));
> + wid_cnt++;

Doesn't that have endian issues?

> + wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
> + wid_list[wid_cnt].type = WID_INT;
> + wid_list[wid_cnt].size = sizeof(u32);
> + wid_list[wid_cnt].val = (s8 *)(&(dummyval));
> + wid_cnt++;

But I'm not really sure what the pointer does, tbh.

> + wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED;
> + wid_list[wid_cnt].type = WID_STR;
> + wid_list[wid_cnt].size = 112;
> + wid_list[wid_cnt].val = kmalloc(wid_list[wid_cnt].size, GFP_KERNEL);

I think you should declare a structure for these 112 bytes, clearly it's
something like

> + if (conn_attr->ssid) {
> + memcpy(cur_byte, conn_attr->ssid, conn_attr->ssid_len);
> + cur_byte[conn_attr->ssid_len] = '\0';
> + }
> + cur_byte += MAX_SSID_LEN;

u8 ssid[32];

> + *(cur_byte++) = INFRASTRUCTURE;

u8 type;

> +
> + if (conn_attr->ch >= 1 && conn_attr->ch <= 14) {
> + *(cur_byte++) = conn_attr->ch;
> + } else {
> + netdev_err(vif->ndev, "Channel out of range\n");
> + *(cur_byte++) = 0xFF;
> + }

u8 channel;

> + *(cur_byte++) = (bss_param->cap_info) & 0xFF;
> + *(cur_byte++) = ((bss_param->cap_info) >> 8) & 0xFF;

__le16 cap_info;

> + if (conn_attr->bssid)
> + memcpy(cur_byte, conn_attr->bssid, 6);
> + cur_byte += 6;

u8 bssid[ETH_ALEN];

> + if (conn_attr->bssid)
> + memcpy(cur_byte, conn_attr->bssid, 6);
> + cur_byte += 6;

again?

> + *(cur_byte++) = (bss_param->beacon_period) & 0xFF;
> + *(cur_byte++) = ((bss_param->beacon_period) >> 8) & 0xFF;

__le16 beacon_period;

> + *(cur_byte++) = bss_param->dtim_period;

u8 dtim_period;

etc.

Declaring it as a struct also means you don't have to do all the
put_le16_unaligned() or whatever, but can just fill the struct properly.

johannes

2018-10-11 06:57:31

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c

Hi,

On 10/8/2018 8:01 PM, Johannes Berg wrote:
>> + *currbyte = (u32)0 & DRV_HANDLER_MASK;
> You do this a few times, not sure what it's supposed to achieve?
>
Agree, the bitwise operation is useless here and this logic should be
modified.
>
> So far I guess I'd say:
> * use more kernel infra, in particular {get,put}_unaligned_le{16,32}
> * name your device/driver-specific constants better, rather than things
> like "SET_CFG" which leave everyone wondering if it's specific to
> this driver or something from elsewhere
>
Thanks for your inputs.
I will use your suggestion while submitting the refactor code.

Regards,
Ajay


2018-10-11 06:59:47

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 05/19] wilc: add wilc_wlan_if.h


On 10/8/2018 8:03 PM, Johannes Berg wrote:
>> +#define WILC_TX_ERR_NO_BUF (-2)
> Hmm? what's wrong with just e.g. -ENOBUFS? If it doesn't go to userspace
> it doesn't matter, and if it does you can't use this anyway? This would
> be -ENOENT which is a bad idea.
>
Actually this value doesn't return to userspace and its used locally for
the error status.
But anyway we can make use of (-ENOBUFS) instead of adding this new macro.
>> +
>> +/********************************************
>> + *
>> + * Wlan Configuration ID
>> + *
>> + ********************************************/
>> +#define WILC_MULTICAST_TABLE_SIZE 8
>> +#define MAX_SSID_LEN 33
> Err, it's 32?
>
>> +#define MAX_RATES_SUPPORTED 12
>> +
>> +enum bss_types {
>> + INFRASTRUCTURE = 0,
>> + INDEPENDENT,
>> + AP,
>> +};
>> +
>> +enum {
>> + B_ONLY_MODE = 0, /* 1, 2 M, otherwise 5, 11 M */
>> + G_ONLY_MODE, /* 6,12,24 otherwise 9,18,36,48,54 */
>> + G_MIXED_11B_1_MODE, /* 1,2,5.5,11 otherwise all on */
>> + G_MIXED_11B_2_MODE, /* 1,2,5,11,6,12,24 otherwise all on */
>> +};
>> +
>> +enum {
>> + G_SHORT_PREAMBLE = 0, /* Short Preamble */
>> + G_LONG_PREAMBLE = 1, /* Long Preamble */
>> + G_AUTO_PREAMBLE = 2, /* Auto Preamble Selection */
>> +};
> here we have a lot of those "constants should have some sort of prefix"
> things ... it's not even clear if they're spec or not:
>
>> +enum authtype {
>> + OPEN_SYSTEM = 1,
>> + SHARED_KEY = 2,
>> + ANY = 3,
>> + IEEE8021 = 5
>> +};
> These look like they're spec but aren't ... not a good idea.
>
Yes,  these are not part of any spec . We will  add the prefix for
better understanding.

Regards,
Ajay


2018-10-11 07:01:12

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 13/19] wilc: add linux_wlan.c


On 10/8/2018 8:11 PM, Johannes Berg wrote:
> On Wed, 2018-09-26 at 15:55 +0530, Ajay Singh wrote:
>> Moved '/driver/staging/wilc1000/linux_wlan.c' to
>> 'drivers/net/wireless/microchip/wilc/'.
>>
>> Signed-off-by: Ajay Singh <[email protected]>
>> ---
>> drivers/net/wireless/microchip/wilc/linux_wlan.c | 1161 ++++++++++++++++++++++
>> 1 file changed, 1161 insertions(+)
>> create mode 100644 drivers/net/wireless/microchip/wilc/linux_wlan.c
> Hmm. It's pretty obviously a linux driver, what's the point?
>
Agree, will rename by avoiding the 'linux' prefix.
>> diff --git a/drivers/net/wireless/microchip/wilc/linux_wlan.c b/drivers/net/wireless/microchip/wilc/linux_wlan.c
>> new file mode 100644
>> index 0000000..76c9012
>> --- /dev/null
>> +++ b/drivers/net/wireless/microchip/wilc/linux_wlan.c
>> @@ -0,0 +1,1161 @@
>> +// 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 "wilc_wfi_cfgoperations.h"
>> +
>> +static int dev_state_ev_handler(struct notifier_block *this,
>> + unsigned long event, void *ptr)
>> +{
>> + struct in_ifaddr *dev_iface = ptr;
>> + struct wilc_priv *priv;
>> + struct host_if_drv *hif_drv;
>> + struct net_device *dev;
>> + u8 *ip_addr_buf;
>> + struct wilc_vif *vif;
>> + u8 null_ip[4] = {0};
>> + char wlan_dev_name[5] = "wlan0";
> Regardless of what you're trying to do, thta seems like a bad idea.
>
>> + if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev)
>> + return NOTIFY_DONE;
>> +
>> + if (memcmp(dev_iface->ifa_label, "wlan0", 5) &&
>> + memcmp(dev_iface->ifa_label, "p2p0", 4))
>> + return NOTIFY_DONE;
> That too. What???
Purpose of this function is to deferred going into powsersave till the
IP address is acquired by the interfaces. This is to avoid any issue in
acquiring the IP address(due to power save mode).
We will investigate and check the better to handle this condition.
>> + dev = (struct net_device *)dev_iface->ifa_dev->dev;
>> + if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
>> + return NOTIFY_DONE;
>> +
>> + priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
>> + if (!priv)
>> + return NOTIFY_DONE;
>> +
>> + hif_drv = (struct host_if_drv *)priv->hif_drv;
>> + vif = netdev_priv(dev);
>> + if (!vif || !hif_drv)
>> + return NOTIFY_DONE;
>> +
>> + switch (event) {
>> + case NETDEV_UP:
>> + if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
>> + hif_drv->ifc_up = 1;
>> + vif->obtaining_ip = false;
>> + del_timer(&vif->during_ip_timer);
>> + }
>> +
>> + if (vif->wilc->enable_ps)
>> + wilc_set_power_mgmt(vif, 1, 0);
>> +
>> + netdev_dbg(dev, "[%s] Up IP\n", dev_iface->ifa_label);
>> +
>> + ip_addr_buf = (char *)&dev_iface->ifa_address;
>> + netdev_dbg(dev, "IP add=%d:%d:%d:%d\n",
>> + ip_addr_buf[0], ip_addr_buf[1],
>> + ip_addr_buf[2], ip_addr_buf[3]);
> %pI4, I believe, but I think you should just remove it, it likely won't
> have an IP address anyway, and you might have multiple, and so this is
> just broken.
>
>> + eth_h = (struct ethhdr *)(skb->data);
>> + if (eth_h->h_proto == cpu_to_be16(0x8e88))
>> + netdev_dbg(ndev, "EAPOL transmitted\n");
> Err, no, just remove that.
Ok.
>> + ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
> Sure, everything is IP. You just checked that it wasn't EAPOL?
>
>> + udp_buf = (char *)ih + sizeof(struct iphdr);
>> + if ((udp_buf[1] == 68 && udp_buf[3] == 67) ||
>> + (udp_buf[1] == 67 && udp_buf[3] == 68))
>> + netdev_dbg(ndev, "DHCP Message transmitted, type:%x %x %x\n",
>> + udp_buf[248], udp_buf[249], udp_buf[250]);
> Umm... no. Just remove that too.
>
Ok
>> + vif->netstats.tx_packets++;
>> + vif->netstats.tx_bytes += tx_data->size;
>> + tx_data->bssid = wilc->vif[vif->idx]->bssid;
>> + queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
>> + tx_data->buff, tx_data->size,
>> + linux_wlan_tx_complete);
>> +
>> + if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
>> + netif_stop_queue(wilc->vif[0]->ndev);
>> + netif_stop_queue(wilc->vif[1]->ndev);
>> + }
> It seems like a pretty bad idea to hard-code two interfaces, we do
> dynamic addition/removal these days, in *particular* for P2P.
>
Did you mean it not good to call stop queue for both the interfaces.
Can you please provide some more details about this comments.
>> +static int wilc_mac_close(struct net_device *ndev)
>> +{
>> + struct wilc_priv *priv;
>> + struct wilc_vif *vif = netdev_priv(ndev);
>> + struct host_if_drv *hif_drv;
>> + struct wilc *wl;
>> +
>> + if (!vif || !vif->ndev || !vif->ndev->ieee80211_ptr ||
>> + !vif->ndev->ieee80211_ptr->wiphy)
>> + return 0;
> I'm not really sure why you're so paranoid, none of that can possibly
> happen.
>
>> + priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy);
>> + wl = vif->wilc;
>> +
>> + if (!priv)
>> + return 0;
> Nor can this.
>
>> + hif_drv = (struct host_if_drv *)priv->hif_drv;
>> +
>> + netdev_dbg(ndev, "Mac close\n");
>> +
>> + if (!wl)
>> + return 0;
>> +
>> + if (!hif_drv)
>> + return 0;
> Nor these.

Sure, will remove the unnecessary check in this function.

Regards,
Ajay


2018-10-11 07:02:12

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c


> Agree. parameter validation can be done before scheduling the work,
> and hence appropriate error can be returned to caller .


> If I got your point correctly, you are referring to the lines that
> stores the parameters into the hif_drv->cfg_values.

Well, I was actually thinking that I'm not even sure why you schedule
work at all!

> Instead of packing the parameters in host structures like struct
> add_sta_param, then repacking it in the device format, it can use
> struct station_parameters and pack them directly into the device
> format

Makes sense. Also note my other email on how there should be structs
involved, rather than open-coded WID entry lists.

johannes

2018-10-11 07:03:21

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 13/19] wilc: add linux_wlan.c

On Thu, 2018-10-11 at 12:30 +0530, Ajay Singh wrote:
>
> > > + if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
> > > + netif_stop_queue(wilc->vif[0]->ndev);
> > > + netif_stop_queue(wilc->vif[1]->ndev);
> > > + }
> >
> > It seems like a pretty bad idea to hard-code two interfaces, we do
> > dynamic addition/removal these days, in *particular* for P2P.
> >
>
> Did you mean it not good to call stop queue for both the interfaces.
> Can you please provide some more details about this comments.

No, I mean you should be more dynamic and have e.g. a list of interfaces
(actually, you can use cfg80211's list, I believe!), instead of hard-
coding that you have "wlan0" and "p2p0".

johannes

2018-10-11 07:13:02

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 14/19] wilc: add linux_mon.c


On 10/8/2018 8:14 PM, Johannes Berg wrote:
> On Wed, 2018-09-26 at 15:55 +0530, Ajay Singh wrote:
>> +static struct net_device *wilc_wfi_mon; /* global monitor netdev */
> There might not exist platforms with multiple devices (yet), but it's
> really bad practice to do this anyway.
>
Sure, will work on to avoid the use of this static variable here.
>> +static u8 srcadd[6];
>> +static u8 bssid[6];
>> +
>> +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
>> +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive*/
> Uh.. we have a radiotap include file and you already use it, why?
>
Right, will remove these macro as header is already included.
>> +void wilc_wfi_deinit_mon_interface(void)
>> +{
>> + bool rollback_lock = false;
>> +
>> + if (wilc_wfi_mon) {
>> + if (rtnl_is_locked()) {
>> + rtnl_unlock();
>> + rollback_lock = true;
>> + }
>> + unregister_netdev(wilc_wfi_mon);
>> +
>> + if (rollback_lock) {
>> + rtnl_lock();
>> + rollback_lock = false;
>> + }
>> + wilc_wfi_mon = NULL;
>> + }
>> +}
> Uh, no, you really cannot do conditional locking like this.
>
> But seeing things like this pretty much destroys all of the confidence I
> might have had of the code, so I'd say we cannot merge this until you
> can demonstrate somebody more familiar with Linux has reviewed it, I'm
> just doing a drive-by review for the stack integration aspects (and
> haven't even found where that happens yet).

I will refactor wilc_wfi_deinit_mon_interface() and submit more cleaner
version of this function.
Currently, I am not clear about which stack integration part is missing
. Can you please provide some more details about it.

Regards,
Ajay


2018-10-11 07:15:32

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 14/19] wilc: add linux_mon.c

On Thu, 2018-10-11 at 12:42 +0530, Ajay Singh wrote:
> > I'm
> > just doing a drive-by review for the stack integration aspects (and
> > haven't even found where that happens yet).
[...]
> Currently, I am not clear about which stack integration part is missing
> . Can you please provide some more details about it.

No, I'm just saying that *I* was looking for how you integrate with the
stack (cfg80211), and not so much trying to review everything else.

johannes

2018-10-11 07:26:47

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 13/19] wilc: add linux_wlan.c


On 10/11/2018 12:33 PM, Johannes Berg wrote:
> On Thu, 2018-10-11 at 12:30 +0530, Ajay Singh wrote:
>>>> + if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
>>>> + netif_stop_queue(wilc->vif[0]->ndev);
>>>> + netif_stop_queue(wilc->vif[1]->ndev);
>>>> + }
>>> It seems like a pretty bad idea to hard-code two interfaces, we do
>>> dynamic addition/removal these days, in *particular* for P2P.
>>>
>> Did you mean it not good to call stop queue for both the interfaces.
>> Can you please provide some more details about this comments.
> No, I mean you should be more dynamic and have e.g. a list of interfaces
> (actually, you can use cfg80211's list, I believe!), instead of hard-
> coding that you have "wlan0" and "p2p0".


I got your point now. I will check on this to add the support.

Regards,
Ajay


2018-10-12 21:55:31

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c



On 10/10/2018 01:14 PM, Johannes Berg wrote:
> Looking at all this wid_list stuff again,
>
>> + wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
>> + wid_list[wid_cnt].type = WID_INT;
>> + wid_list[wid_cnt].size = sizeof(u32);
>> + wid_list[wid_cnt].val = (s8 *)(&(dummyval));
>> + wid_cnt++;
>
> Doesn't that have endian issues?
>
>> + wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
>> + wid_list[wid_cnt].type = WID_INT;
>> + wid_list[wid_cnt].size = sizeof(u32);
>> + wid_list[wid_cnt].val = (s8 *)(&(dummyval));
>> + wid_cnt++;
>
> But I'm not really sure what the pointer does, tbh.

Here the driver is configuring parameters in the device by sending a WID command for each parameters.
The val pointer points to the value of the parameter to be set, and here all parameters being set to 0 were sharing the dummyval variable.
Looking again at this, these constant parameters can be omitted from the driver and done on the device instead.

>
>> + wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED;
>> + wid_list[wid_cnt].type = WID_STR;
>> + wid_list[wid_cnt].size = 112;
>> + wid_list[wid_cnt].val = kmalloc(wid_list[wid_cnt].size, GFP_KERNEL);
>
> I think you should declare a structure for these 112 bytes, clearly it's
> something like
>
>> + if (conn_attr->ssid) {
>> + memcpy(cur_byte, conn_attr->ssid, conn_attr->ssid_len);
>> + cur_byte[conn_attr->ssid_len] = '\0';
>> + }
>> + cur_byte += MAX_SSID_LEN;
>
> u8 ssid[32];
>
>> + *(cur_byte++) = INFRASTRUCTURE;
>
> u8 type;
>
>> +
>> + if (conn_attr->ch >= 1 && conn_attr->ch <= 14) {
>> + *(cur_byte++) = conn_attr->ch;
>> + } else {
>> + netdev_err(vif->ndev, "Channel out of range\n");
>> + *(cur_byte++) = 0xFF;
>> + }
>
> u8 channel;
>
>> + *(cur_byte++) = (bss_param->cap_info) & 0xFF;
>> + *(cur_byte++) = ((bss_param->cap_info) >> 8) & 0xFF;
>
> __le16 cap_info;
>
>> + if (conn_attr->bssid)
>> + memcpy(cur_byte, conn_attr->bssid, 6);
>> + cur_byte += 6;
>
> u8 bssid[ETH_ALEN];
>
>> + if (conn_attr->bssid)
>> + memcpy(cur_byte, conn_attr->bssid, 6);
>> + cur_byte += 6;
>
> again?

Agree. Can be changed to avoid duplication. Requires a matching change on the device.

>
>> + *(cur_byte++) = (bss_param->beacon_period) & 0xFF;
>> + *(cur_byte++) = ((bss_param->beacon_period) >> 8) & 0xFF;
>
> __le16 beacon_period;
>
>> + *(cur_byte++) = bss_param->dtim_period;
>
> u8 dtim_period;
>
> etc.
>
> Declaring it as a struct also means you don't have to do all the
> put_le16_unaligned() or whatever, but can just fill the struct properly.
>

Agree. The idea was of packing the parameters manually was to avoid struct padding issues, but I can declare the struct as packed instead

Thanks,
Adham

2018-10-12 22:08:10

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c



On 10/11/2018 12:01 AM, Johannes Berg wrote:
>
>> Agree. parameter validation can be done before scheduling the work,
>> and hence appropriate error can be returned to caller .
>
>
>> If I got your point correctly, you are referring to the lines that
>> stores the parameters into the hif_drv->cfg_values.
>
> Well, I was actually thinking that I'm not even sure why you schedule
> work at all!

Do you mean we should be doing the work from the cfg context?
Note that this is called cfg80211_ops.set_wiphy_params(), and involves locking mutexes, packing the wids, bus operations, and waiting for the device to respond.

>> Instead of packing the parameters in host structures like struct
>> add_sta_param, then repacking it in the device format, it can use
>> struct station_parameters and pack them directly into the device
>> format
>
> Makes sense. Also note my other email on how there should be structs
> involved, rather than open-coded WID entry lists.

Thanks for the suggestion. I agree to that as well.

2018-10-18 08:23:36

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c

On Fri, 2018-10-12 at 21:55 +0000, [email protected] wrote:
>
> Here the driver is configuring parameters in the device by sending a
> WID command for each parameters.
> The val pointer points to the value of the parameter to be set, and
> here all parameters being set to 0 were sharing the dummyval variable.

Ok.

> Looking again at this, these constant parameters can be omitted from
> the driver and done on the device instead.

I think it's fine, just the pointers look strange. Would probably be
different once you resolve the middle layer though.

> > > + if (conn_attr->bssid)
> > > + memcpy(cur_byte, conn_attr->bssid, 6);
> > > + cur_byte += 6;
> >
> > u8 bssid[ETH_ALEN];
> >
> > > + if (conn_attr->bssid)
> > > + memcpy(cur_byte, conn_attr->bssid, 6);
> > > + cur_byte += 6;
> >
> > again?
>
> Agree. Can be changed to avoid duplication. Requires a matching change on the device.

Again, like above, don't worry too much about changing the
device/firmware. I was just pointing out it's duplicate, if that's the
way it is then too bad, but it doesn't really matter.

The more interesting thing here is to change it to use a struct and not
pack it manually.

johannes


2018-10-18 08:23:58

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c

On Fri, 2018-10-12 at 22:08 +0000, [email protected] wrote:
>
> On 10/11/2018 12:01 AM, Johannes Berg wrote:
> >
> > > Agree. parameter validation can be done before scheduling the work,
> > > and hence appropriate error can be returned to caller .
> >
> >
> > > If I got your point correctly, you are referring to the lines that
> > > stores the parameters into the hif_drv->cfg_values.
> >
> > Well, I was actually thinking that I'm not even sure why you schedule
> > work at all!
>
> Do you mean we should be doing the work from the cfg context?
> Note that this is called cfg80211_ops.set_wiphy_params(), and involves
> locking mutexes, packing the wids, bus operations, and waiting for the
> device to respond.

That *should* be fine - how long do you expect that to take?

johannes



2018-10-18 18:30:45

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c



On 10/18/2018 01:23 AM, Johannes Berg wrote:
> On Fri, 2018-10-12 at 22:08 +0000, [email protected] wrote:
>>
>> On 10/11/2018 12:01 AM, Johannes Berg wrote:
>>>
>>>> Agree. parameter validation can be done before scheduling the work,
>>>> and hence appropriate error can be returned to caller .
>>>
>>>
>>>> If I got your point correctly, you are referring to the lines that
>>>> stores the parameters into the hif_drv->cfg_values.
>>>
>>> Well, I was actually thinking that I'm not even sure why you schedule
>>> work at all!
>>
>> Do you mean we should be doing the work from the cfg context?
>> Note that this is called cfg80211_ops.set_wiphy_params(), and involves
>> locking mutexes, packing the wids, bus operations, and waiting for the
>> device to respond.
>
> That *should* be fine - how long do you expect that to take?
>

It depends on the IO bus used (SPI/SDIO), clock speed.. etc
It would also vary according to the data packets being transferred with the device.
If there's heavy data transfer, configuration packets would take longer to be sent, and for their response to be received.


Thanks,
Adham

2018-10-19 07:02:58

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c


> > > Do you mean we should be doing the work from the cfg context?
> > > Note that this is called cfg80211_ops.set_wiphy_params(), and involves
> > > locking mutexes, packing the wids, bus operations, and waiting for the
> > > device to respond.
> >
> > That *should* be fine - how long do you expect that to take?
> >
>
> It depends on the IO bus used (SPI/SDIO), clock speed.. etc
> It would also vary according to the data packets being transferred
> with the device.
> If there's heavy data transfer, configuration packets would take
> longer to be sent, and for their response to be received.

How much time do you think you're looking at?

I'd argue for trying it though as it makes the code MUCH simpler.

johannes


2018-10-19 20:53:52

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c



On 10/19/2018 12:02 AM, Johannes Berg wrote:
>
>>>> Do you mean we should be doing the work from the cfg context?
>>>> Note that this is called cfg80211_ops.set_wiphy_params(), and involves
>>>> locking mutexes, packing the wids, bus operations, and waiting for the
>>>> device to respond.
>>>
>>> That *should* be fine - how long do you expect that to take?
>>>
>>
>> It depends on the IO bus used (SPI/SDIO), clock speed.. etc
>> It would also vary according to the data packets being transferred
>> with the device.
>> If there's heavy data transfer, configuration packets would take
>> longer to be sent, and for their response to be received.
>
> How much time do you think you're looking at?
>
> I'd argue for trying it though as it makes the code MUCH simpler.

I totally agree that it will be simpler to do the work directly from the cfg context rather than scheduling it.
On a cortex A5 MPU and SPI bus running on 48Mhz, this takes 20ms in the idle case, and 100 to 300ms in case of data being transferred in parallel.

Thanks,
Adham

2018-10-19 21:48:12

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 12/19] wilc: add wilc_wfi_cfgoperations.c



On 10/09/2018 10:15 AM, Adham Abozaeid wrote:
>
>
> On 10/09/2018 12:55 AM, Johannes Berg wrote:
>> On Tue, 2018-10-09 at 04:23 +0000, [email protected] wrote:
>>>
>>>> I don't know what you need the shadow stuff for, but you should remove
>>>> it anyway, and use the cfg80211 functionality instead. If not
>>>> sufficient, propose patches to improve it?
>>>
>>> The point behind using a shadow buffer was to keep the scan results
>>> consistent between consecutive scans, and smooth out the cases where
>>> an AP isn't found momentarily during scanning.
>>> In this implementation, APs found during scanning are added to the
>>> shadow list, and removed if not found again for a period of time.
>>>
>>> I'm not much in favour of this implementation neither since it
>>> complicates the driver's logic, but it was serving the purpose.
>>
>> You really should remove it - cfg80211 *and* wpa_s already do this if
>> required.
>>
>> johannes
>>
>
> Thanks Johannes for the tip. I did some research, and I believe you are
> referring to using bss_expire_age and bss_expire_count.
> We'll go ahead and remove that.


Johannes, shadow buffer has 2 more usage that I missed in my first email:
1- It keeps a copy of scan results to be able to auto-select from if the cfg80211 didn't supply a specific bssid in cfg's connect request (struct cfg80211_connect_params).
In this case the driver will select a network that matches the ssid, while having the highest rssi.
2- It keeps network parameters that the device will need to connect to a network, since the device doesn't keep the scan results internally.
These parameters are stored in struct join_bss_param, and passed to the device when a connect request is received.
Some of these parameters can be extracted from cfg's cfg80211_connect_params (like cap_info.. etc), but others (like bssid, beacon period.. etc) are still required.

I think I can remove the functionality where it keeps older networks that didn't appear in the latest scan results, and let cfg take care of that, but will still need it to keep a copy of the latest scan results.
Let me know what you think.


Thanks,
Adham

2018-10-29 14:56:18

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h

Ajay Singh <[email protected]> writes:

> On 10/9/2018 4:06 PM, Johannes Berg wrote:
>> On Tue, 2018-10-09 at 16:04 +0530, Ajay Singh wrote:
>>
>>>>> +typedef void (*wilc_remain_on_chan_expired)(void *, u32);
>>>>> +typedef void (*wilc_remain_on_chan_ready)(void *);
>>> I think as per coding style the typedef for function pointer are allowed.
>> True, I guess, but why do you need them?
>
> Actually these function pointer are used in multiple places i.e inside
> the struct and also for passing as the argument for the function. So i
> think its better to keep them as typedef to simplify and avoid any 'line
> over 80 chars' checkpatch issue. But anyway if you suggest we can modify
> to remove these typedefs .

Please remove them, they just make the code harder to read.

--
Kalle Valo

2018-10-29 20:10:39

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c


> > I'd argue for trying it though as it makes the code MUCH simpler.
>
> I totally agree that it will be simpler to do the work directly from
> the cfg context rather than scheduling it.
> On a cortex A5 MPU and SPI bus running on 48Mhz, this takes 20ms in
> the idle case, and 100 to 300ms in case of data being transferred in
> parallel.

That does sound pretty slow ... but OTOH, mostly wpa_s etc. would expect
this to actually complete before the next step, so if this is slow and
wpa_s/hostapd is much faster, it might send you a lot of things to do
and so you'd end up being slow anyway?

johannes


2018-10-29 20:12:09

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 12/19] wilc: add wilc_wfi_cfgoperations.c

Hi,

Sorry for the late reply.

On Fri, 2018-10-19 at 21:47 +0000, [email protected] wrote:
>
> Johannes, shadow buffer has 2 more usage that I missed in my first email:
> 1- It keeps a copy of scan results to be able to auto-select from if
> the cfg80211 didn't supply a specific bssid in cfg's connect request
> (struct cfg80211_connect_params).
> In this case the driver will select a network that matches the ssid,
> while having the highest rssi.

You should be able to find this from cfg80211's BSS list as well.

If we lack some API in this area, which is possible, then we can add it.

> 2- It keeps network parameters that the device will need to connect
> to a network, since the device doesn't keep the scan results
> internally.
> These parameters are stored in struct join_bss_param, and passed to
> the device when a connect request is received.
> Some of these parameters can be extracted from cfg's
> cfg80211_connect_params (like cap_info.. etc), but others (like bssid,
> beacon period.. etc) are still required.

Again though, you should be able to extract these from struct
cfg80211_bss, I'd argue?

johannes


2018-10-29 21:32:32

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c

On 10/29/18 1:10 PM, Johannes Berg wrote:
>>> I'd argue for trying it though as it makes the code MUCH simpler.
>> I totally agree that it will be simpler to do the work directly from
>> the cfg context rather than scheduling it.
>> On a cortex A5 MPU and SPI bus running on 48Mhz, this takes 20ms in
>> the idle case, and 100 to 300ms in case of data being transferred in
>> parallel.
> That does sound pretty slow ... but OTOH, mostly wpa_s etc. would expect
> this to actually complete before the next step, so if this is slow and
> wpa_s/hostapd is much faster, it might send you a lot of things to do
> and so you'd end up being slow anyway?
Correct. The speed of executing the work will be the same in both cases (maybe a little slower in case of deferring the work)
The intuition here was to do minimum work in the cfg's context, but since this isn't a concern, I can skip deferring the work.

Thanks,
Adham

2018-10-29 21:34:10

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 04/19] wilc: add host_interface.c

On Mon, 2018-10-29 at 21:32 +0000, [email protected] wrote:
>
> Correct. The speed of executing the work will be the same in both
> cases (maybe a little slower in case of deferring the work)
> The intuition here was to do minimum work in the cfg's context, but
> since this isn't a concern, I can skip deferring the work.

It sort of depends. Practically all of this is done with the RTNL held,
so you might be blocking _other_ things that need the RTNL. I'm not sure
if that matters that much, but still ...

Regardless, I'd try this first. Perhaps you can even see later that only
some commands take a long time, and others are quicker. Having
wpa_supplicant/hostapd not know when an operation is really completed is
unlikely to be a good idea, IMHO.

johannes


2018-10-29 21:43:50

by Adham Abozaeid

[permalink] [raw]
Subject: Re: [PATCH 12/19] wilc: add wilc_wfi_cfgoperations.c

On 10/29/18 1:11 PM, Johannes Berg wrote:
> Hi,
>
> Sorry for the late reply.
No worries! Thanks for taking the time to review the driver.
>
> On Fri, 2018-10-19 at 21:47 +0000, [email protected] wrote:
>> Johannes, shadow buffer has 2 more usage that I missed in my first email:
>> 1- It keeps a copy of scan results to be able to auto-select from if
>> the cfg80211 didn't supply a specific bssid in cfg's connect request
>> (struct cfg80211_connect_params).
>> In this case the driver will select a network that matches the ssid,
>> while having the highest rssi.
> You should be able to find this from cfg80211's BSS list as well.
>
> If we lack some API in this area, which is possible, then we can add it.
Frankly, I wasn't aware that the cfg80211's BSS list is accessible from the driver!
I'll do some research on that and let you know if these APIs didn't serve our purpose completely.
>> 2- It keeps network parameters that the device will need to connect
>> to a network, since the device doesn't keep the scan results
>> internally.
>> These parameters are stored in struct join_bss_param, and passed to
>> the device when a connect request is received.
>> Some of these parameters can be extracted from cfg's
>> cfg80211_connect_params (like cap_info.. etc), but others (like bssid,
>> beacon period.. etc) are still required.
> Again though, you should be able to extract these from struct
> cfg80211_bss, I'd argue?
>
> johannes
>

2018-10-30 03:20:21

by Ajay Singh

[permalink] [raw]
Subject: Re: [PATCH 03/19] wilc: add host_interface.h


On 10/29/2018 8:26 PM, Kalle Valo wrote:
> Ajay Singh <[email protected]> writes:
>
>> On 10/9/2018 4:06 PM, Johannes Berg wrote:
>>> On Tue, 2018-10-09 at 16:04 +0530, Ajay Singh wrote:
>>>
>>>>>> +typedef void (*wilc_remain_on_chan_expired)(void *, u32);
>>>>>> +typedef void (*wilc_remain_on_chan_ready)(void *);
>>>> I think as per coding style the typedef for function pointer are allowed.
>>> True, I guess, but why do you need them?
>> Actually these function pointer are used in multiple places i.e inside
>> the struct and also for passing as the argument for the function. So i
>> think its better to keep them as typedef to simplify and avoid any 'line
>> over 80 chars' checkpatch issue. But anyway if you suggest we can modify
>> to remove these typedefs .
> Please remove them, they just make the code harder to read.

Sure, I will remove it.

Regards,
Ajay

2018-11-15 14:12:00

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC 00/19] wilc: added driver for wilc module

<[email protected]> writes:

> On 10/08/2018 12:38 AM, Kalle Valo wrote:
>> Ajay Singh <[email protected]> writes:
>>
>>> On Sat, 6 Oct 2018 15:45:41 +0300
>>> Kalle Valo <[email protected]> wrote:
>>>
>>>> Ajay Singh <[email protected]> writes:
>>>>
>>>>> This patch set contains the driver files from
>>>>> 'driver/staging/wilc1000'. Renamed the driver from 'wilc1000' to
>>>>> 'wilc' to have generic name, as the same driver will be used by
>>>>> other wilc family members.
>>>>
>>>> I'm worried that the name 'wilc' is just too generic, I liked the
>>>> original name wilc1000 much more. Quite often when we have a new
>>>> generation of wireless devices there's also a new driver, so in the
>>>> long run I'm worried that a generic name like 'wilc' could be a
>>>> source of confusion. I think it's much smaller problem if
>>>> 'wilc1000' (the driver) also supports wilc3000 (the device), people
>>>> are already used to that.
>
>> If I'm understanding correctly you are worried that 'wilc1000-spi.ko'
>> also supports wilc3000 devices, but I don't see that as a problem. I
>> think it's very common (not just in wireless) that the marketing names
>> don't always match with driver names.
>>
>
> It's highly unlikely that microchip will have a new generation of wilc
> devices other than wilc1000 and wilc3000, since a new family is
> already in development.
> And in case a new generation was developed, it will be best to support
> it in the current driver because of the similarities between wilc
> devices.
>
> I'm afraid that it might be more confusing for users to use wilc1000
> naming while they are using wilc3000 hardware. It's not only that the
> name that is different from the marketing name, but it also refers to
> another existing product.

Well, I see it very differently. For example, if I google 'wilc1000' I
get directly to the product page but with 'wilc' I get nothing useful.
And I have been dealing with marketing for so long that "never say
never" about what they will decide ;)

So I'm still not convinced that renaming is a good idea. But actually my
opinion doesn't matter here, as the rename should happen in the staging
tree (when the driver is moved from staging to drivers/net/wireless it
should be a simple rename, no other changes). So I'll leave this for
Greg to decide if the rename is worthwhile or not. My vote would be a
clear "no" :)

--
Kalle Valo