From patchwork Wed Sep 26 10:25:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615587 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0940C15A6 for ; Wed, 26 Sep 2018 10:25:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 05DFA2A7A4 for ; Wed, 26 Sep 2018 10:25:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EEA382A7AF; Wed, 26 Sep 2018 10:25:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DE3722A7A4 for ; Wed, 26 Sep 2018 10:25:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727434AbeIZQhu (ORCPT ); Wed, 26 Sep 2018 12:37:50 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727421AbeIZQhu (ORCPT ); Wed, 26 Sep 2018 12:37:50 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366763" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:25:34 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:25:33 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 01/19] wilc: add coreconfigurator.h Date: Wed, 26 Sep 2018 15:55:07 +0530 Message-ID: <1537957525-11467-2-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/coreconfigurator.h' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- .../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 From patchwork Wed Sep 26 10:25:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615589 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BBAFB15A6 for ; Wed, 26 Sep 2018 10:25:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B7DB72A7A4 for ; Wed, 26 Sep 2018 10:25:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AC46E2A7B1; Wed, 26 Sep 2018 10:25:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1D3812A7A4 for ; Wed, 26 Sep 2018 10:25:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727421AbeIZQhx (ORCPT ); Wed, 26 Sep 2018 12:37:53 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727157AbeIZQhx (ORCPT ); Wed, 26 Sep 2018 12:37:53 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366768" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:25:37 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:25:36 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 02/19] wilc: add coreconfigurator.c Date: Wed, 26 Sep 2018 15:55:08 +0530 Message-ID: <1537957525-11467-3-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/coreconfigurator.c' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- .../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 + +#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; +} From patchwork Wed Sep 26 10:25:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615591 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 66C9714BD for ; Wed, 26 Sep 2018 10:25:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 632532A7A4 for ; Wed, 26 Sep 2018 10:25:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5734F2A7AF; Wed, 26 Sep 2018 10:25:43 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 934782A7A4 for ; Wed, 26 Sep 2018 10:25:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727442AbeIZQh5 (ORCPT ); Wed, 26 Sep 2018 12:37:57 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727157AbeIZQh5 (ORCPT ); Wed, 26 Sep 2018 12:37:57 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366771" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:25:40 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:25:40 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 03/19] wilc: add host_interface.h Date: Wed, 26 Sep 2018 15:55:09 +0530 Message-ID: <1537957525-11467-4-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/host_interface.h' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- .../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 +#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 From patchwork Wed Sep 26 10:25:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615629 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C3A0B15A6 for ; Wed, 26 Sep 2018 10:25:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B53B32A7A4 for ; Wed, 26 Sep 2018 10:25:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A8BFD2A7B4; Wed, 26 Sep 2018 10:25:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9DAEA2A7A9 for ; Wed, 26 Sep 2018 10:25:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727477AbeIZQiC (ORCPT ); Wed, 26 Sep 2018 12:38:02 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727447AbeIZQiC (ORCPT ); Wed, 26 Sep 2018 12:38:02 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366774" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:25:45 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:25:43 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 04/19] wilc: add host_interface.c Date: Wed, 26 Sep 2018 15:55:10 +0530 Message-ID: <1537957525-11467-5-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/host_interface.c' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- .../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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 = ¶m->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 = ¶m->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, ¶m->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; +} From patchwork Wed Sep 26 10:25:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615617 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D96DA15A6 for ; Wed, 26 Sep 2018 10:25:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D3CF92A7AF for ; Wed, 26 Sep 2018 10:25:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C846C2A7B7; Wed, 26 Sep 2018 10:25:52 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 79B292A7AF for ; Wed, 26 Sep 2018 10:25:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727492AbeIZQiG (ORCPT ); Wed, 26 Sep 2018 12:38:06 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727239AbeIZQiF (ORCPT ); Wed, 26 Sep 2018 12:38:05 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366776" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:25:48 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:25:47 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 05/19] wilc: add wilc_wlan_if.h Date: Wed, 26 Sep 2018 15:55:11 +0530 Message-ID: <1537957525-11467-6-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_wlan_if.h' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- 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 + +/******************************************** + * + * 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 From patchwork Wed Sep 26 10:25:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615627 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1AF1E3CF1 for ; Wed, 26 Sep 2018 10:25:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 172652A7A4 for ; Wed, 26 Sep 2018 10:25:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0AE872A7B8; Wed, 26 Sep 2018 10:25:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 895022A7A4 for ; Wed, 26 Sep 2018 10:25:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727501AbeIZQiI (ORCPT ); Wed, 26 Sep 2018 12:38:08 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727502AbeIZQiH (ORCPT ); Wed, 26 Sep 2018 12:38:07 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366778" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:25:51 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:25:50 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 06/19] wilc: add wilc_wlan_cfg.h Date: Wed, 26 Sep 2018 15:55:12 +0530 Message-ID: <1537957525-11467-7-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_wlan_cfg.h' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- .../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 From patchwork Wed Sep 26 10:25:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615651 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EDA03417B for ; Wed, 26 Sep 2018 10:25:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E73B22A7AF for ; Wed, 26 Sep 2018 10:25:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DB0A42A7A9; Wed, 26 Sep 2018 10:25:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2595C2A7B1 for ; Wed, 26 Sep 2018 10:25:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727523AbeIZQiM (ORCPT ); Wed, 26 Sep 2018 12:38:12 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726802AbeIZQiK (ORCPT ); Wed, 26 Sep 2018 12:38:10 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366779" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:25:54 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:25:54 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 07/19] wilc: add wilc_wlan_cfg.c Date: Wed, 26 Sep 2018 15:55:13 +0530 Message-ID: <1537957525-11467-8-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_wlan_cfg.c' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- .../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); +} From patchwork Wed Sep 26 10:25:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615689 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2A78B15A6 for ; Wed, 26 Sep 2018 10:26:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 269762A7A9 for ; Wed, 26 Sep 2018 10:26:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1A0462A7B4; Wed, 26 Sep 2018 10:26:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 42E8F2A7A9 for ; Wed, 26 Sep 2018 10:26:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727630AbeIZQiQ (ORCPT ); Wed, 26 Sep 2018 12:38:16 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727613AbeIZQiO (ORCPT ); Wed, 26 Sep 2018 12:38:14 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366784" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:25:58 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:25:57 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 08/19] wilc: add wilc_wlan.h Date: Wed, 26 Sep 2018 15:55:14 +0530 Message-ID: <1537957525-11467-9-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_wlan.h' to ' drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- 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 + +/******************************************** + * + * 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 From patchwork Wed Sep 26 10:25:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615675 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 69A2114BD for ; Wed, 26 Sep 2018 10:26:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 62DB92A7A4 for ; Wed, 26 Sep 2018 10:26:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 570DC2A7A9; Wed, 26 Sep 2018 10:26:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A8FD22A7AF for ; Wed, 26 Sep 2018 10:26:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727794AbeIZQiU (ORCPT ); Wed, 26 Sep 2018 12:38:20 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726880AbeIZQiS (ORCPT ); Wed, 26 Sep 2018 12:38:18 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366788" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:01 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:00 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 09/19] wilc: add wilc_wlan.c Date: Wed, 26 Sep 2018 15:55:15 +0530 Message-ID: <1537957525-11467-10-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_wlan.c' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- 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 +#include +#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, ®); + + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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 |= 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, ®); + 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, ®); + 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, ®); + 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, + ®); + 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, ®); + 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, ®); + 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; +} From patchwork Wed Sep 26 10:25:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615659 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 99B4E14BD for ; Wed, 26 Sep 2018 10:26:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 93FA82A7A4 for ; Wed, 26 Sep 2018 10:26:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 885732A7B1; Wed, 26 Sep 2018 10:26:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EB2462A7A9 for ; Wed, 26 Sep 2018 10:26:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728077AbeIZQiW (ORCPT ); Wed, 26 Sep 2018 12:38:22 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726937AbeIZQiV (ORCPT ); Wed, 26 Sep 2018 12:38:21 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366790" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:05 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:04 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 10/19] wilc: add wilc_wfi_netdevice.h Date: Wed, 26 Sep 2018 15:55:16 +0530 Message-ID: <1537957525-11467-11-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_wfi_netdevice.h' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- .../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 +#include +#include +#include +#include +#include + +#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 From patchwork Wed Sep 26 10:25:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615663 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0B53D15A6 for ; Wed, 26 Sep 2018 10:26:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 05DEE2A7A4 for ; Wed, 26 Sep 2018 10:26:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EDE592A7AF; Wed, 26 Sep 2018 10:26:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9E0082A7A4 for ; Wed, 26 Sep 2018 10:26:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728079AbeIZQiY (ORCPT ); Wed, 26 Sep 2018 12:38:24 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728080AbeIZQiY (ORCPT ); Wed, 26 Sep 2018 12:38:24 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366792" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:08 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:07 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 11/19] wilc: add wilc_wfi_cfgoperations.h Date: Wed, 26 Sep 2018 15:55:17 +0530 Message-ID: <1537957525-11467-12-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_wfi_cfgoperations.h' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- .../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 From patchwork Wed Sep 26 10:25:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615665 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 17B3514BD for ; Wed, 26 Sep 2018 10:26:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0DB192A7A4 for ; Wed, 26 Sep 2018 10:26:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 017EE2A7B8; Wed, 26 Sep 2018 10:26:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B8DDE2A7A4 for ; Wed, 26 Sep 2018 10:26:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728085AbeIZQi3 (ORCPT ); Wed, 26 Sep 2018 12:38:29 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728080AbeIZQi2 (ORCPT ); Wed, 26 Sep 2018 12:38:28 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366796" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:11 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:10 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 12/19] wilc: add wilc_wfi_cfgoperations.c Date: Wed, 26 Sep 2018 15:55:18 +0530 Message-ID: <1537957525-11467-13-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_wfi_cfgoperations.c' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- .../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); +} From patchwork Wed Sep 26 10:25:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615669 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B069314BD for ; Wed, 26 Sep 2018 10:26:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AAE8D2A7A4 for ; Wed, 26 Sep 2018 10:26:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9F00A2A7B1; Wed, 26 Sep 2018 10:26:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B93D22A7B4 for ; Wed, 26 Sep 2018 10:26:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728093AbeIZQic (ORCPT ); Wed, 26 Sep 2018 12:38:32 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728080AbeIZQib (ORCPT ); Wed, 26 Sep 2018 12:38:31 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366797" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:14 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:13 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 13/19] wilc: add linux_wlan.c Date: Wed, 26 Sep 2018 15:55:19 +0530 Message-ID: <1537957525-11467-14-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/linux_wlan.c' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- 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 +#include +#include +#include +#include + +#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"); From patchwork Wed Sep 26 10:25:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615671 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B2A4214BD for ; Wed, 26 Sep 2018 10:26:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF4E72A7A4 for ; Wed, 26 Sep 2018 10:26:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A38CC2A7B4; Wed, 26 Sep 2018 10:26:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 193F82A7A4 for ; Wed, 26 Sep 2018 10:26:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727444AbeIZQig (ORCPT ); Wed, 26 Sep 2018 12:38:36 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727259AbeIZQif (ORCPT ); Wed, 26 Sep 2018 12:38:35 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366800" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:18 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:18 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 14/19] wilc: add linux_mon.c Date: Wed, 26 Sep 2018 15:55:20 +0530 Message-ID: <1537957525-11467-15-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/linux_mon.c' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- 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; + } +} From patchwork Wed Sep 26 10:25:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615673 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D802215A6 for ; Wed, 26 Sep 2018 10:26:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D175E2A7A4 for ; Wed, 26 Sep 2018 10:26:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C52972A7B1; Wed, 26 Sep 2018 10:26:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 412C72A7A4 for ; Wed, 26 Sep 2018 10:26:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727390AbeIZQij (ORCPT ); Wed, 26 Sep 2018 12:38:39 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727259AbeIZQii (ORCPT ); Wed, 26 Sep 2018 12:38:38 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366808" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:22 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:21 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 15/19] wilc: add wilc_spi.c Date: Wed, 26 Sep 2018 15:55:21 +0530 Message-ID: <1537957525-11467-16-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_spi.c' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- 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 + +#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, ®)) { + /* + * 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, ®)) { + /* + * 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, +}; From patchwork Wed Sep 26 10:25:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615679 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9E8A614BD for ; Wed, 26 Sep 2018 10:26:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 97A822A7A4 for ; Wed, 26 Sep 2018 10:26:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8BCED2A7AF; Wed, 26 Sep 2018 10:26:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0EC022A7A9 for ; Wed, 26 Sep 2018 10:26:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727411AbeIZQin (ORCPT ); Wed, 26 Sep 2018 12:38:43 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727259AbeIZQim (ORCPT ); Wed, 26 Sep 2018 12:38:42 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366815" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:25 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:24 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 16/19] wilc: add wilc_sdio.c Date: Wed, 26 Sep 2018 15:55:22 +0530 Message-ID: <1537957525-11467-17-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Moved '/driver/staging/wilc1000/wilc_sdio.c' to 'drivers/net/wireless/microchip/wilc/'. Signed-off-by: Ajay Singh --- 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 +#include + +#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, ®)) { + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, +}; + From patchwork Wed Sep 26 10:25:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615681 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C962915A6 for ; Wed, 26 Sep 2018 10:26:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C50902A7A4 for ; Wed, 26 Sep 2018 10:26:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B9B652A7AF; Wed, 26 Sep 2018 10:26:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5A8F22A7A4 for ; Wed, 26 Sep 2018 10:26:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727434AbeIZQip (ORCPT ); Wed, 26 Sep 2018 12:38:45 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727259AbeIZQip (ORCPT ); Wed, 26 Sep 2018 12:38:45 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366822" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:29 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:28 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 17/19] wilc: updated DT device binding for wilc device Date: Wed, 26 Sep 2018 15:55:23 +0530 Message-ID: <1537957525-11467-18-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Added the device tree binding document from '/driver/staging/wilc1000/' to '/Documentation/devicetree/bindings/net/wireless/' folder. Signed-off-by: Ajay Singh --- .../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"; + }; +}; From patchwork Wed Sep 26 10:25:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615683 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 77D7015A6 for ; Wed, 26 Sep 2018 10:26:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 751F72A7A4 for ; Wed, 26 Sep 2018 10:26:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 68DEE2A7B1; Wed, 26 Sep 2018 10:26:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DE8452A7A4 for ; Wed, 26 Sep 2018 10:26:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727442AbeIZQit (ORCPT ); Wed, 26 Sep 2018 12:38:49 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726915AbeIZQis (ORCPT ); Wed, 26 Sep 2018 12:38:48 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366829" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:32 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:31 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 18/19] wilc: add Makefile and Kconfig files for wilc compilation Date: Wed, 26 Sep 2018 15:55:24 +0530 Message-ID: <1537957525-11467-19-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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 */ From patchwork Wed Sep 26 10:25:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 10615687 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A09AD15A6 for ; Wed, 26 Sep 2018 10:26:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9C4842A7A9 for ; Wed, 26 Sep 2018 10:26:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 909CB2A7B1; Wed, 26 Sep 2018 10:26:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 477C92A7A9 for ; Wed, 26 Sep 2018 10:26:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727479AbeIZQiw (ORCPT ); Wed, 26 Sep 2018 12:38:52 -0400 Received: from esa1.microchip.iphmx.com ([68.232.147.91]:39495 "EHLO esa1.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726915AbeIZQiv (ORCPT ); Wed, 26 Sep 2018 12:38:51 -0400 X-IronPort-AV: E=Sophos;i="5.54,306,1534834800"; d="scan'208";a="21366832" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES128-SHA; 26 Sep 2018 03:26:35 -0700 Received: from ajaysk-VirtualBox.microchip.com (10.10.76.4) by CHN-SV-EXCH01.mchp-main.com (10.10.76.37) with Microsoft SMTP Server id 14.3.352.0; Wed, 26 Sep 2018 03:26:34 -0700 From: Ajay Singh To: CC: , , , , , , , Ajay Singh Subject: [PATCH 19/19] wilc: added wilc module compilation in wireless Makefile & Kconfig Date: Wed, 26 Sep 2018 15:55:25 +0530 Message-ID: <1537957525-11467-20-git-send-email-ajay.kathat@microchip.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> References: <1537957525-11467-1-git-send-email-ajay.kathat@microchip.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Modified wireless Makefile and Kconfig to include the microchip/wilc files compilation. Signed-off-by: Ajay Singh --- 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