From 50d26aa338fb290f0488e8f87c1c080d2de26e21 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:26 +0300 Subject: wlcore: save seq num only between recoveries We want seq num (freed_pkts) to be initialized on each new connection, but keep persistent between recoveries/suspends. Save the freed_pkts in the private block of the sta struct (we already do a similar thing for AP's stations). However, keep the old wlvif->total_freed_pkts in order to avoid too intrusive change. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/cmd.c | 5 +- drivers/net/wireless/ti/wlcore/main.c | 77 +++++++++++++++++++++++-------- drivers/net/wireless/ti/wlcore/wlcore_i.h | 17 ++++--- 3 files changed, 68 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index e269c0a57017..d298ead88c70 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -372,9 +372,8 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) wl1271_tx_reset_link_queues(wl, *hlid); wl->links[*hlid].wlvif = NULL; - if (wlvif->bss_type == BSS_TYPE_STA_BSS || - (wlvif->bss_type == BSS_TYPE_AP_BSS && - *hlid == wlvif->ap.bcast_hlid)) { + if (wlvif->bss_type == BSS_TYPE_AP_BSS && + *hlid == wlvif->ap.bcast_hlid) { /* * save the total freed packets in the wlvif, in case this is * recovery or suspend diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 48f83868f9cb..2996cefe4aed 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -898,6 +898,41 @@ out: wlcore_set_partition(wl, &old_part); } +static void wlcore_save_freed_pkts(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 hlid, struct ieee80211_sta *sta) +{ + struct wl1271_station *wl_sta; + + wl_sta = (void *)sta->drv_priv; + wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts; + + /* + * increment the initial seq number on recovery to account for + * transmitted packets that we haven't yet got in the FW status + */ + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) + wl_sta->total_freed_pkts += + WL1271_TX_SQN_POST_RECOVERY_PADDING; +} + +static void wlcore_save_freed_pkts_addr(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 hlid, const u8 *addr) +{ + struct ieee80211_sta *sta; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + + if (WARN_ON(hlid == WL12XX_INVALID_LINK_ID || + is_zero_ether_addr(addr))) + return; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, addr); + if (sta) + wlcore_save_freed_pkts(wl, wlvif, hlid, sta); + rcu_read_unlock(); +} + static void wlcore_print_recovery(struct wl1271 *wl) { u32 pc = 0; @@ -961,6 +996,13 @@ static void wl1271_recovery_work(struct work_struct *work) wlvif = list_first_entry(&wl->wlvif_list, struct wl12xx_vif, list); vif = wl12xx_wlvif_to_vif(wlvif); + + if (wlvif->bss_type == BSS_TYPE_STA_BSS && + test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { + wlcore_save_freed_pkts_addr(wl, wlvif, wlvif->sta.hlid, + vif->bss_conf.bssid); + } + __wl1271_op_remove_interface(wl, vif, false); } @@ -4703,10 +4745,6 @@ static int wl1271_allocate_sta(struct wl1271 *wl, void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) { - struct wl1271_station *wl_sta; - struct ieee80211_sta *sta; - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - if (!test_bit(hlid, wlvif->ap.sta_hlid_map)) return; @@ -4718,21 +4756,7 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) * save the last used PN in the private part of iee80211_sta, * in case of recovery/suspend */ - rcu_read_lock(); - sta = ieee80211_find_sta(vif, wl->links[hlid].addr); - if (sta) { - wl_sta = (void *)sta->drv_priv; - wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts; - - /* - * increment the initial seq number on recovery to account for - * transmitted packets that we haven't yet got in the FW status - */ - if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) - wl_sta->total_freed_pkts += - WL1271_TX_SQN_POST_RECOVERY_PADDING; - } - rcu_read_unlock(); + wlcore_save_freed_pkts_addr(wl, wlvif, hlid, wl->links[hlid].addr); wl12xx_free_link(wl, wlvif, &hlid); wl->active_sta_count--; @@ -4915,6 +4939,21 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags); } + /* save seq number on disassoc (suspend) */ + if (is_sta && + old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH) { + wlcore_save_freed_pkts(wl, wlvif, wlvif->sta.hlid, sta); + wlvif->total_freed_pkts = 0; + } + + /* restore seq number on assoc (resume) */ + if (is_sta && + old_state == IEEE80211_STA_AUTH && + new_state == IEEE80211_STA_ASSOC) { + wlvif->total_freed_pkts = wl_sta->total_freed_pkts; + } + /* clear ROCs on failure or authorization */ if (is_sta && (new_state == IEEE80211_STA_AUTHORIZED || diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index c2c34a84ff3d..986da43ecfdd 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -324,6 +324,7 @@ struct wl1271_station { * total freed FW packets on the link to the STA - used for tracking the * AES/TKIP PN across recoveries. Re-initialized each time from the * wl1271_station structure. + * Used in both AP and STA mode. */ u64 total_freed_pkts; }; @@ -459,6 +460,13 @@ struct wl12xx_vif { /* work for canceling ROC after pending auth reply */ struct delayed_work pending_auth_complete_work; + /* + * total freed FW packets on the link. + * For STA this holds the PN of the link to the AP. + * For AP this holds the PN of the broadcast link. + */ + u64 total_freed_pkts; + /* * This struct must be last! * data that has to be saved acrossed reconfigs (e.g. recovery) @@ -466,15 +474,6 @@ struct wl12xx_vif { */ struct { u8 persistent[0]; - - /* - * total freed FW packets on the link - used for - * storing the AES/TKIP PN during recovery, as this - * structure is not zeroed out. - * For STA this holds the PN of the link to the AP. - * For AP this holds the PN of the broadcast link. - */ - u64 total_freed_pkts; }; }; -- cgit v1.2.1 From 30a003588898924964dfa537670f35aac7cd9629 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:27 +0300 Subject: wlcore: user smaller sqn padding for GEM On recovery, we increase the current seq num by WL1271_TX_SQN_POST_RECOVERY_PADDING in order to compensate for packets we might have missed during recovery. It seems that some GEM APs have issues when the gap is too big, so use a smaller padding in this case. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/cmd.c | 7 +++++-- drivers/net/wireless/ti/wlcore/main.c | 7 +++++-- drivers/net/wireless/ti/wlcore/wlcore_i.h | 3 +++ 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index d298ead88c70..05604ee31224 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -374,6 +374,7 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) if (wlvif->bss_type == BSS_TYPE_AP_BSS && *hlid == wlvif->ap.bcast_hlid) { + u32 sqn_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING; /* * save the total freed packets in the wlvif, in case this is * recovery or suspend @@ -384,9 +385,11 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) * increment the initial seq number on recovery to account for * transmitted packets that we haven't yet got in the FW status */ + if (wlvif->encryption_type == KEY_GEM) + sqn_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING_GEM; + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) - wlvif->total_freed_pkts += - WL1271_TX_SQN_POST_RECOVERY_PADDING; + wlvif->total_freed_pkts += sqn_padding; } wl->links[*hlid].total_freed_pkts = 0; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2996cefe4aed..1ab6dbdb47f3 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -902,6 +902,7 @@ static void wlcore_save_freed_pkts(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid, struct ieee80211_sta *sta) { struct wl1271_station *wl_sta; + u32 sqn_recovery_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING; wl_sta = (void *)sta->drv_priv; wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts; @@ -910,9 +911,11 @@ static void wlcore_save_freed_pkts(struct wl1271 *wl, struct wl12xx_vif *wlvif, * increment the initial seq number on recovery to account for * transmitted packets that we haven't yet got in the FW status */ + if (wlvif->encryption_type == KEY_GEM) + sqn_recovery_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING_GEM; + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) - wl_sta->total_freed_pkts += - WL1271_TX_SQN_POST_RECOVERY_PADDING; + wl_sta->total_freed_pkts += sqn_recovery_padding; } static void wlcore_save_freed_pkts_addr(struct wl1271 *wl, diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 986da43ecfdd..0e52556044d9 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -45,6 +45,9 @@ #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) #define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff +/* Use smaller padding for GEM, as some APs have issues when it's too big */ +#define WL1271_TX_SQN_POST_RECOVERY_PADDING_GEM 0x20 + #define WL1271_CIPHER_SUITE_GEM 0x00147201 -- cgit v1.2.1 From 71a301bb461da1e42e6d2764d99c683289c96f33 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:29 +0300 Subject: wlcore: use correct LAA bit The LAA bit is second bit of the MSB, not of the third byte. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 1ab6dbdb47f3..4c16262afa16 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5661,7 +5661,7 @@ static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic) memcpy(&wl->addresses[idx], &wl->addresses[0], sizeof(wl->addresses[0])); /* LAA bit */ - wl->addresses[idx].addr[2] |= BIT(1); + wl->addresses[idx].addr[0] |= BIT(1); } wl->hw->wiphy->n_addresses = WLCORE_NUM_MAC_ADDRESSES; -- cgit v1.2.1 From 936c50dd0605d7d81772f53700ef42f45525ffad Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:30 +0300 Subject: wlcore: add smart config definitions Add definitions for the smart config commands. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/cmd.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 6788d7356ca5..ca6a28b03f8f 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -170,6 +170,9 @@ enum wl1271_commands { /* start of 18xx specific commands */ CMD_DFS_CHANNEL_CONFIG = 60, + CMD_SMART_CONFIG_START = 61, + CMD_SMART_CONFIG_STOP = 62, + CMD_SMART_CONFIG_SET_GROUP_KEY = 63, MAX_COMMAND_ID = 0xFFFF, }; -- cgit v1.2.1 From ccb1df948085abcac0a91154e9cabeb563b65833 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:31 +0300 Subject: wlcore/wl18xx: add smart config commands These commands configures the fw to set key, enter smart config mode, and exit it. Add relevant hw ops as well. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/hw_ops.h | 27 +++++++++++++++++++++++++++ drivers/net/wireless/ti/wlcore/wlcore.h | 4 ++++ 2 files changed, 31 insertions(+) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index 1555ff970050..aa9f82c72296 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -260,4 +260,31 @@ wlcore_hw_lnk_low_prio(struct wl1271 *wl, u8 hlid, return wl->ops->lnk_low_prio(wl, hlid, lnk); } +static inline int +wlcore_smart_config_start(struct wl1271 *wl, u32 group_bitmap) +{ + if (!wl->ops->smart_config_start) + return -EINVAL; + + return wl->ops->smart_config_start(wl, group_bitmap); +} + +static inline int +wlcore_smart_config_stop(struct wl1271 *wl) +{ + if (!wl->ops->smart_config_stop) + return -EINVAL; + + return wl->ops->smart_config_stop(wl); +} + +static inline int +wlcore_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, + u8 key_len, u8 *key) +{ + if (!wl->ops->smart_config_set_group_key) + return -EINVAL; + + return wl->ops->smart_config_set_group_key(wl, group_id, key_len, key); +} #endif diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 71320509b56d..13459c4f74d0 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -117,6 +117,10 @@ struct wlcore_ops { struct wl1271_link *lnk); bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid, struct wl1271_link *lnk); + int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap); + int (*smart_config_stop)(struct wl1271 *wl); + int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id, + u8 key_len, u8 *key); }; enum wlcore_partitions { -- cgit v1.2.1 From 80ff8063e87c352072c6d96fb2d87becaf591966 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:32 +0300 Subject: wlcore: handle smart config vendor commands userspace can ask to perform various smart config actions via custom vendor commands. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/Makefile | 2 +- drivers/net/wireless/ti/wlcore/vendor_cmd.c | 184 ++++++++++++++++++++++++++++ drivers/net/wireless/ti/wlcore/vendor_cmd.h | 36 ++++++ 3 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ti/wlcore/vendor_cmd.c create mode 100644 drivers/net/wireless/ti/wlcore/vendor_cmd.h (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/Makefile b/drivers/net/wireless/ti/wlcore/Makefile index 4f23931d7bd5..0a69c1373643 100644 --- a/drivers/net/wireless/ti/wlcore/Makefile +++ b/drivers/net/wireless/ti/wlcore/Makefile @@ -1,5 +1,5 @@ wlcore-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ - boot.o init.o debugfs.o scan.o sysfs.o + boot.o init.o debugfs.o scan.o sysfs.o vendor_cmd.o wlcore_spi-objs = spi.o wlcore_sdio-objs = sdio.o diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c new file mode 100644 index 000000000000..98852b2ceb4d --- /dev/null +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c @@ -0,0 +1,184 @@ +/* + * This file is part of wlcore + * + * Copyright (C) 2014 Texas Instruments. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include + +#include "wlcore.h" +#include "debug.h" +#include "ps.h" +#include "hw_ops.h" +#include "vendor_cmd.h" + +static const +struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = { + [WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 }, + [WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 }, + [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_U32, + .len = WLAN_MAX_KEY_LEN }, +}; + +static int +wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct wl1271 *wl = hw->priv; + struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR]; + int ret; + + wl1271_debug(DEBUG_CMD, "vendor cmd smart config start"); + + if (!data) + return -EINVAL; + + ret = nla_parse(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len, + wlcore_vendor_attr_policy); + if (ret) + return ret; + + if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID]) + return -EINVAL; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) { + ret = -EINVAL; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wlcore_smart_config_start(wl, + nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID])); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return 0; +} + +static int +wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_CMD, "testmode cmd smart config stop"); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) { + ret = -EINVAL; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wlcore_smart_config_stop(wl); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int +wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct wl1271 *wl = hw->priv; + struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR]; + int ret; + + wl1271_debug(DEBUG_CMD, "testmode cmd smart config set group key"); + + if (!data) + return -EINVAL; + + ret = nla_parse(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len, + wlcore_vendor_attr_policy); + if (ret) + return ret; + + if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID] || + !tb[WLCORE_VENDOR_ATTR_GROUP_KEY]) + return -EINVAL; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) { + ret = -EINVAL; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wlcore_smart_config_set_group_key(wl, + nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]), + nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]), + nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY])); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static const struct wiphy_vendor_command wlcore_vendor_commands[] = { + { + .info = { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_START, + }, + .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlcore_vendor_cmd_smart_config_start, + }, + { + .info = { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_STOP, + }, + .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlcore_vendor_cmd_smart_config_stop, + }, + { + .info = { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY, + }, + .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlcore_vendor_cmd_smart_config_set_group_key, + }, +}; + +void wlcore_set_vendor_commands(struct wiphy *wiphy) +{ + wiphy->vendor_commands = wlcore_vendor_commands; + wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands); +} diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.h b/drivers/net/wireless/ti/wlcore/vendor_cmd.h new file mode 100644 index 000000000000..7e8e92fad16c --- /dev/null +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.h @@ -0,0 +1,36 @@ +/* + * This file is part of wlcore + * + * Copyright (C) 2014 Texas Instruments. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef __WLCORE_VENDOR_H__ +#define __WLCORE_VENDOR_H__ + +#define TI_OUI 0x080028 + +enum wlcore_vendor_commands { + WLCORE_VENDOR_CMD_SMART_CONFIG_START, + WLCORE_VENDOR_CMD_SMART_CONFIG_STOP, + WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY, + + NUM_WLCORE_VENDOR_CMD, + MAX_WLCORE_VENDOR_CMD = NUM_WLCORE_VENDOR_CMD - 1 +}; + +enum wlcore_vendor_attributes { + WLCORE_VENDOR_ATTR_FREQ, + WLCORE_VENDOR_ATTR_PSK, + WLCORE_VENDOR_ATTR_SSID, + WLCORE_VENDOR_ATTR_GROUP_ID, + WLCORE_VENDOR_ATTR_GROUP_KEY, + + NUM_WLCORE_VENDOR_ATTR, + MAX_WLCORE_VENDOR_ATTR = NUM_WLCORE_VENDOR_ATTR - 1 +}; + +#endif /* __WLCORE_VENDOR_H__ */ -- cgit v1.2.1 From e93e15fb47e53bd5dc256e2c3e40785b39ff8ff7 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:33 +0300 Subject: wlcore/wl18xx: handle smart config events add defintions and handling for smart config events (SMART_CONFIG_SYNC_EVENT_ID and SMART_CONFIG_DECODE_EVENT_ID) parse the relevant info and send it to userspace as vendor event. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/vendor_cmd.c | 13 +++++++++++++ drivers/net/wireless/ti/wlcore/vendor_cmd.h | 9 +++++++++ 2 files changed, 22 insertions(+) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c index 98852b2ceb4d..ad86a48dcfcb 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c @@ -177,8 +177,21 @@ static const struct wiphy_vendor_command wlcore_vendor_commands[] = { }, }; +static const struct nl80211_vendor_cmd_info wlcore_vendor_events[] = { + { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_EVENT_SC_SYNC, + }, + { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_EVENT_SC_DECODE, + }, +}; + void wlcore_set_vendor_commands(struct wiphy *wiphy) { wiphy->vendor_commands = wlcore_vendor_commands; wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands); + wiphy->vendor_events = wlcore_vendor_events; + wiphy->n_vendor_events = ARRAY_SIZE(wlcore_vendor_events); } diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.h b/drivers/net/wireless/ti/wlcore/vendor_cmd.h index 7e8e92fad16c..6e0c15e30f03 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.h +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.h @@ -11,6 +11,10 @@ #ifndef __WLCORE_VENDOR_H__ #define __WLCORE_VENDOR_H__ +#ifdef __KERNEL__ +void wlcore_set_vendor_commands(struct wiphy *wiphy); +#endif + #define TI_OUI 0x080028 enum wlcore_vendor_commands { @@ -33,4 +37,9 @@ enum wlcore_vendor_attributes { MAX_WLCORE_VENDOR_ATTR = NUM_WLCORE_VENDOR_ATTR - 1 }; +enum wlcore_vendor_events { + WLCORE_VENDOR_EVENT_SC_SYNC, + WLCORE_VENDOR_EVENT_SC_DECODE, +}; + #endif /* __WLCORE_VENDOR_H__ */ -- cgit v1.2.1 From fbddf587cbd1b75557267b674c8b42a677437c69 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:34 +0300 Subject: wlcore: increase max roc duration to 30 seconds we don't have any actual limitation in the driver, so increase it arbitrarily to 30 seconds. The long ROC is needed for the smart config.flow. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 4c16262afa16..01b4d9e9af69 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5806,7 +5806,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - sizeof(struct ieee80211_header); - wl->hw->wiphy->max_remain_on_channel_duration = 5000; + wl->hw->wiphy->max_remain_on_channel_duration = 30000; wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | -- cgit v1.2.1 From d8c5a48d2751086de9ed0ae9ff97ab094e2d534d Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:35 +0300 Subject: wlcore: register vendor commands All the smart config code is in place now, so register the relevant vendor commands. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 01b4d9e9af69..d92f578dd95c 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -37,6 +37,7 @@ #include "init.h" #include "debugfs.h" #include "testmode.h" +#include "vendor_cmd.h" #include "scan.h" #include "hw_ops.h" #include "sysfs.h" @@ -5875,6 +5876,9 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->iface_combinations = wl->iface_combinations; wl->hw->wiphy->n_iface_combinations = wl->n_iface_combinations; + /* register vendor commands */ + wlcore_set_vendor_commands(wl->hw->wiphy); + SET_IEEE80211_DEV(wl->hw, wl->dev); wl->hw->sta_data_size = sizeof(struct wl1271_station); -- cgit v1.2.1 From e65628691f04f1a9ce57d8036c9b119c43031187 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Fri, 11 Jul 2014 03:01:36 +0300 Subject: wlcore: don't switch channels on disconnected STA vifs Sending the FW a channel switch command on a disconnected vif may result in a beacon loss event. Avoid this corner case. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/main.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d92f578dd95c..ec211413ffe6 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5192,6 +5192,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, if (unlikely(wl->state == WLCORE_STATE_OFF)) { wl12xx_for_each_wlvif_sta(wl, wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + continue; + ieee80211_chswitch_done(vif, false); } goto out; @@ -5207,6 +5211,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, wl12xx_for_each_wlvif_sta(wl, wlvif) { unsigned long delay_usec; + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + continue; + ret = wl->ops->channel_switch(wl, wlvif, ch_switch); if (ret) goto out_sleep; -- cgit v1.2.1 From 5e74b3aa6ffd80128e3df605bf27d8a6a3c04997 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:39 +0300 Subject: wlcore/wl18xx/wl12xx: convert bitmaps to unsigned longs The *_bit operations expect unsigned longs. Instead of casting the pointers, simply define various bitmaps as unsigned long (instead of u32). Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/debugfs.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 8 ++++---- drivers/net/wireless/ti/wlcore/tx.c | 2 +- drivers/net/wireless/ti/wlcore/wlcore.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ti/wlcore') diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index 89893c717025..0be21f62fcb0 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -496,7 +496,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_INT(sg_enabled); DRIVER_STATE_PRINT_INT(enable_11a); DRIVER_STATE_PRINT_INT(noise); - DRIVER_STATE_PRINT_HEX(ap_fw_ps_map); + DRIVER_STATE_PRINT_LHEX(ap_fw_ps_map); DRIVER_STATE_PRINT_LHEX(ap_ps_map); DRIVER_STATE_PRINT_HEX(quirks); DRIVER_STATE_PRINT_HEX(irq); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ec211413ffe6..575c8f6d4009 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -333,7 +333,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, { bool fw_ps; - fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + fw_ps = test_bit(hlid, &wl->ap_fw_ps_map); /* * Wake up from high level PS if the STA is asleep with too little @@ -360,13 +360,13 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct wl_fw_status *status) { - u32 cur_fw_ps_map; + unsigned long cur_fw_ps_map; u8 hlid; cur_fw_ps_map = status->link_ps_bitmap; if (wl->ap_fw_ps_map != cur_fw_ps_map) { wl1271_debug(DEBUG_PSM, - "link ps prev 0x%x cur 0x%x changed 0x%x", + "link ps prev 0x%lx cur 0x%lx changed 0x%lx", wl->ap_fw_ps_map, cur_fw_ps_map, wl->ap_fw_ps_map ^ cur_fw_ps_map); @@ -4754,7 +4754,7 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) clear_bit(hlid, wlvif->ap.sta_hlid_map); __clear_bit(hlid, &wl->ap_ps_map); - __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + __clear_bit(hlid, &wl->ap_fw_ps_map); /* * save the last used PN in the private part of iee80211_sta, diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 40b43115f835..f0ac36139bcc 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -126,7 +126,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, if (WARN_ON(!test_bit(hlid, wlvif->links_map))) return; - fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + fw_ps = test_bit(hlid, &wl->ap_fw_ps_map); tx_pkts = wl->links[hlid].allocated_pkts; /* diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 13459c4f74d0..df78cf12ef15 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -388,10 +388,10 @@ struct wl1271 { int active_link_count; /* Fast/slow links bitmap according to FW */ - u32 fw_fast_lnk_map; + unsigned long fw_fast_lnk_map; /* AP-mode - a bitmap of links currently in PS mode according to FW */ - u32 ap_fw_ps_map; + unsigned long ap_fw_ps_map; /* AP-mode - a bitmap of links currently in PS mode in mac80211 */ unsigned long ap_ps_map; -- cgit v1.2.1