diff options
Diffstat (limited to 'drivers/staging/wilc1000')
-rw-r--r-- | drivers/staging/wilc1000/Makefile | 8 | ||||
-rw-r--r-- | drivers/staging/wilc1000/cfg80211.c (renamed from drivers/staging/wilc1000/wilc_wfi_cfgoperations.c) | 246 | ||||
-rw-r--r-- | drivers/staging/wilc1000/cfg80211.h (renamed from drivers/staging/wilc1000/wilc_wfi_cfgoperations.h) | 8 | ||||
-rw-r--r-- | drivers/staging/wilc1000/hif.c (renamed from drivers/staging/wilc1000/wilc_hif.c) | 43 | ||||
-rw-r--r-- | drivers/staging/wilc1000/hif.h (renamed from drivers/staging/wilc1000/wilc_hif.h) | 6 | ||||
-rw-r--r-- | drivers/staging/wilc1000/mon.c (renamed from drivers/staging/wilc1000/wilc_mon.c) | 4 | ||||
-rw-r--r-- | drivers/staging/wilc1000/netdev.c (renamed from drivers/staging/wilc1000/wilc_netdev.c) | 146 | ||||
-rw-r--r-- | drivers/staging/wilc1000/netdev.h (renamed from drivers/staging/wilc1000/wilc_wfi_netdevice.h) | 34 | ||||
-rw-r--r-- | drivers/staging/wilc1000/sdio.c (renamed from drivers/staging/wilc1000/wilc_sdio.c) | 4 | ||||
-rw-r--r-- | drivers/staging/wilc1000/spi.c (renamed from drivers/staging/wilc1000/wilc_spi.c) | 15 | ||||
-rw-r--r-- | drivers/staging/wilc1000/wlan.c (renamed from drivers/staging/wilc1000/wilc_wlan.c) | 4 | ||||
-rw-r--r-- | drivers/staging/wilc1000/wlan.h (renamed from drivers/staging/wilc1000/wilc_wlan.h) | 2 | ||||
-rw-r--r-- | drivers/staging/wilc1000/wlan_cfg.c (renamed from drivers/staging/wilc1000/wilc_wlan_cfg.c) | 30 | ||||
-rw-r--r-- | drivers/staging/wilc1000/wlan_cfg.h (renamed from drivers/staging/wilc1000/wilc_wlan_cfg.h) | 0 | ||||
-rw-r--r-- | drivers/staging/wilc1000/wlan_if.h (renamed from drivers/staging/wilc1000/wilc_wlan_if.h) | 8 |
15 files changed, 316 insertions, 242 deletions
diff --git a/drivers/staging/wilc1000/Makefile b/drivers/staging/wilc1000/Makefile index a5a8e806b98e..a3305a0a888a 100644 --- a/drivers/staging/wilc1000/Makefile +++ b/drivers/staging/wilc1000/Makefile @@ -4,11 +4,11 @@ obj-$(CONFIG_WILC1000) += wilc1000.o 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 diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/cfg80211.c index 22f21831649b..4863e516ff13 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/cfg80211.c @@ -4,7 +4,7 @@ * All rights reserved. */ -#include "wilc_wfi_cfgoperations.h" +#include "cfg80211.h" #define FRAME_TYPE_ID 0 #define ACTION_CAT_ID 24 @@ -137,6 +137,7 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, 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; @@ -158,12 +159,16 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, memcpy(priv->associated_bss, conn_info->bssid, ETH_ALEN); - cfg80211_connect_result(dev, conn_info->bssid, - conn_info->req_ies, - conn_info->req_ies_len, - conn_info->resp_ies, - conn_info->resp_ies_len, connect_status, - GFP_KERNEL); + 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; @@ -186,15 +191,15 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, } } -static struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl) +struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl) { - int i; + struct wilc_vif *vif; - for (i = 0; i < wl->vif_num; i++) - if (wl->vif[i]) - return wl->vif[i]; + vif = list_first_or_null_rcu(&wl->vif_list, typeof(*vif), list); + if (!vif) + return ERR_PTR(-EINVAL); - return ERR_PTR(-EINVAL); + return vif; } static int set_channel(struct wiphy *wiphy, @@ -204,11 +209,12 @@ static int set_channel(struct wiphy *wiphy, struct wilc_vif *vif; u32 channelnum; int result; + int srcu_idx; - mutex_lock(&wl->vif_mutex); + srcu_idx = srcu_read_lock(&wl->srcu); vif = wilc_get_wl_to_vif(wl); if (IS_ERR(vif)) { - mutex_unlock(&wl->vif_mutex); + srcu_read_unlock(&wl->srcu, srcu_idx); return PTR_ERR(vif); } @@ -219,7 +225,7 @@ static int set_channel(struct wiphy *wiphy, if (result) netdev_err(vif->ndev, "Error in setting channel\n"); - mutex_unlock(&wl->vif_mutex); + srcu_read_unlock(&wl->srcu, srcu_idx); return result; } @@ -405,6 +411,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, goto out_put_bss; } kfree(join_params); + vif->bss = bss; cfg80211_put_bss(wiphy, bss); return 0; @@ -450,6 +457,8 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev, ret = -EINVAL; } + vif->bss = NULL; + return ret; } @@ -620,29 +629,26 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev, bool pairwise, const u8 *mac_addr) { - struct wilc *wl = wiphy_priv(wiphy); struct wilc_vif *vif = netdev_priv(netdev); struct wilc_priv *priv = &vif->priv; - if (netdev == wl->vif[0]->ndev) { - if (priv->wilc_gtk[key_index]) { - kfree(priv->wilc_gtk[key_index]->key); - priv->wilc_gtk[key_index]->key = NULL; - kfree(priv->wilc_gtk[key_index]->seq); - priv->wilc_gtk[key_index]->seq = NULL; + 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; - } + 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 (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]) { @@ -752,33 +758,19 @@ static int change_bss(struct wiphy *wiphy, struct net_device *dev, return 0; } -struct wilc_vif *wilc_get_interface(struct wilc *wl) -{ - int i; - struct wilc_vif *vif = NULL; - - mutex_lock(&wl->vif_mutex); - for (i = 0; i < wl->vif_num; i++) { - if (wl->vif[i]) { - vif = wl->vif[i]; - break; - } - } - mutex_unlock(&wl->vif_mutex); - return vif; -} - static int set_wiphy_params(struct wiphy *wiphy, u32 changed) { - int ret; + 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; - vif = wilc_get_interface(wl); - if (!vif) - return -EINVAL; + 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; @@ -808,7 +800,7 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) } else { netdev_err(vif->ndev, "Fragmentation threshold out of range\n"); - return -EINVAL; + goto out; } } @@ -821,7 +813,7 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) cfg_param_val.rts_threshold = wiphy->rts_threshold; } else { netdev_err(vif->ndev, "RTS threshold out of range\n"); - return -EINVAL; + goto out; } } @@ -829,6 +821,8 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) if (ret) netdev_err(priv->dev, "Error in setting WIPHY PARAMS\n"); +out: + srcu_read_unlock(&wl->srcu, srcu_idx); return ret; } @@ -1144,7 +1138,7 @@ static int remain_on_channel(struct wiphy *wiphy, cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_KERNEL); mod_timer(&vif->hif_drv->remain_on_ch_timer, - jiffies + msecs_to_jiffies(duration)); + jiffies + msecs_to_jiffies(duration + 1000)); return ret; } @@ -1419,8 +1413,10 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) wilc_wfi_deinit_mon_interface(wl, true); vif->iftype = WILC_STATION_MODE; - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), - WILC_STATION_MODE, vif->idx); + + 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); @@ -1432,8 +1428,10 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, priv->wdev.iftype = type; vif->monitor_flag = 0; vif->iftype = WILC_CLIENT_MODE; - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), - WILC_STATION_MODE, vif->idx); + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_STATION_MODE, vif->idx); break; case NL80211_IFTYPE_AP: @@ -1450,8 +1448,10 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, dev->ieee80211_ptr->iftype = type; priv->wdev.iftype = type; vif->iftype = WILC_GO_MODE; - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), - WILC_AP_MODE, vif->idx); + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_AP_MODE, vif->idx); break; default: @@ -1557,20 +1557,16 @@ static int change_station(struct wiphy *wiphy, struct net_device *dev, return ret; } -static int wilc_get_vif_from_type(struct wilc *wl, int type) +static struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type) { - int i; + struct wilc_vif *vif; - mutex_lock(&wl->vif_mutex); - for (i = 0; i < wl->vif_num; i++) { - if (wl->vif[i]->iftype == type) { - mutex_unlock(&wl->vif_mutex); - return i; - } + list_for_each_entry_rcu(vif, &wl->vif_list, list) { + if (vif->iftype == type) + return vif; } - mutex_unlock(&wl->vif_mutex); - return -EINVAL; + return NULL; } static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy, @@ -1583,29 +1579,36 @@ static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy, struct wilc_vif *vif; struct wireless_dev *wdev; int iftype; - int ret; if (type == NL80211_IFTYPE_MONITOR) { struct net_device *ndev; - int ap_index = wilc_get_vif_from_type(wl, WILC_AP_MODE); - - if (ap_index < 0) { - ap_index = wilc_get_vif_from_type(wl, WILC_GO_MODE); - if (ap_index < 0) + 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; + } } - vif = wl->vif[ap_index]; - if (vif->monitor_flag) + 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) + if (ndev) { vif->monitor_flag = 1; - else + } 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; } @@ -1613,9 +1616,10 @@ validate_interface: mutex_lock(&wl->vif_mutex); if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) { pr_err("Reached maximum number of interface\n"); - ret = -EINVAL; - goto out_err; + mutex_unlock(&wl->vif_mutex); + return ERR_PTR(-EINVAL); } + mutex_unlock(&wl->vif_mutex); switch (type) { case NL80211_IFTYPE_STATION: @@ -1625,30 +1629,20 @@ validate_interface: iftype = WILC_AP_MODE; break; default: - ret = -EOPNOTSUPP; - goto out_err; + return ERR_PTR(-EOPNOTSUPP); } vif = wilc_netdev_ifc_init(wl, name, iftype, type, true); - if (IS_ERR(vif)) { - ret = PTR_ERR(vif); - goto out_err; - } - - mutex_unlock(&wl->vif_mutex); + if (IS_ERR(vif)) + return ERR_CAST(vif); return &vif->priv.wdev; - -out_err: - mutex_unlock(&wl->vif_mutex); - return ERR_PTR(ret); } static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { struct wilc *wl = wiphy_priv(wiphy); struct wilc_vif *vif; - int i; if (wdev->iftype == NL80211_IFTYPE_AP || wdev->iftype == NL80211_IFTYPE_P2P_GO) @@ -1658,22 +1652,12 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) unregister_netdevice(vif->ndev); vif->monitor_flag = 0; - mutex_lock(&wl->vif_mutex); wilc_set_operation_mode(vif, 0, 0, 0); - for (i = vif->idx; i < wl->vif_num; i++) { - if ((i + 1) >= wl->vif_num) { - wl->vif[i] = NULL; - } else { - vif = wl->vif[i + 1]; - vif->idx = i; - wl->vif[i] = vif; - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), - vif->iftype, vif->idx); - } - } + mutex_lock(&wl->vif_mutex); + list_del_rcu(&vif->list); wl->vif_num--; mutex_unlock(&wl->vif_mutex); - + synchronize_srcu(&wl->srcu); return 0; } @@ -1698,25 +1682,39 @@ static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled) { struct wilc *wl = wiphy_priv(wiphy); struct wilc_vif *vif; + int srcu_idx; - mutex_lock(&wl->vif_mutex); + srcu_idx = srcu_read_lock(&wl->srcu); vif = wilc_get_wl_to_vif(wl); if (IS_ERR(vif)) { - mutex_unlock(&wl->vif_mutex); + srcu_read_unlock(&wl->srcu, srcu_idx); return; } netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled); - mutex_unlock(&wl->vif_mutex); + 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_vif *vif = netdev_priv(wdev->netdev); + 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) @@ -1724,6 +1722,7 @@ static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, 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; } @@ -1803,6 +1802,17 @@ static void wlan_init_locks(struct wilc *wl) 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, @@ -1816,6 +1826,8 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, if (!wl) return -EINVAL; + wlan_init_locks(wl); + ret = wilc_wlan_cfg_init(wl); if (ret) goto free_wl; @@ -1826,6 +1838,7 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, 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) { @@ -1839,8 +1852,6 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, goto free_hq; } - wlan_init_locks(wl); - return 0; free_hq: @@ -1850,6 +1861,7 @@ free_cfg: wilc_wlan_cfg_deinit(wl); free_wl: + wlan_deinit_locks(wl); wiphy_unregister(wl->wiphy); wiphy_free(wl->wiphy); return ret; diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h b/drivers/staging/wilc1000/cfg80211.h index 234faaabdb82..5e5d63f70df2 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h +++ b/drivers/staging/wilc1000/cfg80211.h @@ -4,9 +4,9 @@ * All rights reserved. */ -#ifndef NM_WFI_CFGOPERATIONS -#define NM_WFI_CFGOPERATIONS -#include "wilc_wfi_netdevice.h" +#ifndef WILC_CFG80211_H +#define WILC_CFG80211_H +#include "netdev.h" struct wiphy *wilc_cfg_alloc(void); int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, @@ -24,4 +24,6 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl, 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 diff --git a/drivers/staging/wilc1000/wilc_hif.c b/drivers/staging/wilc1000/hif.c index f2b7d5a1be17..349e45d58ec9 100644 --- a/drivers/staging/wilc1000/wilc_hif.c +++ b/drivers/staging/wilc1000/hif.c @@ -4,7 +4,7 @@ * All rights reserved. */ -#include "wilc_wfi_netdevice.h" +#include "netdev.h" #define WILC_HIF_SCAN_TIMEOUT_MS 5000 #define WILC_HIF_CONNECT_TIMEOUT_MS 9500 @@ -32,7 +32,7 @@ struct wilc_op_mode { }; struct wilc_reg_frame { - bool reg; + u8 reg; u8 reg_id; __le16 frame_type; } __packed; @@ -183,11 +183,17 @@ int wilc_get_vif_idx(struct wilc_vif *vif) 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; - return wilc->vif[index]; + 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) @@ -473,20 +479,27 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, 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]; + if (rates_len < WILC_MAX_RATES_SUPPORTED) { + supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, + ies->data, ies->len); + if (supp_rates_ie) { + u8 ext_rates = supp_rates_ie[1]; - memcpy(¶m->supp_rates[rates_len + 1], supp_rates_ie + 2, - (param->supp_rates[0] - rates_len)); + if (ext_rates > (WILC_MAX_RATES_SUPPORTED - rates_len)) + param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED; + else + param->supp_rates[0] += ext_rates; + + 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); @@ -544,7 +557,7 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, param->mode_802_11i = 2; param->rsn_found = true; - //extract RSN capabilities + /* extract RSN capabilities */ offset += (rsn_ie[offset] * 4) + 2; offset += (rsn_ie[offset] * 4) + 2; memcpy(param->rsn_cap, &rsn_ie[offset], 2); @@ -1776,7 +1789,9 @@ void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg) wid.val = (u8 *)®_frame; memset(®_frame, 0x0, sizeof(reg_frame)); - reg_frame.reg = reg; + + if (reg) + reg_frame.reg = 1; switch (frame_type) { case IEEE80211_STYPE_ACTION: diff --git a/drivers/staging/wilc1000/wilc_hif.h b/drivers/staging/wilc1000/hif.h index ac5fe57f872b..22ee6fffd599 100644 --- a/drivers/staging/wilc1000/wilc_hif.h +++ b/drivers/staging/wilc1000/hif.h @@ -4,10 +4,10 @@ * All rights reserved. */ -#ifndef HOST_INT_H -#define HOST_INT_H +#ifndef WILC_HIF_H +#define WILC_HIF_H #include <linux/ieee80211.h> -#include "wilc_wlan_if.h" +#include "wlan_if.h" enum { WILC_IDLE_MODE = 0x0, diff --git a/drivers/staging/wilc1000/wilc_mon.c b/drivers/staging/wilc1000/mon.c index d6f14f69ad64..48ac33f06f63 100644 --- a/drivers/staging/wilc1000/wilc_mon.c +++ b/drivers/staging/wilc1000/mon.c @@ -4,7 +4,7 @@ * All rights reserved. */ -#include "wilc_wfi_cfgoperations.h" +#include "cfg80211.h" struct wilc_wfi_radiotap_hdr { struct ieee80211_radiotap_header hdr; @@ -220,7 +220,7 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl, { struct wilc_wfi_mon_priv *priv; - /*If monitor interface is already initialized, return it*/ + /* If monitor interface is already initialized, return it */ if (wl->monitor_dev) return wl->monitor_dev; diff --git a/drivers/staging/wilc1000/wilc_netdev.c b/drivers/staging/wilc1000/netdev.c index 508acb8bb089..d2c0b0f7cf63 100644 --- a/drivers/staging/wilc1000/wilc_netdev.c +++ b/drivers/staging/wilc1000/netdev.c @@ -10,8 +10,8 @@ #include <linux/netdevice.h> #include <linux/inetdevice.h> -#include "wilc_wfi_cfgoperations.h" -#include "wilc_wlan_cfg.h" +#include "cfg80211.h" +#include "wlan_cfg.h" #define WILC_MULTICAST_TABLE_SIZE 8 @@ -97,29 +97,25 @@ void wilc_mac_indicate(struct wilc *wilc) static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header) { u8 *bssid, *bssid1; - int i = 0; struct net_device *ndev = NULL; + struct wilc_vif *vif; bssid = mac_header + 10; bssid1 = mac_header + 4; - mutex_lock(&wilc->vif_mutex); - for (i = 0; i < wilc->vif_num; i++) { - if (wilc->vif[i]->mode == WILC_STATION_MODE) - if (ether_addr_equal_unaligned(bssid, - wilc->vif[i]->bssid)) { - ndev = wilc->vif[i]->ndev; + 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 (wilc->vif[i]->mode == WILC_AP_MODE) - if (ether_addr_equal_unaligned(bssid1, - wilc->vif[i]->bssid)) { - ndev = wilc->vif[i]->ndev; + if (vif->mode == WILC_AP_MODE) + if (ether_addr_equal_unaligned(bssid1, vif->bssid)) { + ndev = vif->ndev; goto out; } } out: - mutex_unlock(&wilc->vif_mutex); return ndev; } @@ -137,13 +133,16 @@ void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode) int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) { - u8 i = 0; + int srcu_idx; u8 ret_val = 0; + struct wilc_vif *vif; - for (i = 0; i < wilc->vif_num; i++) - if (!is_zero_ether_addr(wilc->vif[i]->bssid)) + 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; } @@ -167,16 +166,16 @@ static int wilc_txq_task(void *vp) do { ret = wilc_wlan_handle_txq(wl, &txq_count); if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) { - int i; + int srcu_idx; struct wilc_vif *ifc; - mutex_lock(&wl->vif_mutex); - for (i = 0; i < wl->vif_num; i++) { - ifc = wl->vif[i]; + 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); } - mutex_unlock(&wl->vif_mutex); + srcu_read_unlock(&wl->srcu, srcu_idx); } } while (ret == -ENOBUFS && !wl->close); } @@ -424,18 +423,6 @@ fail: return -1; } -static void wlan_deinit_locks(struct net_device *dev) -{ - struct wilc_vif *vif = netdev_priv(dev); - struct wilc *wilc = vif->wilc; - - mutex_destroy(&wilc->hif_cs); - mutex_destroy(&wilc->rxq_cs); - mutex_destroy(&wilc->cfg_cmd_lock); - mutex_destroy(&wilc->txq_add_to_head_cs); - mutex_destroy(&wilc->vif_mutex); -} - static void wlan_deinitialize_threads(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); @@ -477,7 +464,6 @@ static void wilc_wlan_deinitialize(struct net_device *dev) wilc_wlan_stop(wl, vif); wilc_wlan_cleanup(dev); - wlan_deinit_locks(dev); wl->initialized = false; @@ -738,14 +724,15 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) wilc_tx_complete); if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) { - int i; + int srcu_idx; + struct wilc_vif *vif; - mutex_lock(&wilc->vif_mutex); - for (i = 0; i < wilc->vif_num; i++) { - if (wilc->vif[i]->mac_opened) - netif_stop_queue(wilc->vif[i]->ndev); + 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); } - mutex_unlock(&wilc->vif_mutex); + srcu_read_unlock(&wilc->srcu, srcu_idx); } return 0; @@ -823,26 +810,22 @@ void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) { - int i = 0; + int srcu_idx; struct wilc_vif *vif; - mutex_lock(&wilc->vif_mutex); - for (i = 0; i < wilc->vif_num; i++) { + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { u16 type = le16_to_cpup((__le16 *)buff); - vif = netdev_priv(wilc->vif[i]->ndev); - if ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) || - (type == vif->frame_reg[1].type && vif->frame_reg[1].reg)) { + 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); - break; - } - if (vif->monitor_flag) { + if (vif->monitor_flag) wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size); - break; - } } - mutex_unlock(&wilc->vif_mutex); + srcu_read_unlock(&wilc->srcu, srcu_idx); } static const struct net_device_ops wilc_netdev_ops = { @@ -856,7 +839,8 @@ static const struct net_device_ops wilc_netdev_ops = { void wilc_netdev_cleanup(struct wilc *wilc) { - int i; + struct wilc_vif *vif; + int srcu_idx; if (!wilc) return; @@ -866,21 +850,57 @@ void wilc_netdev_cleanup(struct wilc *wilc) wilc->firmware = NULL; } - for (i = 0; i < wilc->vif_num; i++) { - if (wilc->vif[i] && wilc->vif[i]->ndev) - unregister_netdev(wilc->vif[i]->ndev); + 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) @@ -921,10 +941,14 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, ndev->needs_free_netdev = true; vif->iftype = vif_type; - vif->wilc->vif[wl->vif_num] = vif; - vif->idx = wl->vif_num; - wl->vif_num += 1; + 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; } diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/netdev.h index 978a8bdbfc40..cd8f0d72caaa 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/netdev.h @@ -4,8 +4,8 @@ * All rights reserved. */ -#ifndef WILC_WFI_NETDEVICE -#define WILC_WFI_NETDEVICE +#ifndef WILC_NETDEV_H +#define WILC_NETDEV_H #include <linux/tcp.h> #include <linux/ieee80211.h> @@ -14,9 +14,9 @@ #include <linux/if_arp.h> #include <linux/gpio/consumer.h> -#include "wilc_hif.h" -#include "wilc_wlan.h" -#include "wilc_wlan_cfg.h" +#include "hif.h" +#include "wlan.h" +#include "wlan_cfg.h" #define FLOW_CONTROL_LOWER_THRESHOLD 128 #define FLOW_CONTROL_UPPER_THRESHOLD 256 @@ -60,7 +60,7 @@ struct sta_info { u8 sta_associated_bss[WILC_MAX_NUM_STA][ETH_ALEN]; }; -/*Parameters needed for host interface for remaining on channel*/ +/* Parameters needed for host interface for remaining on channel */ struct wilc_wfi_p2p_listen_params { struct ieee80211_channel *listen_ch; u32 listen_duration; @@ -145,11 +145,13 @@ struct wilc_priv { 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; @@ -208,6 +210,8 @@ struct wilc_vif { struct tcp_ack_filter ack_filter; bool connecting; struct wilc_priv priv; + struct list_head list; + struct cfg80211_bss *bss; }; struct wilc { @@ -221,16 +225,22 @@ struct wilc { int dev_irq_num; int close; u8 vif_num; - struct wilc_vif *vif[WILC_NUM_CONCURRENT_IFC]; - /*protect vif list*/ + struct list_head vif_list; + + /* protect vif list */ struct mutex vif_mutex; + struct srcu_struct srcu; u8 open_ifcs; - /*protect head of transmit queue*/ + + /* protect head of transmit queue */ struct mutex txq_add_to_head_cs; - /*protect txq_entry_t transmit queue*/ + + /* protect txq_entry_t transmit queue */ spinlock_t txq_spinlock; - /*protect rxq_entry_t receiver queue*/ + + /* protect rxq_entry_t receiver queue */ struct mutex rxq_cs; + /* lock to protect hif access */ struct mutex hif_cs; @@ -242,6 +252,7 @@ struct wilc { 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; @@ -268,6 +279,7 @@ struct wilc { struct wilc_cfg cfg; void *bus_data; struct net_device *monitor_dev; + /* deinit lock */ struct mutex deinit_lock; u8 sta_ch; diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/sdio.c index c787c5da8f2b..319e039380b0 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/sdio.c @@ -8,8 +8,8 @@ #include <linux/mmc/sdio_func.h> #include <linux/mmc/host.h> -#include "wilc_wfi_netdevice.h" -#include "wilc_wfi_cfgoperations.h" +#include "netdev.h" +#include "cfg80211.h" #define SDIO_MODALIAS "wilc1000_sdio" diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/spi.c index 3c1ae9e9f9aa..55f8757325f0 100644 --- a/drivers/staging/wilc1000/wilc_spi.c +++ b/drivers/staging/wilc1000/spi.c @@ -4,10 +4,11 @@ * All rights reserved. */ +#include <linux/clk.h> #include <linux/spi/spi.h> -#include "wilc_wfi_netdevice.h" -#include "wilc_wfi_cfgoperations.h" +#include "netdev.h" +#include "cfg80211.h" struct wilc_spi { int crc_off; @@ -132,6 +133,12 @@ static int wilc_bus_probe(struct spi_device *spi) 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; } @@ -142,6 +149,10 @@ static int wilc_bus_remove(struct spi_device *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; } diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wlan.c index 771d8cb68dc1..d3de76126b78 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wlan.c @@ -6,8 +6,8 @@ #include <linux/if_ether.h> #include <linux/ip.h> -#include "wilc_wfi_cfgoperations.h" -#include "wilc_wlan_cfg.h" +#include "cfg80211.h" +#include "wlan_cfg.h" static inline bool is_wilc1000(u32 id) { diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wlan.h index 7469fa47d588..1f6957cf2e9c 100644 --- a/drivers/staging/wilc1000/wilc_wlan.h +++ b/drivers/staging/wilc1000/wlan.h @@ -190,7 +190,7 @@ #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*/ +/* time for expiring the completion of cfg packets */ #define WILC_CFG_PKTS_TIMEOUT msecs_to_jiffies(2000) #define IS_MANAGMEMENT 0x100 diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wlan_cfg.c index 3f53807cee0f..6f6b286788d1 100644 --- a/drivers/staging/wilc1000/wilc_wlan_cfg.c +++ b/drivers/staging/wilc1000/wlan_cfg.c @@ -4,10 +4,10 @@ * All rights reserved. */ -#include "wilc_wlan_if.h" -#include "wilc_wlan.h" -#include "wilc_wlan_cfg.h" -#include "wilc_wfi_netdevice.h" +#include "wlan_if.h" +#include "wlan.h" +#include "wlan_cfg.h" +#include "netdev.h" enum cfg_cmd_type { CFG_BYTE_CMD = 0, @@ -44,6 +44,11 @@ static const struct wilc_cfg_str g_cfg_str[] = { {WID_NIL, NULL} }; +#define WILC_RESP_MSG_TYPE_CONFIG_REPLY 'R' +#define WILC_RESP_MSG_TYPE_STATUS_INFO 'I' +#define WILC_RESP_MSG_TYPE_NETWORK_INFO 'N' +#define WILC_RESP_MSG_TYPE_SCAN_COMPLETE 'S' + /******************************************** * * Configuration Functions @@ -360,33 +365,26 @@ void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size, 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': + case WILC_RESP_MSG_TYPE_CONFIG_REPLY: wilc_wlan_parse_response_frame(wilc, frame, size); rsp->type = WILC_CFG_RSP; rsp->seq_no = msg_id; break; - case 'I': + case WILC_RESP_MSG_TYPE_STATUS_INFO: 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*/ + /* call host interface info parse as well */ wilc_gnrl_async_info_received(wilc, frame - 4, size + 4); break; - case 'N': + case WILC_RESP_MSG_TYPE_NETWORK_INFO: wilc_network_info_received(wilc, frame - 4, size + 4); break; - case 'S': + case WILC_RESP_MSG_TYPE_SCAN_COMPLETE: wilc_scan_complete_received(wilc, frame - 4, size + 4); break; diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.h b/drivers/staging/wilc1000/wlan_cfg.h index 614c5673f232..614c5673f232 100644 --- a/drivers/staging/wilc1000/wilc_wlan_cfg.h +++ b/drivers/staging/wilc1000/wlan_cfg.h diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wlan_if.h index 70eac586f80c..7c7ee66c35f5 100644 --- a/drivers/staging/wilc1000/wilc_wlan_if.h +++ b/drivers/staging/wilc1000/wlan_if.h @@ -750,10 +750,10 @@ enum { WID_REMOVE_KEY = 0x301E, WID_ASSOC_REQ_INFO = 0x301F, WID_ASSOC_RES_INFO = 0x3020, - WID_MANUFACTURER = 0x3026, /*Added for CAPI tool */ - WID_MODEL_NAME = 0x3027, /*Added for CAPI tool */ - WID_MODEL_NUM = 0x3028, /*Added for CAPI tool */ - WID_DEVICE_NAME = 0x3029, /*Added for CAPI tool */ + WID_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, |