ccflags-y += -DFIRMWARE_1002=\"atmel/wilc1002_firmware.bin\" \
-DFIRMWARE_1003=\"atmel/wilc1003_firmware.bin\"
-wilc1000-objs := wilc_wfi_cfgoperations.o wilc_netdev.o wilc_mon.o \
- wilc_hif.o wilc_wlan_cfg.o wilc_wlan.o
+wilc1000-objs := cfg80211.o netdev.o mon.o \
+ hif.o wlan_cfg.o wlan.o
obj-$(CONFIG_WILC1000_SDIO) += wilc1000-sdio.o
-wilc1000-sdio-objs += wilc_sdio.o
+wilc1000-sdio-objs += sdio.o
obj-$(CONFIG_WILC1000_SPI) += wilc1000-spi.o
-wilc1000-spi-objs += wilc_spi.o
+wilc1000-spi-objs += spi.o
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "cfg80211.h"
+
+#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 WILC_INVALID_CHANNEL 0
+
+static const struct ieee80211_txrx_stypes
+ wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4)
+ }
+};
+
+static const struct wiphy_wowlan_support wowlan_support = {
+ .flags = WIPHY_WOWLAN_ANY
+};
+
+struct wilc_p2p_mgmt_data {
+ int size;
+ u8 *buff;
+};
+
+static const u8 p2p_oui[] = {0x50, 0x6f, 0x9A, 0x09};
+static const u8 p2p_vendor_spec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03};
+
+static void cfg_scan_result(enum scan_event scan_event,
+ struct wilc_rcvd_net_info *info, void *user_void)
+{
+ struct wilc_priv *priv = user_void;
+
+ if (!priv->cfg_scanning)
+ return;
+
+ if (scan_event == SCAN_EVENT_NETWORK_FOUND) {
+ s32 freq;
+ struct ieee80211_channel *channel;
+ struct cfg80211_bss *bss;
+ struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy;
+
+ if (!wiphy || !info)
+ return;
+
+ freq = ieee80211_channel_to_frequency((s32)info->ch,
+ NL80211_BAND_2GHZ);
+ channel = ieee80211_get_channel(wiphy, freq);
+ if (!channel)
+ return;
+
+ bss = cfg80211_inform_bss_frame(wiphy, channel, info->mgmt,
+ info->frame_len,
+ (s32)info->rssi * 100,
+ GFP_KERNEL);
+ if (!bss)
+ cfg80211_put_bss(wiphy, bss);
+ } else if (scan_event == SCAN_EVENT_DONE) {
+ mutex_lock(&priv->scan_req_lock);
+
+ if (priv->scan_req) {
+ struct cfg80211_scan_info info = {
+ .aborted = false,
+ };
+
+ cfg80211_scan_done(priv->scan_req, &info);
+ priv->cfg_scanning = false;
+ priv->scan_req = NULL;
+ }
+ mutex_unlock(&priv->scan_req_lock);
+ } else if (scan_event == SCAN_EVENT_ABORTED) {
+ mutex_lock(&priv->scan_req_lock);
+
+ if (priv->scan_req) {
+ struct cfg80211_scan_info info = {
+ .aborted = false,
+ };
+
+ cfg80211_scan_done(priv->scan_req, &info);
+ priv->cfg_scanning = false;
+ priv->scan_req = NULL;
+ }
+ mutex_unlock(&priv->scan_req_lock);
+ }
+}
+
+static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status,
+ void *priv_data)
+{
+ struct wilc_priv *priv = priv_data;
+ struct net_device *dev = priv->dev;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ struct wilc_conn_info *conn_info = &wfi_drv->conn_info;
+ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+
+ vif->connecting = false;
+
+ if (conn_disconn_evt == CONN_DISCONN_EVENT_CONN_RESP) {
+ u16 connect_status = conn_info->status;
+
+ if (mac_status == WILC_MAC_STATUS_DISCONNECTED &&
+ connect_status == WLAN_STATUS_SUCCESS) {
+ connect_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
+
+ if (vif->iftype != WILC_CLIENT_MODE)
+ wl->sta_ch = WILC_INVALID_CHANNEL;
+
+ netdev_err(dev, "Unspecified failure\n");
+ }
+
+ if (connect_status == WLAN_STATUS_SUCCESS)
+ memcpy(priv->associated_bss, conn_info->bssid,
+ ETH_ALEN);
+
+ cfg80211_ref_bss(wiphy, vif->bss);
+ cfg80211_connect_bss(dev, conn_info->bssid, vif->bss,
+ conn_info->req_ies,
+ conn_info->req_ies_len,
+ conn_info->resp_ies,
+ conn_info->resp_ies_len,
+ connect_status, GFP_KERNEL,
+ NL80211_TIMEOUT_UNSPECIFIED);
+
+ vif->bss = NULL;
+ } else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) {
+ u16 reason = 0;
+
+ 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, WILC_STATION_MODE);
+
+ if (vif->iftype != WILC_CLIENT_MODE) {
+ wl->sta_ch = WILC_INVALID_CHANNEL;
+ } else {
+ if (wfi_drv->ifc_up)
+ reason = 3;
+ else
+ reason = 1;
+ }
+
+ cfg80211_disconnected(dev, reason, NULL, 0, false, GFP_KERNEL);
+ }
+}
+
+struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl)
+{
+ struct wilc_vif *vif;
+
+ vif = list_first_or_null_rcu(&wl->vif_list, typeof(*vif), list);
+ if (!vif)
+ return ERR_PTR(-EINVAL);
+
+ return vif;
+}
+
+static int set_channel(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ u32 channelnum;
+ int result;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif)) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return PTR_ERR(vif);
+ }
+
+ channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq);
+
+ wl->op_ch = channelnum;
+ result = wilc_set_mac_chnl_num(vif, channelnum);
+ if (result)
+ netdev_err(vif->ndev, "Error in setting channel\n");
+
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return result;
+}
+
+static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
+{
+ struct wilc_vif *vif = netdev_priv(request->wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+ u32 i;
+ int ret = 0;
+ u8 scan_ch_list[WILC_MAX_NUM_SCANNED_CH];
+ u8 scan_type;
+
+ if (request->n_channels > WILC_MAX_NUM_SCANNED_CH) {
+ netdev_err(vif->ndev, "Requested scanned channels over\n");
+ return -EINVAL;
+ }
+
+ priv->scan_req = request;
+ priv->cfg_scanning = true;
+ for (i = 0; i < request->n_channels; i++) {
+ u16 freq = request->channels[i]->center_freq;
+
+ scan_ch_list[i] = ieee80211_frequency_to_channel(freq);
+ }
+
+ if (request->n_ssids)
+ scan_type = WILC_FW_ACTIVE_SCAN;
+ else
+ scan_type = WILC_FW_PASSIVE_SCAN;
+
+ ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list,
+ request->n_channels, cfg_scan_result, (void *)priv,
+ request);
+
+ if (ret) {
+ priv->scan_req = NULL;
+ priv->cfg_scanning = false;
+ }
+
+ return ret;
+}
+
+static int connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ int ret;
+ u32 i;
+ u8 security = WILC_FW_SEC_NO;
+ enum authtype auth_type = WILC_FW_AUTH_ANY;
+ u32 cipher_group;
+ struct cfg80211_bss *bss;
+ void *join_params;
+ u8 ch;
+
+ vif->connecting = true;
+
+ memset(priv->wep_key, 0, sizeof(priv->wep_key));
+ memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
+
+ cipher_group = sme->crypto.cipher_group;
+ if (cipher_group != 0) {
+ if (cipher_group == WLAN_CIPHER_SUITE_WEP40) {
+ security = WILC_FW_SEC_WEP;
+
+ priv->wep_key_len[sme->key_idx] = sme->key_len;
+ memcpy(priv->wep_key[sme->key_idx], sme->key,
+ sme->key_len);
+
+ wilc_set_wep_default_keyid(vif, sme->key_idx);
+ wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
+ sme->key_idx);
+ } else if (cipher_group == WLAN_CIPHER_SUITE_WEP104) {
+ security = WILC_FW_SEC_WEP_EXTENDED;
+
+ priv->wep_key_len[sme->key_idx] = sme->key_len;
+ memcpy(priv->wep_key[sme->key_idx], sme->key,
+ sme->key_len);
+
+ wilc_set_wep_default_keyid(vif, sme->key_idx);
+ wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
+ sme->key_idx);
+ } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
+ if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
+ security = WILC_FW_SEC_WPA2_TKIP;
+ else
+ security = WILC_FW_SEC_WPA2_AES;
+ } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) {
+ if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
+ security = WILC_FW_SEC_WPA_TKIP;
+ else
+ security = WILC_FW_SEC_WPA_AES;
+ } else {
+ ret = -ENOTSUPP;
+ netdev_err(dev, "%s: Unsupported cipher\n",
+ __func__);
+ goto out_error;
+ }
+ }
+
+ if ((sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ||
+ (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
+ for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) {
+ u32 ciphers_pairwise = sme->crypto.ciphers_pairwise[i];
+
+ if (ciphers_pairwise == WLAN_CIPHER_SUITE_TKIP)
+ security |= WILC_FW_TKIP;
+ else
+ security |= WILC_FW_AES;
+ }
+ }
+
+ switch (sme->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ auth_type = WILC_FW_AUTH_OPEN_SYSTEM;
+ break;
+
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ auth_type = WILC_FW_AUTH_SHARED_KEY;
+ break;
+
+ default:
+ break;
+ }
+
+ if (sme->crypto.n_akm_suites) {
+ if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X)
+ auth_type = WILC_FW_AUTH_IEEE8021;
+ }
+
+ if (wfi_drv->usr_scan_req.scan_result) {
+ netdev_err(vif->ndev, "%s: Scan in progress\n", __func__);
+ ret = -EBUSY;
+ goto out_error;
+ }
+
+ bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid,
+ sme->ssid_len, IEEE80211_BSS_TYPE_ANY,
+ IEEE80211_PRIVACY(sme->privacy));
+ if (!bss) {
+ ret = -EINVAL;
+ goto out_error;
+ }
+
+ if (ether_addr_equal_unaligned(vif->bssid, bss->bssid)) {
+ ret = -EALREADY;
+ goto out_put_bss;
+ }
+
+ join_params = wilc_parse_join_bss_param(bss, &sme->crypto);
+ if (!join_params) {
+ netdev_err(dev, "%s: failed to construct join param\n",
+ __func__);
+ ret = -EINVAL;
+ goto out_put_bss;
+ }
+
+ ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
+ vif->wilc->op_ch = ch;
+ if (vif->iftype != WILC_CLIENT_MODE)
+ vif->wilc->sta_ch = ch;
+
+ wilc_wlan_set_bssid(dev, bss->bssid, WILC_STATION_MODE);
+
+ wfi_drv->conn_info.security = security;
+ wfi_drv->conn_info.auth_type = auth_type;
+ wfi_drv->conn_info.ch = ch;
+ wfi_drv->conn_info.conn_result = cfg_connect_result;
+ wfi_drv->conn_info.arg = priv;
+ wfi_drv->conn_info.param = join_params;
+
+ ret = wilc_set_join_req(vif, bss->bssid, sme->ie, sme->ie_len);
+ if (ret) {
+ netdev_err(dev, "wilc_set_join_req(): Error\n");
+ ret = -ENOENT;
+ if (vif->iftype != WILC_CLIENT_MODE)
+ vif->wilc->sta_ch = WILC_INVALID_CHANNEL;
+ wilc_wlan_set_bssid(dev, NULL, WILC_STATION_MODE);
+ wfi_drv->conn_info.conn_result = NULL;
+ kfree(join_params);
+ goto out_put_bss;
+ }
+ kfree(join_params);
+ vif->bss = bss;
+ cfg80211_put_bss(wiphy, bss);
+ return 0;
+
+out_put_bss:
+ cfg80211_put_bss(wiphy, bss);
+
+out_error:
+ vif->connecting = false;
+ return ret;
+}
+
+static int disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+ struct wilc *wilc = vif->wilc;
+ int ret;
+
+ vif->connecting = false;
+
+ if (!wilc)
+ return -EIO;
+
+ if (wilc->close) {
+ /* already disconnected done */
+ cfg80211_disconnected(dev, 0, NULL, 0, true, GFP_KERNEL);
+ return 0;
+ }
+
+ if (vif->iftype != WILC_CLIENT_MODE)
+ wilc->sta_ch = WILC_INVALID_CHANNEL;
+ wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
+
+ priv->p2p.local_random = 0x01;
+ priv->p2p.recv_random = 0x00;
+ priv->p2p.is_wilc_ie = false;
+ priv->hif_drv->p2p_timeout = 0;
+
+ ret = wilc_disconnect(vif);
+ if (ret != 0) {
+ netdev_err(priv->dev, "Error in disconnecting\n");
+ ret = -EINVAL;
+ }
+
+ vif->bss = NULL;
+
+ return ret;
+}
+
+static inline void wilc_wfi_cfg_copy_wep_info(struct wilc_priv *priv,
+ u8 key_index,
+ struct key_params *params)
+{
+ priv->wep_key_len[key_index] = params->key_len;
+ memcpy(priv->wep_key[key_index], params->key, params->key_len);
+}
+
+static int wilc_wfi_cfg_allocate_wpa_entry(struct wilc_priv *priv, u8 idx)
+{
+ if (!priv->wilc_gtk[idx]) {
+ priv->wilc_gtk[idx] = kzalloc(sizeof(*priv->wilc_gtk[idx]),
+ GFP_KERNEL);
+ if (!priv->wilc_gtk[idx])
+ return -ENOMEM;
+ }
+
+ if (!priv->wilc_ptk[idx]) {
+ priv->wilc_ptk[idx] = kzalloc(sizeof(*priv->wilc_ptk[idx]),
+ GFP_KERNEL);
+ if (!priv->wilc_ptk[idx])
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info,
+ struct key_params *params)
+{
+ kfree(key_info->key);
+
+ key_info->key = kmemdup(params->key, params->key_len, GFP_KERNEL);
+ if (!key_info->key)
+ return -ENOMEM;
+
+ kfree(key_info->seq);
+
+ if (params->seq_len > 0) {
+ key_info->seq = kmemdup(params->seq, params->seq_len,
+ GFP_KERNEL);
+ if (!key_info->seq)
+ return -ENOMEM;
+ }
+
+ key_info->cipher = params->cipher;
+ key_info->key_len = params->key_len;
+ key_info->seq_len = params->seq_len;
+
+ return 0;
+}
+
+static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
+ bool pairwise, const u8 *mac_addr, struct key_params *params)
+
+{
+ int ret = 0, keylen = params->key_len;
+ const u8 *rx_mic = NULL;
+ const u8 *tx_mic = NULL;
+ u8 mode = WILC_FW_SEC_NO;
+ u8 op_mode;
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ if (priv->wdev.iftype == NL80211_IFTYPE_AP) {
+ wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
+
+ if (params->cipher == WLAN_CIPHER_SUITE_WEP40)
+ mode = WILC_FW_SEC_WEP;
+ else
+ mode = WILC_FW_SEC_WEP_EXTENDED;
+
+ ret = wilc_add_wep_key_bss_ap(vif, params->key,
+ params->key_len,
+ key_index, mode,
+ WILC_FW_AUTH_OPEN_SYSTEM);
+ break;
+ }
+ if (memcmp(params->key, priv->wep_key[key_index],
+ params->key_len)) {
+ wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
+
+ ret = wilc_add_wep_key_bss_sta(vif, params->key,
+ params->key_len,
+ key_index);
+ }
+
+ break;
+
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
+ priv->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
+ struct wilc_wfi_key *key;
+
+ ret = wilc_wfi_cfg_allocate_wpa_entry(priv, key_index);
+ if (ret)
+ return -ENOMEM;
+
+ if (params->key_len > 16 &&
+ params->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ tx_mic = params->key + 24;
+ rx_mic = params->key + 16;
+ keylen = params->key_len - 16;
+ }
+
+ if (!pairwise) {
+ if (params->cipher == WLAN_CIPHER_SUITE_TKIP)
+ mode = WILC_FW_SEC_WPA_TKIP;
+ else
+ mode = WILC_FW_SEC_WPA2_AES;
+
+ priv->wilc_groupkey = mode;
+
+ key = priv->wilc_gtk[key_index];
+ } else {
+ if (params->cipher == WLAN_CIPHER_SUITE_TKIP)
+ mode = WILC_FW_SEC_WPA_TKIP;
+ else
+ mode = priv->wilc_groupkey | WILC_FW_AES;
+
+ key = priv->wilc_ptk[key_index];
+ }
+ ret = wilc_wfi_cfg_copy_wpa_info(key, params);
+ if (ret)
+ return -ENOMEM;
+
+ op_mode = WILC_AP_MODE;
+ } else {
+ if (params->key_len > 16 &&
+ params->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ rx_mic = params->key + 24;
+ tx_mic = params->key + 16;
+ keylen = params->key_len - 16;
+ }
+
+ op_mode = WILC_STATION_MODE;
+ }
+
+ if (!pairwise)
+ ret = wilc_add_rx_gtk(vif, params->key, keylen,
+ key_index, params->seq_len,
+ params->seq, rx_mic, tx_mic,
+ op_mode, mode);
+ else
+ ret = wilc_add_ptk(vif, params->key, keylen, mac_addr,
+ rx_mic, tx_mic, op_mode, mode,
+ key_index);
+
+ break;
+
+ default:
+ netdev_err(netdev, "%s: Unsupported cipher\n", __func__);
+ ret = -ENOTSUPP;
+ }
+
+ return ret;
+}
+
+static int del_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index,
+ bool pairwise,
+ const u8 *mac_addr)
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+
+ if (priv->wilc_gtk[key_index]) {
+ kfree(priv->wilc_gtk[key_index]->key);
+ priv->wilc_gtk[key_index]->key = NULL;
+ kfree(priv->wilc_gtk[key_index]->seq);
+ priv->wilc_gtk[key_index]->seq = NULL;
+
+ kfree(priv->wilc_gtk[key_index]);
+ priv->wilc_gtk[key_index] = NULL;
+ }
+
+ if (priv->wilc_ptk[key_index]) {
+ kfree(priv->wilc_ptk[key_index]->key);
+ priv->wilc_ptk[key_index]->key = NULL;
+ kfree(priv->wilc_ptk[key_index]->seq);
+ priv->wilc_ptk[key_index]->seq = NULL;
+ kfree(priv->wilc_ptk[key_index]);
+ priv->wilc_ptk[key_index] = NULL;
+ }
+
+ if (key_index <= 3 && priv->wep_key_len[key_index]) {
+ memset(priv->wep_key[key_index], 0,
+ priv->wep_key_len[key_index]);
+ priv->wep_key_len[key_index] = 0;
+ wilc_remove_wep_key(vif, key_index);
+ }
+
+ return 0;
+}
+
+static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
+ bool pairwise, const u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie, struct key_params *))
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+ struct key_params key_params;
+
+ if (!pairwise) {
+ key_params.key = priv->wilc_gtk[key_index]->key;
+ key_params.cipher = priv->wilc_gtk[key_index]->cipher;
+ key_params.key_len = priv->wilc_gtk[key_index]->key_len;
+ key_params.seq = priv->wilc_gtk[key_index]->seq;
+ key_params.seq_len = priv->wilc_gtk[key_index]->seq_len;
+ } else {
+ key_params.key = priv->wilc_ptk[key_index]->key;
+ key_params.cipher = priv->wilc_ptk[key_index]->cipher;
+ key_params.key_len = priv->wilc_ptk[key_index]->key_len;
+ key_params.seq = priv->wilc_ptk[key_index]->seq;
+ key_params.seq_len = priv->wilc_ptk[key_index]->seq_len;
+ }
+
+ callback(cookie, &key_params);
+
+ return 0;
+}
+
+static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, bool unicast, bool multicast)
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+
+ wilc_set_wep_default_keyid(vif, key_index);
+
+ return 0;
+}
+
+static int get_station(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *mac, struct station_info *sinfo)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+ u32 i = 0;
+ u32 associatedsta = ~0;
+ u32 inactive_time = 0;
+
+ if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
+ for (i = 0; i < NUM_STA_ASSOCIATED; i++) {
+ if (!(memcmp(mac,
+ priv->assoc_stainfo.sta_associated_bss[i],
+ ETH_ALEN))) {
+ associatedsta = i;
+ break;
+ }
+ }
+
+ if (associatedsta == ~0) {
+ netdev_err(dev, "sta required is not associated\n");
+ return -ENOENT;
+ }
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME);
+
+ wilc_get_inactive_time(vif, mac, &inactive_time);
+ sinfo->inactive_time = 1000 * inactive_time;
+ } else if (vif->iftype == WILC_STATION_MODE) {
+ struct rf_info stats;
+
+ wilc_get_statistics(vif, &stats);
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL) |
+ BIT_ULL(NL80211_STA_INFO_RX_PACKETS) |
+ BIT_ULL(NL80211_STA_INFO_TX_PACKETS) |
+ BIT_ULL(NL80211_STA_INFO_TX_FAILED) |
+ BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
+
+ sinfo->signal = stats.rssi;
+ sinfo->rx_packets = stats.rx_cnt;
+ sinfo->tx_packets = stats.tx_cnt + stats.tx_fail_cnt;
+ sinfo->tx_failed = stats.tx_fail_cnt;
+ sinfo->txrate.legacy = stats.link_speed * 10;
+
+ if (stats.link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
+ stats.link_speed != DEFAULT_LINK_SPEED)
+ wilc_enable_tcp_ack_filter(vif, true);
+ else if (stats.link_speed != DEFAULT_LINK_SPEED)
+ wilc_enable_tcp_ack_filter(vif, false);
+ }
+ return 0;
+}
+
+static int change_bss(struct wiphy *wiphy, struct net_device *dev,
+ struct bss_parameters *params)
+{
+ return 0;
+}
+
+static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ int ret = -EINVAL;
+ struct cfg_param_attr cfg_param_val;
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ struct wilc_priv *priv;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif))
+ goto out;
+
+ priv = &vif->priv;
+ cfg_param_val.flag = 0;
+
+ if (changed & WIPHY_PARAM_RETRY_SHORT) {
+ netdev_dbg(vif->ndev,
+ "Setting WIPHY_PARAM_RETRY_SHORT %d\n",
+ wiphy->retry_short);
+ cfg_param_val.flag |= WILC_CFG_PARAM_RETRY_SHORT;
+ cfg_param_val.short_retry_limit = wiphy->retry_short;
+ }
+ if (changed & WIPHY_PARAM_RETRY_LONG) {
+ netdev_dbg(vif->ndev,
+ "Setting WIPHY_PARAM_RETRY_LONG %d\n",
+ wiphy->retry_long);
+ cfg_param_val.flag |= WILC_CFG_PARAM_RETRY_LONG;
+ cfg_param_val.long_retry_limit = wiphy->retry_long;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ if (wiphy->frag_threshold > 255 &&
+ wiphy->frag_threshold < 7937) {
+ netdev_dbg(vif->ndev,
+ "Setting WIPHY_PARAM_FRAG_THRESHOLD %d\n",
+ wiphy->frag_threshold);
+ cfg_param_val.flag |= WILC_CFG_PARAM_FRAG_THRESHOLD;
+ cfg_param_val.frag_threshold = wiphy->frag_threshold;
+ } else {
+ netdev_err(vif->ndev,
+ "Fragmentation threshold out of range\n");
+ goto out;
+ }
+ }
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ if (wiphy->rts_threshold > 255) {
+ netdev_dbg(vif->ndev,
+ "Setting WIPHY_PARAM_RTS_THRESHOLD %d\n",
+ wiphy->rts_threshold);
+ cfg_param_val.flag |= WILC_CFG_PARAM_RTS_THRESHOLD;
+ cfg_param_val.rts_threshold = wiphy->rts_threshold;
+ } else {
+ netdev_err(vif->ndev, "RTS threshold out of range\n");
+ goto out;
+ }
+ }
+
+ ret = wilc_hif_set_cfg(vif, &cfg_param_val);
+ if (ret)
+ netdev_err(priv->dev, "Error in setting WIPHY PARAMS\n");
+
+out:
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return ret;
+}
+
+static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+ u32 i;
+ int ret = 0;
+ u8 flag = 0;
+
+ for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
+ if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
+ ETH_ALEN)) {
+ flag = PMKID_FOUND;
+ break;
+ }
+ }
+ if (i < WILC_MAX_NUM_PMKIDS) {
+ memcpy(priv->pmkid_list.pmkidlist[i].bssid, pmksa->bssid,
+ ETH_ALEN);
+ memcpy(priv->pmkid_list.pmkidlist[i].pmkid, pmksa->pmkid,
+ WLAN_PMKID_LEN);
+ if (!(flag == PMKID_FOUND))
+ priv->pmkid_list.numpmkid++;
+ } else {
+ netdev_err(netdev, "Invalid PMKID index\n");
+ ret = -EINVAL;
+ }
+
+ if (!ret)
+ ret = wilc_set_pmkid_info(vif, &priv->pmkid_list);
+
+ return ret;
+}
+
+static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_pmksa *pmksa)
+{
+ u32 i;
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
+
+ for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
+ if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
+ ETH_ALEN)) {
+ memset(&priv->pmkid_list.pmkidlist[i], 0,
+ sizeof(struct wilc_pmkid));
+ break;
+ }
+ }
+
+ if (i < priv->pmkid_list.numpmkid && 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,
+ WLAN_PMKID_LEN);
+ }
+ priv->pmkid_list.numpmkid--;
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
+{
+ struct wilc_vif *vif = netdev_priv(netdev);
+
+ memset(&vif->priv.pmkid_list, 0, sizeof(struct wilc_pmkid_attr));
+
+ return 0;
+}
+
+static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u8 ch_list_attr_idx,
+ u8 op_ch_attr_idx, u8 sta_ch)
+{
+ 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] = sta_ch;
+ break;
+ }
+ }
+ }
+
+ if (op_ch_attr_idx) {
+ buf[op_ch_attr_idx + 6] = 0x51;
+ buf[op_ch_attr_idx + 7] = sta_ch;
+ }
+}
+
+static void wilc_wfi_cfg_parse_rx_action(u8 *buf, u32 len, u8 sta_ch)
+{
+ 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 (sta_ch != WILC_INVALID_CHANNEL)
+ wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
+ op_channel_attr_index, sta_ch);
+}
+
+static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch,
+ u8 iftype, u8 sta_ch)
+{
+ 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 (sta_ch != WILC_INVALID_CHANNEL && oper_ch)
+ wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
+ op_channel_attr_index, sta_ch);
+}
+
+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),
+ vif->wilc->sta_ch);
+ break;
+ }
+ }
+ }
+}
+
+void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
+{
+ struct wilc *wl = vif->wilc;
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ u32 header, pkt_offset;
+ s32 freq;
+ __le16 fc;
+
+ header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
+ 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(wl->op_ch, 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(vif->ndev, "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(vif->ndev,
+ "%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 wilc_p2p_mgmt_data *pv_data = priv;
+
+ kfree(pv_data->buff);
+ kfree(pv_data);
+}
+
+static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
+{
+ struct wilc_vif *vif = data;
+ struct wilc_priv *priv = &vif->priv;
+ struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params;
+
+ if (cookie != params->listen_cookie)
+ return;
+
+ priv->p2p_listen_state = false;
+
+ cfg80211_remain_on_channel_expired(&priv->wdev, params->listen_cookie,
+ params->listen_ch, GFP_KERNEL);
+}
+
+static int remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct ieee80211_channel *chan,
+ unsigned int duration, u64 *cookie)
+{
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+ u64 id;
+
+ if (wdev->iftype == NL80211_IFTYPE_AP) {
+ netdev_dbg(vif->ndev, "Required while in AP mode\n");
+ return ret;
+ }
+
+ id = ++priv->inc_roc_cookie;
+ if (id == 0)
+ id = ++priv->inc_roc_cookie;
+
+ ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value,
+ wilc_wfi_remain_on_channel_expired,
+ (void *)vif);
+ if (ret)
+ return ret;
+
+ vif->wilc->op_ch = chan->hw_value;
+
+ priv->remain_on_ch_params.listen_ch = chan;
+ priv->remain_on_ch_params.listen_cookie = id;
+ *cookie = id;
+ priv->p2p_listen_state = true;
+ priv->remain_on_ch_params.listen_duration = duration;
+
+ cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_KERNEL);
+ mod_timer(&vif->hif_drv->remain_on_ch_timer,
+ jiffies + msecs_to_jiffies(duration + 1000));
+
+ return ret;
+}
+
+static int cancel_remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u64 cookie)
+{
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+
+ if (cookie != priv->remain_on_ch_params.listen_cookie)
+ return -ENOENT;
+
+ return wilc_listen_state_expired(vif, cookie);
+}
+
+static void wilc_wfi_cfg_tx_vendor_spec(struct wilc_priv *priv,
+ struct wilc_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];
+ struct wilc_vif *vif = netdev_priv(priv->dev);
+
+ 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,
+ vif->wilc->sta_ch);
+
+ 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 wilc_p2p_mgmt_data *mgmt_tx;
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+ u32 buf_len = len + sizeof(p2p_vendor_spec) +
+ sizeof(priv->p2p.local_random);
+ int ret = 0;
+
+ *cookie = prandom_u32();
+ priv->tx_cookie = *cookie;
+ mgmt = (const struct ieee80211_mgmt *)buf;
+
+ if (!ieee80211_is_mgmt(mgmt->frame_control))
+ goto out;
+
+ mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_KERNEL);
+ if (!mgmt_tx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mgmt_tx->buff = kmalloc(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);
+ vif->wilc->op_ch = 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);
+ vif->wilc->op_ch = 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_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
+
+ wfi_drv->p2p_timeout = jiffies;
+
+ if (!priv->p2p_listen_state) {
+ struct wilc_wfi_p2p_listen_params *params;
+
+ params = &priv->remain_on_ch_params;
+
+ cfg80211_remain_on_channel_expired(wdev,
+ params->listen_cookie,
+ params->listen_ch,
+ GFP_KERNEL);
+ }
+
+ return 0;
+}
+
+void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
+ u16 frame_type, bool reg)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+
+ if (!frame_type)
+ return;
+
+ switch (frame_type) {
+ case IEEE80211_STYPE_PROBE_REQ:
+ vif->frame_reg[0].type = frame_type;
+ vif->frame_reg[0].reg = reg;
+ break;
+
+ case IEEE80211_STYPE_ACTION:
+ vif->frame_reg[1].type = frame_type;
+ vif->frame_reg[1].reg = reg;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!wl->initialized)
+ return;
+ wilc_frame_register(vif, frame_type, reg);
+}
+
+static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
+ s32 rssi_thold, u32 rssi_hyst)
+{
+ return 0;
+}
+
+static int dump_station(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *mac, struct station_info *sinfo)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ int ret;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
+
+ ret = wilc_get_rssi(vif, &sinfo->signal);
+ if (ret)
+ return ret;
+
+ memcpy(mac, vif->priv.associated_bss, ETH_ALEN);
+ return 0;
+}
+
+static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+
+ if (!priv->hif_drv)
+ return -EIO;
+
+ wilc_set_power_mgmt(vif, enabled, timeout);
+
+ return 0;
+}
+
+static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
+ enum nl80211_iftype type,
+ struct vif_params *params)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+
+ priv->p2p.local_random = 0x01;
+ priv->p2p.recv_random = 0x00;
+ priv->p2p.is_wilc_ie = false;
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ vif->connecting = false;
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev.iftype = type;
+ vif->monitor_flag = 0;
+ if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)
+ wilc_wfi_deinit_mon_interface(wl, true);
+ vif->iftype = WILC_STATION_MODE;
+
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_STATION_MODE, vif->idx);
+
+ memset(priv->assoc_stainfo.sta_associated_bss, 0,
+ WILC_MAX_NUM_STA * ETH_ALEN);
+ break;
+
+ case NL80211_IFTYPE_P2P_CLIENT:
+ vif->connecting = false;
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev.iftype = type;
+ vif->monitor_flag = 0;
+ vif->iftype = WILC_CLIENT_MODE;
+
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_STATION_MODE, vif->idx);
+ break;
+
+ case NL80211_IFTYPE_AP:
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev.iftype = type;
+ vif->iftype = WILC_AP_MODE;
+
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_AP_MODE, vif->idx);
+ break;
+
+ case NL80211_IFTYPE_P2P_GO:
+ dev->ieee80211_ptr->iftype = type;
+ priv->wdev.iftype = type;
+ vif->iftype = WILC_GO_MODE;
+
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_AP_MODE, vif->idx);
+ break;
+
+ default:
+ netdev_err(dev, "Unknown interface type= %d\n", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int start_ap(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ap_settings *settings)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ int ret;
+
+ ret = set_channel(wiphy, &settings->chandef);
+ if (ret != 0)
+ netdev_err(dev, "Error in setting channel\n");
+
+ wilc_wlan_set_bssid(dev, dev->dev_addr, WILC_AP_MODE);
+
+ return wilc_add_beacon(vif, settings->beacon_interval,
+ settings->dtim_period, &settings->beacon);
+}
+
+static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_beacon_data *beacon)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+
+ return wilc_add_beacon(vif, 0, 0, beacon);
+}
+
+static int stop_ap(struct wiphy *wiphy, struct net_device *dev)
+{
+ int ret;
+ struct wilc_vif *vif = netdev_priv(dev);
+
+ wilc_wlan_set_bssid(dev, NULL, WILC_AP_MODE);
+
+ ret = wilc_del_beacon(vif);
+
+ if (ret)
+ netdev_err(dev, "Host delete beacon fail\n");
+
+ return ret;
+}
+
+static int add_station(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *mac, struct station_parameters *params)
+{
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+
+ if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
+ memcpy(priv->assoc_stainfo.sta_associated_bss[params->aid], mac,
+ ETH_ALEN);
+
+ ret = wilc_add_station(vif, mac, params);
+ if (ret)
+ netdev_err(dev, "Host add station fail\n");
+ }
+
+ return ret;
+}
+
+static int del_station(struct wiphy *wiphy, struct net_device *dev,
+ struct station_del_parameters *params)
+{
+ const u8 *mac = params->mac;
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
+ struct sta_info *info;
+
+ if (!(vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE))
+ return ret;
+
+ info = &priv->assoc_stainfo;
+
+ if (!mac)
+ ret = wilc_del_allstation(vif, info->sta_associated_bss);
+
+ ret = wilc_del_station(vif, mac);
+ if (ret)
+ netdev_err(dev, "Host delete station fail\n");
+ return ret;
+}
+
+static int change_station(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *mac, struct station_parameters *params)
+{
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+
+ if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
+ ret = wilc_edit_station(vif, mac, params);
+ if (ret)
+ netdev_err(dev, "Host edit station fail\n");
+ }
+ return ret;
+}
+
+static struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type)
+{
+ struct wilc_vif *vif;
+
+ list_for_each_entry_rcu(vif, &wl->vif_list, list) {
+ if (vif->iftype == type)
+ return vif;
+ }
+
+ return NULL;
+}
+
+static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
+ const char *name,
+ unsigned char name_assign_type,
+ enum nl80211_iftype type,
+ struct vif_params *params)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ struct wireless_dev *wdev;
+ int iftype;
+
+ if (type == NL80211_IFTYPE_MONITOR) {
+ struct net_device *ndev;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_vif_from_type(wl, WILC_AP_MODE);
+ if (!vif) {
+ vif = wilc_get_vif_from_type(wl, WILC_GO_MODE);
+ if (!vif) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ goto validate_interface;
+ }
+ }
+
+ if (vif->monitor_flag) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ goto validate_interface;
+ }
+
+ ndev = wilc_wfi_init_mon_interface(wl, name, vif->ndev);
+ if (ndev) {
+ vif->monitor_flag = 1;
+ } else {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ wdev = &vif->priv.wdev;
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return wdev;
+ }
+
+validate_interface:
+ mutex_lock(&wl->vif_mutex);
+ if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) {
+ pr_err("Reached maximum number of interface\n");
+ mutex_unlock(&wl->vif_mutex);
+ return ERR_PTR(-EINVAL);
+ }
+ mutex_unlock(&wl->vif_mutex);
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ iftype = WILC_STATION_MODE;
+ break;
+ case NL80211_IFTYPE_AP:
+ iftype = WILC_AP_MODE;
+ break;
+ default:
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
+ vif = wilc_netdev_ifc_init(wl, name, iftype, type, true);
+ if (IS_ERR(vif))
+ return ERR_CAST(vif);
+
+ return &vif->priv.wdev;
+}
+
+static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+
+ if (wdev->iftype == NL80211_IFTYPE_AP ||
+ wdev->iftype == NL80211_IFTYPE_P2P_GO)
+ wilc_wfi_deinit_mon_interface(wl, true);
+ vif = netdev_priv(wdev->netdev);
+ cfg80211_stop_iface(wiphy, wdev, GFP_KERNEL);
+ unregister_netdevice(vif->ndev);
+ vif->monitor_flag = 0;
+
+ wilc_set_operation_mode(vif, 0, 0, 0);
+ mutex_lock(&wl->vif_mutex);
+ list_del_rcu(&vif->list);
+ wl->vif_num--;
+ mutex_unlock(&wl->vif_mutex);
+ synchronize_srcu(&wl->srcu);
+ return 0;
+}
+
+static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+
+ if (!wow && wilc_wlan_get_num_conn_ifcs(wl))
+ wl->suspend_event = true;
+ else
+ wl->suspend_event = false;
+
+ return 0;
+}
+
+static int wilc_resume(struct wiphy *wiphy)
+{
+ return 0;
+}
+
+static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled)
+{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif)) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return;
+ }
+
+ netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled);
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+}
+
+static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, int mbm)
+{
+ int ret;
+ int srcu_idx;
+ s32 tx_power = MBM_TO_DBM(mbm);
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+
+ if (!wl->initialized)
+ return -EIO;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif)) {
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return -EINVAL;
+ }
+
+ netdev_info(vif->ndev, "Setting tx power %d\n", tx_power);
+ if (tx_power < 0)
+ tx_power = 0;
+ else if (tx_power > 18)
+ tx_power = 18;
+ ret = wilc_set_tx_power(vif, tx_power);
+ if (ret)
+ netdev_err(vif->ndev, "Failed to set tx power\n");
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+
+ return ret;
+}
+
+static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ int *dbm)
+{
+ int ret;
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc *wl = vif->wilc;
+
+ /* If firmware is not started, return. */
+ if (!wl->initialized)
+ return -EIO;
+
+ ret = wilc_get_tx_power(vif, (u8 *)dbm);
+ if (ret)
+ netdev_err(vif->ndev, "Failed to get tx power\n");
+
+ return ret;
+}
+
+static const struct cfg80211_ops wilc_cfg80211_ops = {
+ .set_monitor_channel = set_channel,
+ .scan = scan,
+ .connect = connect,
+ .disconnect = disconnect,
+ .add_key = add_key,
+ .del_key = del_key,
+ .get_key = get_key,
+ .set_default_key = set_default_key,
+ .add_virtual_intf = add_virtual_intf,
+ .del_virtual_intf = del_virtual_intf,
+ .change_virtual_intf = change_virtual_intf,
+
+ .start_ap = start_ap,
+ .change_beacon = change_beacon,
+ .stop_ap = stop_ap,
+ .add_station = add_station,
+ .del_station = del_station,
+ .change_station = change_station,
+ .get_station = get_station,
+ .dump_station = dump_station,
+ .change_bss = change_bss,
+ .set_wiphy_params = set_wiphy_params,
+
+ .set_pmksa = set_pmksa,
+ .del_pmksa = del_pmksa,
+ .flush_pmksa = flush_pmksa,
+ .remain_on_channel = remain_on_channel,
+ .cancel_remain_on_channel = cancel_remain_on_channel,
+ .mgmt_tx_cancel_wait = mgmt_tx_cancel_wait,
+ .mgmt_tx = mgmt_tx,
+ .mgmt_frame_register = wilc_mgmt_frame_register,
+ .set_power_mgmt = set_power_mgmt,
+ .set_cqm_rssi_config = set_cqm_rssi_config,
+
+ .suspend = wilc_suspend,
+ .resume = wilc_resume,
+ .set_wakeup = wilc_set_wakeup,
+ .set_tx_power = set_tx_power,
+ .get_tx_power = get_tx_power,
+
+};
+
+static void wlan_init_locks(struct wilc *wl)
+{
+ mutex_init(&wl->hif_cs);
+ mutex_init(&wl->rxq_cs);
+ mutex_init(&wl->cfg_cmd_lock);
+ mutex_init(&wl->vif_mutex);
+
+ spin_lock_init(&wl->txq_spinlock);
+ mutex_init(&wl->txq_add_to_head_cs);
+
+ init_completion(&wl->txq_event);
+ init_completion(&wl->cfg_event);
+ init_completion(&wl->sync_event);
+ init_completion(&wl->txq_thread_started);
+ init_srcu_struct(&wl->srcu);
+}
+
+void wlan_deinit_locks(struct wilc *wilc)
+{
+ mutex_destroy(&wilc->hif_cs);
+ mutex_destroy(&wilc->rxq_cs);
+ mutex_destroy(&wilc->cfg_cmd_lock);
+ mutex_destroy(&wilc->txq_add_to_head_cs);
+ mutex_destroy(&wilc->vif_mutex);
+ cleanup_srcu_struct(&wilc->srcu);
+}
+
+int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
+ const struct wilc_hif_func *ops)
+{
+ struct wilc *wl;
+ struct wilc_vif *vif;
+ int ret;
+
+ wl = wilc_create_wiphy(dev);
+ if (!wl)
+ return -EINVAL;
+
+ wlan_init_locks(wl);
+
+ ret = wilc_wlan_cfg_init(wl);
+ if (ret)
+ goto free_wl;
+
+ *wilc = wl;
+ wl->io_type = io_type;
+ wl->hif_func = ops;
+ wl->chip_ps_state = WILC_CHIP_WAKEDUP;
+ INIT_LIST_HEAD(&wl->txq_head.list);
+ INIT_LIST_HEAD(&wl->rxq_head.list);
+ INIT_LIST_HEAD(&wl->vif_list);
+
+ wl->hif_workqueue = create_singlethread_workqueue("WILC_wq");
+ if (!wl->hif_workqueue) {
+ ret = -ENOMEM;
+ goto free_cfg;
+ }
+ vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE,
+ NL80211_IFTYPE_STATION, false);
+ if (IS_ERR(vif)) {
+ ret = PTR_ERR(vif);
+ goto free_hq;
+ }
+
+ return 0;
+
+free_hq:
+ destroy_workqueue(wl->hif_workqueue);
+
+free_cfg:
+ wilc_wlan_cfg_deinit(wl);
+
+free_wl:
+ wlan_deinit_locks(wl);
+ wiphy_unregister(wl->wiphy);
+ wiphy_free(wl->wiphy);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
+
+struct wilc *wilc_create_wiphy(struct device *dev)
+{
+ struct wiphy *wiphy;
+ struct wilc *wl;
+ int ret;
+
+ wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl));
+ if (!wiphy)
+ return NULL;
+
+ wl = wiphy_priv(wiphy);
+
+ memcpy(wl->bitrates, wilc_bitrates, sizeof(wilc_bitrates));
+ memcpy(wl->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels));
+ wl->band.bitrates = wl->bitrates;
+ wl->band.n_bitrates = ARRAY_SIZE(wl->bitrates);
+ wl->band.channels = wl->channels;
+ wl->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels);
+
+ wl->band.ht_cap.ht_supported = 1;
+ wl->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+ wl->band.ht_cap.mcs.rx_mask[0] = 0xff;
+ wl->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
+ wl->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
+
+ wiphy->bands[NL80211_BAND_2GHZ] = &wl->band;
+
+ wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID;
+#ifdef CONFIG_PM
+ wiphy->wowlan = &wowlan_support;
+#endif
+ wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
+ wiphy->max_scan_ie_len = 1000;
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ memcpy(wl->cipher_suites, wilc_cipher_suites,
+ sizeof(wilc_cipher_suites));
+ wiphy->cipher_suites = wl->cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites);
+ wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
+
+ wiphy->max_remain_on_channel_duration = 500;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MONITOR) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT);
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
+ set_wiphy_dev(wiphy, dev);
+ wl->wiphy = wiphy;
+ ret = wiphy_register(wiphy);
+ if (ret) {
+ wiphy_free(wiphy);
+ return NULL;
+ }
+ return wl;
+}
+
+int wilc_init_host_int(struct net_device *net)
+{
+ int ret;
+ struct wilc_vif *vif = netdev_priv(net);
+ struct wilc_priv *priv = &vif->priv;
+
+ priv->p2p_listen_state = false;
+
+ mutex_init(&priv->scan_req_lock);
+ ret = wilc_init(net, &priv->hif_drv);
+ if (ret)
+ netdev_err(net, "Error while initializing hostinterface\n");
+
+ return ret;
+}
+
+void wilc_deinit_host_int(struct net_device *net)
+{
+ int ret;
+ struct wilc_vif *vif = netdev_priv(net);
+ struct wilc_priv *priv = &vif->priv;
+
+ priv->p2p_listen_state = false;
+
+ flush_workqueue(vif->wilc->hif_workqueue);
+ mutex_destroy(&priv->scan_req_lock);
+ ret = wilc_deinit(vif);
+
+ if (ret)
+ netdev_err(net, "Error while deinitializing host interface\n");
+}
+
--- /dev/null
+/* 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 "netdev.h"
+
+struct wiphy *wilc_cfg_alloc(void);
+int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
+ const struct wilc_hif_func *ops);
+struct wilc *wilc_create_wiphy(struct device *dev);
+void wilc_deinit_host_int(struct net_device *net);
+int wilc_init_host_int(struct net_device *net);
+void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size);
+struct wilc_vif *wilc_netdev_interface(struct wilc *wl, const char *name,
+ enum nl80211_iftype type);
+void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked);
+struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
+ 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);
+struct wilc_vif *wilc_get_interface(struct wilc *wl);
+struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl);
+void wlan_deinit_locks(struct wilc *wilc);
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "netdev.h"
+
+#define WILC_HIF_SCAN_TIMEOUT_MS 5000
+#define WILC_HIF_CONNECT_TIMEOUT_MS 9500
+
+#define WILC_FALSE_FRMWR_CHANNEL 100
+#define WILC_MAX_RATES_SUPPORTED 12
+
+struct wilc_rcvd_mac_info {
+ u8 status;
+};
+
+struct wilc_set_multicast {
+ u32 enabled;
+ u32 cnt;
+ u8 *mc_list;
+};
+
+struct wilc_del_all_sta {
+ u8 assoc_sta;
+ u8 mac[WILC_MAX_NUM_STA][ETH_ALEN];
+};
+
+struct wilc_op_mode {
+ __le32 mode;
+};
+
+struct wilc_reg_frame {
+ u8 reg;
+ u8 reg_id;
+ __le16 frame_type;
+} __packed;
+
+struct wilc_drv_handler {
+ __le32 handler;
+ u8 mode;
+} __packed;
+
+struct wilc_wep_key {
+ u8 index;
+ u8 key_len;
+ u8 key[0];
+} __packed;
+
+struct wilc_sta_wpa_ptk {
+ u8 mac_addr[ETH_ALEN];
+ u8 key_len;
+ u8 key[0];
+} __packed;
+
+struct wilc_ap_wpa_ptk {
+ u8 mac_addr[ETH_ALEN];
+ u8 index;
+ u8 key_len;
+ u8 key[0];
+} __packed;
+
+struct wilc_gtk_key {
+ u8 mac_addr[ETH_ALEN];
+ u8 rsc[8];
+ u8 index;
+ u8 key_len;
+ u8 key[0];
+} __packed;
+
+union wilc_message_body {
+ struct wilc_rcvd_net_info net_info;
+ struct wilc_rcvd_mac_info mac_info;
+ struct wilc_set_multicast mc_info;
+ struct wilc_remain_ch remain_on_ch;
+ char *data;
+};
+
+struct host_if_msg {
+ union wilc_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 wilc_noa_opp_enable {
+ u8 ct_window;
+ u8 cnt;
+ __le32 duration;
+ __le32 interval;
+ __le32 start_time;
+} __packed;
+
+struct wilc_noa_opp_disable {
+ u8 cnt;
+ __le32 duration;
+ __le32 interval;
+ __le32 start_time;
+} __packed;
+
+struct wilc_join_bss_param {
+ char ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid_terminator;
+ u8 bss_type;
+ u8 ch;
+ __le16 cap_info;
+ u8 sa[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ __le16 beacon_period;
+ u8 dtim_period;
+ u8 supp_rates[WILC_MAX_RATES_SUPPORTED + 1];
+ u8 wmm_cap;
+ u8 uapsd_cap;
+ u8 ht_capable;
+ u8 rsn_found;
+ u8 rsn_grp_policy;
+ u8 mode_802_11i;
+ u8 p_suites[3];
+ u8 akm_suites[3];
+ u8 rsn_cap[2];
+ u8 noa_enabled;
+ __le32 tsf_lo;
+ u8 idx;
+ u8 opp_enabled;
+ union {
+ struct wilc_noa_opp_disable opp_dis;
+ struct wilc_noa_opp_enable opp_en;
+ };
+} __packed;
+
+/* '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;
+ struct wilc_vif *vif;
+
+ if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC)
+ return NULL;
+
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ if (vif->idx == index)
+ return vif;
+ }
+
+ return NULL;
+}
+
+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 wilc_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, WILC_SET_CFG, &wid, 1);
+ 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);
+ scan_req->scan_result = NULL;
+ }
+
+ return result;
+}
+
+int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
+ u8 *ch_freq_list, u8 ch_list_len,
+ void (*scan_result_fn)(enum scan_event,
+ struct wilc_rcvd_net_info *, void *),
+ void *user_arg, struct cfg80211_scan_request *request)
+{
+ int result = 0;
+ struct wid wid_list[5];
+ u32 index = 0;
+ u32 i, scan_timeout;
+ u8 *buffer;
+ u8 valuesize = 0;
+ u8 *search_ssid_vals = NULL;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ 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->connecting) {
+ netdev_err(vif->ndev, "Don't do obss scan\n");
+ result = -EBUSY;
+ goto error;
+ }
+
+ hif_drv->usr_scan_req.ch_cnt = 0;
+
+ if (request->n_ssids) {
+ for (i = 0; i < request->n_ssids; i++)
+ valuesize += ((request->ssids[i].ssid_len) + 1);
+ search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL);
+ if (search_ssid_vals) {
+ wid_list[index].id = WID_SSID_PROBE_REQ;
+ wid_list[index].type = WID_STR;
+ wid_list[index].val = search_ssid_vals;
+ buffer = wid_list[index].val;
+
+ *buffer++ = request->n_ssids;
+
+ for (i = 0; i < request->n_ssids; i++) {
+ *buffer++ = request->ssids[i].ssid_len;
+ memcpy(buffer, request->ssids[i].ssid,
+ request->ssids[i].ssid_len);
+ buffer += request->ssids[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 = (s8 *)request->ie;
+ wid_list[index].size = request->ie_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_type;
+ index++;
+
+ if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) {
+ wid_list[index].id = WID_PASSIVE_SCAN_TIME;
+ wid_list[index].type = WID_SHORT;
+ wid_list[index].size = sizeof(u16);
+ wid_list[index].val = (s8 *)&request->duration;
+ index++;
+
+ scan_timeout = (request->duration * ch_list_len) + 500;
+ } else {
+ scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS;
+ }
+
+ wid_list[index].id = WID_SCAN_CHANNEL_LIST;
+ wid_list[index].type = WID_BIN_DATA;
+
+ if (ch_freq_list && ch_list_len > 0) {
+ for (i = 0; i < ch_list_len; i++) {
+ if (ch_freq_list[i] > 0)
+ ch_freq_list[i] -= 1;
+ }
+ }
+
+ wid_list[index].val = ch_freq_list;
+ wid_list[index].size = 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_source;
+ index++;
+
+ hif_drv->usr_scan_req.scan_result = scan_result_fn;
+ hif_drv->usr_scan_req.arg = user_arg;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index);
+ if (result) {
+ netdev_err(vif->ndev, "Failed to send scan parameters\n");
+ goto error;
+ }
+
+ hif_drv->scan_timer_vif = vif;
+ mod_timer(&hif_drv->scan_timer,
+ jiffies + msecs_to_jiffies(scan_timeout));
+
+error:
+
+ kfree(search_ssid_vals);
+
+ return result;
+}
+
+static int wilc_send_connect_wid(struct wilc_vif *vif)
+{
+ int result = 0;
+ struct wid wid_list[4];
+ u32 wid_cnt = 0;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_conn_info *conn_attr = &hif_drv->conn_info;
+ struct wilc_join_bss_param *bss_param = conn_attr->param;
+
+ wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
+ wid_list[wid_cnt].type = WID_BIN_DATA;
+ wid_list[wid_cnt].val = conn_attr->req_ies;
+ wid_list[wid_cnt].size = conn_attr->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 *)&conn_attr->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 *)&conn_attr->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 = sizeof(*bss_param);
+ wid_list[wid_cnt].val = (u8 *)bss_param;
+ wid_cnt++;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt);
+ if (result) {
+ netdev_err(vif->ndev, "failed to send config packet\n");
+ goto error;
+ } else {
+ hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
+ }
+
+ return 0;
+
+error:
+
+ kfree(conn_attr->req_ies);
+ conn_attr->req_ies = NULL;
+
+ return result;
+}
+
+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 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;
+
+ if (hif_drv->conn_info.conn_result) {
+ hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
+ WILC_MAC_STATUS_DISCONNECTED,
+ hif_drv->conn_info.arg);
+
+ } 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, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send disconnect\n");
+
+ hif_drv->conn_info.req_ies_len = 0;
+ kfree(hif_drv->conn_info.req_ies);
+ hif_drv->conn_info.req_ies = NULL;
+
+out:
+ kfree(msg);
+}
+
+void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
+ struct cfg80211_crypto_settings *crypto)
+{
+ struct wilc_join_bss_param *param;
+ struct ieee80211_p2p_noa_attr noa_attr;
+ u8 rates_len = 0;
+ const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie;
+ const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie;
+ int ret;
+ const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies);
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param)
+ return NULL;
+
+ param->beacon_period = cpu_to_le16(bss->beacon_interval);
+ param->cap_info = cpu_to_le16(bss->capability);
+ param->bss_type = WILC_FW_BSS_TYPE_INFRA;
+ param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
+ ether_addr_copy(param->bssid, bss->bssid);
+
+ ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
+ if (ssid_elm) {
+ if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN)
+ memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]);
+ }
+
+ tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
+ if (tim_elm && tim_elm[1] >= 2)
+ param->dtim_period = tim_elm[3];
+
+ memset(param->p_suites, 0xFF, 3);
+ memset(param->akm_suites, 0xFF, 3);
+
+ rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len);
+ if (rates_ie) {
+ rates_len = rates_ie[1];
+ if (rates_len > WILC_MAX_RATES_SUPPORTED)
+ rates_len = WILC_MAX_RATES_SUPPORTED;
+ param->supp_rates[0] = rates_len;
+ memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len);
+ }
+
+ supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data,
+ ies->len);
+ if (supp_rates_ie) {
+ if (supp_rates_ie[1] > (WILC_MAX_RATES_SUPPORTED - rates_len))
+ param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED;
+ else
+ param->supp_rates[0] += supp_rates_ie[1];
+
+ memcpy(¶m->supp_rates[rates_len + 1], supp_rates_ie + 2,
+ (param->supp_rates[0] - rates_len));
+ }
+
+ ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len);
+ if (ht_ie)
+ param->ht_capable = true;
+
+ ret = cfg80211_get_p2p_attr(ies->data, ies->len,
+ IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
+ (u8 *)&noa_attr, sizeof(noa_attr));
+ if (ret > 0) {
+ param->tsf_lo = cpu_to_le32(ies->tsf);
+ param->noa_enabled = 1;
+ param->idx = noa_attr.index;
+ if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) {
+ param->opp_enabled = 1;
+ param->opp_en.ct_window = noa_attr.oppps_ctwindow;
+ param->opp_en.cnt = noa_attr.desc[0].count;
+ param->opp_en.duration = noa_attr.desc[0].duration;
+ param->opp_en.interval = noa_attr.desc[0].interval;
+ param->opp_en.start_time = noa_attr.desc[0].start_time;
+ } else {
+ param->opp_enabled = 0;
+ param->opp_dis.cnt = noa_attr.desc[0].count;
+ param->opp_dis.duration = noa_attr.desc[0].duration;
+ param->opp_dis.interval = noa_attr.desc[0].interval;
+ param->opp_dis.start_time = noa_attr.desc[0].start_time;
+ }
+ }
+ wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+ WLAN_OUI_TYPE_MICROSOFT_WMM,
+ ies->data, ies->len);
+ if (wmm_ie) {
+ struct ieee80211_wmm_param_ie *ie;
+
+ ie = (struct ieee80211_wmm_param_ie *)wmm_ie;
+ if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) &&
+ ie->version == 1) {
+ param->wmm_cap = true;
+ if (ie->qos_info & BIT(7))
+ param->uapsd_cap = true;
+ }
+ }
+
+ wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+ WLAN_OUI_TYPE_MICROSOFT_WPA,
+ ies->data, ies->len);
+ if (wpa_ie) {
+ param->mode_802_11i = 1;
+ param->rsn_found = true;
+ }
+
+ rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len);
+ if (rsn_ie) {
+ int offset = 8;
+
+ param->mode_802_11i = 2;
+ param->rsn_found = true;
+ //extract RSN capabilities
+ offset += (rsn_ie[offset] * 4) + 2;
+ offset += (rsn_ie[offset] * 4) + 2;
+ memcpy(param->rsn_cap, &rsn_ie[offset], 2);
+ }
+
+ if (param->rsn_found) {
+ int i;
+
+ param->rsn_grp_policy = crypto->cipher_group & 0xFF;
+ for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++)
+ param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF;
+
+ for (i = 0; i < crypto->n_akm_suites && i < 3; i++)
+ param->akm_suites[i] = crypto->akm_suites[i] & 0xFF;
+ }
+
+ 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_rcvd_net_info *rcvd_info = &msg->body.net_info;
+ struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req;
+ const u8 *ch_elm;
+ u8 *ies;
+ int ies_len;
+ size_t offset;
+
+ if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control))
+ offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control))
+ offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ else
+ goto done;
+
+ ies = rcvd_info->mgmt->u.beacon.variable;
+ ies_len = rcvd_info->frame_len - offset;
+ if (ies_len <= 0)
+ goto done;
+
+ ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len);
+ if (ch_elm && ch_elm[1] > 0)
+ rcvd_info->ch = ch_elm[2];
+
+ if (scan_req->scan_result)
+ scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info,
+ scan_req->arg);
+
+done:
+ kfree(rcvd_info->mgmt);
+ 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, WILC_GET_CFG, &wid, 1);
+ 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 s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
+ struct wilc_conn_info *ret_conn_info)
+{
+ u8 *ies;
+ u16 ies_len;
+ struct assoc_resp *res = (struct assoc_resp *)buffer;
+
+ ret_conn_info->status = le16_to_cpu(res->status_code);
+ if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {
+ ies = &buffer[sizeof(*res)];
+ ies_len = buffer_len - sizeof(*res);
+
+ 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;
+}
+
+static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
+ u8 mac_status)
+{
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_conn_info *conn_info = &hif_drv->conn_info;
+
+ if (mac_status == WILC_MAC_STATUS_CONNECTED) {
+ u32 assoc_resp_info_len;
+
+ memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE);
+
+ host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,
+ WILC_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);
+ }
+ }
+
+ del_timer(&hif_drv->connect_timer);
+ conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,
+ hif_drv->conn_info.arg);
+
+ if (mac_status == WILC_MAC_STATUS_CONNECTED &&
+ conn_info->status == WLAN_STATUS_SUCCESS) {
+ ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid);
+ hif_drv->hif_state = HOST_IF_CONNECTED;
+ } else {
+ hif_drv->hif_state = HOST_IF_IDLE;
+ }
+
+ kfree(conn_info->resp_ies);
+ conn_info->resp_ies = NULL;
+ conn_info->resp_ies_len = 0;
+
+ kfree(conn_info->req_ies);
+ conn_info->req_ies = NULL;
+ conn_info->req_ies_len = 0;
+}
+
+static inline void host_int_handle_disconnect(struct wilc_vif *vif)
+{
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (hif_drv->usr_scan_req.scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
+ }
+
+ if (hif_drv->conn_info.conn_result)
+ hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
+ 0, hif_drv->conn_info.arg);
+ else
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+
+ eth_zero_addr(hif_drv->assoc_bssid);
+
+ hif_drv->conn_info.req_ies_len = 0;
+ kfree(hif_drv->conn_info.req_ies);
+ hif_drv->conn_info.req_ies = NULL;
+ 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 wilc_rcvd_mac_info *mac_info = &msg->body.mac_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
+ goto free_msg;
+ }
+
+ if (!hif_drv->conn_info.conn_result) {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ goto free_msg;
+ }
+
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
+ host_int_parse_assoc_resp_info(vif, mac_info->status);
+ } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) {
+ if (hif_drv->hif_state == HOST_IF_CONNECTED) {
+ host_int_handle_disconnect(vif);
+ } else if (hif_drv->usr_scan_req.scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
+ }
+ }
+
+free_msg:
+ kfree(msg);
+}
+
+int wilc_disconnect(struct wilc_vif *vif)
+{
+ struct wid wid;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_user_scan_req *scan_req;
+ struct wilc_conn_info *conn_info;
+ 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);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result) {
+ netdev_err(vif->ndev, "Failed to send disconnect\n");
+ return result;
+ }
+
+ scan_req = &hif_drv->usr_scan_req;
+ conn_info = &hif_drv->conn_info;
+
+ if (scan_req->scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg);
+ scan_req->scan_result = NULL;
+ }
+
+ if (conn_info->conn_result) {
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
+ del_timer(&hif_drv->connect_timer);
+
+ conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,
+ conn_info->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_info->req_ies_len = 0;
+ kfree(conn_info->req_ies);
+ conn_info->req_ies = NULL;
+
+ return 0;
+}
+
+int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)
+{
+ struct wid wid_list[5];
+ u32 wid_cnt = 0, result;
+
+ 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, WILC_GET_CFG, wid_list, wid_cnt);
+ if (result) {
+ netdev_err(vif->ndev, "Failed to send scan parameters\n");
+ return result;
+ }
+
+ 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 result;
+}
+
+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 rf_info *stats = (struct rf_info *)msg->body.data;
+
+ wilc_get_statistics(vif, stats);
+
+ kfree(msg);
+}
+
+static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,
+ struct station_parameters *params)
+{
+ ether_addr_copy(cur_byte, mac);
+ cur_byte += ETH_ALEN;
+
+ put_unaligned_le16(params->aid, cur_byte);
+ cur_byte += 2;
+
+ *cur_byte++ = params->supported_rates_len;
+ if (params->supported_rates_len > 0)
+ memcpy(cur_byte, params->supported_rates,
+ params->supported_rates_len);
+ cur_byte += params->supported_rates_len;
+
+ if (params->ht_capa) {
+ *cur_byte++ = true;
+ memcpy(cur_byte, ¶ms->ht_capa,
+ sizeof(struct ieee80211_ht_cap));
+ } else {
+ *cur_byte++ = false;
+ }
+ cur_byte += sizeof(struct ieee80211_ht_cap);
+
+ put_unaligned_le16(params->sta_flags_mask, cur_byte);
+ cur_byte += 2;
+ put_unaligned_le16(params->sta_flags_set, cur_byte);
+}
+
+static int handle_remain_on_chan(struct wilc_vif *vif,
+ struct wilc_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->usr_scan_req.scan_result)
+ return -EBUSY;
+
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
+ return -EBUSY;
+
+ if (vif->connecting)
+ return -EBUSY;
+
+ 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)
+ return -ENOMEM;
+
+ wid.val[0] = remain_on_chan_flag;
+ wid.val[1] = (s8)hif_remain_ch->ch;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ kfree(wid.val);
+ if (result)
+ return -EBUSY;
+
+ 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.ch = hif_remain_ch->ch;
+ hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie;
+ hif_drv->remain_on_ch_timer_vif = vif;
+
+ return 0;
+}
+
+static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)
+{
+ 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)
+ return -ENOMEM;
+
+ wid.val[0] = remain_on_chan_flag;
+ wid.val[1] = WILC_FALSE_FRMWR_CHANNEL;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ kfree(wid.val);
+ if (result != 0) {
+ netdev_err(vif->ndev, "Failed to set remain channel\n");
+ return -EINVAL;
+ }
+
+ if (hif_drv->remain_on_ch.expired) {
+ hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
+ cookie);
+ }
+ } else {
+ netdev_dbg(vif->ndev, "Not in listen state\n");
+ }
+
+ return 0;
+}
+
+static void wilc_handle_listen_state_expired(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+
+ wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie);
+ 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, wilc_handle_listen_state_expired, false);
+ if (IS_ERR(msg))
+ return;
+
+ msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie;
+
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ 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 wilc_set_multicast *set_mc = &msg->body.mc_info;
+ int result;
+ struct wid wid;
+ u8 *cur_byte;
+
+ wid.id = WID_SETUP_MULTICAST_FILTER;
+ wid.type = WID_BIN;
+ wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN);
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ goto error;
+
+ cur_byte = wid.val;
+ put_unaligned_le32(set_mc->enabled, cur_byte);
+ cur_byte += 4;
+
+ put_unaligned_le32(set_mc->cnt, cur_byte);
+ cur_byte += 4;
+
+ if (set_mc->cnt > 0 && set_mc->mc_list)
+ memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send setup multicast\n");
+
+error:
+ kfree(set_mc->mc_list);
+ kfree(wid.val);
+ kfree(msg);
+}
+
+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_scan_complete(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+
+ del_timer(&msg->vif->hif_drv->scan_timer);
+
+ handle_scan_done(msg->vif, SCAN_EVENT_DONE);
+
+ 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)
+{
+ struct wid wid;
+ int result;
+
+ wid.id = WID_REMOVE_WEP_KEY;
+ wid.type = WID_STR;
+ wid.size = sizeof(char);
+ wid.val = &index;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev,
+ "Failed to send remove wep key config packet\n");
+ return result;
+}
+
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
+{
+ struct wid wid;
+ int result;
+
+ wid.id = WID_KEY_ID;
+ wid.type = WID_CHAR;
+ wid.size = sizeof(char);
+ wid.val = &index;
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev,
+ "Failed to send wep default key config packet\n");
+
+ return result;
+}
+
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index)
+{
+ struct wid wid;
+ int result;
+ struct wilc_wep_key *wep_key;
+
+ wid.id = WID_ADD_WEP_KEY;
+ wid.type = WID_STR;
+ wid.size = sizeof(*wep_key) + len;
+ wep_key = kzalloc(wid.size, GFP_KERNEL);
+ if (!wep_key)
+ return -ENOMEM;
+
+ wid.val = (u8 *)wep_key;
+
+ wep_key->index = index;
+ wep_key->key_len = len;
+ memcpy(wep_key->key, key, len);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev,
+ "Failed to add wep key config packet\n");
+
+ kfree(wep_key);
+ 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)
+{
+ struct wid wid_list[3];
+ int result;
+ struct wilc_wep_key *wep_key;
+
+ wid_list[0].id = WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = &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 *)&auth_type;
+
+ wid_list[2].id = WID_WEP_KEY_VALUE;
+ wid_list[2].type = WID_STR;
+ wid_list[2].size = sizeof(*wep_key) + len;
+ wep_key = kzalloc(wid_list[2].size, GFP_KERNEL);
+ if (!wep_key)
+ return -ENOMEM;
+
+ wid_list[2].val = (u8 *)wep_key;
+
+ wep_key->index = index;
+ wep_key->key_len = len;
+ memcpy(wep_key->key, key, len);
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
+ ARRAY_SIZE(wid_list));
+ if (result)
+ netdev_err(vif->ndev,
+ "Failed to add wep ap key config packet\n");
+
+ kfree(wep_key);
+ 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 = 0;
+ u8 t_key_len = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
+
+ if (mode == WILC_AP_MODE) {
+ struct wid wid_list[2];
+ struct wilc_ap_wpa_ptk *key_buf;
+
+ wid_list[0].id = WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&cipher_mode;
+
+ key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+ if (!key_buf)
+ return -ENOMEM;
+
+ ether_addr_copy(key_buf->mac_addr, mac_addr);
+ key_buf->index = index;
+ key_buf->key_len = t_key_len;
+ memcpy(&key_buf->key[0], ptk, ptk_key_len);
+
+ if (rx_mic)
+ memcpy(&key_buf->key[ptk_key_len], rx_mic,
+ WILC_RX_MIC_KEY_LEN);
+
+ if (tx_mic)
+ memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
+ tx_mic, WILC_TX_MIC_KEY_LEN);
+
+ wid_list[1].id = WID_ADD_PTK;
+ wid_list[1].type = WID_STR;
+ wid_list[1].size = sizeof(*key_buf) + t_key_len;
+ wid_list[1].val = (u8 *)key_buf;
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
+ ARRAY_SIZE(wid_list));
+ kfree(key_buf);
+ } else if (mode == WILC_STATION_MODE) {
+ struct wid wid;
+ struct wilc_sta_wpa_ptk *key_buf;
+
+ key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+ if (!key_buf)
+ return -ENOMEM;
+
+ ether_addr_copy(key_buf->mac_addr, mac_addr);
+ key_buf->key_len = t_key_len;
+ memcpy(&key_buf->key[0], ptk, ptk_key_len);
+
+ if (rx_mic)
+ memcpy(&key_buf->key[ptk_key_len], rx_mic,
+ WILC_RX_MIC_KEY_LEN);
+
+ if (tx_mic)
+ memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
+ tx_mic, WILC_TX_MIC_KEY_LEN);
+
+ wid.id = WID_ADD_PTK;
+ wid.type = WID_STR;
+ wid.size = sizeof(*key_buf) + t_key_len;
+ wid.val = (s8 *)key_buf;
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ kfree(key_buf);
+ }
+
+ 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 = 0;
+ struct wilc_gtk_key *gtk_key;
+ int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
+
+ gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL);
+ if (!gtk_key)
+ return -ENOMEM;
+
+ /* fill bssid value only in station mode */
+ if (mode == WILC_STATION_MODE &&
+ vif->hif_drv->hif_state == HOST_IF_CONNECTED)
+ memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN);
+
+ if (key_rsc)
+ memcpy(gtk_key->rsc, key_rsc, 8);
+ gtk_key->index = index;
+ gtk_key->key_len = t_key_len;
+ memcpy(>k_key->key[0], rx_gtk, gtk_key_len);
+
+ if (rx_mic)
+ memcpy(>k_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN);
+
+ if (tx_mic)
+ memcpy(>k_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN],
+ tx_mic, WILC_TX_MIC_KEY_LEN);
+
+ if (mode == WILC_AP_MODE) {
+ struct wid wid_list[2];
+
+ wid_list[0].id = WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&cipher_mode;
+
+ wid_list[1].id = WID_ADD_RX_GTK;
+ wid_list[1].type = WID_STR;
+ wid_list[1].size = sizeof(*gtk_key) + t_key_len;
+ wid_list[1].val = (u8 *)gtk_key;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
+ ARRAY_SIZE(wid_list));
+ } else if (mode == WILC_STATION_MODE) {
+ struct wid wid;
+
+ wid.id = WID_ADD_RX_GTK;
+ wid.type = WID_STR;
+ wid.size = sizeof(*gtk_key) + t_key_len;
+ wid.val = (u8 *)gtk_key;
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ }
+
+ kfree(gtk_key);
+ return result;
+}
+
+int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid)
+{
+ struct wid wid;
+
+ wid.id = WID_PMKID_INFO;
+ wid.type = WID_STR;
+ wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1;
+ wid.val = (u8 *)pmkid;
+
+ return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+}
+
+int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
+{
+ int result;
+ struct wid wid;
+
+ wid.id = WID_MAC_ADDR;
+ wid.type = WID_STR;
+ wid.size = ETH_ALEN;
+ wid.val = mac_addr;
+
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to get mac address\n");
+
+ return result;
+}
+
+int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
+ size_t ies_len)
+{
+ int result;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_conn_info *conn_info = &hif_drv->conn_info;
+
+ if (bssid)
+ ether_addr_copy(conn_info->bssid, bssid);
+
+ if (ies) {
+ conn_info->req_ies_len = ies_len;
+ conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL);
+ if (!conn_info->req_ies)
+ return -ENOMEM;
+ }
+
+ result = wilc_send_connect_wid(vif);
+ if (result)
+ goto free_ies;
+
+ hif_drv->connect_timer_vif = vif;
+ mod_timer(&hif_drv->connect_timer,
+ jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS));
+
+ return 0;
+
+free_ies:
+ kfree(conn_info->req_ies);
+
+ return result;
+}
+
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
+{
+ struct wid wid;
+ int result;
+
+ wid.id = WID_CURRENT_CHANNEL;
+ wid.type = WID_CHAR;
+ wid.size = sizeof(char);
+ wid.val = &channel;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to set channel\n");
+
+ return result;
+}
+
+int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id)
+{
+ struct wid wid;
+ int result;
+ struct wilc_drv_handler drv;
+
+ wid.id = WID_SET_OPERATION_MODE;
+ wid.type = WID_STR;
+ wid.size = sizeof(drv);
+ wid.val = (u8 *)&drv;
+
+ drv.handler = cpu_to_le32(index);
+ drv.mode = (ifc_id | (mode << 1));
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to set driver handler\n");
+
+ return result;
+}
+
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
+{
+ struct wid wid;
+ s32 result;
+
+ wid.id = WID_SET_STA_MAC_INACTIVE_TIME;
+ wid.type = WID_STR;
+ wid.size = ETH_ALEN;
+ wid.val = kzalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ ether_addr_copy(wid.val, mac);
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ kfree(wid.val);
+ if (result) {
+ netdev_err(vif->ndev, "Failed to set inactive mac\n");
+ return result;
+ }
+
+ wid.id = WID_GET_INACTIVE_TIME;
+ wid.type = WID_INT;
+ wid.val = (s8 *)out_val;
+ wid.size = sizeof(u32);
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to get inactive time\n");
+
+ return result;
+}
+
+int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level)
+{
+ struct wid wid;
+ int result;
+
+ if (!rssi_level) {
+ netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__);
+ return -EFAULT;
+ }
+
+ wid.id = WID_RSSI;
+ wid.type = WID_CHAR;
+ wid.size = sizeof(char);
+ wid.val = rssi_level;
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to get RSSI value\n");
+
+ return result;
+}
+
+static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats)
+{
+ int result;
+ struct host_if_msg *msg;
+
+ msg = wilc_alloc_work(vif, handle_get_statistics, false);
+ 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;
+ }
+
+ return result;
+}
+
+int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param)
+{
+ struct wid wid_list[4];
+ int i = 0;
+
+ if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) {
+ 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);
+ i++;
+ }
+ if (param->flag & WILC_CFG_PARAM_RETRY_LONG) {
+ 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);
+ i++;
+ }
+ if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) {
+ 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);
+ i++;
+ }
+ if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) {
+ 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);
+ i++;
+ }
+
+ return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, i);
+}
+
+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_stats_async(vif, &vif->periodic_stat);
+
+ 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;
+
+ hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL);
+ if (!hif_drv)
+ return -ENOMEM;
+
+ *hif_drv_handler = hif_drv;
+
+ vif->hif_drv = hif_drv;
+
+ if (wilc->clients_count == 0)
+ mutex_init(&wilc->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);
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+
+ hif_drv->p2p_timeout = 0;
+
+ 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(&vif->wilc->deinit_lock);
+
+ 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);
+
+ 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);
+ hif_drv->usr_scan_req.scan_result = NULL;
+ }
+
+ hif_drv->hif_state = HOST_IF_IDLE;
+
+ kfree(hif_drv);
+ vif->hif_drv = NULL;
+ vif->wilc->clients_count--;
+ mutex_unlock(&vif->wilc->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 = get_unaligned_le32(&buffer[length - 4]);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif)
+ return;
+ hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ 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.frame_len = get_unaligned_le16(&buffer[6]) - 1;
+ msg->body.net_info.rssi = buffer[8];
+ msg->body.net_info.mgmt = kmemdup(&buffer[9],
+ msg->body.net_info.frame_len,
+ GFP_KERNEL);
+ if (!msg->body.net_info.mgmt) {
+ 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.mgmt);
+ 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(&wilc->deinit_lock);
+
+ id = get_unaligned_le32(&buffer[length - 4]);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif) {
+ mutex_unlock(&wilc->deinit_lock);
+ return;
+ }
+
+ hif_drv = vif->hif_drv;
+
+ if (!hif_drv) {
+ mutex_unlock(&wilc->deinit_lock);
+ return;
+ }
+
+ if (!hif_drv->conn_info.conn_result) {
+ netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
+ mutex_unlock(&wilc->deinit_lock);
+ return;
+ }
+
+ msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false);
+ if (IS_ERR(msg)) {
+ mutex_unlock(&wilc->deinit_lock);
+ return;
+ }
+
+ msg->body.mac_info.status = buffer[7];
+ result = wilc_enqueue_work(msg);
+ if (result) {
+ netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
+ kfree(msg);
+ }
+
+ mutex_unlock(&wilc->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 = get_unaligned_le32(&buffer[length - 4]);
+ vif = wilc_get_vif_from_idx(wilc, id);
+ if (!vif)
+ return;
+ hif_drv = vif->hif_drv;
+
+ if (!hif_drv)
+ 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, u64 cookie,
+ u32 duration, u16 chan,
+ void (*expired)(void *, u64),
+ void *user_arg)
+{
+ struct wilc_remain_ch roc;
+ int result;
+
+ roc.ch = chan;
+ roc.expired = expired;
+ roc.arg = user_arg;
+ roc.duration = duration;
+ roc.cookie = cookie;
+ result = handle_remain_on_chan(vif, &roc);
+ if (result)
+ netdev_err(vif->ndev, "%s: failed to set remain on channel\n",
+ __func__);
+
+ return result;
+}
+
+int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie)
+{
+ if (!vif->hif_drv) {
+ netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
+ return -EFAULT;
+ }
+
+ del_timer(&vif->hif_drv->remain_on_ch_timer);
+
+ return wilc_handle_roc_expired(vif, cookie);
+}
+
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
+{
+ struct wid wid;
+ int result;
+ struct wilc_reg_frame reg_frame;
+
+ wid.id = WID_REGISTER_FRAME;
+ wid.type = WID_STR;
+ wid.size = sizeof(reg_frame);
+ wid.val = (u8 *)®_frame;
+
+ memset(®_frame, 0x0, sizeof(reg_frame));
+
+ if (reg)
+ reg_frame.reg = 1;
+
+ switch (frame_type) {
+ case IEEE80211_STYPE_ACTION:
+ reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX;
+ break;
+
+ case IEEE80211_STYPE_PROBE_REQ:
+ reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX;
+ break;
+
+ default:
+ break;
+ }
+ reg_frame.frame_type = cpu_to_le16(frame_type);
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to frame register\n");
+}
+
+int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
+ struct cfg80211_beacon_data *params)
+{
+ struct wid wid;
+ int result;
+ u8 *cur_byte;
+
+ wid.id = WID_ADD_BEACON;
+ wid.type = WID_BIN;
+ wid.size = params->head_len + params->tail_len + 16;
+ wid.val = kzalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ cur_byte = wid.val;
+ put_unaligned_le32(interval, cur_byte);
+ cur_byte += 4;
+ put_unaligned_le32(dtim_period, cur_byte);
+ cur_byte += 4;
+ put_unaligned_le32(params->head_len, cur_byte);
+ cur_byte += 4;
+
+ if (params->head_len > 0)
+ memcpy(cur_byte, params->head, params->head_len);
+ cur_byte += params->head_len;
+
+ put_unaligned_le32(params->tail_len, cur_byte);
+ cur_byte += 4;
+
+ if (params->tail_len > 0)
+ memcpy(cur_byte, params->tail, params->tail_len);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send add beacon\n");
+
+ kfree(wid.val);
+
+ return result;
+}
+
+int wilc_del_beacon(struct wilc_vif *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, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send delete beacon\n");
+
+ return result;
+}
+
+int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params)
+{
+ struct wid wid;
+ int result;
+ u8 *cur_byte;
+
+ wid.id = WID_ADD_STA;
+ wid.type = WID_BIN;
+ wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ cur_byte = wid.val;
+ wilc_hif_pack_sta_param(cur_byte, mac, params);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result != 0)
+ netdev_err(vif->ndev, "Failed to send add station\n");
+
+ kfree(wid.val);
+
+ return result;
+}
+
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)
+{
+ struct wid wid;
+ int result;
+
+ wid.id = WID_REMOVE_STA;
+ wid.type = WID_BIN;
+ wid.size = ETH_ALEN;
+ wid.val = kzalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ if (!mac_addr)
+ eth_broadcast_addr(wid.val);
+ else
+ ether_addr_copy(wid.val, mac_addr);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to del station\n");
+
+ kfree(wid.val);
+
+ return result;
+}
+
+int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])
+{
+ struct wid wid;
+ int result;
+ int i;
+ u8 assoc_sta = 0;
+ struct wilc_del_all_sta del_sta;
+
+ memset(&del_sta, 0x0, sizeof(del_sta));
+ for (i = 0; i < WILC_MAX_NUM_STA; i++) {
+ if (!is_zero_ether_addr(mac_addr[i])) {
+ assoc_sta++;
+ ether_addr_copy(del_sta.mac[i], mac_addr[i]);
+ }
+ }
+
+ if (!assoc_sta)
+ return 0;
+
+ del_sta.assoc_sta = assoc_sta;
+
+ wid.id = WID_DEL_ALL_STA;
+ wid.type = WID_STR;
+ wid.size = (assoc_sta * ETH_ALEN) + 1;
+ wid.val = (u8 *)&del_sta;
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send delete all station\n");
+
+ return result;
+}
+
+int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params)
+{
+ struct wid wid;
+ int result;
+ u8 *cur_byte;
+
+ wid.id = WID_EDIT_STA;
+ wid.type = WID_BIN;
+ wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
+ if (!wid.val)
+ return -ENOMEM;
+
+ cur_byte = wid.val;
+ wilc_hif_pack_sta_param(cur_byte, mac, params);
+
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send edit station\n");
+
+ kfree(wid.val);
+ return result;
+}
+
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
+{
+ struct wid wid;
+ int result;
+ s8 power_mode;
+
+ if (enabled)
+ power_mode = WILC_FW_MIN_FAST_PS;
+ else
+ power_mode = WILC_FW_NO_POWERSAVE;
+
+ wid.id = WID_POWER_MANAGEMENT;
+ wid.val = &power_mode;
+ wid.size = sizeof(char);
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+ if (result)
+ netdev_err(vif->ndev, "Failed to send power management\n");
+
+ return result;
+}
+
+int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 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.mc_info.enabled = enabled;
+ msg->body.mc_info.cnt = count;
+ msg->body.mc_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)
+{
+ struct wid wid;
+
+ wid.id = WID_TX_POWER;
+ wid.type = WID_CHAR;
+ wid.val = &tx_power;
+ wid.size = sizeof(char);
+
+ return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+}
+
+int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
+{
+ struct wid wid;
+
+ wid.id = WID_TX_POWER;
+ wid.type = WID_CHAR;
+ wid.val = tx_power;
+ wid.size = sizeof(char);
+
+ return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
+}
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries
+ * All rights reserved.
+ */
+
+#ifndef HOST_INT_H
+#define HOST_INT_H
+#include <linux/ieee80211.h>
+#include "wlan_if.h"
+
+enum {
+ WILC_IDLE_MODE = 0x0,
+ WILC_AP_MODE = 0x1,
+ WILC_STATION_MODE = 0x2,
+ WILC_GO_MODE = 0x3,
+ WILC_CLIENT_MODE = 0x4
+};
+
+#define WILC_MAX_NUM_STA 9
+#define WILC_MAX_NUM_SCANNED_CH 14
+#define WILC_MAX_NUM_PROBED_SSID 10
+
+#define WILC_TX_MIC_KEY_LEN 8
+#define WILC_RX_MIC_KEY_LEN 8
+
+#define WILC_MAX_NUM_PMKIDS 16
+#define WILC_ADD_STA_LENGTH 40
+#define WILC_NUM_CONCURRENT_IFC 2
+
+enum {
+ WILC_SET_CFG = 0,
+ WILC_GET_CFG
+};
+
+#define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256
+
+struct assoc_resp {
+ __le16 capab_info;
+ __le16 status_code;
+ __le16 aid;
+} __packed;
+
+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 wilc_pmkid {
+ u8 bssid[ETH_ALEN];
+ u8 pmkid[WLAN_PMKID_LEN];
+} __packed;
+
+struct wilc_pmkid_attr {
+ u8 numpmkid;
+ struct wilc_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS];
+} __packed;
+
+struct cfg_param_attr {
+ u32 flag;
+ u16 short_retry_limit;
+ u16 long_retry_limit;
+ u16 frag_threshold;
+ u16 rts_threshold;
+};
+
+enum cfg_param {
+ WILC_CFG_PARAM_RETRY_SHORT = BIT(0),
+ WILC_CFG_PARAM_RETRY_LONG = BIT(1),
+ WILC_CFG_PARAM_FRAG_THRESHOLD = BIT(2),
+ WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3)
+};
+
+enum scan_event {
+ SCAN_EVENT_NETWORK_FOUND = 0,
+ SCAN_EVENT_DONE = 1,
+ SCAN_EVENT_ABORTED = 2,
+ SCAN_EVENT_FORCE_32BIT = 0xFFFFFFFF
+};
+
+enum conn_event {
+ CONN_DISCONN_EVENT_CONN_RESP = 0,
+ CONN_DISCONN_EVENT_DISCONN_NOTIF = 1,
+ CONN_DISCONN_EVENT_FORCE_32BIT = 0xFFFFFFFF
+};
+
+enum {
+ WILC_HIF_SDIO = 0,
+ WILC_HIF_SPI = BIT(0)
+};
+
+enum {
+ WILC_MAC_STATUS_INIT = -1,
+ WILC_MAC_STATUS_DISCONNECTED = 0,
+ WILC_MAC_STATUS_CONNECTED = 1
+};
+
+struct wilc_rcvd_net_info {
+ s8 rssi;
+ u8 ch;
+ u16 frame_len;
+ struct ieee80211_mgmt *mgmt;
+};
+
+struct wilc_user_scan_req {
+ void (*scan_result)(enum scan_event evt,
+ struct wilc_rcvd_net_info *info, void *priv);
+ void *arg;
+ u32 ch_cnt;
+};
+
+struct wilc_conn_info {
+ u8 bssid[ETH_ALEN];
+ u8 security;
+ enum authtype auth_type;
+ u8 ch;
+ u8 *req_ies;
+ size_t req_ies_len;
+ u8 *resp_ies;
+ u16 resp_ies_len;
+ u16 status;
+ void (*conn_result)(enum conn_event evt, u8 status, void *priv_data);
+ void *arg;
+ void *param;
+};
+
+struct wilc_remain_ch {
+ u16 ch;
+ u32 duration;
+ void (*expired)(void *priv, u64 cookie);
+ void *arg;
+ u32 cookie;
+};
+
+struct wilc;
+struct host_if_drv {
+ struct wilc_user_scan_req usr_scan_req;
+ struct wilc_conn_info conn_info;
+ struct wilc_remain_ch remain_on_ch;
+ u64 p2p_timeout;
+
+ enum host_if_state hif_state;
+
+ u8 assoc_bssid[ETH_ALEN];
+
+ struct timer_list scan_timer;
+ struct wilc_vif *scan_timer_vif;
+
+ struct timer_list connect_timer;
+ struct wilc_vif *connect_timer_vif;
+
+ struct timer_list remain_on_ch_timer;
+ struct wilc_vif *remain_on_ch_timer_vif;
+
+ bool ifc_up;
+ u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
+};
+
+struct wilc_vif;
+int wilc_remove_wep_key(struct wilc_vif *vif, u8 index);
+int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index);
+int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index);
+int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
+ u8 index, u8 mode, enum authtype auth_type);
+int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
+ const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
+ u8 mode, u8 cipher_mode, u8 index);
+s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
+ u32 *out_val);
+int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
+ u8 index, u32 key_rsc_len, const u8 *key_rsc,
+ const u8 *rx_mic, const u8 *tx_mic, u8 mode,
+ u8 cipher_mode);
+int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid);
+int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr);
+int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
+ size_t ies_len);
+int wilc_disconnect(struct wilc_vif *vif);
+int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel);
+int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level);
+int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
+ u8 *ch_freq_list, u8 ch_list_len,
+ void (*scan_result_fn)(enum scan_event,
+ struct wilc_rcvd_net_info *, void *),
+ void *user_arg, struct cfg80211_scan_request *request);
+int wilc_hif_set_cfg(struct wilc_vif *vif,
+ struct cfg_param_attr *cfg_param);
+int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler);
+int wilc_deinit(struct wilc_vif *vif);
+int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
+ struct cfg80211_beacon_data *params);
+int wilc_del_beacon(struct wilc_vif *vif);
+int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params);
+int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]);
+int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr);
+int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
+ struct station_parameters *params);
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
+int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
+ u8 *mc_list);
+int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
+ u32 duration, u16 chan,
+ void (*expired)(void *, u64),
+ void *user_arg);
+int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie);
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
+int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id);
+int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats);
+int wilc_get_vif_idx(struct wilc_vif *vif);
+int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
+int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
+void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length);
+void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length);
+void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length);
+void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
+ struct cfg80211_crypto_settings *crypto);
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "cfg80211.h"
+
+struct wilc_wfi_radiotap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 rate;
+} __packed;
+
+struct wilc_wfi_radiotap_cb_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 rate;
+ u8 dump;
+ u16 tx_flags;
+} __packed;
+
+#define TX_RADIOTAP_PRESENT ((1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_TX_FLAGS))
+
+void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size)
+{
+ u32 header, pkt_offset;
+ struct sk_buff *skb = NULL;
+ struct wilc_wfi_radiotap_hdr *hdr;
+ struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
+
+ if (!mon_dev)
+ return;
+
+ if (!netif_running(mon_dev))
+ return;
+
+ /* Get WILC header */
+ header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
+ /*
+ * The packet offset field contain info about what type of management
+ * the frame we are dealing with and ack status
+ */
+ pkt_offset = 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 = mon_dev;
+ skb_reset_mac_header(skb);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+
+ netif_rx(skb);
+}
+
+struct tx_complete_mon_data {
+ int size;
+ void *buff;
+};
+
+static void mgmt_tx_complete(void *priv, int status)
+{
+ struct tx_complete_mon_data *pv_data = priv;
+ /*
+ * in case of fully hosting mode, the freeing will be done
+ * in response to the cfg packet
+ */
+ kfree(pv_data->buff);
+
+ kfree(pv_data);
+}
+
+static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
+{
+ struct tx_complete_mon_data *mgmt_tx = NULL;
+
+ if (!dev)
+ return -EFAULT;
+
+ netif_stop_queue(dev);
+ mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_ATOMIC);
+ if (!mgmt_tx)
+ return -ENOMEM;
+
+ mgmt_tx->buff = kmemdup(buf, len, GFP_ATOMIC);
+ if (!mgmt_tx->buff) {
+ kfree(mgmt_tx);
+ return -ENOMEM;
+ }
+
+ mgmt_tx->size = len;
+
+ wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
+ mgmt_tx_complete);
+
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static netdev_tx_t wilc_wfi_mon_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ u32 rtap_len, ret = 0;
+ struct wilc_wfi_mon_priv *mon_priv;
+ struct sk_buff *skb2;
+ struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
+ u8 srcadd[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+
+ mon_priv = netdev_priv(dev);
+ if (!mon_priv)
+ return -EFAULT;
+
+ rtap_len = ieee80211_get_radiotap_len(skb->data);
+ if (skb->len < rtap_len)
+ return -1;
+
+ skb_pull(skb, rtap_len);
+
+ if (skb->data[0] == 0xc0 && is_broadcast_ether_addr(&skb->data[4])) {
+ skb2 = dev_alloc_skb(skb->len + sizeof(*cb_hdr));
+ if (!skb2)
+ return -ENOMEM;
+
+ skb_put_data(skb2, skb->data, skb->len);
+
+ cb_hdr = skb_push(skb2, sizeof(*cb_hdr));
+ memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
+
+ cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
+
+ cb_hdr->hdr.it_len = cpu_to_le16(sizeof(*cb_hdr));
+
+ cb_hdr->hdr.it_present = cpu_to_le32(TX_RADIOTAP_PRESENT);
+
+ cb_hdr->rate = 5;
+ cb_hdr->tx_flags = 0x0004;
+
+ skb2->dev = dev;
+ skb_reset_mac_header(skb2);
+ skb2->ip_summed = CHECKSUM_UNNECESSARY;
+ skb2->pkt_type = PACKET_OTHERHOST;
+ skb2->protocol = htons(ETH_P_802_2);
+ memset(skb2->cb, 0, sizeof(skb2->cb));
+
+ netif_rx(skb2);
+
+ return 0;
+ }
+ skb->dev = mon_priv->real_ndev;
+
+ ether_addr_copy(srcadd, &skb->data[10]);
+ ether_addr_copy(bssid, &skb->data[16]);
+ /*
+ * Identify if data or mgmt packet, if source address and bssid
+ * fields are equal send it to mgmt frames handler
+ */
+ if (!(memcmp(srcadd, bssid, 6))) {
+ ret = mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len);
+ if (ret)
+ netdev_err(dev, "fail to mgmt tx\n");
+ dev_kfree_skb(skb);
+ } else {
+ ret = wilc_mac_xmit(skb, mon_priv->real_ndev);
+ }
+
+ return ret;
+}
+
+static const struct net_device_ops wilc_wfi_netdev_ops = {
+ .ndo_start_xmit = wilc_wfi_mon_xmit,
+
+};
+
+struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
+ const char *name,
+ struct net_device *real_dev)
+{
+ struct wilc_wfi_mon_priv *priv;
+
+ /*If monitor interface is already initialized, return it*/
+ if (wl->monitor_dev)
+ return wl->monitor_dev;
+
+ wl->monitor_dev = alloc_etherdev(sizeof(struct wilc_wfi_mon_priv));
+ if (!wl->monitor_dev)
+ return NULL;
+
+ wl->monitor_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ strncpy(wl->monitor_dev->name, name, IFNAMSIZ);
+ wl->monitor_dev->name[IFNAMSIZ - 1] = 0;
+ wl->monitor_dev->netdev_ops = &wilc_wfi_netdev_ops;
+ wl->monitor_dev->needs_free_netdev = true;
+
+ if (register_netdevice(wl->monitor_dev)) {
+ netdev_err(real_dev, "register_netdevice failed\n");
+ return NULL;
+ }
+ priv = netdev_priv(wl->monitor_dev);
+ if (!priv)
+ return NULL;
+
+ priv->real_ndev = real_dev;
+
+ return wl->monitor_dev;
+}
+
+void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked)
+{
+ if (!wl->monitor_dev)
+ return;
+
+ if (rtnl_locked)
+ unregister_netdevice(wl->monitor_dev);
+ else
+ unregister_netdev(wl->monitor_dev);
+ wl->monitor_dev = NULL;
+}
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+
+#include "cfg80211.h"
+#include "wlan_cfg.h"
+
+#define WILC_MULTICAST_TABLE_SIZE 8
+
+static irqreturn_t isr_uh_routine(int irq, void *user_data)
+{
+ struct net_device *dev = user_data;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ if (wilc->close) {
+ netdev_err(dev, "Can't handle UH interrupt\n");
+ return IRQ_HANDLED;
+ }
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t isr_bh_routine(int irq, void *userdata)
+{
+ struct net_device *dev = userdata;
+ struct wilc_vif *vif = netdev_priv(userdata);
+ struct wilc *wilc = vif->wilc;
+
+ if (wilc->close) {
+ netdev_err(dev, "Can't handle BH interrupt\n");
+ return IRQ_HANDLED;
+ }
+
+ wilc_handle_isr(wilc);
+
+ return IRQ_HANDLED;
+}
+
+static int init_irq(struct net_device *dev)
+{
+ int ret = 0;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+
+ ret = gpiod_direction_input(wl->gpio_irq);
+ if (ret) {
+ netdev_err(dev, "could not obtain gpio for WILC_INTR\n");
+ return ret;
+ }
+
+ wl->dev_irq_num = gpiod_to_irq(wl->gpio_irq);
+
+ ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine,
+ isr_bh_routine,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "WILC_IRQ", dev);
+ if (ret < 0)
+ netdev_err(dev, "Failed to request IRQ\n");
+ else
+ netdev_dbg(dev, "IRQ request succeeded IRQ-NUM= %d\n",
+ wl->dev_irq_num);
+
+ return ret;
+}
+
+static void deinit_irq(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ /* Deinitialize IRQ */
+ if (wilc->dev_irq_num)
+ free_irq(wilc->dev_irq_num, wilc);
+}
+
+void wilc_mac_indicate(struct wilc *wilc)
+{
+ s8 status;
+
+ wilc_wlan_cfg_get_val(wilc, WID_STATUS, &status, 1);
+ if (wilc->mac_status == WILC_MAC_STATUS_INIT) {
+ wilc->mac_status = status;
+ complete(&wilc->sync_event);
+ } else {
+ wilc->mac_status = status;
+ }
+}
+
+static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
+{
+ u8 *bssid, *bssid1;
+ struct net_device *ndev = NULL;
+ struct wilc_vif *vif;
+
+ bssid = mac_header + 10;
+ bssid1 = mac_header + 4;
+
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ if (vif->mode == WILC_STATION_MODE)
+ if (ether_addr_equal_unaligned(bssid, vif->bssid)) {
+ ndev = vif->ndev;
+ goto out;
+ }
+ if (vif->mode == WILC_AP_MODE)
+ if (ether_addr_equal_unaligned(bssid1, vif->bssid)) {
+ ndev = vif->ndev;
+ goto out;
+ }
+ }
+out:
+ return ndev;
+}
+
+void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
+{
+ struct wilc_vif *vif = netdev_priv(wilc_netdev);
+
+ if (bssid)
+ ether_addr_copy(vif->bssid, bssid);
+ else
+ eth_zero_addr(vif->bssid);
+
+ vif->mode = mode;
+}
+
+int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
+{
+ int srcu_idx;
+ u8 ret_val = 0;
+ struct wilc_vif *vif;
+
+ srcu_idx = srcu_read_lock(&wilc->srcu);
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ if (!is_zero_ether_addr(vif->bssid))
+ ret_val++;
+ }
+ srcu_read_unlock(&wilc->srcu, srcu_idx);
+ return ret_val;
+}
+
+static int wilc_txq_task(void *vp)
+{
+ int ret;
+ u32 txq_count;
+ struct wilc *wl = vp;
+
+ complete(&wl->txq_thread_started);
+ while (1) {
+ wait_for_completion(&wl->txq_event);
+
+ if (wl->close) {
+ complete(&wl->txq_thread_started);
+
+ while (!kthread_should_stop())
+ schedule();
+ break;
+ }
+ do {
+ ret = wilc_wlan_handle_txq(wl, &txq_count);
+ if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
+ int srcu_idx;
+ struct wilc_vif *ifc;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ list_for_each_entry_rcu(ifc, &wl->vif_list,
+ list) {
+ if (ifc->mac_opened && ifc->ndev)
+ netif_wake_queue(ifc->ndev);
+ }
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ }
+ } while (ret == -ENOBUFS && !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 wilc_start_firmware(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+ int ret = 0;
+
+ ret = wilc_wlan_start(wilc);
+ if (ret < 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 wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif)
+{
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *hif_drv;
+ u8 b;
+ u16 hw;
+ u32 w;
+
+ netdev_dbg(dev, "Start configuring Firmware\n");
+ hif_drv = (struct host_if_drv *)priv->hif_drv;
+ netdev_dbg(dev, "Host = %p\n", hif_drv);
+
+ w = vif->iftype;
+ cpu_to_le32s(&w);
+ if (!wilc_wlan_cfg_set(vif, 1, WID_SET_OPERATION_MODE, (u8 *)&w, 4,
+ 0, 0))
+ goto fail;
+
+ b = WILC_FW_BSS_TYPE_INFRA;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_TX_RATE_AUTO;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_OPER_MODE_G_MIXED_11B_2;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_PREAMBLE_SHORT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_11N_PROT_AUTO;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_ACTIVE_SCAN;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_SITE_SURVEY_OFF;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, &b, 1, 0, 0))
+ goto fail;
+
+ hw = 0xffff;
+ cpu_to_le16s(&hw);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, (u8 *)&hw, 2, 0, 0))
+ goto fail;
+
+ hw = 2346;
+ cpu_to_le16s(&hw);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, (u8 *)&hw, 2, 0, 0))
+ goto fail;
+
+ b = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, &b, 1, 0, 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_NO_POWERSAVE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_SEC_NO;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_AUTH_OPEN_SYSTEM;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = 3;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, &b, 1, 0, 0))
+ goto fail;
+
+ b = 3;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_ACK_POLICY_NORMAL;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, &b, 1, 0, 0))
+ goto fail;
+
+ b = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, &b, 1,
+ 0, 0))
+ goto fail;
+
+ b = 48;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, &b, 1, 0, 0))
+ goto fail;
+
+ b = 28;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, &b, 1, 0, 0))
+ goto fail;
+
+ hw = 100;
+ cpu_to_le16s(&hw);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, (u8 *)&hw, 2, 0, 0))
+ goto fail;
+
+ b = WILC_FW_REKEY_POLICY_DISABLE;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, &b, 1, 0, 0))
+ goto fail;
+
+ w = 84600;
+ cpu_to_le32s(&w);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, (u8 *)&w, 4, 0, 0))
+ goto fail;
+
+ w = 500;
+ cpu_to_le32s(&w);
+ if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, (u8 *)&w, 4, 0,
+ 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, &b, 1, 0,
+ 0))
+ goto fail;
+
+ b = WILC_FW_ERP_PROT_SELF_CTS;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_11N_OP_MODE_HT_MIXED;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, &b, 1, 0, 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, &b, 1, 0, 0))
+ goto fail;
+
+ b = WILC_FW_OBBS_NONHT_DETECT_PROTECT_REPORT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, &b, 1,
+ 0, 0))
+ goto fail;
+
+ b = WILC_FW_HT_PROT_RTS_CTS_NONHT;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, &b, 1, 0, 0))
+ goto fail;
+
+ b = 0;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, &b, 1, 0,
+ 0))
+ goto fail;
+
+ b = 7;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, &b, 1, 0, 0))
+ goto fail;
+
+ b = 1;
+ if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, &b, 1,
+ 1, 1))
+ goto fail;
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+static void wlan_deinitialize_threads(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+
+ wl->close = 1;
+
+ complete(&wl->txq_event);
+
+ if (wl->txq_thread) {
+ kthread_stop(wl->txq_thread);
+ wl->txq_thread = NULL;
+ }
+}
+
+static void wilc_wlan_deinitialize(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wl = vif->wilc;
+
+ if (!wl) {
+ netdev_err(dev, "wl is NULL\n");
+ return;
+ }
+
+ if (wl->initialized) {
+ netdev_info(dev, "Deinitializing wilc1000...\n");
+
+ if (!wl->dev_irq_num &&
+ wl->hif_func->disable_interrupt) {
+ mutex_lock(&wl->hif_cs);
+ wl->hif_func->disable_interrupt(wl);
+ mutex_unlock(&wl->hif_cs);
+ }
+ complete(&wl->txq_event);
+
+ wlan_deinitialize_threads(dev);
+ deinit_irq(dev);
+
+ wilc_wlan_stop(wl, vif);
+ wilc_wlan_cleanup(dev);
+
+ wl->initialized = false;
+
+ netdev_dbg(dev, "wilc1000 deinitialization Done\n");
+ } else {
+ netdev_dbg(dev, "wilc1000 is not initialized\n");
+ }
+}
+
+static int wlan_initialize_threads(struct net_device *dev)
+{
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc *wilc = vif->wilc;
+
+ wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc,
+ "K_TXQ_TASK");
+ if (IS_ERR(wilc->txq_thread)) {
+ netdev_err(dev, "couldn't create TXQ thread\n");
+ wilc->close = 0;
+ return PTR_ERR(wilc->txq_thread);
+ }
+ wait_for_completion(&wilc->txq_thread_started);
+
+ return 0;
+}
+
+static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
+{
+ int ret = 0;
+ struct wilc *wl = vif->wilc;
+
+ if (!wl->initialized) {
+ wl->mac_status = WILC_MAC_STATUS_INIT;
+ wl->close = 0;
+
+ ret = wilc_wlan_init(dev);
+ if (ret < 0)
+ return -EIO;
+
+ ret = wlan_initialize_threads(dev);
+ if (ret < 0) {
+ ret = -EIO;
+ goto fail_wilc_wlan;
+ }
+
+ if (wl->gpio_irq && init_irq(dev)) {
+ ret = -EIO;
+ goto fail_threads;
+ }
+
+ if (!wl->dev_irq_num &&
+ wl->hif_func->enable_interrupt &&
+ wl->hif_func->enable_interrupt(wl)) {
+ ret = -EIO;
+ goto fail_irq_init;
+ }
+
+ 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 = wilc_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 = wilc_init_fw_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, vif);
+
+fail_irq_enable:
+ if (!wl->dev_irq_num &&
+ wl->hif_func->disable_interrupt)
+ wl->hif_func->disable_interrupt(wl);
+fail_irq_init:
+ if (wl->dev_irq_num)
+ deinit_irq(dev);
+fail_threads:
+ wlan_deinitialize_threads(dev);
+fail_wilc_wlan:
+ wilc_wlan_cleanup(dev);
+ netdev_err(dev, "WLAN initialization FAILED\n");
+ } else {
+ netdev_dbg(dev, "wilc1000 already initialized\n");
+ }
+ return ret;
+}
+
+static int mac_init_fn(struct net_device *ndev)
+{
+ netif_start_queue(ndev);
+ netif_stop_queue(ndev);
+
+ return 0;
+}
+
+static int wilc_mac_open(struct net_device *ndev)
+{
+ struct wilc_vif *vif = netdev_priv(ndev);
+ struct wilc *wl = vif->wilc;
+ struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
+ unsigned char mac_add[ETH_ALEN] = {0};
+ int ret = 0;
+
+ if (!wl || !wl->dev) {
+ netdev_err(ndev, "device not ready\n");
+ return -ENODEV;
+ }
+
+ netdev_dbg(ndev, "MAC OPEN[%p]\n", ndev);
+
+ ret = wilc_init_host_int(ndev);
+ if (ret < 0)
+ return ret;
+
+ ret = wilc_wlan_initialize(ndev, vif);
+ if (ret < 0) {
+ wilc_deinit_host_int(ndev);
+ return ret;
+ }
+
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype,
+ vif->idx);
+ wilc_get_mac_address(vif, mac_add);
+ netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
+ ether_addr_copy(ndev->dev_addr, mac_add);
+
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ netdev_err(ndev, "Wrong MAC address\n");
+ wilc_deinit_host_int(ndev);
+ wilc_wlan_deinitialize(ndev);
+ return -EINVAL;
+ }
+
+ wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
+ vif->ndev->ieee80211_ptr,
+ vif->frame_reg[0].type,
+ vif->frame_reg[0].reg);
+ wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
+ vif->ndev->ieee80211_ptr,
+ vif->frame_reg[1].type,
+ vif->frame_reg[1].reg);
+ netif_wake_queue(ndev);
+ wl->open_ifcs++;
+ 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, 0, 0, NULL);
+ return;
+ }
+
+ if (dev->mc.count == 0) {
+ wilc_setup_multicast_filter(vif, 1, 0, NULL);
+ return;
+ }
+
+ mc_list = kmalloc_array(dev->mc.count, ETH_ALEN, GFP_ATOMIC);
+ if (!mc_list)
+ return;
+
+ cur_mc = mc_list;
+ i = 0;
+ netdev_for_each_mc_addr(ha, dev) {
+ memcpy(cur_mc, ha->addr, ETH_ALEN);
+ netdev_dbg(dev, "Entry[%d]: %pM\n", i, cur_mc);
+ i++;
+ cur_mc += ETH_ALEN;
+ }
+
+ if (wilc_setup_multicast_filter(vif, 1, dev->mc.count, mc_list))
+ kfree(mc_list);
+}
+
+static void wilc_tx_complete(void *priv, int status)
+{
+ struct tx_complete_data *pv_data = priv;
+
+ dev_kfree_skb(pv_data->skb);
+ kfree(pv_data);
+}
+
+netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct wilc_vif *vif = netdev_priv(ndev);
+ struct wilc *wilc = vif->wilc;
+ struct tx_complete_data *tx_data = NULL;
+ int queue_count;
+
+ if (skb->dev != ndev) {
+ netdev_err(ndev, "Packet not destined to this device\n");
+ return 0;
+ }
+
+ tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
+ if (!tx_data) {
+ dev_kfree_skb(skb);
+ netif_wake_queue(ndev);
+ return 0;
+ }
+
+ tx_data->buff = skb->data;
+ tx_data->size = skb->len;
+ tx_data->skb = skb;
+
+ vif->netstats.tx_packets++;
+ vif->netstats.tx_bytes += tx_data->size;
+ queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
+ tx_data->buff, tx_data->size,
+ wilc_tx_complete);
+
+ if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
+ int srcu_idx;
+ struct wilc_vif *vif;
+
+ srcu_idx = srcu_read_lock(&wilc->srcu);
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ if (vif->mac_opened)
+ netif_stop_queue(vif->ndev);
+ }
+ srcu_read_unlock(&wilc->srcu, srcu_idx);
+ }
+
+ return 0;
+}
+
+static int wilc_mac_close(struct net_device *ndev)
+{
+ struct wilc_vif *vif = netdev_priv(ndev);
+ struct wilc *wl = vif->wilc;
+
+ netdev_dbg(ndev, "Mac close\n");
+
+ if (wl->open_ifcs > 0)
+ wl->open_ifcs--;
+ else
+ return 0;
+
+ if (vif->ndev) {
+ netif_stop_queue(vif->ndev);
+
+ wilc_deinit_host_int(vif->ndev);
+ }
+
+ if (wl->open_ifcs == 0) {
+ netdev_dbg(ndev, "Deinitializing wilc1000\n");
+ wl->close = 1;
+ wilc_wlan_deinitialize(ndev);
+ }
+
+ vif->mac_opened = 0;
+
+ return 0;
+}
+
+void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size,
+ u32 pkt_offset)
+{
+ unsigned int frame_len = 0;
+ int stats;
+ unsigned char *buff_to_send = NULL;
+ struct sk_buff *skb;
+ struct net_device *wilc_netdev;
+ struct wilc_vif *vif;
+
+ if (!wilc)
+ return;
+
+ wilc_netdev = get_if_handler(wilc, buff);
+ if (!wilc_netdev)
+ return;
+
+ buff += pkt_offset;
+ vif = netdev_priv(wilc_netdev);
+
+ if (size > 0) {
+ frame_len = size;
+ buff_to_send = buff;
+
+ skb = dev_alloc_skb(frame_len);
+ if (!skb)
+ return;
+
+ skb->dev = wilc_netdev;
+
+ skb_put_data(skb, buff_to_send, frame_len);
+
+ skb->protocol = eth_type_trans(skb, wilc_netdev);
+ vif->netstats.rx_packets++;
+ vif->netstats.rx_bytes += frame_len;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ stats = netif_rx(skb);
+ netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats);
+ }
+}
+
+void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
+{
+ int srcu_idx;
+ struct wilc_vif *vif;
+
+ srcu_idx = srcu_read_lock(&wilc->srcu);
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ u16 type = le16_to_cpup((__le16 *)buff);
+
+ if (vif->priv.p2p_listen_state &&
+ ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
+ (type == vif->frame_reg[1].type && vif->frame_reg[1].reg)))
+ wilc_wfi_p2p_rx(vif, buff, size);
+
+ if (vif->monitor_flag)
+ wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size);
+ }
+ srcu_read_unlock(&wilc->srcu, srcu_idx);
+}
+
+static const struct net_device_ops wilc_netdev_ops = {
+ .ndo_init = mac_init_fn,
+ .ndo_open = wilc_mac_open,
+ .ndo_stop = wilc_mac_close,
+ .ndo_start_xmit = wilc_mac_xmit,
+ .ndo_get_stats = mac_stats,
+ .ndo_set_rx_mode = wilc_set_multicast_list,
+};
+
+void wilc_netdev_cleanup(struct wilc *wilc)
+{
+ struct wilc_vif *vif;
+ int srcu_idx;
+
+ if (!wilc)
+ return;
+
+ if (wilc->firmware) {
+ release_firmware(wilc->firmware);
+ wilc->firmware = NULL;
+ }
+
+ srcu_idx = srcu_read_lock(&wilc->srcu);
+ list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+ if (vif->ndev)
+ unregister_netdev(vif->ndev);
+ }
+ srcu_read_unlock(&wilc->srcu, srcu_idx);
+
+ wilc_wfi_deinit_mon_interface(wilc, false);
+ flush_workqueue(wilc->hif_workqueue);
+ destroy_workqueue(wilc->hif_workqueue);
+
+ do {
+ mutex_lock(&wilc->vif_mutex);
+ if (wilc->vif_num <= 0) {
+ mutex_unlock(&wilc->vif_mutex);
+ break;
+ }
+ vif = wilc_get_wl_to_vif(wilc);
+ if (!IS_ERR(vif))
+ list_del_rcu(&vif->list);
+
+ wilc->vif_num--;
+ mutex_unlock(&wilc->vif_mutex);
+ synchronize_srcu(&wilc->srcu);
+ } while (1);
+
+ wilc_wlan_cfg_deinit(wilc);
+ wlan_deinit_locks(wilc);
+ kfree(wilc->bus_data);
+ wiphy_unregister(wilc->wiphy);
+ wiphy_free(wilc->wiphy);
+}
+EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
+
+static u8 wilc_get_available_idx(struct wilc *wl)
+{
+ int idx = 0;
+ struct wilc_vif *vif;
+ int srcu_idx;
+
+ srcu_idx = srcu_read_lock(&wl->srcu);
+ list_for_each_entry_rcu(vif, &wl->vif_list, list) {
+ if (vif->idx == 0)
+ idx = 1;
+ else
+ idx = 0;
+ }
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+ return idx;
+}
+
+struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
+ int vif_type, enum nl80211_iftype type,
+ bool rtnl_locked)
+{
+ struct net_device *ndev;
+ struct wilc_vif *vif;
+ int ret;
+
+ ndev = alloc_etherdev(sizeof(*vif));
+ if (!ndev)
+ return ERR_PTR(-ENOMEM);
+
+ vif = netdev_priv(ndev);
+ ndev->ieee80211_ptr = &vif->priv.wdev;
+ strcpy(ndev->name, name);
+ vif->wilc = wl;
+ vif->ndev = ndev;
+ ndev->ml_priv = vif;
+
+ ndev->netdev_ops = &wilc_netdev_ops;
+
+ SET_NETDEV_DEV(ndev, wiphy_dev(wl->wiphy));
+
+ vif->priv.wdev.wiphy = wl->wiphy;
+ vif->priv.wdev.netdev = ndev;
+ vif->priv.wdev.iftype = type;
+ vif->priv.dev = ndev;
+
+ if (rtnl_locked)
+ ret = register_netdevice(ndev);
+ else
+ ret = register_netdev(ndev);
+
+ if (ret) {
+ free_netdev(ndev);
+ return ERR_PTR(-EFAULT);
+ }
+
+ ndev->needs_free_netdev = true;
+ vif->iftype = vif_type;
+ vif->idx = wilc_get_available_idx(wl);
+ vif->mac_opened = 0;
+ mutex_lock(&wl->vif_mutex);
+ list_add_tail_rcu(&vif->list, &wl->vif_list);
+ wl->vif_num += 1;
+ mutex_unlock(&wl->vif_mutex);
+ synchronize_srcu(&wl->srcu);
+
+ return vif;
+}
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#ifndef WILC_WFI_NETDEVICE
+#define WILC_WFI_NETDEVICE
+
+#include <linux/tcp.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include <net/ieee80211_radiotap.h>
+#include <linux/if_arp.h>
+#include <linux/gpio/consumer.h>
+
+#include "hif.h"
+#include "wlan.h"
+#include "wlan_cfg.h"
+
+#define FLOW_CONTROL_LOWER_THRESHOLD 128
+#define FLOW_CONTROL_UPPER_THRESHOLD 256
+
+#define WILC_MAX_NUM_PMKIDS 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[WILC_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;
+};
+
+struct wilc_p2p_var {
+ u8 local_random;
+ u8 recv_random;
+ bool is_wilc_ie;
+};
+
+static const u32 wilc_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC
+};
+
+#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 const struct ieee80211_channel wilc_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 wilc_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 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;
+
+ 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 wilc_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[WILC_MAX_NUM_STA];
+ struct wilc_wfi_key *wilc_ptk[WILC_MAX_NUM_STA];
+ u8 wilc_groupkey;
+ /* mutexes */
+ struct mutex scan_req_lock;
+ bool p2p_listen_state;
+ int scanned_cnt;
+ struct wilc_p2p_var p2p;
+
+ u64 inc_roc_cookie;
+};
+
+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 bssid[ETH_ALEN];
+ struct host_if_drv *hif_drv;
+ struct net_device *ndev;
+ u8 mode;
+ struct timer_list during_ip_timer;
+ struct timer_list periodic_rssi;
+ struct rf_info periodic_stat;
+ struct tcp_ack_filter ack_filter;
+ bool connecting;
+ struct wilc_priv priv;
+ struct list_head list;
+ struct cfg80211_bss *bss;
+};
+
+struct wilc {
+ struct wiphy *wiphy;
+ const struct wilc_hif_func *hif_func;
+ int io_type;
+ s8 mac_status;
+ struct gpio_desc *gpio_irq;
+ struct clk *rtc_clk;
+ bool initialized;
+ int dev_irq_num;
+ int close;
+ u8 vif_num;
+ struct list_head vif_list;
+ /*protect vif list*/
+ struct mutex vif_mutex;
+ struct srcu_struct srcu;
+ 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;
+ /* lock to protect issue of wid command to firmware */
+ struct mutex cfg_cmd_lock;
+ struct wilc_cfg_frame cfg_frame;
+ u32 cfg_frame_offset;
+ u8 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;
+
+ int clients_count;
+ struct workqueue_struct *hif_workqueue;
+ enum chip_ps_states chip_ps_state;
+ struct wilc_cfg cfg;
+ void *bus_data;
+ struct net_device *monitor_dev;
+ /* deinit lock */
+ struct mutex deinit_lock;
+ u8 sta_ch;
+ u8 op_ch;
+ struct ieee80211_channel channels[ARRAY_SIZE(wilc_2ghz_channels)];
+ struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)];
+ struct ieee80211_supported_band band;
+ u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)];
+};
+
+struct wilc_wfi_mon_priv {
+ struct net_device *real_ndev;
+};
+
+void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset);
+void wilc_mac_indicate(struct wilc *wilc);
+void wilc_netdev_cleanup(struct wilc *wilc);
+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);
+struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
+ int vif_type, enum nl80211_iftype type,
+ bool rtnl_locked);
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/host.h>
+
+#include "netdev.h"
+#include "cfg80211.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;
+};
+
+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;
+};
+
+static const struct wilc_hif_func wilc_hif_sdio;
+
+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 wilc_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");
+ }
+ }
+
+ ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO,
+ &wilc_hif_sdio);
+ if (ret) {
+ kfree(sdio_priv);
+ return ret;
+ }
+ sdio_set_drvdata(func, wilc);
+ wilc->bus_data = sdio_priv;
+ wilc->dev = &func->dev;
+ wilc->gpio_irq = gpio;
+
+ wilc->rtc_clk = devm_clk_get(&func->card->dev, "rtc_clk");
+ if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else if (!IS_ERR(wilc->rtc_clk))
+ clk_prepare_enable(wilc->rtc_clk);
+
+ dev_info(&func->dev, "Driver Initializing success\n");
+ return 0;
+}
+
+static void wilc_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);
+
+ if (!IS_ERR(wilc->rtc_clk))
+ clk_disable_unprepare(wilc->rtc_clk);
+
+ wilc_netdev_cleanup(wilc);
+}
+
+static int wilc_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 (!IS_ERR(wilc->rtc_clk))
+ clk_disable_unprepare(wilc->rtc_clk);
+
+ if (wilc->suspend_event) {
+ host_sleep_notify(wilc);
+ chip_allow_sleep(wilc);
+ }
+
+ ret = wilc_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_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 wilc_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 wilc_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 wilc_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 wilc_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 (!wilc_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 wilc_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 (!wilc_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 (!wilc_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 wilc_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 (!wilc_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 wilc_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 (!wilc_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 (!wilc_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 wilc_sdio_deinit(struct wilc *wilc)
+{
+ return 1;
+}
+
+static int wilc_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 (!wilc_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 (!wilc_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 (!wilc_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 wilc_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 wilc_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;
+
+ wilc_sdio_read_size(wilc, &tmp);
+
+ /**
+ * Read IRQ flags
+ **/
+ if (!sdio_priv->irq_gpio) {
+ int i;
+
+ cmd.read_write = 0;
+ 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 wilc_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 wilc_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 (!wilc_sdio_read_reg(wilc, WILC_MISC, ®)) {
+ dev_err(&func->dev, "Failed read misc reg...\n");
+ return 0;
+ }
+
+ reg &= ~BIT(8);
+ if (!wilc_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 = wilc_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 = wilc_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 = wilc_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 = wilc_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 = wilc_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 = wilc_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 = wilc_sdio_init,
+ .hif_deinit = wilc_sdio_deinit,
+ .hif_read_reg = wilc_sdio_read_reg,
+ .hif_write_reg = wilc_sdio_write_reg,
+ .hif_block_rx = wilc_sdio_read,
+ .hif_block_tx = wilc_sdio_write,
+ .hif_read_int = wilc_sdio_read_int,
+ .hif_clear_int_ext = wilc_sdio_clear_int_ext,
+ .hif_read_size = wilc_sdio_read_size,
+ .hif_block_tx_ext = wilc_sdio_write,
+ .hif_block_rx_ext = wilc_sdio_read,
+ .hif_sync_ext = wilc_sdio_sync_ext,
+ .enable_interrupt = wilc_sdio_enable_interrupt,
+ .disable_interrupt = wilc_sdio_disable_interrupt,
+};
+
+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);
+ 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 = wilc_sdio_probe,
+ .remove = wilc_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");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+
+#include "netdev.h"
+#include "cfg80211.h"
+
+struct wilc_spi {
+ int crc_off;
+ 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_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi);
+ if (ret) {
+ kfree(spi_priv);
+ return ret;
+ }
+
+ spi_set_drvdata(spi, wilc);
+ wilc->dev = &spi->dev;
+ wilc->bus_data = spi_priv;
+ wilc->gpio_irq = gpio;
+
+ wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk");
+ if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else if (!IS_ERR(wilc->rtc_clk))
+ clk_prepare_enable(wilc->rtc_clk);
+
+ return 0;
+}
+
+static int wilc_bus_remove(struct spi_device *spi)
+{
+ struct wilc *wilc = spi_get_drvdata(spi);
+
+ /* free the GPIO in module remove */
+ if (wilc->gpio_irq)
+ gpiod_put(wilc->gpio_irq);
+
+ if (!IS_ERR(wilc->rtc_clk))
+ clk_disable_unprepare(wilc->rtc_clk);
+
+ wilc_netdev_cleanup(wilc);
+ return 0;
+}
+
+static const struct of_device_id wilc_of_match[] = {
+ { .compatible = "microchip,wilc1000-spi", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, wilc_of_match);
+
+static struct spi_driver wilc_spi_driver = {
+ .driver = {
+ .name = MODALIAS,
+ .of_match_table = wilc_of_match,
+ },
+ .probe = wilc_bus_probe,
+ .remove = wilc_bus_remove,
+};
+module_spi_driver(wilc_spi_driver);
+MODULE_LICENSE("GPL");
+
+static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int ret;
+ struct spi_message msg;
+
+ if (len > 0 && b) {
+ struct spi_transfer tr = {
+ .tx_buf = b,
+ .len = len,
+ .delay_usecs = 0,
+ };
+ char *r_buffer = kzalloc(len, GFP_KERNEL);
+
+ if (!r_buffer)
+ return -ENOMEM;
+
+ tr.rx_buf = r_buffer;
+ dev_dbg(&spi->dev, "Request writing %d bytes\n", len);
+
+ memset(&msg, 0, sizeof(msg));
+ spi_message_init(&msg);
+ msg.spi = spi;
+ msg.is_dma_mapped = USE_SPI_DMA;
+ spi_message_add_tail(&tr, &msg);
+
+ ret = spi_sync(spi, &msg);
+ if (ret < 0)
+ dev_err(&spi->dev, "SPI transaction failed\n");
+
+ kfree(r_buffer);
+ } else {
+ dev_err(&spi->dev,
+ "can't write data with the following length: %d\n",
+ len);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int ret;
+
+ if (rlen > 0) {
+ struct spi_message msg;
+ struct spi_transfer tr = {
+ .rx_buf = rb,
+ .len = rlen,
+ .delay_usecs = 0,
+
+ };
+ char *t_buffer = kzalloc(rlen, GFP_KERNEL);
+
+ if (!t_buffer)
+ return -ENOMEM;
+
+ tr.tx_buf = t_buffer;
+
+ memset(&msg, 0, sizeof(msg));
+ spi_message_init(&msg);
+ msg.spi = spi;
+ msg.is_dma_mapped = USE_SPI_DMA;
+ spi_message_add_tail(&tr, &msg);
+
+ ret = spi_sync(spi, &msg);
+ if (ret < 0)
+ dev_err(&spi->dev, "SPI transaction failed\n");
+ kfree(t_buffer);
+ } else {
+ dev_err(&spi->dev,
+ "can't read data with the following length: %u\n",
+ rlen);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int ret;
+
+ if (rlen > 0) {
+ struct spi_message msg;
+ struct spi_transfer tr = {
+ .rx_buf = rb,
+ .tx_buf = wb,
+ .len = rlen,
+ .bits_per_word = 8,
+ .delay_usecs = 0,
+
+ };
+
+ memset(&msg, 0, sizeof(msg));
+ spi_message_init(&msg);
+ msg.spi = spi;
+ msg.is_dma_mapped = USE_SPI_DMA;
+
+ spi_message_add_tail(&tr, &msg);
+ ret = spi_sync(spi, &msg);
+ if (ret < 0)
+ dev_err(&spi->dev, "SPI transaction failed\n");
+ } else {
+ dev_err(&spi->dev,
+ "can't read data with the following length: %u\n",
+ rlen);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int spi_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;
+ bool unexpected_irq;
+ int j;
+ u32 unknown_mask;
+ u32 irq_flags;
+ int k = IRG_FLAGS_OFFSET + 5;
+
+ if (spi_priv->has_thrpt_enh)
+ return spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
+ int_status);
+ 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 {
+ 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);
+
+ unexpected_irq = (tmp >> IRG_FLAGS_OFFSET) & unknown_mask;
+ if (unexpected_irq) {
+ dev_err(&spi->dev,
+ "Unexpected interrupt(2):j=%d,tmp=%x,mask=%x\n",
+ j, tmp, unknown_mask);
+ }
+
+ j++;
+ } while (unexpected_irq);
+
+ *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) {
+ return spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE,
+ val);
+ }
+
+ 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,
+};
+++ /dev/null
-// 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 WILC_HIF_SCAN_TIMEOUT_MS 5000
-#define WILC_HIF_CONNECT_TIMEOUT_MS 9500
-
-#define WILC_FALSE_FRMWR_CHANNEL 100
-#define WILC_MAX_RATES_SUPPORTED 12
-
-struct wilc_rcvd_mac_info {
- u8 status;
-};
-
-struct wilc_set_multicast {
- u32 enabled;
- u32 cnt;
- u8 *mc_list;
-};
-
-struct wilc_del_all_sta {
- u8 assoc_sta;
- u8 mac[WILC_MAX_NUM_STA][ETH_ALEN];
-};
-
-struct wilc_op_mode {
- __le32 mode;
-};
-
-struct wilc_reg_frame {
- u8 reg;
- u8 reg_id;
- __le16 frame_type;
-} __packed;
-
-struct wilc_drv_handler {
- __le32 handler;
- u8 mode;
-} __packed;
-
-struct wilc_wep_key {
- u8 index;
- u8 key_len;
- u8 key[0];
-} __packed;
-
-struct wilc_sta_wpa_ptk {
- u8 mac_addr[ETH_ALEN];
- u8 key_len;
- u8 key[0];
-} __packed;
-
-struct wilc_ap_wpa_ptk {
- u8 mac_addr[ETH_ALEN];
- u8 index;
- u8 key_len;
- u8 key[0];
-} __packed;
-
-struct wilc_gtk_key {
- u8 mac_addr[ETH_ALEN];
- u8 rsc[8];
- u8 index;
- u8 key_len;
- u8 key[0];
-} __packed;
-
-union wilc_message_body {
- struct wilc_rcvd_net_info net_info;
- struct wilc_rcvd_mac_info mac_info;
- struct wilc_set_multicast mc_info;
- struct wilc_remain_ch remain_on_ch;
- char *data;
-};
-
-struct host_if_msg {
- union wilc_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 wilc_noa_opp_enable {
- u8 ct_window;
- u8 cnt;
- __le32 duration;
- __le32 interval;
- __le32 start_time;
-} __packed;
-
-struct wilc_noa_opp_disable {
- u8 cnt;
- __le32 duration;
- __le32 interval;
- __le32 start_time;
-} __packed;
-
-struct wilc_join_bss_param {
- char ssid[IEEE80211_MAX_SSID_LEN];
- u8 ssid_terminator;
- u8 bss_type;
- u8 ch;
- __le16 cap_info;
- u8 sa[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- __le16 beacon_period;
- u8 dtim_period;
- u8 supp_rates[WILC_MAX_RATES_SUPPORTED + 1];
- u8 wmm_cap;
- u8 uapsd_cap;
- u8 ht_capable;
- u8 rsn_found;
- u8 rsn_grp_policy;
- u8 mode_802_11i;
- u8 p_suites[3];
- u8 akm_suites[3];
- u8 rsn_cap[2];
- u8 noa_enabled;
- __le32 tsf_lo;
- u8 idx;
- u8 opp_enabled;
- union {
- struct wilc_noa_opp_disable opp_dis;
- struct wilc_noa_opp_enable opp_en;
- };
-} __packed;
-
-/* '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;
- struct wilc_vif *vif;
-
- if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC)
- return NULL;
-
- list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
- if (vif->idx == index)
- return vif;
- }
-
- return NULL;
-}
-
-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 wilc_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, WILC_SET_CFG, &wid, 1);
- 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);
- scan_req->scan_result = NULL;
- }
-
- return result;
-}
-
-int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
- u8 *ch_freq_list, u8 ch_list_len,
- void (*scan_result_fn)(enum scan_event,
- struct wilc_rcvd_net_info *, void *),
- void *user_arg, struct cfg80211_scan_request *request)
-{
- int result = 0;
- struct wid wid_list[5];
- u32 index = 0;
- u32 i, scan_timeout;
- u8 *buffer;
- u8 valuesize = 0;
- u8 *search_ssid_vals = NULL;
- struct host_if_drv *hif_drv = vif->hif_drv;
-
- 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->connecting) {
- netdev_err(vif->ndev, "Don't do obss scan\n");
- result = -EBUSY;
- goto error;
- }
-
- hif_drv->usr_scan_req.ch_cnt = 0;
-
- if (request->n_ssids) {
- for (i = 0; i < request->n_ssids; i++)
- valuesize += ((request->ssids[i].ssid_len) + 1);
- search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL);
- if (search_ssid_vals) {
- wid_list[index].id = WID_SSID_PROBE_REQ;
- wid_list[index].type = WID_STR;
- wid_list[index].val = search_ssid_vals;
- buffer = wid_list[index].val;
-
- *buffer++ = request->n_ssids;
-
- for (i = 0; i < request->n_ssids; i++) {
- *buffer++ = request->ssids[i].ssid_len;
- memcpy(buffer, request->ssids[i].ssid,
- request->ssids[i].ssid_len);
- buffer += request->ssids[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 = (s8 *)request->ie;
- wid_list[index].size = request->ie_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_type;
- index++;
-
- if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) {
- wid_list[index].id = WID_PASSIVE_SCAN_TIME;
- wid_list[index].type = WID_SHORT;
- wid_list[index].size = sizeof(u16);
- wid_list[index].val = (s8 *)&request->duration;
- index++;
-
- scan_timeout = (request->duration * ch_list_len) + 500;
- } else {
- scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS;
- }
-
- wid_list[index].id = WID_SCAN_CHANNEL_LIST;
- wid_list[index].type = WID_BIN_DATA;
-
- if (ch_freq_list && ch_list_len > 0) {
- for (i = 0; i < ch_list_len; i++) {
- if (ch_freq_list[i] > 0)
- ch_freq_list[i] -= 1;
- }
- }
-
- wid_list[index].val = ch_freq_list;
- wid_list[index].size = 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_source;
- index++;
-
- hif_drv->usr_scan_req.scan_result = scan_result_fn;
- hif_drv->usr_scan_req.arg = user_arg;
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index);
- if (result) {
- netdev_err(vif->ndev, "Failed to send scan parameters\n");
- goto error;
- }
-
- hif_drv->scan_timer_vif = vif;
- mod_timer(&hif_drv->scan_timer,
- jiffies + msecs_to_jiffies(scan_timeout));
-
-error:
-
- kfree(search_ssid_vals);
-
- return result;
-}
-
-static int wilc_send_connect_wid(struct wilc_vif *vif)
-{
- int result = 0;
- struct wid wid_list[4];
- u32 wid_cnt = 0;
- struct host_if_drv *hif_drv = vif->hif_drv;
- struct wilc_conn_info *conn_attr = &hif_drv->conn_info;
- struct wilc_join_bss_param *bss_param = conn_attr->param;
-
- wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
- wid_list[wid_cnt].type = WID_BIN_DATA;
- wid_list[wid_cnt].val = conn_attr->req_ies;
- wid_list[wid_cnt].size = conn_attr->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 *)&conn_attr->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 *)&conn_attr->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 = sizeof(*bss_param);
- wid_list[wid_cnt].val = (u8 *)bss_param;
- wid_cnt++;
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt);
- if (result) {
- netdev_err(vif->ndev, "failed to send config packet\n");
- goto error;
- } else {
- hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
- }
-
- return 0;
-
-error:
-
- kfree(conn_attr->req_ies);
- conn_attr->req_ies = NULL;
-
- return result;
-}
-
-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 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;
-
- if (hif_drv->conn_info.conn_result) {
- hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
- WILC_MAC_STATUS_DISCONNECTED,
- hif_drv->conn_info.arg);
-
- } 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, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to send disconnect\n");
-
- hif_drv->conn_info.req_ies_len = 0;
- kfree(hif_drv->conn_info.req_ies);
- hif_drv->conn_info.req_ies = NULL;
-
-out:
- kfree(msg);
-}
-
-void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
- struct cfg80211_crypto_settings *crypto)
-{
- struct wilc_join_bss_param *param;
- struct ieee80211_p2p_noa_attr noa_attr;
- u8 rates_len = 0;
- const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie;
- const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie;
- int ret;
- const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies);
-
- param = kzalloc(sizeof(*param), GFP_KERNEL);
- if (!param)
- return NULL;
-
- param->beacon_period = cpu_to_le16(bss->beacon_interval);
- param->cap_info = cpu_to_le16(bss->capability);
- param->bss_type = WILC_FW_BSS_TYPE_INFRA;
- param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
- ether_addr_copy(param->bssid, bss->bssid);
-
- ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
- if (ssid_elm) {
- if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN)
- memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]);
- }
-
- tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
- if (tim_elm && tim_elm[1] >= 2)
- param->dtim_period = tim_elm[3];
-
- memset(param->p_suites, 0xFF, 3);
- memset(param->akm_suites, 0xFF, 3);
-
- rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len);
- if (rates_ie) {
- rates_len = rates_ie[1];
- if (rates_len > WILC_MAX_RATES_SUPPORTED)
- rates_len = WILC_MAX_RATES_SUPPORTED;
- param->supp_rates[0] = rates_len;
- memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len);
- }
-
- supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data,
- ies->len);
- if (supp_rates_ie) {
- if (supp_rates_ie[1] > (WILC_MAX_RATES_SUPPORTED - rates_len))
- param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED;
- else
- param->supp_rates[0] += supp_rates_ie[1];
-
- memcpy(¶m->supp_rates[rates_len + 1], supp_rates_ie + 2,
- (param->supp_rates[0] - rates_len));
- }
-
- ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len);
- if (ht_ie)
- param->ht_capable = true;
-
- ret = cfg80211_get_p2p_attr(ies->data, ies->len,
- IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
- (u8 *)&noa_attr, sizeof(noa_attr));
- if (ret > 0) {
- param->tsf_lo = cpu_to_le32(ies->tsf);
- param->noa_enabled = 1;
- param->idx = noa_attr.index;
- if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) {
- param->opp_enabled = 1;
- param->opp_en.ct_window = noa_attr.oppps_ctwindow;
- param->opp_en.cnt = noa_attr.desc[0].count;
- param->opp_en.duration = noa_attr.desc[0].duration;
- param->opp_en.interval = noa_attr.desc[0].interval;
- param->opp_en.start_time = noa_attr.desc[0].start_time;
- } else {
- param->opp_enabled = 0;
- param->opp_dis.cnt = noa_attr.desc[0].count;
- param->opp_dis.duration = noa_attr.desc[0].duration;
- param->opp_dis.interval = noa_attr.desc[0].interval;
- param->opp_dis.start_time = noa_attr.desc[0].start_time;
- }
- }
- wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
- WLAN_OUI_TYPE_MICROSOFT_WMM,
- ies->data, ies->len);
- if (wmm_ie) {
- struct ieee80211_wmm_param_ie *ie;
-
- ie = (struct ieee80211_wmm_param_ie *)wmm_ie;
- if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) &&
- ie->version == 1) {
- param->wmm_cap = true;
- if (ie->qos_info & BIT(7))
- param->uapsd_cap = true;
- }
- }
-
- wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
- WLAN_OUI_TYPE_MICROSOFT_WPA,
- ies->data, ies->len);
- if (wpa_ie) {
- param->mode_802_11i = 1;
- param->rsn_found = true;
- }
-
- rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len);
- if (rsn_ie) {
- int offset = 8;
-
- param->mode_802_11i = 2;
- param->rsn_found = true;
- //extract RSN capabilities
- offset += (rsn_ie[offset] * 4) + 2;
- offset += (rsn_ie[offset] * 4) + 2;
- memcpy(param->rsn_cap, &rsn_ie[offset], 2);
- }
-
- if (param->rsn_found) {
- int i;
-
- param->rsn_grp_policy = crypto->cipher_group & 0xFF;
- for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++)
- param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF;
-
- for (i = 0; i < crypto->n_akm_suites && i < 3; i++)
- param->akm_suites[i] = crypto->akm_suites[i] & 0xFF;
- }
-
- 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_rcvd_net_info *rcvd_info = &msg->body.net_info;
- struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req;
- const u8 *ch_elm;
- u8 *ies;
- int ies_len;
- size_t offset;
-
- if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control))
- offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
- else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control))
- offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
- else
- goto done;
-
- ies = rcvd_info->mgmt->u.beacon.variable;
- ies_len = rcvd_info->frame_len - offset;
- if (ies_len <= 0)
- goto done;
-
- ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len);
- if (ch_elm && ch_elm[1] > 0)
- rcvd_info->ch = ch_elm[2];
-
- if (scan_req->scan_result)
- scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info,
- scan_req->arg);
-
-done:
- kfree(rcvd_info->mgmt);
- 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, WILC_GET_CFG, &wid, 1);
- 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 s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
- struct wilc_conn_info *ret_conn_info)
-{
- u8 *ies;
- u16 ies_len;
- struct assoc_resp *res = (struct assoc_resp *)buffer;
-
- ret_conn_info->status = le16_to_cpu(res->status_code);
- if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {
- ies = &buffer[sizeof(*res)];
- ies_len = buffer_len - sizeof(*res);
-
- 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;
-}
-
-static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
- u8 mac_status)
-{
- struct host_if_drv *hif_drv = vif->hif_drv;
- struct wilc_conn_info *conn_info = &hif_drv->conn_info;
-
- if (mac_status == WILC_MAC_STATUS_CONNECTED) {
- u32 assoc_resp_info_len;
-
- memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE);
-
- host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,
- WILC_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);
- }
- }
-
- del_timer(&hif_drv->connect_timer);
- conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,
- hif_drv->conn_info.arg);
-
- if (mac_status == WILC_MAC_STATUS_CONNECTED &&
- conn_info->status == WLAN_STATUS_SUCCESS) {
- ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid);
- hif_drv->hif_state = HOST_IF_CONNECTED;
- } else {
- hif_drv->hif_state = HOST_IF_IDLE;
- }
-
- kfree(conn_info->resp_ies);
- conn_info->resp_ies = NULL;
- conn_info->resp_ies_len = 0;
-
- kfree(conn_info->req_ies);
- conn_info->req_ies = NULL;
- conn_info->req_ies_len = 0;
-}
-
-static inline void host_int_handle_disconnect(struct wilc_vif *vif)
-{
- struct host_if_drv *hif_drv = vif->hif_drv;
-
- if (hif_drv->usr_scan_req.scan_result) {
- del_timer(&hif_drv->scan_timer);
- handle_scan_done(vif, SCAN_EVENT_ABORTED);
- }
-
- if (hif_drv->conn_info.conn_result)
- hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
- 0, hif_drv->conn_info.arg);
- else
- netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
-
- eth_zero_addr(hif_drv->assoc_bssid);
-
- hif_drv->conn_info.req_ies_len = 0;
- kfree(hif_drv->conn_info.req_ies);
- hif_drv->conn_info.req_ies = NULL;
- 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 wilc_rcvd_mac_info *mac_info = &msg->body.mac_info;
- struct host_if_drv *hif_drv = vif->hif_drv;
-
- if (!hif_drv) {
- netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
- goto free_msg;
- }
-
- if (!hif_drv->conn_info.conn_result) {
- netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
- goto free_msg;
- }
-
- if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
- host_int_parse_assoc_resp_info(vif, mac_info->status);
- } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) {
- if (hif_drv->hif_state == HOST_IF_CONNECTED) {
- host_int_handle_disconnect(vif);
- } else if (hif_drv->usr_scan_req.scan_result) {
- del_timer(&hif_drv->scan_timer);
- handle_scan_done(vif, SCAN_EVENT_ABORTED);
- }
- }
-
-free_msg:
- kfree(msg);
-}
-
-int wilc_disconnect(struct wilc_vif *vif)
-{
- struct wid wid;
- struct host_if_drv *hif_drv = vif->hif_drv;
- struct wilc_user_scan_req *scan_req;
- struct wilc_conn_info *conn_info;
- 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);
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result) {
- netdev_err(vif->ndev, "Failed to send disconnect\n");
- return result;
- }
-
- scan_req = &hif_drv->usr_scan_req;
- conn_info = &hif_drv->conn_info;
-
- if (scan_req->scan_result) {
- del_timer(&hif_drv->scan_timer);
- scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg);
- scan_req->scan_result = NULL;
- }
-
- if (conn_info->conn_result) {
- if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
- del_timer(&hif_drv->connect_timer);
-
- conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,
- conn_info->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_info->req_ies_len = 0;
- kfree(conn_info->req_ies);
- conn_info->req_ies = NULL;
-
- return 0;
-}
-
-int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)
-{
- struct wid wid_list[5];
- u32 wid_cnt = 0, result;
-
- 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, WILC_GET_CFG, wid_list, wid_cnt);
- if (result) {
- netdev_err(vif->ndev, "Failed to send scan parameters\n");
- return result;
- }
-
- 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 result;
-}
-
-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 rf_info *stats = (struct rf_info *)msg->body.data;
-
- wilc_get_statistics(vif, stats);
-
- kfree(msg);
-}
-
-static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,
- struct station_parameters *params)
-{
- ether_addr_copy(cur_byte, mac);
- cur_byte += ETH_ALEN;
-
- put_unaligned_le16(params->aid, cur_byte);
- cur_byte += 2;
-
- *cur_byte++ = params->supported_rates_len;
- if (params->supported_rates_len > 0)
- memcpy(cur_byte, params->supported_rates,
- params->supported_rates_len);
- cur_byte += params->supported_rates_len;
-
- if (params->ht_capa) {
- *cur_byte++ = true;
- memcpy(cur_byte, ¶ms->ht_capa,
- sizeof(struct ieee80211_ht_cap));
- } else {
- *cur_byte++ = false;
- }
- cur_byte += sizeof(struct ieee80211_ht_cap);
-
- put_unaligned_le16(params->sta_flags_mask, cur_byte);
- cur_byte += 2;
- put_unaligned_le16(params->sta_flags_set, cur_byte);
-}
-
-static int handle_remain_on_chan(struct wilc_vif *vif,
- struct wilc_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->usr_scan_req.scan_result)
- return -EBUSY;
-
- if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
- return -EBUSY;
-
- if (vif->connecting)
- return -EBUSY;
-
- 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)
- return -ENOMEM;
-
- wid.val[0] = remain_on_chan_flag;
- wid.val[1] = (s8)hif_remain_ch->ch;
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- kfree(wid.val);
- if (result)
- return -EBUSY;
-
- 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.ch = hif_remain_ch->ch;
- hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie;
- hif_drv->remain_on_ch_timer_vif = vif;
-
- return 0;
-}
-
-static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)
-{
- 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)
- return -ENOMEM;
-
- wid.val[0] = remain_on_chan_flag;
- wid.val[1] = WILC_FALSE_FRMWR_CHANNEL;
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- kfree(wid.val);
- if (result != 0) {
- netdev_err(vif->ndev, "Failed to set remain channel\n");
- return -EINVAL;
- }
-
- if (hif_drv->remain_on_ch.expired) {
- hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
- cookie);
- }
- } else {
- netdev_dbg(vif->ndev, "Not in listen state\n");
- }
-
- return 0;
-}
-
-static void wilc_handle_listen_state_expired(struct work_struct *work)
-{
- struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-
- wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie);
- 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, wilc_handle_listen_state_expired, false);
- if (IS_ERR(msg))
- return;
-
- msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie;
-
- result = wilc_enqueue_work(msg);
- if (result) {
- netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
- 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 wilc_set_multicast *set_mc = &msg->body.mc_info;
- int result;
- struct wid wid;
- u8 *cur_byte;
-
- wid.id = WID_SETUP_MULTICAST_FILTER;
- wid.type = WID_BIN;
- wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN);
- wid.val = kmalloc(wid.size, GFP_KERNEL);
- if (!wid.val)
- goto error;
-
- cur_byte = wid.val;
- put_unaligned_le32(set_mc->enabled, cur_byte);
- cur_byte += 4;
-
- put_unaligned_le32(set_mc->cnt, cur_byte);
- cur_byte += 4;
-
- if (set_mc->cnt > 0 && set_mc->mc_list)
- memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN);
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to send setup multicast\n");
-
-error:
- kfree(set_mc->mc_list);
- kfree(wid.val);
- kfree(msg);
-}
-
-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_scan_complete(struct work_struct *work)
-{
- struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-
- del_timer(&msg->vif->hif_drv->scan_timer);
-
- handle_scan_done(msg->vif, SCAN_EVENT_DONE);
-
- 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)
-{
- struct wid wid;
- int result;
-
- wid.id = WID_REMOVE_WEP_KEY;
- wid.type = WID_STR;
- wid.size = sizeof(char);
- wid.val = &index;
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev,
- "Failed to send remove wep key config packet\n");
- return result;
-}
-
-int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
-{
- struct wid wid;
- int result;
-
- wid.id = WID_KEY_ID;
- wid.type = WID_CHAR;
- wid.size = sizeof(char);
- wid.val = &index;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev,
- "Failed to send wep default key config packet\n");
-
- return result;
-}
-
-int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
- u8 index)
-{
- struct wid wid;
- int result;
- struct wilc_wep_key *wep_key;
-
- wid.id = WID_ADD_WEP_KEY;
- wid.type = WID_STR;
- wid.size = sizeof(*wep_key) + len;
- wep_key = kzalloc(wid.size, GFP_KERNEL);
- if (!wep_key)
- return -ENOMEM;
-
- wid.val = (u8 *)wep_key;
-
- wep_key->index = index;
- wep_key->key_len = len;
- memcpy(wep_key->key, key, len);
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev,
- "Failed to add wep key config packet\n");
-
- kfree(wep_key);
- 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)
-{
- struct wid wid_list[3];
- int result;
- struct wilc_wep_key *wep_key;
-
- wid_list[0].id = WID_11I_MODE;
- wid_list[0].type = WID_CHAR;
- wid_list[0].size = sizeof(char);
- wid_list[0].val = &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 *)&auth_type;
-
- wid_list[2].id = WID_WEP_KEY_VALUE;
- wid_list[2].type = WID_STR;
- wid_list[2].size = sizeof(*wep_key) + len;
- wep_key = kzalloc(wid_list[2].size, GFP_KERNEL);
- if (!wep_key)
- return -ENOMEM;
-
- wid_list[2].val = (u8 *)wep_key;
-
- wep_key->index = index;
- wep_key->key_len = len;
- memcpy(wep_key->key, key, len);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
- ARRAY_SIZE(wid_list));
- if (result)
- netdev_err(vif->ndev,
- "Failed to add wep ap key config packet\n");
-
- kfree(wep_key);
- 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 = 0;
- u8 t_key_len = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
-
- if (mode == WILC_AP_MODE) {
- struct wid wid_list[2];
- struct wilc_ap_wpa_ptk *key_buf;
-
- wid_list[0].id = WID_11I_MODE;
- wid_list[0].type = WID_CHAR;
- wid_list[0].size = sizeof(char);
- wid_list[0].val = (s8 *)&cipher_mode;
-
- key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
- if (!key_buf)
- return -ENOMEM;
-
- ether_addr_copy(key_buf->mac_addr, mac_addr);
- key_buf->index = index;
- key_buf->key_len = t_key_len;
- memcpy(&key_buf->key[0], ptk, ptk_key_len);
-
- if (rx_mic)
- memcpy(&key_buf->key[ptk_key_len], rx_mic,
- WILC_RX_MIC_KEY_LEN);
-
- if (tx_mic)
- memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
- tx_mic, WILC_TX_MIC_KEY_LEN);
-
- wid_list[1].id = WID_ADD_PTK;
- wid_list[1].type = WID_STR;
- wid_list[1].size = sizeof(*key_buf) + t_key_len;
- wid_list[1].val = (u8 *)key_buf;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
- ARRAY_SIZE(wid_list));
- kfree(key_buf);
- } else if (mode == WILC_STATION_MODE) {
- struct wid wid;
- struct wilc_sta_wpa_ptk *key_buf;
-
- key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
- if (!key_buf)
- return -ENOMEM;
-
- ether_addr_copy(key_buf->mac_addr, mac_addr);
- key_buf->key_len = t_key_len;
- memcpy(&key_buf->key[0], ptk, ptk_key_len);
-
- if (rx_mic)
- memcpy(&key_buf->key[ptk_key_len], rx_mic,
- WILC_RX_MIC_KEY_LEN);
-
- if (tx_mic)
- memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
- tx_mic, WILC_TX_MIC_KEY_LEN);
-
- wid.id = WID_ADD_PTK;
- wid.type = WID_STR;
- wid.size = sizeof(*key_buf) + t_key_len;
- wid.val = (s8 *)key_buf;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- kfree(key_buf);
- }
-
- 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 = 0;
- struct wilc_gtk_key *gtk_key;
- int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
-
- gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL);
- if (!gtk_key)
- return -ENOMEM;
-
- /* fill bssid value only in station mode */
- if (mode == WILC_STATION_MODE &&
- vif->hif_drv->hif_state == HOST_IF_CONNECTED)
- memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN);
-
- if (key_rsc)
- memcpy(gtk_key->rsc, key_rsc, 8);
- gtk_key->index = index;
- gtk_key->key_len = t_key_len;
- memcpy(>k_key->key[0], rx_gtk, gtk_key_len);
-
- if (rx_mic)
- memcpy(>k_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN);
-
- if (tx_mic)
- memcpy(>k_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN],
- tx_mic, WILC_TX_MIC_KEY_LEN);
-
- if (mode == WILC_AP_MODE) {
- struct wid wid_list[2];
-
- wid_list[0].id = WID_11I_MODE;
- wid_list[0].type = WID_CHAR;
- wid_list[0].size = sizeof(char);
- wid_list[0].val = (s8 *)&cipher_mode;
-
- wid_list[1].id = WID_ADD_RX_GTK;
- wid_list[1].type = WID_STR;
- wid_list[1].size = sizeof(*gtk_key) + t_key_len;
- wid_list[1].val = (u8 *)gtk_key;
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
- ARRAY_SIZE(wid_list));
- } else if (mode == WILC_STATION_MODE) {
- struct wid wid;
-
- wid.id = WID_ADD_RX_GTK;
- wid.type = WID_STR;
- wid.size = sizeof(*gtk_key) + t_key_len;
- wid.val = (u8 *)gtk_key;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- }
-
- kfree(gtk_key);
- return result;
-}
-
-int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid)
-{
- struct wid wid;
-
- wid.id = WID_PMKID_INFO;
- wid.type = WID_STR;
- wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1;
- wid.val = (u8 *)pmkid;
-
- return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
-}
-
-int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
-{
- int result;
- struct wid wid;
-
- wid.id = WID_MAC_ADDR;
- wid.type = WID_STR;
- wid.size = ETH_ALEN;
- wid.val = mac_addr;
-
- result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to get mac address\n");
-
- return result;
-}
-
-int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
- size_t ies_len)
-{
- int result;
- struct host_if_drv *hif_drv = vif->hif_drv;
- struct wilc_conn_info *conn_info = &hif_drv->conn_info;
-
- if (bssid)
- ether_addr_copy(conn_info->bssid, bssid);
-
- if (ies) {
- conn_info->req_ies_len = ies_len;
- conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL);
- if (!conn_info->req_ies)
- return -ENOMEM;
- }
-
- result = wilc_send_connect_wid(vif);
- if (result)
- goto free_ies;
-
- hif_drv->connect_timer_vif = vif;
- mod_timer(&hif_drv->connect_timer,
- jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS));
-
- return 0;
-
-free_ies:
- kfree(conn_info->req_ies);
-
- return result;
-}
-
-int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
-{
- struct wid wid;
- int result;
-
- wid.id = WID_CURRENT_CHANNEL;
- wid.type = WID_CHAR;
- wid.size = sizeof(char);
- wid.val = &channel;
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to set channel\n");
-
- return result;
-}
-
-int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
- u8 ifc_id)
-{
- struct wid wid;
- int result;
- struct wilc_drv_handler drv;
-
- wid.id = WID_SET_OPERATION_MODE;
- wid.type = WID_STR;
- wid.size = sizeof(drv);
- wid.val = (u8 *)&drv;
-
- drv.handler = cpu_to_le32(index);
- drv.mode = (ifc_id | (mode << 1));
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to set driver handler\n");
-
- return result;
-}
-
-s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
-{
- struct wid wid;
- s32 result;
-
- wid.id = WID_SET_STA_MAC_INACTIVE_TIME;
- wid.type = WID_STR;
- wid.size = ETH_ALEN;
- wid.val = kzalloc(wid.size, GFP_KERNEL);
- if (!wid.val)
- return -ENOMEM;
-
- ether_addr_copy(wid.val, mac);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- kfree(wid.val);
- if (result) {
- netdev_err(vif->ndev, "Failed to set inactive mac\n");
- return result;
- }
-
- wid.id = WID_GET_INACTIVE_TIME;
- wid.type = WID_INT;
- wid.val = (s8 *)out_val;
- wid.size = sizeof(u32);
- result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to get inactive time\n");
-
- return result;
-}
-
-int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level)
-{
- struct wid wid;
- int result;
-
- if (!rssi_level) {
- netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__);
- return -EFAULT;
- }
-
- wid.id = WID_RSSI;
- wid.type = WID_CHAR;
- wid.size = sizeof(char);
- wid.val = rssi_level;
- result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to get RSSI value\n");
-
- return result;
-}
-
-static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats)
-{
- int result;
- struct host_if_msg *msg;
-
- msg = wilc_alloc_work(vif, handle_get_statistics, false);
- 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;
- }
-
- return result;
-}
-
-int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param)
-{
- struct wid wid_list[4];
- int i = 0;
-
- if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) {
- 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);
- i++;
- }
- if (param->flag & WILC_CFG_PARAM_RETRY_LONG) {
- 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);
- i++;
- }
- if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) {
- 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);
- i++;
- }
- if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) {
- 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);
- i++;
- }
-
- return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, i);
-}
-
-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_stats_async(vif, &vif->periodic_stat);
-
- 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;
-
- hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL);
- if (!hif_drv)
- return -ENOMEM;
-
- *hif_drv_handler = hif_drv;
-
- vif->hif_drv = hif_drv;
-
- if (wilc->clients_count == 0)
- mutex_init(&wilc->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);
-
- hif_drv->hif_state = HOST_IF_IDLE;
-
- hif_drv->p2p_timeout = 0;
-
- 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(&vif->wilc->deinit_lock);
-
- 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);
-
- 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);
- hif_drv->usr_scan_req.scan_result = NULL;
- }
-
- hif_drv->hif_state = HOST_IF_IDLE;
-
- kfree(hif_drv);
- vif->hif_drv = NULL;
- vif->wilc->clients_count--;
- mutex_unlock(&vif->wilc->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 = get_unaligned_le32(&buffer[length - 4]);
- vif = wilc_get_vif_from_idx(wilc, id);
- if (!vif)
- return;
- hif_drv = vif->hif_drv;
-
- if (!hif_drv) {
- 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.frame_len = get_unaligned_le16(&buffer[6]) - 1;
- msg->body.net_info.rssi = buffer[8];
- msg->body.net_info.mgmt = kmemdup(&buffer[9],
- msg->body.net_info.frame_len,
- GFP_KERNEL);
- if (!msg->body.net_info.mgmt) {
- 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.mgmt);
- 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(&wilc->deinit_lock);
-
- id = get_unaligned_le32(&buffer[length - 4]);
- vif = wilc_get_vif_from_idx(wilc, id);
- if (!vif) {
- mutex_unlock(&wilc->deinit_lock);
- return;
- }
-
- hif_drv = vif->hif_drv;
-
- if (!hif_drv) {
- mutex_unlock(&wilc->deinit_lock);
- return;
- }
-
- if (!hif_drv->conn_info.conn_result) {
- netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
- mutex_unlock(&wilc->deinit_lock);
- return;
- }
-
- msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false);
- if (IS_ERR(msg)) {
- mutex_unlock(&wilc->deinit_lock);
- return;
- }
-
- msg->body.mac_info.status = buffer[7];
- result = wilc_enqueue_work(msg);
- if (result) {
- netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
- kfree(msg);
- }
-
- mutex_unlock(&wilc->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 = get_unaligned_le32(&buffer[length - 4]);
- vif = wilc_get_vif_from_idx(wilc, id);
- if (!vif)
- return;
- hif_drv = vif->hif_drv;
-
- if (!hif_drv)
- 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, u64 cookie,
- u32 duration, u16 chan,
- void (*expired)(void *, u64),
- void *user_arg)
-{
- struct wilc_remain_ch roc;
- int result;
-
- roc.ch = chan;
- roc.expired = expired;
- roc.arg = user_arg;
- roc.duration = duration;
- roc.cookie = cookie;
- result = handle_remain_on_chan(vif, &roc);
- if (result)
- netdev_err(vif->ndev, "%s: failed to set remain on channel\n",
- __func__);
-
- return result;
-}
-
-int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie)
-{
- if (!vif->hif_drv) {
- netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
- return -EFAULT;
- }
-
- del_timer(&vif->hif_drv->remain_on_ch_timer);
-
- return wilc_handle_roc_expired(vif, cookie);
-}
-
-void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
-{
- struct wid wid;
- int result;
- struct wilc_reg_frame reg_frame;
-
- wid.id = WID_REGISTER_FRAME;
- wid.type = WID_STR;
- wid.size = sizeof(reg_frame);
- wid.val = (u8 *)®_frame;
-
- memset(®_frame, 0x0, sizeof(reg_frame));
-
- if (reg)
- reg_frame.reg = 1;
-
- switch (frame_type) {
- case IEEE80211_STYPE_ACTION:
- reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX;
- break;
-
- case IEEE80211_STYPE_PROBE_REQ:
- reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX;
- break;
-
- default:
- break;
- }
- reg_frame.frame_type = cpu_to_le16(frame_type);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to frame register\n");
-}
-
-int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
- struct cfg80211_beacon_data *params)
-{
- struct wid wid;
- int result;
- u8 *cur_byte;
-
- wid.id = WID_ADD_BEACON;
- wid.type = WID_BIN;
- wid.size = params->head_len + params->tail_len + 16;
- wid.val = kzalloc(wid.size, GFP_KERNEL);
- if (!wid.val)
- return -ENOMEM;
-
- cur_byte = wid.val;
- put_unaligned_le32(interval, cur_byte);
- cur_byte += 4;
- put_unaligned_le32(dtim_period, cur_byte);
- cur_byte += 4;
- put_unaligned_le32(params->head_len, cur_byte);
- cur_byte += 4;
-
- if (params->head_len > 0)
- memcpy(cur_byte, params->head, params->head_len);
- cur_byte += params->head_len;
-
- put_unaligned_le32(params->tail_len, cur_byte);
- cur_byte += 4;
-
- if (params->tail_len > 0)
- memcpy(cur_byte, params->tail, params->tail_len);
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to send add beacon\n");
-
- kfree(wid.val);
-
- return result;
-}
-
-int wilc_del_beacon(struct wilc_vif *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, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to send delete beacon\n");
-
- return result;
-}
-
-int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
- struct station_parameters *params)
-{
- struct wid wid;
- int result;
- u8 *cur_byte;
-
- wid.id = WID_ADD_STA;
- wid.type = WID_BIN;
- wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
- wid.val = kmalloc(wid.size, GFP_KERNEL);
- if (!wid.val)
- return -ENOMEM;
-
- cur_byte = wid.val;
- wilc_hif_pack_sta_param(cur_byte, mac, params);
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result != 0)
- netdev_err(vif->ndev, "Failed to send add station\n");
-
- kfree(wid.val);
-
- return result;
-}
-
-int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)
-{
- struct wid wid;
- int result;
-
- wid.id = WID_REMOVE_STA;
- wid.type = WID_BIN;
- wid.size = ETH_ALEN;
- wid.val = kzalloc(wid.size, GFP_KERNEL);
- if (!wid.val)
- return -ENOMEM;
-
- if (!mac_addr)
- eth_broadcast_addr(wid.val);
- else
- ether_addr_copy(wid.val, mac_addr);
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to del station\n");
-
- kfree(wid.val);
-
- return result;
-}
-
-int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])
-{
- struct wid wid;
- int result;
- int i;
- u8 assoc_sta = 0;
- struct wilc_del_all_sta del_sta;
-
- memset(&del_sta, 0x0, sizeof(del_sta));
- for (i = 0; i < WILC_MAX_NUM_STA; i++) {
- if (!is_zero_ether_addr(mac_addr[i])) {
- assoc_sta++;
- ether_addr_copy(del_sta.mac[i], mac_addr[i]);
- }
- }
-
- if (!assoc_sta)
- return 0;
-
- del_sta.assoc_sta = assoc_sta;
-
- wid.id = WID_DEL_ALL_STA;
- wid.type = WID_STR;
- wid.size = (assoc_sta * ETH_ALEN) + 1;
- wid.val = (u8 *)&del_sta;
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to send delete all station\n");
-
- return result;
-}
-
-int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
- struct station_parameters *params)
-{
- struct wid wid;
- int result;
- u8 *cur_byte;
-
- wid.id = WID_EDIT_STA;
- wid.type = WID_BIN;
- wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
- wid.val = kmalloc(wid.size, GFP_KERNEL);
- if (!wid.val)
- return -ENOMEM;
-
- cur_byte = wid.val;
- wilc_hif_pack_sta_param(cur_byte, mac, params);
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to send edit station\n");
-
- kfree(wid.val);
- return result;
-}
-
-int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
-{
- struct wid wid;
- int result;
- s8 power_mode;
-
- if (enabled)
- power_mode = WILC_FW_MIN_FAST_PS;
- else
- power_mode = WILC_FW_NO_POWERSAVE;
-
- wid.id = WID_POWER_MANAGEMENT;
- wid.val = &power_mode;
- wid.size = sizeof(char);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to send power management\n");
-
- return result;
-}
-
-int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 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.mc_info.enabled = enabled;
- msg->body.mc_info.cnt = count;
- msg->body.mc_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)
-{
- struct wid wid;
-
- wid.id = WID_TX_POWER;
- wid.type = WID_CHAR;
- wid.val = &tx_power;
- wid.size = sizeof(char);
-
- return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
-}
-
-int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
-{
- struct wid wid;
-
- wid.id = WID_TX_POWER;
- wid.type = WID_CHAR;
- wid.val = tx_power;
- wid.size = sizeof(char);
-
- return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries
- * All rights reserved.
- */
-
-#ifndef HOST_INT_H
-#define HOST_INT_H
-#include <linux/ieee80211.h>
-#include "wilc_wlan_if.h"
-
-enum {
- WILC_IDLE_MODE = 0x0,
- WILC_AP_MODE = 0x1,
- WILC_STATION_MODE = 0x2,
- WILC_GO_MODE = 0x3,
- WILC_CLIENT_MODE = 0x4
-};
-
-#define WILC_MAX_NUM_STA 9
-#define WILC_MAX_NUM_SCANNED_CH 14
-#define WILC_MAX_NUM_PROBED_SSID 10
-
-#define WILC_TX_MIC_KEY_LEN 8
-#define WILC_RX_MIC_KEY_LEN 8
-
-#define WILC_MAX_NUM_PMKIDS 16
-#define WILC_ADD_STA_LENGTH 40
-#define WILC_NUM_CONCURRENT_IFC 2
-
-enum {
- WILC_SET_CFG = 0,
- WILC_GET_CFG
-};
-
-#define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256
-
-struct assoc_resp {
- __le16 capab_info;
- __le16 status_code;
- __le16 aid;
-} __packed;
-
-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 wilc_pmkid {
- u8 bssid[ETH_ALEN];
- u8 pmkid[WLAN_PMKID_LEN];
-} __packed;
-
-struct wilc_pmkid_attr {
- u8 numpmkid;
- struct wilc_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS];
-} __packed;
-
-struct cfg_param_attr {
- u32 flag;
- u16 short_retry_limit;
- u16 long_retry_limit;
- u16 frag_threshold;
- u16 rts_threshold;
-};
-
-enum cfg_param {
- WILC_CFG_PARAM_RETRY_SHORT = BIT(0),
- WILC_CFG_PARAM_RETRY_LONG = BIT(1),
- WILC_CFG_PARAM_FRAG_THRESHOLD = BIT(2),
- WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3)
-};
-
-enum scan_event {
- SCAN_EVENT_NETWORK_FOUND = 0,
- SCAN_EVENT_DONE = 1,
- SCAN_EVENT_ABORTED = 2,
- SCAN_EVENT_FORCE_32BIT = 0xFFFFFFFF
-};
-
-enum conn_event {
- CONN_DISCONN_EVENT_CONN_RESP = 0,
- CONN_DISCONN_EVENT_DISCONN_NOTIF = 1,
- CONN_DISCONN_EVENT_FORCE_32BIT = 0xFFFFFFFF
-};
-
-enum {
- WILC_HIF_SDIO = 0,
- WILC_HIF_SPI = BIT(0)
-};
-
-enum {
- WILC_MAC_STATUS_INIT = -1,
- WILC_MAC_STATUS_DISCONNECTED = 0,
- WILC_MAC_STATUS_CONNECTED = 1
-};
-
-struct wilc_rcvd_net_info {
- s8 rssi;
- u8 ch;
- u16 frame_len;
- struct ieee80211_mgmt *mgmt;
-};
-
-struct wilc_user_scan_req {
- void (*scan_result)(enum scan_event evt,
- struct wilc_rcvd_net_info *info, void *priv);
- void *arg;
- u32 ch_cnt;
-};
-
-struct wilc_conn_info {
- u8 bssid[ETH_ALEN];
- u8 security;
- enum authtype auth_type;
- u8 ch;
- u8 *req_ies;
- size_t req_ies_len;
- u8 *resp_ies;
- u16 resp_ies_len;
- u16 status;
- void (*conn_result)(enum conn_event evt, u8 status, void *priv_data);
- void *arg;
- void *param;
-};
-
-struct wilc_remain_ch {
- u16 ch;
- u32 duration;
- void (*expired)(void *priv, u64 cookie);
- void *arg;
- u32 cookie;
-};
-
-struct wilc;
-struct host_if_drv {
- struct wilc_user_scan_req usr_scan_req;
- struct wilc_conn_info conn_info;
- struct wilc_remain_ch remain_on_ch;
- u64 p2p_timeout;
-
- enum host_if_state hif_state;
-
- u8 assoc_bssid[ETH_ALEN];
-
- struct timer_list scan_timer;
- struct wilc_vif *scan_timer_vif;
-
- struct timer_list connect_timer;
- struct wilc_vif *connect_timer_vif;
-
- struct timer_list remain_on_ch_timer;
- struct wilc_vif *remain_on_ch_timer_vif;
-
- bool ifc_up;
- u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
-};
-
-struct wilc_vif;
-int wilc_remove_wep_key(struct wilc_vif *vif, u8 index);
-int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index);
-int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
- u8 index);
-int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
- u8 index, u8 mode, enum authtype auth_type);
-int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
- const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
- u8 mode, u8 cipher_mode, u8 index);
-s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
- u32 *out_val);
-int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
- u8 index, u32 key_rsc_len, const u8 *key_rsc,
- const u8 *rx_mic, const u8 *tx_mic, u8 mode,
- u8 cipher_mode);
-int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid);
-int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr);
-int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
- size_t ies_len);
-int wilc_disconnect(struct wilc_vif *vif);
-int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel);
-int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level);
-int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
- u8 *ch_freq_list, u8 ch_list_len,
- void (*scan_result_fn)(enum scan_event,
- struct wilc_rcvd_net_info *, void *),
- void *user_arg, struct cfg80211_scan_request *request);
-int wilc_hif_set_cfg(struct wilc_vif *vif,
- struct cfg_param_attr *cfg_param);
-int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler);
-int wilc_deinit(struct wilc_vif *vif);
-int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
- struct cfg80211_beacon_data *params);
-int wilc_del_beacon(struct wilc_vif *vif);
-int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
- struct station_parameters *params);
-int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]);
-int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr);
-int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
- struct station_parameters *params);
-int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
-int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
- u8 *mc_list);
-int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
- u32 duration, u16 chan,
- void (*expired)(void *, u64),
- void *user_arg);
-int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie);
-void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
-int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
- u8 ifc_id);
-int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats);
-int wilc_get_vif_idx(struct wilc_vif *vif);
-int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
-int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
-void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length);
-void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length);
-void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length);
-void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
- struct cfg80211_crypto_settings *crypto);
-#endif
+++ /dev/null
-// 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;
-
-#define TX_RADIOTAP_PRESENT ((1 << IEEE80211_RADIOTAP_RATE) | \
- (1 << IEEE80211_RADIOTAP_TX_FLAGS))
-
-void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size)
-{
- u32 header, pkt_offset;
- struct sk_buff *skb = NULL;
- struct wilc_wfi_radiotap_hdr *hdr;
- struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
-
- if (!mon_dev)
- return;
-
- if (!netif_running(mon_dev))
- return;
-
- /* Get WILC header */
- header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
- /*
- * The packet offset field contain info about what type of management
- * the frame we are dealing with and ack status
- */
- pkt_offset = 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 = mon_dev;
- skb_reset_mac_header(skb);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = htons(ETH_P_802_2);
- memset(skb->cb, 0, sizeof(skb->cb));
-
- netif_rx(skb);
-}
-
-struct tx_complete_mon_data {
- int size;
- void *buff;
-};
-
-static void mgmt_tx_complete(void *priv, int status)
-{
- struct tx_complete_mon_data *pv_data = priv;
- /*
- * in case of fully hosting mode, the freeing will be done
- * in response to the cfg packet
- */
- kfree(pv_data->buff);
-
- kfree(pv_data);
-}
-
-static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
-{
- struct tx_complete_mon_data *mgmt_tx = NULL;
-
- if (!dev)
- return -EFAULT;
-
- netif_stop_queue(dev);
- mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_ATOMIC);
- if (!mgmt_tx)
- return -ENOMEM;
-
- mgmt_tx->buff = kmemdup(buf, len, GFP_ATOMIC);
- if (!mgmt_tx->buff) {
- kfree(mgmt_tx);
- return -ENOMEM;
- }
-
- mgmt_tx->size = len;
-
- wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
- mgmt_tx_complete);
-
- netif_wake_queue(dev);
- return 0;
-}
-
-static netdev_tx_t wilc_wfi_mon_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- u32 rtap_len, ret = 0;
- struct wilc_wfi_mon_priv *mon_priv;
- struct sk_buff *skb2;
- struct wilc_wfi_radiotap_cb_hdr *cb_hdr;
- u8 srcadd[ETH_ALEN];
- u8 bssid[ETH_ALEN];
-
- mon_priv = netdev_priv(dev);
- if (!mon_priv)
- return -EFAULT;
-
- rtap_len = ieee80211_get_radiotap_len(skb->data);
- if (skb->len < rtap_len)
- return -1;
-
- skb_pull(skb, rtap_len);
-
- if (skb->data[0] == 0xc0 && is_broadcast_ether_addr(&skb->data[4])) {
- skb2 = dev_alloc_skb(skb->len + sizeof(*cb_hdr));
- if (!skb2)
- return -ENOMEM;
-
- skb_put_data(skb2, skb->data, skb->len);
-
- cb_hdr = skb_push(skb2, sizeof(*cb_hdr));
- memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr));
-
- cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */
-
- cb_hdr->hdr.it_len = cpu_to_le16(sizeof(*cb_hdr));
-
- cb_hdr->hdr.it_present = cpu_to_le32(TX_RADIOTAP_PRESENT);
-
- cb_hdr->rate = 5;
- cb_hdr->tx_flags = 0x0004;
-
- skb2->dev = dev;
- skb_reset_mac_header(skb2);
- skb2->ip_summed = CHECKSUM_UNNECESSARY;
- skb2->pkt_type = PACKET_OTHERHOST;
- skb2->protocol = htons(ETH_P_802_2);
- memset(skb2->cb, 0, sizeof(skb2->cb));
-
- netif_rx(skb2);
-
- return 0;
- }
- skb->dev = mon_priv->real_ndev;
-
- ether_addr_copy(srcadd, &skb->data[10]);
- ether_addr_copy(bssid, &skb->data[16]);
- /*
- * Identify if data or mgmt packet, if source address and bssid
- * fields are equal send it to mgmt frames handler
- */
- if (!(memcmp(srcadd, bssid, 6))) {
- ret = mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len);
- if (ret)
- netdev_err(dev, "fail to mgmt tx\n");
- dev_kfree_skb(skb);
- } else {
- ret = wilc_mac_xmit(skb, mon_priv->real_ndev);
- }
-
- return ret;
-}
-
-static const struct net_device_ops wilc_wfi_netdev_ops = {
- .ndo_start_xmit = wilc_wfi_mon_xmit,
-
-};
-
-struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
- const char *name,
- struct net_device *real_dev)
-{
- struct wilc_wfi_mon_priv *priv;
-
- /*If monitor interface is already initialized, return it*/
- if (wl->monitor_dev)
- return wl->monitor_dev;
-
- wl->monitor_dev = alloc_etherdev(sizeof(struct wilc_wfi_mon_priv));
- if (!wl->monitor_dev)
- return NULL;
-
- wl->monitor_dev->type = ARPHRD_IEEE80211_RADIOTAP;
- strncpy(wl->monitor_dev->name, name, IFNAMSIZ);
- wl->monitor_dev->name[IFNAMSIZ - 1] = 0;
- wl->monitor_dev->netdev_ops = &wilc_wfi_netdev_ops;
- wl->monitor_dev->needs_free_netdev = true;
-
- if (register_netdevice(wl->monitor_dev)) {
- netdev_err(real_dev, "register_netdevice failed\n");
- return NULL;
- }
- priv = netdev_priv(wl->monitor_dev);
- if (!priv)
- return NULL;
-
- priv->real_ndev = real_dev;
-
- return wl->monitor_dev;
-}
-
-void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked)
-{
- if (!wl->monitor_dev)
- return;
-
- if (rtnl_locked)
- unregister_netdevice(wl->monitor_dev);
- else
- unregister_netdev(wl->monitor_dev);
- wl->monitor_dev = NULL;
-}
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#include <linux/irq.h>
-#include <linux/kthread.h>
-#include <linux/firmware.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-
-#include "wilc_wfi_cfgoperations.h"
-#include "wilc_wlan_cfg.h"
-
-#define WILC_MULTICAST_TABLE_SIZE 8
-
-static irqreturn_t isr_uh_routine(int irq, void *user_data)
-{
- struct net_device *dev = user_data;
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wilc = vif->wilc;
-
- if (wilc->close) {
- netdev_err(dev, "Can't handle UH interrupt\n");
- return IRQ_HANDLED;
- }
- return IRQ_WAKE_THREAD;
-}
-
-static irqreturn_t isr_bh_routine(int irq, void *userdata)
-{
- struct net_device *dev = userdata;
- struct wilc_vif *vif = netdev_priv(userdata);
- struct wilc *wilc = vif->wilc;
-
- if (wilc->close) {
- netdev_err(dev, "Can't handle BH interrupt\n");
- return IRQ_HANDLED;
- }
-
- wilc_handle_isr(wilc);
-
- return IRQ_HANDLED;
-}
-
-static int init_irq(struct net_device *dev)
-{
- int ret = 0;
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wl = vif->wilc;
-
- ret = gpiod_direction_input(wl->gpio_irq);
- if (ret) {
- netdev_err(dev, "could not obtain gpio for WILC_INTR\n");
- return ret;
- }
-
- wl->dev_irq_num = gpiod_to_irq(wl->gpio_irq);
-
- ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine,
- isr_bh_routine,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- "WILC_IRQ", dev);
- if (ret < 0)
- netdev_err(dev, "Failed to request IRQ\n");
- else
- netdev_dbg(dev, "IRQ request succeeded IRQ-NUM= %d\n",
- wl->dev_irq_num);
-
- return ret;
-}
-
-static void deinit_irq(struct net_device *dev)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wilc = vif->wilc;
-
- /* Deinitialize IRQ */
- if (wilc->dev_irq_num)
- free_irq(wilc->dev_irq_num, wilc);
-}
-
-void wilc_mac_indicate(struct wilc *wilc)
-{
- s8 status;
-
- wilc_wlan_cfg_get_val(wilc, WID_STATUS, &status, 1);
- if (wilc->mac_status == WILC_MAC_STATUS_INIT) {
- wilc->mac_status = status;
- complete(&wilc->sync_event);
- } else {
- wilc->mac_status = status;
- }
-}
-
-static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
-{
- u8 *bssid, *bssid1;
- struct net_device *ndev = NULL;
- struct wilc_vif *vif;
-
- bssid = mac_header + 10;
- bssid1 = mac_header + 4;
-
- list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
- if (vif->mode == WILC_STATION_MODE)
- if (ether_addr_equal_unaligned(bssid, vif->bssid)) {
- ndev = vif->ndev;
- goto out;
- }
- if (vif->mode == WILC_AP_MODE)
- if (ether_addr_equal_unaligned(bssid1, vif->bssid)) {
- ndev = vif->ndev;
- goto out;
- }
- }
-out:
- return ndev;
-}
-
-void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
-{
- struct wilc_vif *vif = netdev_priv(wilc_netdev);
-
- if (bssid)
- ether_addr_copy(vif->bssid, bssid);
- else
- eth_zero_addr(vif->bssid);
-
- vif->mode = mode;
-}
-
-int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
-{
- int srcu_idx;
- u8 ret_val = 0;
- struct wilc_vif *vif;
-
- srcu_idx = srcu_read_lock(&wilc->srcu);
- list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
- if (!is_zero_ether_addr(vif->bssid))
- ret_val++;
- }
- srcu_read_unlock(&wilc->srcu, srcu_idx);
- return ret_val;
-}
-
-static int wilc_txq_task(void *vp)
-{
- int ret;
- u32 txq_count;
- struct wilc *wl = vp;
-
- complete(&wl->txq_thread_started);
- while (1) {
- wait_for_completion(&wl->txq_event);
-
- if (wl->close) {
- complete(&wl->txq_thread_started);
-
- while (!kthread_should_stop())
- schedule();
- break;
- }
- do {
- ret = wilc_wlan_handle_txq(wl, &txq_count);
- if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
- int srcu_idx;
- struct wilc_vif *ifc;
-
- srcu_idx = srcu_read_lock(&wl->srcu);
- list_for_each_entry_rcu(ifc, &wl->vif_list,
- list) {
- if (ifc->mac_opened && ifc->ndev)
- netif_wake_queue(ifc->ndev);
- }
- srcu_read_unlock(&wl->srcu, srcu_idx);
- }
- } while (ret == -ENOBUFS && !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 wilc_start_firmware(struct net_device *dev)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wilc = vif->wilc;
- int ret = 0;
-
- ret = wilc_wlan_start(wilc);
- if (ret < 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 wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif)
-{
- struct wilc_priv *priv = &vif->priv;
- struct host_if_drv *hif_drv;
- u8 b;
- u16 hw;
- u32 w;
-
- netdev_dbg(dev, "Start configuring Firmware\n");
- hif_drv = (struct host_if_drv *)priv->hif_drv;
- netdev_dbg(dev, "Host = %p\n", hif_drv);
-
- w = vif->iftype;
- cpu_to_le32s(&w);
- if (!wilc_wlan_cfg_set(vif, 1, WID_SET_OPERATION_MODE, (u8 *)&w, 4,
- 0, 0))
- goto fail;
-
- b = WILC_FW_BSS_TYPE_INFRA;
- if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_TX_RATE_AUTO;
- if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_OPER_MODE_G_MIXED_11B_2;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_PREAMBLE_SHORT;
- if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_11N_PROT_AUTO;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_ACTIVE_SCAN;
- if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_SITE_SURVEY_OFF;
- if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, &b, 1, 0, 0))
- goto fail;
-
- hw = 0xffff;
- cpu_to_le16s(&hw);
- if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, (u8 *)&hw, 2, 0, 0))
- goto fail;
-
- hw = 2346;
- cpu_to_le16s(&hw);
- if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, (u8 *)&hw, 2, 0, 0))
- goto fail;
-
- b = 0;
- if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, &b, 1, 0, 0))
- goto fail;
-
- b = 1;
- if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_NO_POWERSAVE;
- if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_SEC_NO;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_AUTH_OPEN_SYSTEM;
- if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, &b, 1, 0, 0))
- goto fail;
-
- b = 3;
- if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, &b, 1, 0, 0))
- goto fail;
-
- b = 3;
- if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_ACK_POLICY_NORMAL;
- if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, &b, 1, 0, 0))
- goto fail;
-
- b = 0;
- if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, &b, 1,
- 0, 0))
- goto fail;
-
- b = 48;
- if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, &b, 1, 0, 0))
- goto fail;
-
- b = 28;
- if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, &b, 1, 0, 0))
- goto fail;
-
- hw = 100;
- cpu_to_le16s(&hw);
- if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, (u8 *)&hw, 2, 0, 0))
- goto fail;
-
- b = WILC_FW_REKEY_POLICY_DISABLE;
- if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, &b, 1, 0, 0))
- goto fail;
-
- w = 84600;
- cpu_to_le32s(&w);
- if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, (u8 *)&w, 4, 0, 0))
- goto fail;
-
- w = 500;
- cpu_to_le32s(&w);
- if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, (u8 *)&w, 4, 0,
- 0))
- goto fail;
-
- b = 1;
- if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, &b, 1, 0,
- 0))
- goto fail;
-
- b = WILC_FW_ERP_PROT_SELF_CTS;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, &b, 1, 0, 0))
- goto fail;
-
- b = 1;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_11N_OP_MODE_HT_MIXED;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, &b, 1, 0, 0))
- goto fail;
-
- b = 1;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, &b, 1, 0, 0))
- goto fail;
-
- b = WILC_FW_OBBS_NONHT_DETECT_PROTECT_REPORT;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, &b, 1,
- 0, 0))
- goto fail;
-
- b = WILC_FW_HT_PROT_RTS_CTS_NONHT;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, &b, 1, 0, 0))
- goto fail;
-
- b = 0;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, &b, 1, 0,
- 0))
- goto fail;
-
- b = 7;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, &b, 1, 0, 0))
- goto fail;
-
- b = 1;
- if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, &b, 1,
- 1, 1))
- goto fail;
-
- return 0;
-
-fail:
- return -1;
-}
-
-static void wlan_deinitialize_threads(struct net_device *dev)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wl = vif->wilc;
-
- wl->close = 1;
-
- complete(&wl->txq_event);
-
- if (wl->txq_thread) {
- kthread_stop(wl->txq_thread);
- wl->txq_thread = NULL;
- }
-}
-
-static void wilc_wlan_deinitialize(struct net_device *dev)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wl = vif->wilc;
-
- if (!wl) {
- netdev_err(dev, "wl is NULL\n");
- return;
- }
-
- if (wl->initialized) {
- netdev_info(dev, "Deinitializing wilc1000...\n");
-
- if (!wl->dev_irq_num &&
- wl->hif_func->disable_interrupt) {
- mutex_lock(&wl->hif_cs);
- wl->hif_func->disable_interrupt(wl);
- mutex_unlock(&wl->hif_cs);
- }
- complete(&wl->txq_event);
-
- wlan_deinitialize_threads(dev);
- deinit_irq(dev);
-
- wilc_wlan_stop(wl, vif);
- wilc_wlan_cleanup(dev);
-
- wl->initialized = false;
-
- netdev_dbg(dev, "wilc1000 deinitialization Done\n");
- } else {
- netdev_dbg(dev, "wilc1000 is not initialized\n");
- }
-}
-
-static int wlan_initialize_threads(struct net_device *dev)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wilc = vif->wilc;
-
- wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc,
- "K_TXQ_TASK");
- if (IS_ERR(wilc->txq_thread)) {
- netdev_err(dev, "couldn't create TXQ thread\n");
- wilc->close = 0;
- return PTR_ERR(wilc->txq_thread);
- }
- wait_for_completion(&wilc->txq_thread_started);
-
- return 0;
-}
-
-static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
-{
- int ret = 0;
- struct wilc *wl = vif->wilc;
-
- if (!wl->initialized) {
- wl->mac_status = WILC_MAC_STATUS_INIT;
- wl->close = 0;
-
- ret = wilc_wlan_init(dev);
- if (ret < 0)
- return -EIO;
-
- ret = wlan_initialize_threads(dev);
- if (ret < 0) {
- ret = -EIO;
- goto fail_wilc_wlan;
- }
-
- if (wl->gpio_irq && init_irq(dev)) {
- ret = -EIO;
- goto fail_threads;
- }
-
- if (!wl->dev_irq_num &&
- wl->hif_func->enable_interrupt &&
- wl->hif_func->enable_interrupt(wl)) {
- ret = -EIO;
- goto fail_irq_init;
- }
-
- 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 = wilc_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 = wilc_init_fw_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, vif);
-
-fail_irq_enable:
- if (!wl->dev_irq_num &&
- wl->hif_func->disable_interrupt)
- wl->hif_func->disable_interrupt(wl);
-fail_irq_init:
- if (wl->dev_irq_num)
- deinit_irq(dev);
-fail_threads:
- wlan_deinitialize_threads(dev);
-fail_wilc_wlan:
- wilc_wlan_cleanup(dev);
- netdev_err(dev, "WLAN initialization FAILED\n");
- } else {
- netdev_dbg(dev, "wilc1000 already initialized\n");
- }
- return ret;
-}
-
-static int mac_init_fn(struct net_device *ndev)
-{
- netif_start_queue(ndev);
- netif_stop_queue(ndev);
-
- return 0;
-}
-
-static int wilc_mac_open(struct net_device *ndev)
-{
- struct wilc_vif *vif = netdev_priv(ndev);
- struct wilc *wl = vif->wilc;
- struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
- unsigned char mac_add[ETH_ALEN] = {0};
- int ret = 0;
-
- if (!wl || !wl->dev) {
- netdev_err(ndev, "device not ready\n");
- return -ENODEV;
- }
-
- netdev_dbg(ndev, "MAC OPEN[%p]\n", ndev);
-
- ret = wilc_init_host_int(ndev);
- if (ret < 0)
- return ret;
-
- ret = wilc_wlan_initialize(ndev, vif);
- if (ret < 0) {
- wilc_deinit_host_int(ndev);
- return ret;
- }
-
- wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype,
- vif->idx);
- wilc_get_mac_address(vif, mac_add);
- netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
- ether_addr_copy(ndev->dev_addr, mac_add);
-
- if (!is_valid_ether_addr(ndev->dev_addr)) {
- netdev_err(ndev, "Wrong MAC address\n");
- wilc_deinit_host_int(ndev);
- wilc_wlan_deinitialize(ndev);
- return -EINVAL;
- }
-
- wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
- vif->ndev->ieee80211_ptr,
- vif->frame_reg[0].type,
- vif->frame_reg[0].reg);
- wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
- vif->ndev->ieee80211_ptr,
- vif->frame_reg[1].type,
- vif->frame_reg[1].reg);
- netif_wake_queue(ndev);
- wl->open_ifcs++;
- 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, 0, 0, NULL);
- return;
- }
-
- if (dev->mc.count == 0) {
- wilc_setup_multicast_filter(vif, 1, 0, NULL);
- return;
- }
-
- mc_list = kmalloc_array(dev->mc.count, ETH_ALEN, GFP_ATOMIC);
- if (!mc_list)
- return;
-
- cur_mc = mc_list;
- i = 0;
- netdev_for_each_mc_addr(ha, dev) {
- memcpy(cur_mc, ha->addr, ETH_ALEN);
- netdev_dbg(dev, "Entry[%d]: %pM\n", i, cur_mc);
- i++;
- cur_mc += ETH_ALEN;
- }
-
- if (wilc_setup_multicast_filter(vif, 1, dev->mc.count, mc_list))
- kfree(mc_list);
-}
-
-static void wilc_tx_complete(void *priv, int status)
-{
- struct tx_complete_data *pv_data = priv;
-
- dev_kfree_skb(pv_data->skb);
- kfree(pv_data);
-}
-
-netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
- struct wilc_vif *vif = netdev_priv(ndev);
- struct wilc *wilc = vif->wilc;
- struct tx_complete_data *tx_data = NULL;
- int queue_count;
-
- if (skb->dev != ndev) {
- netdev_err(ndev, "Packet not destined to this device\n");
- return 0;
- }
-
- tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
- if (!tx_data) {
- dev_kfree_skb(skb);
- netif_wake_queue(ndev);
- return 0;
- }
-
- tx_data->buff = skb->data;
- tx_data->size = skb->len;
- tx_data->skb = skb;
-
- vif->netstats.tx_packets++;
- vif->netstats.tx_bytes += tx_data->size;
- queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
- tx_data->buff, tx_data->size,
- wilc_tx_complete);
-
- if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
- int srcu_idx;
- struct wilc_vif *vif;
-
- srcu_idx = srcu_read_lock(&wilc->srcu);
- list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
- if (vif->mac_opened)
- netif_stop_queue(vif->ndev);
- }
- srcu_read_unlock(&wilc->srcu, srcu_idx);
- }
-
- return 0;
-}
-
-static int wilc_mac_close(struct net_device *ndev)
-{
- struct wilc_vif *vif = netdev_priv(ndev);
- struct wilc *wl = vif->wilc;
-
- netdev_dbg(ndev, "Mac close\n");
-
- if (wl->open_ifcs > 0)
- wl->open_ifcs--;
- else
- return 0;
-
- if (vif->ndev) {
- netif_stop_queue(vif->ndev);
-
- wilc_deinit_host_int(vif->ndev);
- }
-
- if (wl->open_ifcs == 0) {
- netdev_dbg(ndev, "Deinitializing wilc1000\n");
- wl->close = 1;
- wilc_wlan_deinitialize(ndev);
- }
-
- vif->mac_opened = 0;
-
- return 0;
-}
-
-void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size,
- u32 pkt_offset)
-{
- unsigned int frame_len = 0;
- int stats;
- unsigned char *buff_to_send = NULL;
- struct sk_buff *skb;
- struct net_device *wilc_netdev;
- struct wilc_vif *vif;
-
- if (!wilc)
- return;
-
- wilc_netdev = get_if_handler(wilc, buff);
- if (!wilc_netdev)
- return;
-
- buff += pkt_offset;
- vif = netdev_priv(wilc_netdev);
-
- if (size > 0) {
- frame_len = size;
- buff_to_send = buff;
-
- skb = dev_alloc_skb(frame_len);
- if (!skb)
- return;
-
- skb->dev = wilc_netdev;
-
- skb_put_data(skb, buff_to_send, frame_len);
-
- skb->protocol = eth_type_trans(skb, wilc_netdev);
- vif->netstats.rx_packets++;
- vif->netstats.rx_bytes += frame_len;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- stats = netif_rx(skb);
- netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats);
- }
-}
-
-void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
-{
- int srcu_idx;
- struct wilc_vif *vif;
-
- srcu_idx = srcu_read_lock(&wilc->srcu);
- list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
- u16 type = le16_to_cpup((__le16 *)buff);
-
- if (vif->priv.p2p_listen_state &&
- ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
- (type == vif->frame_reg[1].type && vif->frame_reg[1].reg)))
- wilc_wfi_p2p_rx(vif, buff, size);
-
- if (vif->monitor_flag)
- wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size);
- }
- srcu_read_unlock(&wilc->srcu, srcu_idx);
-}
-
-static const struct net_device_ops wilc_netdev_ops = {
- .ndo_init = mac_init_fn,
- .ndo_open = wilc_mac_open,
- .ndo_stop = wilc_mac_close,
- .ndo_start_xmit = wilc_mac_xmit,
- .ndo_get_stats = mac_stats,
- .ndo_set_rx_mode = wilc_set_multicast_list,
-};
-
-void wilc_netdev_cleanup(struct wilc *wilc)
-{
- struct wilc_vif *vif;
- int srcu_idx;
-
- if (!wilc)
- return;
-
- if (wilc->firmware) {
- release_firmware(wilc->firmware);
- wilc->firmware = NULL;
- }
-
- srcu_idx = srcu_read_lock(&wilc->srcu);
- list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
- if (vif->ndev)
- unregister_netdev(vif->ndev);
- }
- srcu_read_unlock(&wilc->srcu, srcu_idx);
-
- wilc_wfi_deinit_mon_interface(wilc, false);
- flush_workqueue(wilc->hif_workqueue);
- destroy_workqueue(wilc->hif_workqueue);
-
- do {
- mutex_lock(&wilc->vif_mutex);
- if (wilc->vif_num <= 0) {
- mutex_unlock(&wilc->vif_mutex);
- break;
- }
- vif = wilc_get_wl_to_vif(wilc);
- if (!IS_ERR(vif))
- list_del_rcu(&vif->list);
-
- wilc->vif_num--;
- mutex_unlock(&wilc->vif_mutex);
- synchronize_srcu(&wilc->srcu);
- } while (1);
-
- wilc_wlan_cfg_deinit(wilc);
- wlan_deinit_locks(wilc);
- kfree(wilc->bus_data);
- wiphy_unregister(wilc->wiphy);
- wiphy_free(wilc->wiphy);
-}
-EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
-
-static u8 wilc_get_available_idx(struct wilc *wl)
-{
- int idx = 0;
- struct wilc_vif *vif;
- int srcu_idx;
-
- srcu_idx = srcu_read_lock(&wl->srcu);
- list_for_each_entry_rcu(vif, &wl->vif_list, list) {
- if (vif->idx == 0)
- idx = 1;
- else
- idx = 0;
- }
- srcu_read_unlock(&wl->srcu, srcu_idx);
- return idx;
-}
-
-struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
- int vif_type, enum nl80211_iftype type,
- bool rtnl_locked)
-{
- struct net_device *ndev;
- struct wilc_vif *vif;
- int ret;
-
- ndev = alloc_etherdev(sizeof(*vif));
- if (!ndev)
- return ERR_PTR(-ENOMEM);
-
- vif = netdev_priv(ndev);
- ndev->ieee80211_ptr = &vif->priv.wdev;
- strcpy(ndev->name, name);
- vif->wilc = wl;
- vif->ndev = ndev;
- ndev->ml_priv = vif;
-
- ndev->netdev_ops = &wilc_netdev_ops;
-
- SET_NETDEV_DEV(ndev, wiphy_dev(wl->wiphy));
-
- vif->priv.wdev.wiphy = wl->wiphy;
- vif->priv.wdev.netdev = ndev;
- vif->priv.wdev.iftype = type;
- vif->priv.dev = ndev;
-
- if (rtnl_locked)
- ret = register_netdevice(ndev);
- else
- ret = register_netdev(ndev);
-
- if (ret) {
- free_netdev(ndev);
- return ERR_PTR(-EFAULT);
- }
-
- ndev->needs_free_netdev = true;
- vif->iftype = vif_type;
- vif->idx = wilc_get_available_idx(wl);
- vif->mac_opened = 0;
- mutex_lock(&wl->vif_mutex);
- list_add_tail_rcu(&vif->list, &wl->vif_list);
- wl->vif_num += 1;
- mutex_unlock(&wl->vif_mutex);
- synchronize_srcu(&wl->srcu);
-
- return vif;
-}
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#include <linux/clk.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/host.h>
-
-#include "wilc_wfi_netdevice.h"
-#include "wilc_wfi_cfgoperations.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;
-};
-
-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;
-};
-
-static const struct wilc_hif_func wilc_hif_sdio;
-
-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 wilc_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");
- }
- }
-
- ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO,
- &wilc_hif_sdio);
- if (ret) {
- kfree(sdio_priv);
- return ret;
- }
- sdio_set_drvdata(func, wilc);
- wilc->bus_data = sdio_priv;
- wilc->dev = &func->dev;
- wilc->gpio_irq = gpio;
-
- wilc->rtc_clk = devm_clk_get(&func->card->dev, "rtc_clk");
- if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- else if (!IS_ERR(wilc->rtc_clk))
- clk_prepare_enable(wilc->rtc_clk);
-
- dev_info(&func->dev, "Driver Initializing success\n");
- return 0;
-}
-
-static void wilc_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);
-
- if (!IS_ERR(wilc->rtc_clk))
- clk_disable_unprepare(wilc->rtc_clk);
-
- wilc_netdev_cleanup(wilc);
-}
-
-static int wilc_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 (!IS_ERR(wilc->rtc_clk))
- clk_disable_unprepare(wilc->rtc_clk);
-
- if (wilc->suspend_event) {
- host_sleep_notify(wilc);
- chip_allow_sleep(wilc);
- }
-
- ret = wilc_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_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 wilc_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 wilc_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 wilc_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 wilc_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 (!wilc_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 wilc_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 (!wilc_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 (!wilc_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 wilc_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 (!wilc_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 wilc_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 (!wilc_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 (!wilc_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 wilc_sdio_deinit(struct wilc *wilc)
-{
- return 1;
-}
-
-static int wilc_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 (!wilc_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 (!wilc_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 (!wilc_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 wilc_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 wilc_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;
-
- wilc_sdio_read_size(wilc, &tmp);
-
- /**
- * Read IRQ flags
- **/
- if (!sdio_priv->irq_gpio) {
- int i;
-
- cmd.read_write = 0;
- 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 wilc_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 wilc_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 (!wilc_sdio_read_reg(wilc, WILC_MISC, ®)) {
- dev_err(&func->dev, "Failed read misc reg...\n");
- return 0;
- }
-
- reg &= ~BIT(8);
- if (!wilc_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 = wilc_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 = wilc_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 = wilc_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 = wilc_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 = wilc_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 = wilc_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 = wilc_sdio_init,
- .hif_deinit = wilc_sdio_deinit,
- .hif_read_reg = wilc_sdio_read_reg,
- .hif_write_reg = wilc_sdio_write_reg,
- .hif_block_rx = wilc_sdio_read,
- .hif_block_tx = wilc_sdio_write,
- .hif_read_int = wilc_sdio_read_int,
- .hif_clear_int_ext = wilc_sdio_clear_int_ext,
- .hif_read_size = wilc_sdio_read_size,
- .hif_block_tx_ext = wilc_sdio_write,
- .hif_block_rx_ext = wilc_sdio_read,
- .hif_sync_ext = wilc_sdio_sync_ext,
- .enable_interrupt = wilc_sdio_enable_interrupt,
- .disable_interrupt = wilc_sdio_disable_interrupt,
-};
-
-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);
- 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 = wilc_sdio_probe,
- .remove = wilc_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");
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#include <linux/clk.h>
-#include <linux/spi/spi.h>
-
-#include "wilc_wfi_netdevice.h"
-#include "wilc_wfi_cfgoperations.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_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi);
- if (ret) {
- kfree(spi_priv);
- return ret;
- }
-
- spi_set_drvdata(spi, wilc);
- wilc->dev = &spi->dev;
- wilc->bus_data = spi_priv;
- wilc->gpio_irq = gpio;
-
- wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk");
- if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- else if (!IS_ERR(wilc->rtc_clk))
- clk_prepare_enable(wilc->rtc_clk);
-
- return 0;
-}
-
-static int wilc_bus_remove(struct spi_device *spi)
-{
- struct wilc *wilc = spi_get_drvdata(spi);
-
- /* free the GPIO in module remove */
- if (wilc->gpio_irq)
- gpiod_put(wilc->gpio_irq);
-
- if (!IS_ERR(wilc->rtc_clk))
- clk_disable_unprepare(wilc->rtc_clk);
-
- wilc_netdev_cleanup(wilc);
- return 0;
-}
-
-static const struct of_device_id wilc_of_match[] = {
- { .compatible = "microchip,wilc1000-spi", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, wilc_of_match);
-
-static struct spi_driver wilc_spi_driver = {
- .driver = {
- .name = MODALIAS,
- .of_match_table = wilc_of_match,
- },
- .probe = wilc_bus_probe,
- .remove = wilc_bus_remove,
-};
-module_spi_driver(wilc_spi_driver);
-MODULE_LICENSE("GPL");
-
-static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len)
-{
- struct spi_device *spi = to_spi_device(wilc->dev);
- int ret;
- struct spi_message msg;
-
- if (len > 0 && b) {
- struct spi_transfer tr = {
- .tx_buf = b,
- .len = len,
- .delay_usecs = 0,
- };
- char *r_buffer = kzalloc(len, GFP_KERNEL);
-
- if (!r_buffer)
- return -ENOMEM;
-
- tr.rx_buf = r_buffer;
- dev_dbg(&spi->dev, "Request writing %d bytes\n", len);
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
- msg.spi = spi;
- msg.is_dma_mapped = USE_SPI_DMA;
- spi_message_add_tail(&tr, &msg);
-
- ret = spi_sync(spi, &msg);
- if (ret < 0)
- dev_err(&spi->dev, "SPI transaction failed\n");
-
- kfree(r_buffer);
- } else {
- dev_err(&spi->dev,
- "can't write data with the following length: %d\n",
- len);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen)
-{
- struct spi_device *spi = to_spi_device(wilc->dev);
- int ret;
-
- if (rlen > 0) {
- struct spi_message msg;
- struct spi_transfer tr = {
- .rx_buf = rb,
- .len = rlen,
- .delay_usecs = 0,
-
- };
- char *t_buffer = kzalloc(rlen, GFP_KERNEL);
-
- if (!t_buffer)
- return -ENOMEM;
-
- tr.tx_buf = t_buffer;
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
- msg.spi = spi;
- msg.is_dma_mapped = USE_SPI_DMA;
- spi_message_add_tail(&tr, &msg);
-
- ret = spi_sync(spi, &msg);
- if (ret < 0)
- dev_err(&spi->dev, "SPI transaction failed\n");
- kfree(t_buffer);
- } else {
- dev_err(&spi->dev,
- "can't read data with the following length: %u\n",
- rlen);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen)
-{
- struct spi_device *spi = to_spi_device(wilc->dev);
- int ret;
-
- if (rlen > 0) {
- struct spi_message msg;
- struct spi_transfer tr = {
- .rx_buf = rb,
- .tx_buf = wb,
- .len = rlen,
- .bits_per_word = 8,
- .delay_usecs = 0,
-
- };
-
- memset(&msg, 0, sizeof(msg));
- spi_message_init(&msg);
- msg.spi = spi;
- msg.is_dma_mapped = USE_SPI_DMA;
-
- spi_message_add_tail(&tr, &msg);
- ret = spi_sync(spi, &msg);
- if (ret < 0)
- dev_err(&spi->dev, "SPI transaction failed\n");
- } else {
- dev_err(&spi->dev,
- "can't read data with the following length: %u\n",
- rlen);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int spi_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;
- bool unexpected_irq;
- int j;
- u32 unknown_mask;
- u32 irq_flags;
- int k = IRG_FLAGS_OFFSET + 5;
-
- if (spi_priv->has_thrpt_enh)
- return spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
- int_status);
- 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 {
- 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);
-
- unexpected_irq = (tmp >> IRG_FLAGS_OFFSET) & unknown_mask;
- if (unexpected_irq) {
- dev_err(&spi->dev,
- "Unexpected interrupt(2):j=%d,tmp=%x,mask=%x\n",
- j, tmp, unknown_mask);
- }
-
- j++;
- } while (unexpected_irq);
-
- *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) {
- return spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE,
- val);
- }
-
- 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,
-};
+++ /dev/null
-// 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 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 WILC_INVALID_CHANNEL 0
-
-static const struct ieee80211_txrx_stypes
- wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = {
- [NL80211_IFTYPE_STATION] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
- },
- [NL80211_IFTYPE_AP] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
- BIT(IEEE80211_STYPE_DISASSOC >> 4) |
- BIT(IEEE80211_STYPE_AUTH >> 4) |
- BIT(IEEE80211_STYPE_DEAUTH >> 4) |
- BIT(IEEE80211_STYPE_ACTION >> 4)
- },
- [NL80211_IFTYPE_P2P_CLIENT] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
- BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_DISASSOC >> 4) |
- BIT(IEEE80211_STYPE_AUTH >> 4) |
- BIT(IEEE80211_STYPE_DEAUTH >> 4)
- }
-};
-
-static const struct wiphy_wowlan_support wowlan_support = {
- .flags = WIPHY_WOWLAN_ANY
-};
-
-struct wilc_p2p_mgmt_data {
- int size;
- u8 *buff;
-};
-
-static const u8 p2p_oui[] = {0x50, 0x6f, 0x9A, 0x09};
-static const u8 p2p_vendor_spec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03};
-
-static void cfg_scan_result(enum scan_event scan_event,
- struct wilc_rcvd_net_info *info, void *user_void)
-{
- struct wilc_priv *priv = user_void;
-
- if (!priv->cfg_scanning)
- return;
-
- if (scan_event == SCAN_EVENT_NETWORK_FOUND) {
- s32 freq;
- struct ieee80211_channel *channel;
- struct cfg80211_bss *bss;
- struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy;
-
- if (!wiphy || !info)
- return;
-
- freq = ieee80211_channel_to_frequency((s32)info->ch,
- NL80211_BAND_2GHZ);
- channel = ieee80211_get_channel(wiphy, freq);
- if (!channel)
- return;
-
- bss = cfg80211_inform_bss_frame(wiphy, channel, info->mgmt,
- info->frame_len,
- (s32)info->rssi * 100,
- GFP_KERNEL);
- if (!bss)
- cfg80211_put_bss(wiphy, bss);
- } else if (scan_event == SCAN_EVENT_DONE) {
- mutex_lock(&priv->scan_req_lock);
-
- if (priv->scan_req) {
- struct cfg80211_scan_info info = {
- .aborted = false,
- };
-
- cfg80211_scan_done(priv->scan_req, &info);
- priv->cfg_scanning = false;
- priv->scan_req = NULL;
- }
- mutex_unlock(&priv->scan_req_lock);
- } else if (scan_event == SCAN_EVENT_ABORTED) {
- mutex_lock(&priv->scan_req_lock);
-
- if (priv->scan_req) {
- struct cfg80211_scan_info info = {
- .aborted = false,
- };
-
- cfg80211_scan_done(priv->scan_req, &info);
- priv->cfg_scanning = false;
- priv->scan_req = NULL;
- }
- mutex_unlock(&priv->scan_req_lock);
- }
-}
-
-static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status,
- void *priv_data)
-{
- struct wilc_priv *priv = priv_data;
- struct net_device *dev = priv->dev;
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wl = vif->wilc;
- struct host_if_drv *wfi_drv = priv->hif_drv;
- struct wilc_conn_info *conn_info = &wfi_drv->conn_info;
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
-
- vif->connecting = false;
-
- if (conn_disconn_evt == CONN_DISCONN_EVENT_CONN_RESP) {
- u16 connect_status = conn_info->status;
-
- if (mac_status == WILC_MAC_STATUS_DISCONNECTED &&
- connect_status == WLAN_STATUS_SUCCESS) {
- connect_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
- wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
-
- if (vif->iftype != WILC_CLIENT_MODE)
- wl->sta_ch = WILC_INVALID_CHANNEL;
-
- netdev_err(dev, "Unspecified failure\n");
- }
-
- if (connect_status == WLAN_STATUS_SUCCESS)
- memcpy(priv->associated_bss, conn_info->bssid,
- ETH_ALEN);
-
- cfg80211_ref_bss(wiphy, vif->bss);
- cfg80211_connect_bss(dev, conn_info->bssid, vif->bss,
- conn_info->req_ies,
- conn_info->req_ies_len,
- conn_info->resp_ies,
- conn_info->resp_ies_len,
- connect_status, GFP_KERNEL,
- NL80211_TIMEOUT_UNSPECIFIED);
-
- vif->bss = NULL;
- } else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) {
- u16 reason = 0;
-
- 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, WILC_STATION_MODE);
-
- if (vif->iftype != WILC_CLIENT_MODE) {
- wl->sta_ch = WILC_INVALID_CHANNEL;
- } else {
- if (wfi_drv->ifc_up)
- reason = 3;
- else
- reason = 1;
- }
-
- cfg80211_disconnected(dev, reason, NULL, 0, false, GFP_KERNEL);
- }
-}
-
-struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl)
-{
- struct wilc_vif *vif;
-
- vif = list_first_or_null_rcu(&wl->vif_list, typeof(*vif), list);
- if (!vif)
- return ERR_PTR(-EINVAL);
-
- return vif;
-}
-
-static int set_channel(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef)
-{
- struct wilc *wl = wiphy_priv(wiphy);
- struct wilc_vif *vif;
- u32 channelnum;
- int result;
- int srcu_idx;
-
- srcu_idx = srcu_read_lock(&wl->srcu);
- vif = wilc_get_wl_to_vif(wl);
- if (IS_ERR(vif)) {
- srcu_read_unlock(&wl->srcu, srcu_idx);
- return PTR_ERR(vif);
- }
-
- channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq);
-
- wl->op_ch = channelnum;
- result = wilc_set_mac_chnl_num(vif, channelnum);
- if (result)
- netdev_err(vif->ndev, "Error in setting channel\n");
-
- srcu_read_unlock(&wl->srcu, srcu_idx);
- return result;
-}
-
-static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
-{
- struct wilc_vif *vif = netdev_priv(request->wdev->netdev);
- struct wilc_priv *priv = &vif->priv;
- u32 i;
- int ret = 0;
- u8 scan_ch_list[WILC_MAX_NUM_SCANNED_CH];
- u8 scan_type;
-
- if (request->n_channels > WILC_MAX_NUM_SCANNED_CH) {
- netdev_err(vif->ndev, "Requested scanned channels over\n");
- return -EINVAL;
- }
-
- priv->scan_req = request;
- priv->cfg_scanning = true;
- for (i = 0; i < request->n_channels; i++) {
- u16 freq = request->channels[i]->center_freq;
-
- scan_ch_list[i] = ieee80211_frequency_to_channel(freq);
- }
-
- if (request->n_ssids)
- scan_type = WILC_FW_ACTIVE_SCAN;
- else
- scan_type = WILC_FW_PASSIVE_SCAN;
-
- ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list,
- request->n_channels, cfg_scan_result, (void *)priv,
- request);
-
- if (ret) {
- priv->scan_req = NULL;
- priv->cfg_scanning = false;
- }
-
- return ret;
-}
-
-static int connect(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_connect_params *sme)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc_priv *priv = &vif->priv;
- struct host_if_drv *wfi_drv = priv->hif_drv;
- int ret;
- u32 i;
- u8 security = WILC_FW_SEC_NO;
- enum authtype auth_type = WILC_FW_AUTH_ANY;
- u32 cipher_group;
- struct cfg80211_bss *bss;
- void *join_params;
- u8 ch;
-
- vif->connecting = true;
-
- memset(priv->wep_key, 0, sizeof(priv->wep_key));
- memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
-
- cipher_group = sme->crypto.cipher_group;
- if (cipher_group != 0) {
- if (cipher_group == WLAN_CIPHER_SUITE_WEP40) {
- security = WILC_FW_SEC_WEP;
-
- priv->wep_key_len[sme->key_idx] = sme->key_len;
- memcpy(priv->wep_key[sme->key_idx], sme->key,
- sme->key_len);
-
- wilc_set_wep_default_keyid(vif, sme->key_idx);
- wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
- sme->key_idx);
- } else if (cipher_group == WLAN_CIPHER_SUITE_WEP104) {
- security = WILC_FW_SEC_WEP_EXTENDED;
-
- priv->wep_key_len[sme->key_idx] = sme->key_len;
- memcpy(priv->wep_key[sme->key_idx], sme->key,
- sme->key_len);
-
- wilc_set_wep_default_keyid(vif, sme->key_idx);
- wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
- sme->key_idx);
- } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
- if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
- security = WILC_FW_SEC_WPA2_TKIP;
- else
- security = WILC_FW_SEC_WPA2_AES;
- } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) {
- if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
- security = WILC_FW_SEC_WPA_TKIP;
- else
- security = WILC_FW_SEC_WPA_AES;
- } else {
- ret = -ENOTSUPP;
- netdev_err(dev, "%s: Unsupported cipher\n",
- __func__);
- goto out_error;
- }
- }
-
- if ((sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ||
- (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
- for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) {
- u32 ciphers_pairwise = sme->crypto.ciphers_pairwise[i];
-
- if (ciphers_pairwise == WLAN_CIPHER_SUITE_TKIP)
- security |= WILC_FW_TKIP;
- else
- security |= WILC_FW_AES;
- }
- }
-
- switch (sme->auth_type) {
- case NL80211_AUTHTYPE_OPEN_SYSTEM:
- auth_type = WILC_FW_AUTH_OPEN_SYSTEM;
- break;
-
- case NL80211_AUTHTYPE_SHARED_KEY:
- auth_type = WILC_FW_AUTH_SHARED_KEY;
- break;
-
- default:
- break;
- }
-
- if (sme->crypto.n_akm_suites) {
- if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X)
- auth_type = WILC_FW_AUTH_IEEE8021;
- }
-
- if (wfi_drv->usr_scan_req.scan_result) {
- netdev_err(vif->ndev, "%s: Scan in progress\n", __func__);
- ret = -EBUSY;
- goto out_error;
- }
-
- bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid,
- sme->ssid_len, IEEE80211_BSS_TYPE_ANY,
- IEEE80211_PRIVACY(sme->privacy));
- if (!bss) {
- ret = -EINVAL;
- goto out_error;
- }
-
- if (ether_addr_equal_unaligned(vif->bssid, bss->bssid)) {
- ret = -EALREADY;
- goto out_put_bss;
- }
-
- join_params = wilc_parse_join_bss_param(bss, &sme->crypto);
- if (!join_params) {
- netdev_err(dev, "%s: failed to construct join param\n",
- __func__);
- ret = -EINVAL;
- goto out_put_bss;
- }
-
- ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
- vif->wilc->op_ch = ch;
- if (vif->iftype != WILC_CLIENT_MODE)
- vif->wilc->sta_ch = ch;
-
- wilc_wlan_set_bssid(dev, bss->bssid, WILC_STATION_MODE);
-
- wfi_drv->conn_info.security = security;
- wfi_drv->conn_info.auth_type = auth_type;
- wfi_drv->conn_info.ch = ch;
- wfi_drv->conn_info.conn_result = cfg_connect_result;
- wfi_drv->conn_info.arg = priv;
- wfi_drv->conn_info.param = join_params;
-
- ret = wilc_set_join_req(vif, bss->bssid, sme->ie, sme->ie_len);
- if (ret) {
- netdev_err(dev, "wilc_set_join_req(): Error\n");
- ret = -ENOENT;
- if (vif->iftype != WILC_CLIENT_MODE)
- vif->wilc->sta_ch = WILC_INVALID_CHANNEL;
- wilc_wlan_set_bssid(dev, NULL, WILC_STATION_MODE);
- wfi_drv->conn_info.conn_result = NULL;
- kfree(join_params);
- goto out_put_bss;
- }
- kfree(join_params);
- vif->bss = bss;
- cfg80211_put_bss(wiphy, bss);
- return 0;
-
-out_put_bss:
- cfg80211_put_bss(wiphy, bss);
-
-out_error:
- vif->connecting = false;
- return ret;
-}
-
-static int disconnect(struct wiphy *wiphy, struct net_device *dev,
- u16 reason_code)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc_priv *priv = &vif->priv;
- struct wilc *wilc = vif->wilc;
- int ret;
-
- vif->connecting = false;
-
- if (!wilc)
- return -EIO;
-
- if (wilc->close) {
- /* already disconnected done */
- cfg80211_disconnected(dev, 0, NULL, 0, true, GFP_KERNEL);
- return 0;
- }
-
- if (vif->iftype != WILC_CLIENT_MODE)
- wilc->sta_ch = WILC_INVALID_CHANNEL;
- wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
-
- priv->p2p.local_random = 0x01;
- priv->p2p.recv_random = 0x00;
- priv->p2p.is_wilc_ie = false;
- priv->hif_drv->p2p_timeout = 0;
-
- ret = wilc_disconnect(vif);
- if (ret != 0) {
- netdev_err(priv->dev, "Error in disconnecting\n");
- ret = -EINVAL;
- }
-
- vif->bss = NULL;
-
- return ret;
-}
-
-static inline void wilc_wfi_cfg_copy_wep_info(struct wilc_priv *priv,
- u8 key_index,
- struct key_params *params)
-{
- priv->wep_key_len[key_index] = params->key_len;
- memcpy(priv->wep_key[key_index], params->key, params->key_len);
-}
-
-static int wilc_wfi_cfg_allocate_wpa_entry(struct wilc_priv *priv, u8 idx)
-{
- if (!priv->wilc_gtk[idx]) {
- priv->wilc_gtk[idx] = kzalloc(sizeof(*priv->wilc_gtk[idx]),
- GFP_KERNEL);
- if (!priv->wilc_gtk[idx])
- return -ENOMEM;
- }
-
- if (!priv->wilc_ptk[idx]) {
- priv->wilc_ptk[idx] = kzalloc(sizeof(*priv->wilc_ptk[idx]),
- GFP_KERNEL);
- if (!priv->wilc_ptk[idx])
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info,
- struct key_params *params)
-{
- kfree(key_info->key);
-
- key_info->key = kmemdup(params->key, params->key_len, GFP_KERNEL);
- if (!key_info->key)
- return -ENOMEM;
-
- kfree(key_info->seq);
-
- if (params->seq_len > 0) {
- key_info->seq = kmemdup(params->seq, params->seq_len,
- GFP_KERNEL);
- if (!key_info->seq)
- return -ENOMEM;
- }
-
- key_info->cipher = params->cipher;
- key_info->key_len = params->key_len;
- key_info->seq_len = params->seq_len;
-
- return 0;
-}
-
-static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
- bool pairwise, const u8 *mac_addr, struct key_params *params)
-
-{
- int ret = 0, keylen = params->key_len;
- const u8 *rx_mic = NULL;
- const u8 *tx_mic = NULL;
- u8 mode = WILC_FW_SEC_NO;
- u8 op_mode;
- struct wilc_vif *vif = netdev_priv(netdev);
- struct wilc_priv *priv = &vif->priv;
-
- switch (params->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- if (priv->wdev.iftype == NL80211_IFTYPE_AP) {
- wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
-
- if (params->cipher == WLAN_CIPHER_SUITE_WEP40)
- mode = WILC_FW_SEC_WEP;
- else
- mode = WILC_FW_SEC_WEP_EXTENDED;
-
- ret = wilc_add_wep_key_bss_ap(vif, params->key,
- params->key_len,
- key_index, mode,
- WILC_FW_AUTH_OPEN_SYSTEM);
- break;
- }
- if (memcmp(params->key, priv->wep_key[key_index],
- params->key_len)) {
- wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
-
- ret = wilc_add_wep_key_bss_sta(vif, params->key,
- params->key_len,
- key_index);
- }
-
- break;
-
- case WLAN_CIPHER_SUITE_TKIP:
- case WLAN_CIPHER_SUITE_CCMP:
- if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
- priv->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
- struct wilc_wfi_key *key;
-
- ret = wilc_wfi_cfg_allocate_wpa_entry(priv, key_index);
- if (ret)
- return -ENOMEM;
-
- if (params->key_len > 16 &&
- params->cipher == WLAN_CIPHER_SUITE_TKIP) {
- tx_mic = params->key + 24;
- rx_mic = params->key + 16;
- keylen = params->key_len - 16;
- }
-
- if (!pairwise) {
- if (params->cipher == WLAN_CIPHER_SUITE_TKIP)
- mode = WILC_FW_SEC_WPA_TKIP;
- else
- mode = WILC_FW_SEC_WPA2_AES;
-
- priv->wilc_groupkey = mode;
-
- key = priv->wilc_gtk[key_index];
- } else {
- if (params->cipher == WLAN_CIPHER_SUITE_TKIP)
- mode = WILC_FW_SEC_WPA_TKIP;
- else
- mode = priv->wilc_groupkey | WILC_FW_AES;
-
- key = priv->wilc_ptk[key_index];
- }
- ret = wilc_wfi_cfg_copy_wpa_info(key, params);
- if (ret)
- return -ENOMEM;
-
- op_mode = WILC_AP_MODE;
- } else {
- if (params->key_len > 16 &&
- params->cipher == WLAN_CIPHER_SUITE_TKIP) {
- rx_mic = params->key + 24;
- tx_mic = params->key + 16;
- keylen = params->key_len - 16;
- }
-
- op_mode = WILC_STATION_MODE;
- }
-
- if (!pairwise)
- ret = wilc_add_rx_gtk(vif, params->key, keylen,
- key_index, params->seq_len,
- params->seq, rx_mic, tx_mic,
- op_mode, mode);
- else
- ret = wilc_add_ptk(vif, params->key, keylen, mac_addr,
- rx_mic, tx_mic, op_mode, mode,
- key_index);
-
- break;
-
- default:
- netdev_err(netdev, "%s: Unsupported cipher\n", __func__);
- ret = -ENOTSUPP;
- }
-
- return ret;
-}
-
-static int del_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index,
- bool pairwise,
- const u8 *mac_addr)
-{
- struct wilc_vif *vif = netdev_priv(netdev);
- struct wilc_priv *priv = &vif->priv;
-
- if (priv->wilc_gtk[key_index]) {
- kfree(priv->wilc_gtk[key_index]->key);
- priv->wilc_gtk[key_index]->key = NULL;
- kfree(priv->wilc_gtk[key_index]->seq);
- priv->wilc_gtk[key_index]->seq = NULL;
-
- kfree(priv->wilc_gtk[key_index]);
- priv->wilc_gtk[key_index] = NULL;
- }
-
- if (priv->wilc_ptk[key_index]) {
- kfree(priv->wilc_ptk[key_index]->key);
- priv->wilc_ptk[key_index]->key = NULL;
- kfree(priv->wilc_ptk[key_index]->seq);
- priv->wilc_ptk[key_index]->seq = NULL;
- kfree(priv->wilc_ptk[key_index]);
- priv->wilc_ptk[key_index] = NULL;
- }
-
- if (key_index <= 3 && priv->wep_key_len[key_index]) {
- memset(priv->wep_key[key_index], 0,
- priv->wep_key_len[key_index]);
- priv->wep_key_len[key_index] = 0;
- wilc_remove_wep_key(vif, key_index);
- }
-
- return 0;
-}
-
-static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
- bool pairwise, const u8 *mac_addr, void *cookie,
- void (*callback)(void *cookie, struct key_params *))
-{
- struct wilc_vif *vif = netdev_priv(netdev);
- struct wilc_priv *priv = &vif->priv;
- struct key_params key_params;
-
- if (!pairwise) {
- key_params.key = priv->wilc_gtk[key_index]->key;
- key_params.cipher = priv->wilc_gtk[key_index]->cipher;
- key_params.key_len = priv->wilc_gtk[key_index]->key_len;
- key_params.seq = priv->wilc_gtk[key_index]->seq;
- key_params.seq_len = priv->wilc_gtk[key_index]->seq_len;
- } else {
- key_params.key = priv->wilc_ptk[key_index]->key;
- key_params.cipher = priv->wilc_ptk[key_index]->cipher;
- key_params.key_len = priv->wilc_ptk[key_index]->key_len;
- key_params.seq = priv->wilc_ptk[key_index]->seq;
- key_params.seq_len = priv->wilc_ptk[key_index]->seq_len;
- }
-
- callback(cookie, &key_params);
-
- return 0;
-}
-
-static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, bool unicast, bool multicast)
-{
- struct wilc_vif *vif = netdev_priv(netdev);
-
- wilc_set_wep_default_keyid(vif, key_index);
-
- return 0;
-}
-
-static int get_station(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac, struct station_info *sinfo)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc_priv *priv = &vif->priv;
- u32 i = 0;
- u32 associatedsta = ~0;
- u32 inactive_time = 0;
-
- if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
- for (i = 0; i < NUM_STA_ASSOCIATED; i++) {
- if (!(memcmp(mac,
- priv->assoc_stainfo.sta_associated_bss[i],
- ETH_ALEN))) {
- associatedsta = i;
- break;
- }
- }
-
- if (associatedsta == ~0) {
- netdev_err(dev, "sta required is not associated\n");
- return -ENOENT;
- }
-
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME);
-
- wilc_get_inactive_time(vif, mac, &inactive_time);
- sinfo->inactive_time = 1000 * inactive_time;
- } else if (vif->iftype == WILC_STATION_MODE) {
- struct rf_info stats;
-
- wilc_get_statistics(vif, &stats);
-
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL) |
- BIT_ULL(NL80211_STA_INFO_RX_PACKETS) |
- BIT_ULL(NL80211_STA_INFO_TX_PACKETS) |
- BIT_ULL(NL80211_STA_INFO_TX_FAILED) |
- BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
-
- sinfo->signal = stats.rssi;
- sinfo->rx_packets = stats.rx_cnt;
- sinfo->tx_packets = stats.tx_cnt + stats.tx_fail_cnt;
- sinfo->tx_failed = stats.tx_fail_cnt;
- sinfo->txrate.legacy = stats.link_speed * 10;
-
- if (stats.link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
- stats.link_speed != DEFAULT_LINK_SPEED)
- wilc_enable_tcp_ack_filter(vif, true);
- else if (stats.link_speed != DEFAULT_LINK_SPEED)
- wilc_enable_tcp_ack_filter(vif, false);
- }
- return 0;
-}
-
-static int change_bss(struct wiphy *wiphy, struct net_device *dev,
- struct bss_parameters *params)
-{
- return 0;
-}
-
-static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
-{
- int ret = -EINVAL;
- struct cfg_param_attr cfg_param_val;
- struct wilc *wl = wiphy_priv(wiphy);
- struct wilc_vif *vif;
- struct wilc_priv *priv;
- int srcu_idx;
-
- srcu_idx = srcu_read_lock(&wl->srcu);
- vif = wilc_get_wl_to_vif(wl);
- if (IS_ERR(vif))
- goto out;
-
- priv = &vif->priv;
- cfg_param_val.flag = 0;
-
- if (changed & WIPHY_PARAM_RETRY_SHORT) {
- netdev_dbg(vif->ndev,
- "Setting WIPHY_PARAM_RETRY_SHORT %d\n",
- wiphy->retry_short);
- cfg_param_val.flag |= WILC_CFG_PARAM_RETRY_SHORT;
- cfg_param_val.short_retry_limit = wiphy->retry_short;
- }
- if (changed & WIPHY_PARAM_RETRY_LONG) {
- netdev_dbg(vif->ndev,
- "Setting WIPHY_PARAM_RETRY_LONG %d\n",
- wiphy->retry_long);
- cfg_param_val.flag |= WILC_CFG_PARAM_RETRY_LONG;
- cfg_param_val.long_retry_limit = wiphy->retry_long;
- }
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
- if (wiphy->frag_threshold > 255 &&
- wiphy->frag_threshold < 7937) {
- netdev_dbg(vif->ndev,
- "Setting WIPHY_PARAM_FRAG_THRESHOLD %d\n",
- wiphy->frag_threshold);
- cfg_param_val.flag |= WILC_CFG_PARAM_FRAG_THRESHOLD;
- cfg_param_val.frag_threshold = wiphy->frag_threshold;
- } else {
- netdev_err(vif->ndev,
- "Fragmentation threshold out of range\n");
- goto out;
- }
- }
-
- if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
- if (wiphy->rts_threshold > 255) {
- netdev_dbg(vif->ndev,
- "Setting WIPHY_PARAM_RTS_THRESHOLD %d\n",
- wiphy->rts_threshold);
- cfg_param_val.flag |= WILC_CFG_PARAM_RTS_THRESHOLD;
- cfg_param_val.rts_threshold = wiphy->rts_threshold;
- } else {
- netdev_err(vif->ndev, "RTS threshold out of range\n");
- goto out;
- }
- }
-
- ret = wilc_hif_set_cfg(vif, &cfg_param_val);
- if (ret)
- netdev_err(priv->dev, "Error in setting WIPHY PARAMS\n");
-
-out:
- srcu_read_unlock(&wl->srcu, srcu_idx);
- return ret;
-}
-
-static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
- struct cfg80211_pmksa *pmksa)
-{
- struct wilc_vif *vif = netdev_priv(netdev);
- struct wilc_priv *priv = &vif->priv;
- u32 i;
- int ret = 0;
- u8 flag = 0;
-
- for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
- if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
- ETH_ALEN)) {
- flag = PMKID_FOUND;
- break;
- }
- }
- if (i < WILC_MAX_NUM_PMKIDS) {
- memcpy(priv->pmkid_list.pmkidlist[i].bssid, pmksa->bssid,
- ETH_ALEN);
- memcpy(priv->pmkid_list.pmkidlist[i].pmkid, pmksa->pmkid,
- WLAN_PMKID_LEN);
- if (!(flag == PMKID_FOUND))
- priv->pmkid_list.numpmkid++;
- } else {
- netdev_err(netdev, "Invalid PMKID index\n");
- ret = -EINVAL;
- }
-
- if (!ret)
- ret = wilc_set_pmkid_info(vif, &priv->pmkid_list);
-
- return ret;
-}
-
-static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
- struct cfg80211_pmksa *pmksa)
-{
- u32 i;
- int ret = 0;
- struct wilc_vif *vif = netdev_priv(netdev);
- struct wilc_priv *priv = &vif->priv;
-
- for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
- if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
- ETH_ALEN)) {
- memset(&priv->pmkid_list.pmkidlist[i], 0,
- sizeof(struct wilc_pmkid));
- break;
- }
- }
-
- if (i < priv->pmkid_list.numpmkid && 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,
- WLAN_PMKID_LEN);
- }
- priv->pmkid_list.numpmkid--;
- } else {
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
-{
- struct wilc_vif *vif = netdev_priv(netdev);
-
- memset(&vif->priv.pmkid_list, 0, sizeof(struct wilc_pmkid_attr));
-
- return 0;
-}
-
-static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u8 ch_list_attr_idx,
- u8 op_ch_attr_idx, u8 sta_ch)
-{
- 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] = sta_ch;
- break;
- }
- }
- }
-
- if (op_ch_attr_idx) {
- buf[op_ch_attr_idx + 6] = 0x51;
- buf[op_ch_attr_idx + 7] = sta_ch;
- }
-}
-
-static void wilc_wfi_cfg_parse_rx_action(u8 *buf, u32 len, u8 sta_ch)
-{
- 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 (sta_ch != WILC_INVALID_CHANNEL)
- wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
- op_channel_attr_index, sta_ch);
-}
-
-static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch,
- u8 iftype, u8 sta_ch)
-{
- 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 (sta_ch != WILC_INVALID_CHANNEL && oper_ch)
- wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
- op_channel_attr_index, sta_ch);
-}
-
-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),
- vif->wilc->sta_ch);
- break;
- }
- }
- }
-}
-
-void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
-{
- struct wilc *wl = vif->wilc;
- struct wilc_priv *priv = &vif->priv;
- struct host_if_drv *wfi_drv = priv->hif_drv;
- u32 header, pkt_offset;
- s32 freq;
- __le16 fc;
-
- header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
- 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(wl->op_ch, 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(vif->ndev, "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(vif->ndev,
- "%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 wilc_p2p_mgmt_data *pv_data = priv;
-
- kfree(pv_data->buff);
- kfree(pv_data);
-}
-
-static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
-{
- struct wilc_vif *vif = data;
- struct wilc_priv *priv = &vif->priv;
- struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params;
-
- if (cookie != params->listen_cookie)
- return;
-
- priv->p2p_listen_state = false;
-
- cfg80211_remain_on_channel_expired(&priv->wdev, params->listen_cookie,
- params->listen_ch, GFP_KERNEL);
-}
-
-static int remain_on_channel(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- struct ieee80211_channel *chan,
- unsigned int duration, u64 *cookie)
-{
- int ret = 0;
- struct wilc_vif *vif = netdev_priv(wdev->netdev);
- struct wilc_priv *priv = &vif->priv;
- u64 id;
-
- if (wdev->iftype == NL80211_IFTYPE_AP) {
- netdev_dbg(vif->ndev, "Required while in AP mode\n");
- return ret;
- }
-
- id = ++priv->inc_roc_cookie;
- if (id == 0)
- id = ++priv->inc_roc_cookie;
-
- ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value,
- wilc_wfi_remain_on_channel_expired,
- (void *)vif);
- if (ret)
- return ret;
-
- vif->wilc->op_ch = chan->hw_value;
-
- priv->remain_on_ch_params.listen_ch = chan;
- priv->remain_on_ch_params.listen_cookie = id;
- *cookie = id;
- priv->p2p_listen_state = true;
- priv->remain_on_ch_params.listen_duration = duration;
-
- cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_KERNEL);
- mod_timer(&vif->hif_drv->remain_on_ch_timer,
- jiffies + msecs_to_jiffies(duration + 1000));
-
- return ret;
-}
-
-static int cancel_remain_on_channel(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- u64 cookie)
-{
- struct wilc_vif *vif = netdev_priv(wdev->netdev);
- struct wilc_priv *priv = &vif->priv;
-
- if (cookie != priv->remain_on_ch_params.listen_cookie)
- return -ENOENT;
-
- return wilc_listen_state_expired(vif, cookie);
-}
-
-static void wilc_wfi_cfg_tx_vendor_spec(struct wilc_priv *priv,
- struct wilc_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];
- struct wilc_vif *vif = netdev_priv(priv->dev);
-
- 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,
- vif->wilc->sta_ch);
-
- 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 wilc_p2p_mgmt_data *mgmt_tx;
- struct wilc_vif *vif = netdev_priv(wdev->netdev);
- struct wilc_priv *priv = &vif->priv;
- struct host_if_drv *wfi_drv = priv->hif_drv;
- u32 buf_len = len + sizeof(p2p_vendor_spec) +
- sizeof(priv->p2p.local_random);
- int ret = 0;
-
- *cookie = prandom_u32();
- priv->tx_cookie = *cookie;
- mgmt = (const struct ieee80211_mgmt *)buf;
-
- if (!ieee80211_is_mgmt(mgmt->frame_control))
- goto out;
-
- mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_KERNEL);
- if (!mgmt_tx) {
- ret = -ENOMEM;
- goto out;
- }
-
- mgmt_tx->buff = kmalloc(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);
- vif->wilc->op_ch = 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);
- vif->wilc->op_ch = 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_vif *vif = netdev_priv(wdev->netdev);
- struct wilc_priv *priv = &vif->priv;
- struct host_if_drv *wfi_drv = priv->hif_drv;
-
- wfi_drv->p2p_timeout = jiffies;
-
- if (!priv->p2p_listen_state) {
- struct wilc_wfi_p2p_listen_params *params;
-
- params = &priv->remain_on_ch_params;
-
- cfg80211_remain_on_channel_expired(wdev,
- params->listen_cookie,
- params->listen_ch,
- GFP_KERNEL);
- }
-
- return 0;
-}
-
-void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
- u16 frame_type, bool reg)
-{
- struct wilc *wl = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(wdev->netdev);
-
- if (!frame_type)
- return;
-
- switch (frame_type) {
- case IEEE80211_STYPE_PROBE_REQ:
- vif->frame_reg[0].type = frame_type;
- vif->frame_reg[0].reg = reg;
- break;
-
- case IEEE80211_STYPE_ACTION:
- vif->frame_reg[1].type = frame_type;
- vif->frame_reg[1].reg = reg;
- break;
-
- default:
- break;
- }
-
- if (!wl->initialized)
- return;
- wilc_frame_register(vif, frame_type, reg);
-}
-
-static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
- s32 rssi_thold, u32 rssi_hyst)
-{
- return 0;
-}
-
-static int dump_station(struct wiphy *wiphy, struct net_device *dev,
- int idx, u8 *mac, struct station_info *sinfo)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- int ret;
-
- if (idx != 0)
- return -ENOENT;
-
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
-
- ret = wilc_get_rssi(vif, &sinfo->signal);
- if (ret)
- return ret;
-
- memcpy(mac, vif->priv.associated_bss, ETH_ALEN);
- return 0;
-}
-
-static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
- bool enabled, int timeout)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc_priv *priv = &vif->priv;
-
- if (!priv->hif_drv)
- return -EIO;
-
- wilc_set_power_mgmt(vif, enabled, timeout);
-
- return 0;
-}
-
-static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
- enum nl80211_iftype type,
- struct vif_params *params)
-{
- struct wilc *wl = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc_priv *priv = &vif->priv;
-
- priv->p2p.local_random = 0x01;
- priv->p2p.recv_random = 0x00;
- priv->p2p.is_wilc_ie = false;
-
- switch (type) {
- case NL80211_IFTYPE_STATION:
- vif->connecting = false;
- dev->ieee80211_ptr->iftype = type;
- priv->wdev.iftype = type;
- vif->monitor_flag = 0;
- if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)
- wilc_wfi_deinit_mon_interface(wl, true);
- vif->iftype = WILC_STATION_MODE;
-
- if (wl->initialized)
- wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
- WILC_STATION_MODE, vif->idx);
-
- memset(priv->assoc_stainfo.sta_associated_bss, 0,
- WILC_MAX_NUM_STA * ETH_ALEN);
- break;
-
- case NL80211_IFTYPE_P2P_CLIENT:
- vif->connecting = false;
- dev->ieee80211_ptr->iftype = type;
- priv->wdev.iftype = type;
- vif->monitor_flag = 0;
- vif->iftype = WILC_CLIENT_MODE;
-
- if (wl->initialized)
- wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
- WILC_STATION_MODE, vif->idx);
- break;
-
- case NL80211_IFTYPE_AP:
- dev->ieee80211_ptr->iftype = type;
- priv->wdev.iftype = type;
- vif->iftype = WILC_AP_MODE;
-
- if (wl->initialized)
- wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
- WILC_AP_MODE, vif->idx);
- break;
-
- case NL80211_IFTYPE_P2P_GO:
- dev->ieee80211_ptr->iftype = type;
- priv->wdev.iftype = type;
- vif->iftype = WILC_GO_MODE;
-
- if (wl->initialized)
- wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
- WILC_AP_MODE, vif->idx);
- break;
-
- default:
- netdev_err(dev, "Unknown interface type= %d\n", type);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int start_ap(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_ap_settings *settings)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- int ret;
-
- ret = set_channel(wiphy, &settings->chandef);
- if (ret != 0)
- netdev_err(dev, "Error in setting channel\n");
-
- wilc_wlan_set_bssid(dev, dev->dev_addr, WILC_AP_MODE);
-
- return wilc_add_beacon(vif, settings->beacon_interval,
- settings->dtim_period, &settings->beacon);
-}
-
-static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_beacon_data *beacon)
-{
- struct wilc_vif *vif = netdev_priv(dev);
-
- return wilc_add_beacon(vif, 0, 0, beacon);
-}
-
-static int stop_ap(struct wiphy *wiphy, struct net_device *dev)
-{
- int ret;
- struct wilc_vif *vif = netdev_priv(dev);
-
- wilc_wlan_set_bssid(dev, NULL, WILC_AP_MODE);
-
- ret = wilc_del_beacon(vif);
-
- if (ret)
- netdev_err(dev, "Host delete beacon fail\n");
-
- return ret;
-}
-
-static int add_station(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac, struct station_parameters *params)
-{
- int ret = 0;
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc_priv *priv = &vif->priv;
-
- if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
- memcpy(priv->assoc_stainfo.sta_associated_bss[params->aid], mac,
- ETH_ALEN);
-
- ret = wilc_add_station(vif, mac, params);
- if (ret)
- netdev_err(dev, "Host add station fail\n");
- }
-
- return ret;
-}
-
-static int del_station(struct wiphy *wiphy, struct net_device *dev,
- struct station_del_parameters *params)
-{
- const u8 *mac = params->mac;
- int ret = 0;
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc_priv *priv = &vif->priv;
- struct sta_info *info;
-
- if (!(vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE))
- return ret;
-
- info = &priv->assoc_stainfo;
-
- if (!mac)
- ret = wilc_del_allstation(vif, info->sta_associated_bss);
-
- ret = wilc_del_station(vif, mac);
- if (ret)
- netdev_err(dev, "Host delete station fail\n");
- return ret;
-}
-
-static int change_station(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac, struct station_parameters *params)
-{
- int ret = 0;
- struct wilc_vif *vif = netdev_priv(dev);
-
- if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
- ret = wilc_edit_station(vif, mac, params);
- if (ret)
- netdev_err(dev, "Host edit station fail\n");
- }
- return ret;
-}
-
-static struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type)
-{
- struct wilc_vif *vif;
-
- list_for_each_entry_rcu(vif, &wl->vif_list, list) {
- if (vif->iftype == type)
- return vif;
- }
-
- return NULL;
-}
-
-static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
- const char *name,
- unsigned char name_assign_type,
- enum nl80211_iftype type,
- struct vif_params *params)
-{
- struct wilc *wl = wiphy_priv(wiphy);
- struct wilc_vif *vif;
- struct wireless_dev *wdev;
- int iftype;
-
- if (type == NL80211_IFTYPE_MONITOR) {
- struct net_device *ndev;
- int srcu_idx;
-
- srcu_idx = srcu_read_lock(&wl->srcu);
- vif = wilc_get_vif_from_type(wl, WILC_AP_MODE);
- if (!vif) {
- vif = wilc_get_vif_from_type(wl, WILC_GO_MODE);
- if (!vif) {
- srcu_read_unlock(&wl->srcu, srcu_idx);
- goto validate_interface;
- }
- }
-
- if (vif->monitor_flag) {
- srcu_read_unlock(&wl->srcu, srcu_idx);
- goto validate_interface;
- }
-
- ndev = wilc_wfi_init_mon_interface(wl, name, vif->ndev);
- if (ndev) {
- vif->monitor_flag = 1;
- } else {
- srcu_read_unlock(&wl->srcu, srcu_idx);
- return ERR_PTR(-EINVAL);
- }
-
- wdev = &vif->priv.wdev;
- srcu_read_unlock(&wl->srcu, srcu_idx);
- return wdev;
- }
-
-validate_interface:
- mutex_lock(&wl->vif_mutex);
- if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) {
- pr_err("Reached maximum number of interface\n");
- mutex_unlock(&wl->vif_mutex);
- return ERR_PTR(-EINVAL);
- }
- mutex_unlock(&wl->vif_mutex);
-
- switch (type) {
- case NL80211_IFTYPE_STATION:
- iftype = WILC_STATION_MODE;
- break;
- case NL80211_IFTYPE_AP:
- iftype = WILC_AP_MODE;
- break;
- default:
- return ERR_PTR(-EOPNOTSUPP);
- }
-
- vif = wilc_netdev_ifc_init(wl, name, iftype, type, true);
- if (IS_ERR(vif))
- return ERR_CAST(vif);
-
- return &vif->priv.wdev;
-}
-
-static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
-{
- struct wilc *wl = wiphy_priv(wiphy);
- struct wilc_vif *vif;
-
- if (wdev->iftype == NL80211_IFTYPE_AP ||
- wdev->iftype == NL80211_IFTYPE_P2P_GO)
- wilc_wfi_deinit_mon_interface(wl, true);
- vif = netdev_priv(wdev->netdev);
- cfg80211_stop_iface(wiphy, wdev, GFP_KERNEL);
- unregister_netdevice(vif->ndev);
- vif->monitor_flag = 0;
-
- wilc_set_operation_mode(vif, 0, 0, 0);
- mutex_lock(&wl->vif_mutex);
- list_del_rcu(&vif->list);
- wl->vif_num--;
- mutex_unlock(&wl->vif_mutex);
- synchronize_srcu(&wl->srcu);
- return 0;
-}
-
-static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
-{
- struct wilc *wl = wiphy_priv(wiphy);
-
- if (!wow && wilc_wlan_get_num_conn_ifcs(wl))
- wl->suspend_event = true;
- else
- wl->suspend_event = false;
-
- return 0;
-}
-
-static int wilc_resume(struct wiphy *wiphy)
-{
- return 0;
-}
-
-static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled)
-{
- struct wilc *wl = wiphy_priv(wiphy);
- struct wilc_vif *vif;
- int srcu_idx;
-
- srcu_idx = srcu_read_lock(&wl->srcu);
- vif = wilc_get_wl_to_vif(wl);
- if (IS_ERR(vif)) {
- srcu_read_unlock(&wl->srcu, srcu_idx);
- return;
- }
-
- netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled);
- srcu_read_unlock(&wl->srcu, srcu_idx);
-}
-
-static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
- enum nl80211_tx_power_setting type, int mbm)
-{
- int ret;
- int srcu_idx;
- s32 tx_power = MBM_TO_DBM(mbm);
- struct wilc *wl = wiphy_priv(wiphy);
- struct wilc_vif *vif;
-
- if (!wl->initialized)
- return -EIO;
-
- srcu_idx = srcu_read_lock(&wl->srcu);
- vif = wilc_get_wl_to_vif(wl);
- if (IS_ERR(vif)) {
- srcu_read_unlock(&wl->srcu, srcu_idx);
- return -EINVAL;
- }
-
- netdev_info(vif->ndev, "Setting tx power %d\n", tx_power);
- if (tx_power < 0)
- tx_power = 0;
- else if (tx_power > 18)
- tx_power = 18;
- ret = wilc_set_tx_power(vif, tx_power);
- if (ret)
- netdev_err(vif->ndev, "Failed to set tx power\n");
- srcu_read_unlock(&wl->srcu, srcu_idx);
-
- return ret;
-}
-
-static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
- int *dbm)
-{
- int ret;
- struct wilc_vif *vif = netdev_priv(wdev->netdev);
- struct wilc *wl = vif->wilc;
-
- /* If firmware is not started, return. */
- if (!wl->initialized)
- return -EIO;
-
- ret = wilc_get_tx_power(vif, (u8 *)dbm);
- if (ret)
- netdev_err(vif->ndev, "Failed to get tx power\n");
-
- return ret;
-}
-
-static const struct cfg80211_ops wilc_cfg80211_ops = {
- .set_monitor_channel = set_channel,
- .scan = scan,
- .connect = connect,
- .disconnect = disconnect,
- .add_key = add_key,
- .del_key = del_key,
- .get_key = get_key,
- .set_default_key = set_default_key,
- .add_virtual_intf = add_virtual_intf,
- .del_virtual_intf = del_virtual_intf,
- .change_virtual_intf = change_virtual_intf,
-
- .start_ap = start_ap,
- .change_beacon = change_beacon,
- .stop_ap = stop_ap,
- .add_station = add_station,
- .del_station = del_station,
- .change_station = change_station,
- .get_station = get_station,
- .dump_station = dump_station,
- .change_bss = change_bss,
- .set_wiphy_params = set_wiphy_params,
-
- .set_pmksa = set_pmksa,
- .del_pmksa = del_pmksa,
- .flush_pmksa = flush_pmksa,
- .remain_on_channel = remain_on_channel,
- .cancel_remain_on_channel = cancel_remain_on_channel,
- .mgmt_tx_cancel_wait = mgmt_tx_cancel_wait,
- .mgmt_tx = mgmt_tx,
- .mgmt_frame_register = wilc_mgmt_frame_register,
- .set_power_mgmt = set_power_mgmt,
- .set_cqm_rssi_config = set_cqm_rssi_config,
-
- .suspend = wilc_suspend,
- .resume = wilc_resume,
- .set_wakeup = wilc_set_wakeup,
- .set_tx_power = set_tx_power,
- .get_tx_power = get_tx_power,
-
-};
-
-static void wlan_init_locks(struct wilc *wl)
-{
- mutex_init(&wl->hif_cs);
- mutex_init(&wl->rxq_cs);
- mutex_init(&wl->cfg_cmd_lock);
- mutex_init(&wl->vif_mutex);
-
- spin_lock_init(&wl->txq_spinlock);
- mutex_init(&wl->txq_add_to_head_cs);
-
- init_completion(&wl->txq_event);
- init_completion(&wl->cfg_event);
- init_completion(&wl->sync_event);
- init_completion(&wl->txq_thread_started);
- init_srcu_struct(&wl->srcu);
-}
-
-void wlan_deinit_locks(struct wilc *wilc)
-{
- mutex_destroy(&wilc->hif_cs);
- mutex_destroy(&wilc->rxq_cs);
- mutex_destroy(&wilc->cfg_cmd_lock);
- mutex_destroy(&wilc->txq_add_to_head_cs);
- mutex_destroy(&wilc->vif_mutex);
- cleanup_srcu_struct(&wilc->srcu);
-}
-
-int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
- const struct wilc_hif_func *ops)
-{
- struct wilc *wl;
- struct wilc_vif *vif;
- int ret;
-
- wl = wilc_create_wiphy(dev);
- if (!wl)
- return -EINVAL;
-
- wlan_init_locks(wl);
-
- ret = wilc_wlan_cfg_init(wl);
- if (ret)
- goto free_wl;
-
- *wilc = wl;
- wl->io_type = io_type;
- wl->hif_func = ops;
- wl->chip_ps_state = WILC_CHIP_WAKEDUP;
- INIT_LIST_HEAD(&wl->txq_head.list);
- INIT_LIST_HEAD(&wl->rxq_head.list);
- INIT_LIST_HEAD(&wl->vif_list);
-
- wl->hif_workqueue = create_singlethread_workqueue("WILC_wq");
- if (!wl->hif_workqueue) {
- ret = -ENOMEM;
- goto free_cfg;
- }
- vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE,
- NL80211_IFTYPE_STATION, false);
- if (IS_ERR(vif)) {
- ret = PTR_ERR(vif);
- goto free_hq;
- }
-
- return 0;
-
-free_hq:
- destroy_workqueue(wl->hif_workqueue);
-
-free_cfg:
- wilc_wlan_cfg_deinit(wl);
-
-free_wl:
- wlan_deinit_locks(wl);
- wiphy_unregister(wl->wiphy);
- wiphy_free(wl->wiphy);
- return ret;
-}
-EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
-
-struct wilc *wilc_create_wiphy(struct device *dev)
-{
- struct wiphy *wiphy;
- struct wilc *wl;
- int ret;
-
- wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl));
- if (!wiphy)
- return NULL;
-
- wl = wiphy_priv(wiphy);
-
- memcpy(wl->bitrates, wilc_bitrates, sizeof(wilc_bitrates));
- memcpy(wl->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels));
- wl->band.bitrates = wl->bitrates;
- wl->band.n_bitrates = ARRAY_SIZE(wl->bitrates);
- wl->band.channels = wl->channels;
- wl->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels);
-
- wl->band.ht_cap.ht_supported = 1;
- wl->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
- wl->band.ht_cap.mcs.rx_mask[0] = 0xff;
- wl->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
- wl->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
-
- wiphy->bands[NL80211_BAND_2GHZ] = &wl->band;
-
- wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID;
-#ifdef CONFIG_PM
- wiphy->wowlan = &wowlan_support;
-#endif
- wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
- wiphy->max_scan_ie_len = 1000;
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
- memcpy(wl->cipher_suites, wilc_cipher_suites,
- sizeof(wilc_cipher_suites));
- wiphy->cipher_suites = wl->cipher_suites;
- wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites);
- wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
-
- wiphy->max_remain_on_channel_duration = 500;
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_MONITOR) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_CLIENT);
- wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
-
- set_wiphy_dev(wiphy, dev);
- wl->wiphy = wiphy;
- ret = wiphy_register(wiphy);
- if (ret) {
- wiphy_free(wiphy);
- return NULL;
- }
- return wl;
-}
-
-int wilc_init_host_int(struct net_device *net)
-{
- int ret;
- struct wilc_vif *vif = netdev_priv(net);
- struct wilc_priv *priv = &vif->priv;
-
- priv->p2p_listen_state = false;
-
- mutex_init(&priv->scan_req_lock);
- ret = wilc_init(net, &priv->hif_drv);
- if (ret)
- netdev_err(net, "Error while initializing hostinterface\n");
-
- return ret;
-}
-
-void wilc_deinit_host_int(struct net_device *net)
-{
- int ret;
- struct wilc_vif *vif = netdev_priv(net);
- struct wilc_priv *priv = &vif->priv;
-
- priv->p2p_listen_state = false;
-
- flush_workqueue(vif->wilc->hif_workqueue);
- mutex_destroy(&priv->scan_req_lock);
- ret = wilc_deinit(vif);
-
- if (ret)
- netdev_err(net, "Error while deinitializing host interface\n");
-}
-
+++ /dev/null
-/* 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 wiphy *wilc_cfg_alloc(void);
-int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
- const struct wilc_hif_func *ops);
-struct wilc *wilc_create_wiphy(struct device *dev);
-void wilc_deinit_host_int(struct net_device *net);
-int wilc_init_host_int(struct net_device *net);
-void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size);
-struct wilc_vif *wilc_netdev_interface(struct wilc *wl, const char *name,
- enum nl80211_iftype type);
-void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked);
-struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
- 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);
-struct wilc_vif *wilc_get_interface(struct wilc *wl);
-struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl);
-void wlan_deinit_locks(struct wilc *wilc);
-#endif
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#ifndef WILC_WFI_NETDEVICE
-#define WILC_WFI_NETDEVICE
-
-#include <linux/tcp.h>
-#include <linux/ieee80211.h>
-#include <net/cfg80211.h>
-#include <net/ieee80211_radiotap.h>
-#include <linux/if_arp.h>
-#include <linux/gpio/consumer.h>
-
-#include "wilc_hif.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_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[WILC_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;
-};
-
-struct wilc_p2p_var {
- u8 local_random;
- u8 recv_random;
- bool is_wilc_ie;
-};
-
-static const u32 wilc_cipher_suites[] = {
- WLAN_CIPHER_SUITE_WEP40,
- WLAN_CIPHER_SUITE_WEP104,
- WLAN_CIPHER_SUITE_TKIP,
- WLAN_CIPHER_SUITE_CCMP,
- WLAN_CIPHER_SUITE_AES_CMAC
-};
-
-#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 const struct ieee80211_channel wilc_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 wilc_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 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;
-
- 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 wilc_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[WILC_MAX_NUM_STA];
- struct wilc_wfi_key *wilc_ptk[WILC_MAX_NUM_STA];
- u8 wilc_groupkey;
- /* mutexes */
- struct mutex scan_req_lock;
- bool p2p_listen_state;
- int scanned_cnt;
- struct wilc_p2p_var p2p;
-
- u64 inc_roc_cookie;
-};
-
-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 bssid[ETH_ALEN];
- struct host_if_drv *hif_drv;
- struct net_device *ndev;
- u8 mode;
- struct timer_list during_ip_timer;
- struct timer_list periodic_rssi;
- struct rf_info periodic_stat;
- struct tcp_ack_filter ack_filter;
- bool connecting;
- struct wilc_priv priv;
- struct list_head list;
- struct cfg80211_bss *bss;
-};
-
-struct wilc {
- struct wiphy *wiphy;
- const struct wilc_hif_func *hif_func;
- int io_type;
- s8 mac_status;
- struct gpio_desc *gpio_irq;
- struct clk *rtc_clk;
- bool initialized;
- int dev_irq_num;
- int close;
- u8 vif_num;
- struct list_head vif_list;
- /*protect vif list*/
- struct mutex vif_mutex;
- struct srcu_struct srcu;
- 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;
- /* lock to protect issue of wid command to firmware */
- struct mutex cfg_cmd_lock;
- struct wilc_cfg_frame cfg_frame;
- u32 cfg_frame_offset;
- u8 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;
-
- int clients_count;
- struct workqueue_struct *hif_workqueue;
- enum chip_ps_states chip_ps_state;
- struct wilc_cfg cfg;
- void *bus_data;
- struct net_device *monitor_dev;
- /* deinit lock */
- struct mutex deinit_lock;
- u8 sta_ch;
- u8 op_ch;
- struct ieee80211_channel channels[ARRAY_SIZE(wilc_2ghz_channels)];
- struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)];
- struct ieee80211_supported_band band;
- u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)];
-};
-
-struct wilc_wfi_mon_priv {
- struct net_device *real_ndev;
-};
-
-void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset);
-void wilc_mac_indicate(struct wilc *wilc);
-void wilc_netdev_cleanup(struct wilc *wilc);
-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);
-struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
- int vif_type, enum nl80211_iftype type,
- bool rtnl_locked);
-#endif
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include "wilc_wfi_cfgoperations.h"
-#include "wilc_wlan_cfg.h"
-
-static inline bool is_wilc1000(u32 id)
-{
- return (id & 0xfffff000) == 0x100000;
-}
-
-static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
-{
- mutex_lock(&wilc->hif_cs);
- if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP)
- chip_wakeup(wilc);
-}
-
-static inline void release_bus(struct wilc *wilc, enum bus_release release)
-{
- if (release == WILC_BUS_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;
- tqe->vif = vif;
-
- 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,
- void (*tx_complete_fn)(void *, int))
-{
- 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 = tx_complete_fn;
- tqe->priv = priv;
- tqe->vif = vif;
-
- 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,
- void (*tx_complete_fn)(void *, int))
-{
- 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_MGMT_PKT;
- tqe->buffer = buffer;
- tqe->buffer_size = buffer_size;
- tqe->tx_complete_func = tx_complete_fn;
- tqe->priv = priv;
- tqe->ack_idx = NOT_TCP_ACK;
- tqe->vif = vif;
- 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) == WILC_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(2000, 2500);
- 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) == WILC_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(2000, 2500);
-
- 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 == WILC_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 = WILC_CHIP_WAKEDUP;
-}
-EXPORT_SYMBOL_GPL(chip_wakeup);
-
-void host_wakeup_notify(struct wilc *wilc)
-{
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
- wilc->hif_func->hif_write_reg(wilc, 0x10b0, 1);
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
-}
-EXPORT_SYMBOL_GPL(host_wakeup_notify);
-
-void host_sleep_notify(struct wilc *wilc)
-{
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
- wilc->hif_func->hif_write_reg(wilc, 0x10ac, 1);
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
-}
-EXPORT_SYMBOL_GPL(host_sleep_notify);
-
-int wilc_wlan_handle_txq(struct wilc *wilc, 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];
- const struct wilc_hif_func *func;
- u8 *txb = wilc->tx_buffer;
- struct net_device *dev;
- struct wilc_vif *vif;
-
- if (wilc->quit)
- goto out;
-
- mutex_lock(&wilc->txq_add_to_head_cs);
- tqe = wilc_wlan_txq_get_first(wilc);
- if (!tqe)
- goto out;
- dev = tqe->vif->ndev;
- wilc_wlan_txq_filter_dup_tcp_ack(dev);
- 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) > WILC_TX_BUFF_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, WILC_BUS_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, WILC_BUS_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 = -ENOBUFS;
- goto out_release_bus;
- }
-
- release_bus(wilc, WILC_BUS_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;
-
- vif = tqe->vif;
- 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 = tqe->vif->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, WILC_BUS_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, WILC_BUS_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;
- header = get_unaligned_le32(buff_ptr);
-
- 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) {
- 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_host(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_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 (WILC_RX_BUFF_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, WILC_BUS_ACQUIRE_AND_WAKEUP);
- wilc->hif_func->hif_read_int(wilc, &int_status);
-
- if (int_status & DATA_INT_EXT)
- wilc_wlan_handle_isr_ext(wilc, int_status);
-
- if (!(int_status & (ALL_INT_EXT)))
- wilc_unknown_isr_ext(wilc);
-
- release_bus(wilc, WILC_BUS_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 {
- addr = get_unaligned_le32(&buffer[offset]);
- size = get_unaligned_le32(&buffer[offset + 4]);
- acquire_bus(wilc, WILC_BUS_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, WILC_BUS_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 == WILC_HIF_SDIO) {
- reg = 0;
- reg |= BIT(3);
- } else if (wilc->io_type == WILC_HIF_SPI) {
- reg = 1;
- }
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);
- if (!ret) {
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
- return -EIO;
- }
- reg = 0;
- if (wilc->io_type == WILC_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, WILC_BUS_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, WILC_BUS_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, WILC_BUS_RELEASE_ONLY);
-
- return (ret < 0) ? ret : 0;
-}
-
-int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
-{
- u32 reg = 0;
- int ret;
-
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
-
- ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®);
- if (!ret) {
- netdev_err(vif->ndev, "Error while reading reg\n");
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return -EIO;
- }
-
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
- (reg | WILC_ABORT_REQ_BIT));
- if (!ret) {
- netdev_err(vif->ndev, "Error while writing reg\n");
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return -EIO;
- }
-
- ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®);
- if (!ret) {
- netdev_err(vif->ndev, "Error while reading reg\n");
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return -EIO;
- }
- reg = BIT(0);
-
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg);
- if (!ret) {
- netdev_err(vif->ndev, "Error while writing reg\n");
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return -EIO;
- }
-
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
-
- return 0;
-}
-
-void wilc_wlan_cleanup(struct net_device *dev)
-{
- struct txq_entry_t *tqe;
- struct rxq_entry_t *rqe;
- 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;
- 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 t_len = wilc->cfg_frame_offset + sizeof(struct wilc_cfg_cmd_hdr);
-
- if (type == WILC_CFG_SET)
- cfg->hdr.cmd_type = 'W';
- else
- cfg->hdr.cmd_type = 'Q';
-
- cfg->hdr.seq_no = wilc->cfg_seq_no % 256;
- cfg->hdr.total_len = cpu_to_le16(t_len);
- cfg->hdr.driver_handler = cpu_to_le32(drv_handler);
- wilc->cfg_seq_no = cfg->hdr.seq_no;
-
- if (!wilc_wlan_txq_add_cfg_pkt(vif, (u8 *)&cfg->hdr, t_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;
-
- mutex_lock(&wilc->cfg_cmd_lock);
-
- 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) {
- mutex_unlock(&wilc->cfg_cmd_lock);
- return ret_size;
- }
-
- netdev_dbg(vif->ndev, "%s: seqno[%d]\n", __func__, wilc->cfg_seq_no);
-
- if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler))
- ret_size = 0;
-
- if (!wait_for_completion_timeout(&wilc->cfg_event,
- WILC_CFG_PKTS_TIMEOUT)) {
- netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);
- ret_size = 0;
- }
-
- wilc->cfg_frame_offset = 0;
- wilc->cfg_seq_no += 1;
- mutex_unlock(&wilc->cfg_cmd_lock);
-
- 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;
-
- mutex_lock(&wilc->cfg_cmd_lock);
-
- 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) {
- mutex_unlock(&wilc->cfg_cmd_lock);
- return ret_size;
- }
-
- if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler))
- ret_size = 0;
-
- if (!wait_for_completion_timeout(&wilc->cfg_event,
- WILC_CFG_PKTS_TIMEOUT)) {
- netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);
- ret_size = 0;
- }
- wilc->cfg_frame_offset = 0;
- wilc->cfg_seq_no += 1;
- mutex_unlock(&wilc->cfg_cmd_lock);
-
- return ret_size;
-}
-
-int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
- u32 count)
-{
- int i;
- int ret = 0;
- u32 drv = wilc_get_vif_idx(vif);
-
- if (mode == WILC_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 == WILC_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, WILC_BUS_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");
- goto release;
- }
- reg |= BIT(0);
- ret = wilc->hif_func->hif_write_reg(wilc, 0x1118, reg);
- if (!ret) {
- netdev_err(dev, "fail write reg 0x1118\n");
- goto release;
- }
- ret = wilc->hif_func->hif_write_reg(wilc, 0xc0000, 0x71);
- if (!ret) {
- netdev_err(dev, "fail write reg 0xc0000\n");
- goto release;
- }
- }
-
-release:
- release_bus(wilc, WILC_BUS_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(WILC_TX_BUFF_SIZE, GFP_KERNEL);
-
- if (!wilc->tx_buffer) {
- ret = -ENOBUFS;
- goto fail;
- }
-
- if (!wilc->rx_buffer)
- wilc->rx_buffer = kmalloc(WILC_RX_BUFF_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;
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#ifndef WILC_WLAN_H
-#define WILC_WLAN_H
-
-#include <linux/types.h>
-
-/********************************************
- *
- * Mac eth header length
- *
- ********************************************/
-#define 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_FW_HOST_COMM 0x13c0
-#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_ABORT_REQ_BIT BIT(31)
-
-#define WILC_RX_BUFF_SIZE (96 * 1024)
-#define WILC_TX_BUFF_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 ALL_INT_EXT DATA_INT_EXT
-#define NUM_INT_EXT 1
-
-#define DATA_INT_CLR CLR_INT0
-
-#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 WILC_CFG_PKTS_TIMEOUT msecs_to_jiffies(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;
- struct wilc_vif *vif;
- 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 WILC_MAX_CFG_FRAME_SIZE 1468
-
-struct tx_complete_data {
- int size;
- void *buff;
- struct sk_buff *skb;
-};
-
-struct wilc_cfg_cmd_hdr {
- u8 cmd_type;
- u8 seq_no;
- __le16 total_len;
- __le32 driver_handler;
-};
-
-struct wilc_cfg_frame {
- struct wilc_cfg_cmd_hdr hdr;
- u8 frame[WILC_MAX_CFG_FRAME_SIZE];
-};
-
-struct wilc_cfg_rsp {
- u8 type;
- u8 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, struct wilc_vif *vif);
-int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
- u32 buffer_size,
- void (*tx_complete_fn)(void *, int));
-int wilc_wlan_handle_txq(struct wilc *wl, 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_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
- u32 buffer_size, void (*func)(void *, int));
-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 wilc_vif *vif, 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);
-int wilc_wlan_init(struct net_device *dev);
-u32 wilc_get_chipid(struct wilc *wilc, bool update);
-#endif
+++ /dev/null
-// 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 "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)
-{
- if ((offset + 4) >= WILC_MAX_CFG_FRAME_SIZE)
- return 0;
-
- put_unaligned_le16(id, &frame[offset]);
- put_unaligned_le16(1, &frame[offset + 2]);
- frame[offset + 4] = val8;
- return 5;
-}
-
-static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16)
-{
- if ((offset + 5) >= WILC_MAX_CFG_FRAME_SIZE)
- return 0;
-
- put_unaligned_le16(id, &frame[offset]);
- put_unaligned_le16(2, &frame[offset + 2]);
- put_unaligned_le16(val16, &frame[offset + 4]);
-
- return 6;
-}
-
-static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
-{
- if ((offset + 7) >= WILC_MAX_CFG_FRAME_SIZE)
- return 0;
-
- put_unaligned_le16(id, &frame[offset]);
- put_unaligned_le16(4, &frame[offset + 2]);
- put_unaligned_le32(val32, &frame[offset + 4]);
-
- return 8;
-}
-
-static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str,
- u32 size)
-{
- if ((offset + size + 4) >= WILC_MAX_CFG_FRAME_SIZE)
- return 0;
-
- put_unaligned_le16(id, &frame[offset]);
- put_unaligned_le16(size, &frame[offset + 2]);
- if (str && size != 0)
- memcpy(&frame[offset + 4], str, size);
-
- return (size + 4);
-}
-
-static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size)
-{
- u32 i;
- u8 checksum = 0;
-
- if ((offset + size + 5) >= WILC_MAX_CFG_FRAME_SIZE)
- return 0;
-
- put_unaligned_le16(id, &frame[offset]);
- put_unaligned_le16(size, &frame[offset + 2]);
-
- if ((b) && size != 0) {
- memcpy(&frame[offset + 4], b, size);
- for (i = 0; i < size; i++)
- checksum += frame[offset + i + 4];
- }
-
- frame[offset + 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 = get_unaligned_le16(info);
-
- 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 {
- struct wilc_cfg_hword *hw = &wl->cfg.hw[i];
-
- if (hw->id == WID_NIL)
- break;
-
- if (hw->id == wid) {
- hw->val = get_unaligned_le16(&info[4]);
- break;
- }
- i++;
- } while (1);
- len = 4;
- break;
-
- case WID_INT:
- do {
- struct wilc_cfg_word *w = &wl->cfg.w[i];
-
- if (w->id == WID_NIL)
- break;
-
- if (w->id == wid) {
- w->val = get_unaligned_le32(&info[4]);
- 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 = get_unaligned_le16(info);
-
- 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)
-{
- if ((offset + 2) >= WILC_MAX_CFG_FRAME_SIZE)
- return 0;
-
- put_unaligned_le16(id, &frame[offset]);
-
- return 2;
-}
-
-int wilc_wlan_cfg_get_val(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) {
- u16 size = get_unaligned_le16(wl->cfg.s[i].str);
-
- 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);
-}
+++ /dev/null
-/* 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_val(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
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#ifndef WILC_WLAN_IF_H
-#define WILC_WLAN_IF_H
-
-#include <linux/netdevice.h>
-
-/********************************************
- *
- * Wlan Configuration ID
- *
- ********************************************/
-
-enum bss_types {
- WILC_FW_BSS_TYPE_INFRA = 0,
- WILC_FW_BSS_TYPE_INDEPENDENT,
- WILC_FW_BSS_TYPE_AP,
-};
-
-enum {
- WILC_FW_OPER_MODE_B_ONLY = 0, /* 1, 2 M, otherwise 5, 11 M */
- WILC_FW_OPER_MODE_G_ONLY, /* 6,12,24 otherwise 9,18,36,48,54 */
- WILC_FW_OPER_MODE_G_MIXED_11B_1, /* 1,2,5.5,11 otherwise all on */
- WILC_FW_OPER_MODE_G_MIXED_11B_2, /* 1,2,5,11,6,12,24 otherwise all on */
-};
-
-enum {
- WILC_FW_PREAMBLE_SHORT = 0, /* Short Preamble */
- WILC_FW_PREAMBLE_LONG = 1, /* Long Preamble */
- WILC_FW_PREAMBLE_AUTO = 2, /* Auto Preamble Selection */
-};
-
-enum {
- WILC_FW_PASSIVE_SCAN = 0,
- WILC_FW_ACTIVE_SCAN = 1,
-};
-
-enum {
- WILC_FW_NO_POWERSAVE = 0,
- WILC_FW_MIN_FAST_PS = 1,
- WILC_FW_MAX_FAST_PS = 2,
- WILC_FW_MIN_PSPOLL_PS = 3,
- WILC_FW_MAX_PSPOLL_PS = 4
-};
-
-enum chip_ps_states {
- WILC_CHIP_WAKEDUP = 0,
- WILC_CHIP_SLEEPING_AUTO = 1,
- WILC_CHIP_SLEEPING_MANUAL = 2
-};
-
-enum bus_acquire {
- WILC_BUS_ACQUIRE_ONLY = 0,
- WILC_BUS_ACQUIRE_AND_WAKEUP = 1,
-};
-
-enum bus_release {
- WILC_BUS_RELEASE_ONLY = 0,
- WILC_BUS_RELEASE_ALLOW_SLEEP = 1,
-};
-
-enum {
- WILC_FW_NO_ENCRYPT = 0,
- WILC_FW_ENCRYPT_ENABLED = BIT(0),
- WILC_FW_WEP = BIT(1),
- WILC_FW_WEP_EXTENDED = BIT(2),
- WILC_FW_WPA = BIT(3),
- WILC_FW_WPA2 = BIT(4),
- WILC_FW_AES = BIT(5),
- WILC_FW_TKIP = BIT(6)
-};
-
-enum {
- WILC_FW_SEC_NO = WILC_FW_NO_ENCRYPT,
- WILC_FW_SEC_WEP = WILC_FW_WEP | WILC_FW_ENCRYPT_ENABLED,
- WILC_FW_SEC_WEP_EXTENDED = WILC_FW_WEP_EXTENDED | WILC_FW_SEC_WEP,
- WILC_FW_SEC_WPA = WILC_FW_WPA | WILC_FW_ENCRYPT_ENABLED,
- WILC_FW_SEC_WPA_AES = WILC_FW_AES | WILC_FW_SEC_WPA,
- WILC_FW_SEC_WPA_TKIP = WILC_FW_TKIP | WILC_FW_SEC_WPA,
- WILC_FW_SEC_WPA2 = WILC_FW_WPA2 | WILC_FW_ENCRYPT_ENABLED,
- WILC_FW_SEC_WPA2_AES = WILC_FW_AES | WILC_FW_SEC_WPA2,
- WILC_FW_SEC_WPA2_TKIP = WILC_FW_TKIP | WILC_FW_SEC_WPA2
-};
-
-enum authtype {
- WILC_FW_AUTH_OPEN_SYSTEM = 1,
- WILC_FW_AUTH_SHARED_KEY = 2,
- WILC_FW_AUTH_ANY = 3,
- WILC_FW_AUTH_IEEE8021 = 5
-};
-
-enum site_survey {
- WILC_FW_SITE_SURVEY_1CH = 0,
- WILC_FW_SITE_SURVEY_ALL_CH = 1,
- WILC_FW_SITE_SURVEY_OFF = 2
-};
-
-enum {
- WILC_FW_ACK_POLICY_NORMAL = 0,
- WILC_FW_ACK_NO_POLICY,
-};
-
-enum {
- WILC_FW_REKEY_POLICY_DISABLE = 1,
- WILC_FW_REKEY_POLICY_TIME_BASE,
- WILC_FW_REKEY_POLICY_PKT_BASE,
- WILC_FW_REKEY_POLICY_TIME_PKT_BASE
-};
-
-enum {
- WILC_FW_FILTER_NO = 0x00,
- WILC_FW_FILTER_AP_ONLY = 0x01,
- WILC_FW_FILTER_STA_ONLY = 0x02
-};
-
-enum {
- WILC_FW_11N_PROT_AUTO = 0, /* Auto */
- WILC_FW_11N_NO_PROT, /* Do not use any protection */
- WILC_FW_11N_PROT_ERP, /* Protect all ERP frame exchanges */
- WILC_FW_11N_PROT_HT, /* Protect all HT frame exchanges */
- WILC_FW_11N_PROT_GF /* Protect all GF frame exchanges */
-};
-
-enum {
- WILC_FW_ERP_PROT_SELF_CTS,
- WILC_FW_ERP_PROT_RTS_CTS,
-};
-
-enum {
- WILC_FW_11N_OP_MODE_HT_MIXED = 1,
- WILC_FW_11N_OP_MODE_HT_ONLY_20MHZ,
- WILC_FW_11N_OP_MODE_HT_ONLY_20_40MHZ,
-};
-
-enum {
- WILC_FW_OBBS_NONHT_NO_DETECT = 0,
- WILC_FW_OBBS_NONHT_DETECT_ONLY = 1,
- WILC_FW_OBBS_NONHT_DETECT_PROTECT = 2,
- WILC_FW_OBBS_NONHT_DETECT_PROTECT_REPORT = 3,
-};
-
-enum {
- WILC_FW_HT_PROT_RTS_CTS_NONHT = 0, /* RTS-CTS at non-HT rate */
- WILC_FW_HT_PROT_FIRST_FRAME_NONHT, /* First frame at non-HT rate */
- WILC_FW_HT_PROT_LSIG_TXOP, /* LSIG TXOP Protection */
- WILC_FW_HT_PROT_FIRST_FRAME_MIXED, /* First frame at Mixed format */
-};
-
-enum {
- WILC_FW_SMPS_MODE_STATIC = 1,
- WILC_FW_SMPS_MODE_DYNAMIC = 2,
- WILC_FW_SMPS_MODE_MIMO = 3, /* power save disable */
-};
-
-enum {
- WILC_FW_TX_RATE_AUTO = 0,
- WILC_FW_TX_RATE_MBPS_1 = 1,
- WILC_FW_TX_RATE_MBPS_2 = 2,
- WILC_FW_TX_RATE_MBPS_5_5 = 5,
- WILC_FW_TX_RATE_MBPS_11 = 11,
- WILC_FW_TX_RATE_MBPS_6 = 6,
- WILC_FW_TX_RATE_MBPS_9 = 9,
- WILC_FW_TX_RATE_MBPS_12 = 12,
- WILC_FW_TX_RATE_MBPS_18 = 18,
- WILC_FW_TX_RATE_MBPS_24 = 24,
- WILC_FW_TX_RATE_MBPS_36 = 36,
- WILC_FW_TX_RATE_MBPS_48 = 48,
- WILC_FW_TX_RATE_MBPS_54 = 54
-};
-
-enum {
- WILC_FW_DEFAULT_SCAN = 0,
- WILC_FW_USER_SCAN = BIT(0),
- WILC_FW_OBSS_PERIODIC_SCAN = BIT(1),
- WILC_FW_OBSS_ONETIME_SCAN = BIT(2)
-};
-
-enum {
- WILC_FW_ACTION_FRM_IDX = 0,
- WILC_FW_PROBE_REQ_IDX = 1
-};
-
-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 */
- /* 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_PASSIVE_SCAN_TIME = 0x100D,
- WID_JOIN_START_TIMEOUT = 0x100F,
- 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,
-
- /* NMAC Integer WID list */
- /* Custom Integer WID list */
- WID_GET_INACTIVE_TIME = 0x2084,
- /* 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_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 */
-
- /* NMAC String WID list */
- WID_SET_OPERATION_MODE = 0x3079,
- 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
-};
-
-#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include "cfg80211.h"
+#include "wlan_cfg.h"
+
+static inline bool is_wilc1000(u32 id)
+{
+ return (id & 0xfffff000) == 0x100000;
+}
+
+static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
+{
+ mutex_lock(&wilc->hif_cs);
+ if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP)
+ chip_wakeup(wilc);
+}
+
+static inline void release_bus(struct wilc *wilc, enum bus_release release)
+{
+ if (release == WILC_BUS_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;
+ tqe->vif = vif;
+
+ 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,
+ void (*tx_complete_fn)(void *, int))
+{
+ 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 = tx_complete_fn;
+ tqe->priv = priv;
+ tqe->vif = vif;
+
+ 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,
+ void (*tx_complete_fn)(void *, int))
+{
+ 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_MGMT_PKT;
+ tqe->buffer = buffer;
+ tqe->buffer_size = buffer_size;
+ tqe->tx_complete_func = tx_complete_fn;
+ tqe->priv = priv;
+ tqe->ack_idx = NOT_TCP_ACK;
+ tqe->vif = vif;
+ 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) == WILC_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(2000, 2500);
+ 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) == WILC_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(2000, 2500);
+
+ 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 == WILC_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 = WILC_CHIP_WAKEDUP;
+}
+EXPORT_SYMBOL_GPL(chip_wakeup);
+
+void host_wakeup_notify(struct wilc *wilc)
+{
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ wilc->hif_func->hif_write_reg(wilc, 0x10b0, 1);
+ release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+}
+EXPORT_SYMBOL_GPL(host_wakeup_notify);
+
+void host_sleep_notify(struct wilc *wilc)
+{
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ wilc->hif_func->hif_write_reg(wilc, 0x10ac, 1);
+ release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+}
+EXPORT_SYMBOL_GPL(host_sleep_notify);
+
+int wilc_wlan_handle_txq(struct wilc *wilc, 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];
+ const struct wilc_hif_func *func;
+ u8 *txb = wilc->tx_buffer;
+ struct net_device *dev;
+ struct wilc_vif *vif;
+
+ if (wilc->quit)
+ goto out;
+
+ mutex_lock(&wilc->txq_add_to_head_cs);
+ tqe = wilc_wlan_txq_get_first(wilc);
+ if (!tqe)
+ goto out;
+ dev = tqe->vif->ndev;
+ wilc_wlan_txq_filter_dup_tcp_ack(dev);
+ 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) > WILC_TX_BUFF_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, WILC_BUS_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, WILC_BUS_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 = -ENOBUFS;
+ goto out_release_bus;
+ }
+
+ release_bus(wilc, WILC_BUS_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;
+
+ vif = tqe->vif;
+ 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 = tqe->vif->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, WILC_BUS_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, WILC_BUS_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;
+ header = get_unaligned_le32(buff_ptr);
+
+ 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) {
+ 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_host(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_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 (WILC_RX_BUFF_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, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ wilc->hif_func->hif_read_int(wilc, &int_status);
+
+ if (int_status & DATA_INT_EXT)
+ wilc_wlan_handle_isr_ext(wilc, int_status);
+
+ if (!(int_status & (ALL_INT_EXT)))
+ wilc_unknown_isr_ext(wilc);
+
+ release_bus(wilc, WILC_BUS_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 {
+ addr = get_unaligned_le32(&buffer[offset]);
+ size = get_unaligned_le32(&buffer[offset + 4]);
+ acquire_bus(wilc, WILC_BUS_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, WILC_BUS_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 == WILC_HIF_SDIO) {
+ reg = 0;
+ reg |= BIT(3);
+ } else if (wilc->io_type == WILC_HIF_SPI) {
+ reg = 1;
+ }
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);
+ if (!ret) {
+ release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ return -EIO;
+ }
+ reg = 0;
+ if (wilc->io_type == WILC_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, WILC_BUS_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, WILC_BUS_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, WILC_BUS_RELEASE_ONLY);
+
+ return (ret < 0) ? ret : 0;
+}
+
+int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
+{
+ u32 reg = 0;
+ int ret;
+
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®);
+ if (!ret) {
+ netdev_err(vif->ndev, "Error while reading reg\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return -EIO;
+ }
+
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
+ (reg | WILC_ABORT_REQ_BIT));
+ if (!ret) {
+ netdev_err(vif->ndev, "Error while writing reg\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return -EIO;
+ }
+
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®);
+ if (!ret) {
+ netdev_err(vif->ndev, "Error while reading reg\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return -EIO;
+ }
+ reg = BIT(0);
+
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg);
+ if (!ret) {
+ netdev_err(vif->ndev, "Error while writing reg\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return -EIO;
+ }
+
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+
+ return 0;
+}
+
+void wilc_wlan_cleanup(struct net_device *dev)
+{
+ struct txq_entry_t *tqe;
+ struct rxq_entry_t *rqe;
+ 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;
+ 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 t_len = wilc->cfg_frame_offset + sizeof(struct wilc_cfg_cmd_hdr);
+
+ if (type == WILC_CFG_SET)
+ cfg->hdr.cmd_type = 'W';
+ else
+ cfg->hdr.cmd_type = 'Q';
+
+ cfg->hdr.seq_no = wilc->cfg_seq_no % 256;
+ cfg->hdr.total_len = cpu_to_le16(t_len);
+ cfg->hdr.driver_handler = cpu_to_le32(drv_handler);
+ wilc->cfg_seq_no = cfg->hdr.seq_no;
+
+ if (!wilc_wlan_txq_add_cfg_pkt(vif, (u8 *)&cfg->hdr, t_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;
+
+ mutex_lock(&wilc->cfg_cmd_lock);
+
+ 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) {
+ mutex_unlock(&wilc->cfg_cmd_lock);
+ return ret_size;
+ }
+
+ netdev_dbg(vif->ndev, "%s: seqno[%d]\n", __func__, wilc->cfg_seq_no);
+
+ if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler))
+ ret_size = 0;
+
+ if (!wait_for_completion_timeout(&wilc->cfg_event,
+ WILC_CFG_PKTS_TIMEOUT)) {
+ netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);
+ ret_size = 0;
+ }
+
+ wilc->cfg_frame_offset = 0;
+ wilc->cfg_seq_no += 1;
+ mutex_unlock(&wilc->cfg_cmd_lock);
+
+ 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;
+
+ mutex_lock(&wilc->cfg_cmd_lock);
+
+ 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) {
+ mutex_unlock(&wilc->cfg_cmd_lock);
+ return ret_size;
+ }
+
+ if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler))
+ ret_size = 0;
+
+ if (!wait_for_completion_timeout(&wilc->cfg_event,
+ WILC_CFG_PKTS_TIMEOUT)) {
+ netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);
+ ret_size = 0;
+ }
+ wilc->cfg_frame_offset = 0;
+ wilc->cfg_seq_no += 1;
+ mutex_unlock(&wilc->cfg_cmd_lock);
+
+ return ret_size;
+}
+
+int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
+ u32 count)
+{
+ int i;
+ int ret = 0;
+ u32 drv = wilc_get_vif_idx(vif);
+
+ if (mode == WILC_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 == WILC_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, WILC_BUS_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");
+ goto release;
+ }
+ reg |= BIT(0);
+ ret = wilc->hif_func->hif_write_reg(wilc, 0x1118, reg);
+ if (!ret) {
+ netdev_err(dev, "fail write reg 0x1118\n");
+ goto release;
+ }
+ ret = wilc->hif_func->hif_write_reg(wilc, 0xc0000, 0x71);
+ if (!ret) {
+ netdev_err(dev, "fail write reg 0xc0000\n");
+ goto release;
+ }
+ }
+
+release:
+ release_bus(wilc, WILC_BUS_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(WILC_TX_BUFF_SIZE, GFP_KERNEL);
+
+ if (!wilc->tx_buffer) {
+ ret = -ENOBUFS;
+ goto fail;
+ }
+
+ if (!wilc->rx_buffer)
+ wilc->rx_buffer = kmalloc(WILC_RX_BUFF_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;
+}
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#ifndef WILC_WLAN_H
+#define WILC_WLAN_H
+
+#include <linux/types.h>
+
+/********************************************
+ *
+ * Mac eth header length
+ *
+ ********************************************/
+#define 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_FW_HOST_COMM 0x13c0
+#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_ABORT_REQ_BIT BIT(31)
+
+#define WILC_RX_BUFF_SIZE (96 * 1024)
+#define WILC_TX_BUFF_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 ALL_INT_EXT DATA_INT_EXT
+#define NUM_INT_EXT 1
+
+#define DATA_INT_CLR CLR_INT0
+
+#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 WILC_CFG_PKTS_TIMEOUT msecs_to_jiffies(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;
+ struct wilc_vif *vif;
+ 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 WILC_MAX_CFG_FRAME_SIZE 1468
+
+struct tx_complete_data {
+ int size;
+ void *buff;
+ struct sk_buff *skb;
+};
+
+struct wilc_cfg_cmd_hdr {
+ u8 cmd_type;
+ u8 seq_no;
+ __le16 total_len;
+ __le32 driver_handler;
+};
+
+struct wilc_cfg_frame {
+ struct wilc_cfg_cmd_hdr hdr;
+ u8 frame[WILC_MAX_CFG_FRAME_SIZE];
+};
+
+struct wilc_cfg_rsp {
+ u8 type;
+ u8 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, struct wilc_vif *vif);
+int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
+ u32 buffer_size,
+ void (*tx_complete_fn)(void *, int));
+int wilc_wlan_handle_txq(struct wilc *wl, 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_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
+ u32 buffer_size, void (*func)(void *, int));
+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 wilc_vif *vif, 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);
+int wilc_wlan_init(struct net_device *dev);
+u32 wilc_get_chipid(struct wilc *wilc, bool update);
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include "wlan_if.h"
+#include "wlan.h"
+#include "wlan_cfg.h"
+#include "netdev.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)
+{
+ if ((offset + 4) >= WILC_MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(1, &frame[offset + 2]);
+ frame[offset + 4] = val8;
+ return 5;
+}
+
+static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16)
+{
+ if ((offset + 5) >= WILC_MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(2, &frame[offset + 2]);
+ put_unaligned_le16(val16, &frame[offset + 4]);
+
+ return 6;
+}
+
+static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
+{
+ if ((offset + 7) >= WILC_MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(4, &frame[offset + 2]);
+ put_unaligned_le32(val32, &frame[offset + 4]);
+
+ return 8;
+}
+
+static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str,
+ u32 size)
+{
+ if ((offset + size + 4) >= WILC_MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(size, &frame[offset + 2]);
+ if (str && size != 0)
+ memcpy(&frame[offset + 4], str, size);
+
+ return (size + 4);
+}
+
+static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size)
+{
+ u32 i;
+ u8 checksum = 0;
+
+ if ((offset + size + 5) >= WILC_MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ put_unaligned_le16(id, &frame[offset]);
+ put_unaligned_le16(size, &frame[offset + 2]);
+
+ if ((b) && size != 0) {
+ memcpy(&frame[offset + 4], b, size);
+ for (i = 0; i < size; i++)
+ checksum += frame[offset + i + 4];
+ }
+
+ frame[offset + 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 = get_unaligned_le16(info);
+
+ 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 {
+ struct wilc_cfg_hword *hw = &wl->cfg.hw[i];
+
+ if (hw->id == WID_NIL)
+ break;
+
+ if (hw->id == wid) {
+ hw->val = get_unaligned_le16(&info[4]);
+ break;
+ }
+ i++;
+ } while (1);
+ len = 4;
+ break;
+
+ case WID_INT:
+ do {
+ struct wilc_cfg_word *w = &wl->cfg.w[i];
+
+ if (w->id == WID_NIL)
+ break;
+
+ if (w->id == wid) {
+ w->val = get_unaligned_le32(&info[4]);
+ 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 = get_unaligned_le16(info);
+
+ 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)
+{
+ if ((offset + 2) >= WILC_MAX_CFG_FRAME_SIZE)
+ return 0;
+
+ put_unaligned_le16(id, &frame[offset]);
+
+ return 2;
+}
+
+int wilc_wlan_cfg_get_val(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) {
+ u16 size = get_unaligned_le16(wl->cfg.s[i].str);
+
+ 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);
+}
--- /dev/null
+/* 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_val(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
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#ifndef WILC_WLAN_IF_H
+#define WILC_WLAN_IF_H
+
+#include <linux/netdevice.h>
+
+/********************************************
+ *
+ * Wlan Configuration ID
+ *
+ ********************************************/
+
+enum bss_types {
+ WILC_FW_BSS_TYPE_INFRA = 0,
+ WILC_FW_BSS_TYPE_INDEPENDENT,
+ WILC_FW_BSS_TYPE_AP,
+};
+
+enum {
+ WILC_FW_OPER_MODE_B_ONLY = 0, /* 1, 2 M, otherwise 5, 11 M */
+ WILC_FW_OPER_MODE_G_ONLY, /* 6,12,24 otherwise 9,18,36,48,54 */
+ WILC_FW_OPER_MODE_G_MIXED_11B_1, /* 1,2,5.5,11 otherwise all on */
+ WILC_FW_OPER_MODE_G_MIXED_11B_2, /* 1,2,5,11,6,12,24 otherwise all on */
+};
+
+enum {
+ WILC_FW_PREAMBLE_SHORT = 0, /* Short Preamble */
+ WILC_FW_PREAMBLE_LONG = 1, /* Long Preamble */
+ WILC_FW_PREAMBLE_AUTO = 2, /* Auto Preamble Selection */
+};
+
+enum {
+ WILC_FW_PASSIVE_SCAN = 0,
+ WILC_FW_ACTIVE_SCAN = 1,
+};
+
+enum {
+ WILC_FW_NO_POWERSAVE = 0,
+ WILC_FW_MIN_FAST_PS = 1,
+ WILC_FW_MAX_FAST_PS = 2,
+ WILC_FW_MIN_PSPOLL_PS = 3,
+ WILC_FW_MAX_PSPOLL_PS = 4
+};
+
+enum chip_ps_states {
+ WILC_CHIP_WAKEDUP = 0,
+ WILC_CHIP_SLEEPING_AUTO = 1,
+ WILC_CHIP_SLEEPING_MANUAL = 2
+};
+
+enum bus_acquire {
+ WILC_BUS_ACQUIRE_ONLY = 0,
+ WILC_BUS_ACQUIRE_AND_WAKEUP = 1,
+};
+
+enum bus_release {
+ WILC_BUS_RELEASE_ONLY = 0,
+ WILC_BUS_RELEASE_ALLOW_SLEEP = 1,
+};
+
+enum {
+ WILC_FW_NO_ENCRYPT = 0,
+ WILC_FW_ENCRYPT_ENABLED = BIT(0),
+ WILC_FW_WEP = BIT(1),
+ WILC_FW_WEP_EXTENDED = BIT(2),
+ WILC_FW_WPA = BIT(3),
+ WILC_FW_WPA2 = BIT(4),
+ WILC_FW_AES = BIT(5),
+ WILC_FW_TKIP = BIT(6)
+};
+
+enum {
+ WILC_FW_SEC_NO = WILC_FW_NO_ENCRYPT,
+ WILC_FW_SEC_WEP = WILC_FW_WEP | WILC_FW_ENCRYPT_ENABLED,
+ WILC_FW_SEC_WEP_EXTENDED = WILC_FW_WEP_EXTENDED | WILC_FW_SEC_WEP,
+ WILC_FW_SEC_WPA = WILC_FW_WPA | WILC_FW_ENCRYPT_ENABLED,
+ WILC_FW_SEC_WPA_AES = WILC_FW_AES | WILC_FW_SEC_WPA,
+ WILC_FW_SEC_WPA_TKIP = WILC_FW_TKIP | WILC_FW_SEC_WPA,
+ WILC_FW_SEC_WPA2 = WILC_FW_WPA2 | WILC_FW_ENCRYPT_ENABLED,
+ WILC_FW_SEC_WPA2_AES = WILC_FW_AES | WILC_FW_SEC_WPA2,
+ WILC_FW_SEC_WPA2_TKIP = WILC_FW_TKIP | WILC_FW_SEC_WPA2
+};
+
+enum authtype {
+ WILC_FW_AUTH_OPEN_SYSTEM = 1,
+ WILC_FW_AUTH_SHARED_KEY = 2,
+ WILC_FW_AUTH_ANY = 3,
+ WILC_FW_AUTH_IEEE8021 = 5
+};
+
+enum site_survey {
+ WILC_FW_SITE_SURVEY_1CH = 0,
+ WILC_FW_SITE_SURVEY_ALL_CH = 1,
+ WILC_FW_SITE_SURVEY_OFF = 2
+};
+
+enum {
+ WILC_FW_ACK_POLICY_NORMAL = 0,
+ WILC_FW_ACK_NO_POLICY,
+};
+
+enum {
+ WILC_FW_REKEY_POLICY_DISABLE = 1,
+ WILC_FW_REKEY_POLICY_TIME_BASE,
+ WILC_FW_REKEY_POLICY_PKT_BASE,
+ WILC_FW_REKEY_POLICY_TIME_PKT_BASE
+};
+
+enum {
+ WILC_FW_FILTER_NO = 0x00,
+ WILC_FW_FILTER_AP_ONLY = 0x01,
+ WILC_FW_FILTER_STA_ONLY = 0x02
+};
+
+enum {
+ WILC_FW_11N_PROT_AUTO = 0, /* Auto */
+ WILC_FW_11N_NO_PROT, /* Do not use any protection */
+ WILC_FW_11N_PROT_ERP, /* Protect all ERP frame exchanges */
+ WILC_FW_11N_PROT_HT, /* Protect all HT frame exchanges */
+ WILC_FW_11N_PROT_GF /* Protect all GF frame exchanges */
+};
+
+enum {
+ WILC_FW_ERP_PROT_SELF_CTS,
+ WILC_FW_ERP_PROT_RTS_CTS,
+};
+
+enum {
+ WILC_FW_11N_OP_MODE_HT_MIXED = 1,
+ WILC_FW_11N_OP_MODE_HT_ONLY_20MHZ,
+ WILC_FW_11N_OP_MODE_HT_ONLY_20_40MHZ,
+};
+
+enum {
+ WILC_FW_OBBS_NONHT_NO_DETECT = 0,
+ WILC_FW_OBBS_NONHT_DETECT_ONLY = 1,
+ WILC_FW_OBBS_NONHT_DETECT_PROTECT = 2,
+ WILC_FW_OBBS_NONHT_DETECT_PROTECT_REPORT = 3,
+};
+
+enum {
+ WILC_FW_HT_PROT_RTS_CTS_NONHT = 0, /* RTS-CTS at non-HT rate */
+ WILC_FW_HT_PROT_FIRST_FRAME_NONHT, /* First frame at non-HT rate */
+ WILC_FW_HT_PROT_LSIG_TXOP, /* LSIG TXOP Protection */
+ WILC_FW_HT_PROT_FIRST_FRAME_MIXED, /* First frame at Mixed format */
+};
+
+enum {
+ WILC_FW_SMPS_MODE_STATIC = 1,
+ WILC_FW_SMPS_MODE_DYNAMIC = 2,
+ WILC_FW_SMPS_MODE_MIMO = 3, /* power save disable */
+};
+
+enum {
+ WILC_FW_TX_RATE_AUTO = 0,
+ WILC_FW_TX_RATE_MBPS_1 = 1,
+ WILC_FW_TX_RATE_MBPS_2 = 2,
+ WILC_FW_TX_RATE_MBPS_5_5 = 5,
+ WILC_FW_TX_RATE_MBPS_11 = 11,
+ WILC_FW_TX_RATE_MBPS_6 = 6,
+ WILC_FW_TX_RATE_MBPS_9 = 9,
+ WILC_FW_TX_RATE_MBPS_12 = 12,
+ WILC_FW_TX_RATE_MBPS_18 = 18,
+ WILC_FW_TX_RATE_MBPS_24 = 24,
+ WILC_FW_TX_RATE_MBPS_36 = 36,
+ WILC_FW_TX_RATE_MBPS_48 = 48,
+ WILC_FW_TX_RATE_MBPS_54 = 54
+};
+
+enum {
+ WILC_FW_DEFAULT_SCAN = 0,
+ WILC_FW_USER_SCAN = BIT(0),
+ WILC_FW_OBSS_PERIODIC_SCAN = BIT(1),
+ WILC_FW_OBSS_ONETIME_SCAN = BIT(2)
+};
+
+enum {
+ WILC_FW_ACTION_FRM_IDX = 0,
+ WILC_FW_PROBE_REQ_IDX = 1
+};
+
+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 */
+ /* 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_PASSIVE_SCAN_TIME = 0x100D,
+ WID_JOIN_START_TIMEOUT = 0x100F,
+ 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,
+
+ /* NMAC Integer WID list */
+ /* Custom Integer WID list */
+ WID_GET_INACTIVE_TIME = 0x2084,
+ /* 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_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 */
+
+ /* NMAC String WID list */
+ WID_SET_OPERATION_MODE = 0x3079,
+ 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
+};
+
+#endif