Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
This commit is contained in:
commit
1e5023c7cc
@ -30,3 +30,12 @@ config ATH6KL_DEBUG
|
||||
depends on ATH6KL
|
||||
---help---
|
||||
Enables debug support
|
||||
|
||||
config ATH6KL_REGDOMAIN
|
||||
bool "Atheros ath6kl regdomain support"
|
||||
depends on ATH6KL
|
||||
depends on CFG80211_CERTIFICATION_ONUS
|
||||
---help---
|
||||
Enabling this makes it possible to change the regdomain in
|
||||
the firmware. This can be only enabled if regulatory requirements
|
||||
are taken into account.
|
||||
|
@ -34,6 +34,7 @@ ath6kl_core-y += main.o
|
||||
ath6kl_core-y += txrx.o
|
||||
ath6kl_core-y += wmi.o
|
||||
ath6kl_core-y += core.o
|
||||
ath6kl_core-y += recovery.o
|
||||
ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
|
||||
obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o
|
||||
|
@ -147,15 +147,15 @@ static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
|
||||
{
|
||||
struct ath6kl *ar = vif->ar;
|
||||
|
||||
if (ar->state != ATH6KL_STATE_SCHED_SCAN)
|
||||
if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags))
|
||||
return false;
|
||||
|
||||
del_timer_sync(&vif->sched_scan_timer);
|
||||
|
||||
ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_HOST_MODE_AWAKE);
|
||||
if (ar->state == ATH6KL_STATE_RECOVERY)
|
||||
return true;
|
||||
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -369,17 +369,13 @@ static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
|
||||
{
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
*nw_type = INFRA_NETWORK;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
*nw_type = ADHOC_NETWORK;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
*nw_type = AP_NETWORK;
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
*nw_type = INFRA_NETWORK;
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
*nw_type = AP_NETWORK;
|
||||
break;
|
||||
@ -1031,30 +1027,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy,
|
||||
|
||||
vif->scan_req = request;
|
||||
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
|
||||
ar->fw_capabilities)) {
|
||||
/*
|
||||
* If capable of doing P2P mgmt operations using
|
||||
* station interface, send additional information like
|
||||
* supported rates to advertise and xmit rates for
|
||||
* probe requests
|
||||
*/
|
||||
ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WMI_LONG_SCAN, force_fg_scan,
|
||||
false, 0,
|
||||
ATH6KL_FG_SCAN_INTERVAL,
|
||||
n_channels, channels,
|
||||
request->no_cck,
|
||||
request->rates);
|
||||
} else {
|
||||
ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WMI_LONG_SCAN, force_fg_scan,
|
||||
false, 0,
|
||||
ATH6KL_FG_SCAN_INTERVAL,
|
||||
n_channels, channels);
|
||||
}
|
||||
ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WMI_LONG_SCAN, force_fg_scan,
|
||||
false, 0,
|
||||
ATH6KL_FG_SCAN_INTERVAL,
|
||||
n_channels, channels,
|
||||
request->no_cck,
|
||||
request->rates);
|
||||
if (ret) {
|
||||
ath6kl_err("wmi_startscan_cmd failed\n");
|
||||
ath6kl_err("failed to start scan: %d\n", ret);
|
||||
vif->scan_req = NULL;
|
||||
}
|
||||
|
||||
@ -1888,7 +1869,7 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,
|
||||
struct cfg80211_wowlan *wow, u32 *filter)
|
||||
{
|
||||
int ret, pos;
|
||||
u8 mask[WOW_MASK_SIZE];
|
||||
u8 mask[WOW_PATTERN_SIZE];
|
||||
u16 i;
|
||||
|
||||
/* Configure the patterns that we received from the user. */
|
||||
@ -2106,33 +2087,16 @@ static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif,
|
||||
struct cfg80211_wowlan *wow, u32 *filter)
|
||||
{
|
||||
struct ath6kl *ar = vif->ar;
|
||||
struct in_device *in_dev;
|
||||
struct in_ifaddr *ifa;
|
||||
struct ath6kl_vif *vif;
|
||||
int ret;
|
||||
u32 filter = 0;
|
||||
u16 i, bmiss_time;
|
||||
u8 index = 0;
|
||||
__be32 ips[MAX_IP_ADDRS];
|
||||
|
||||
/* The FW currently can't support multi-vif WoW properly. */
|
||||
if (ar->num_vif > 1)
|
||||
return -EIO;
|
||||
|
||||
vif = ath6kl_vif_first(ar);
|
||||
if (!vif)
|
||||
return -EIO;
|
||||
|
||||
if (!ath6kl_cfg80211_ready(vif))
|
||||
return -EIO;
|
||||
|
||||
if (!test_bit(CONNECTED, &vif->flags))
|
||||
return -ENOTCONN;
|
||||
|
||||
if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
|
||||
return -EINVAL;
|
||||
u8 index = 0;
|
||||
|
||||
if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&
|
||||
test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
|
||||
@ -2154,7 +2118,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
* the user.
|
||||
*/
|
||||
if (wow)
|
||||
ret = ath6kl_wow_usr(ar, vif, wow, &filter);
|
||||
ret = ath6kl_wow_usr(ar, vif, wow, filter);
|
||||
else if (vif->nw_type == AP_NETWORK)
|
||||
ret = ath6kl_wow_ap(ar, vif);
|
||||
else
|
||||
@ -2189,12 +2153,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->state = ATH6KL_STATE_SUSPENDING;
|
||||
|
||||
/* Setup own IP addr for ARP agent. */
|
||||
in_dev = __in_dev_get_rtnl(vif->ndev);
|
||||
if (!in_dev)
|
||||
goto skip_arp;
|
||||
return 0;
|
||||
|
||||
ifa = in_dev->ifa_list;
|
||||
memset(&ips, 0, sizeof(ips));
|
||||
@ -2217,41 +2179,61 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
return ret;
|
||||
}
|
||||
|
||||
skip_arp:
|
||||
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
{
|
||||
struct ath6kl_vif *first_vif, *vif;
|
||||
int ret = 0;
|
||||
u32 filter = 0;
|
||||
bool connected = false;
|
||||
|
||||
/* enter / leave wow suspend on first vif always */
|
||||
first_vif = ath6kl_vif_first(ar);
|
||||
if (WARN_ON(unlikely(!first_vif)) ||
|
||||
!ath6kl_cfg80211_ready(first_vif))
|
||||
return -EIO;
|
||||
|
||||
if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
|
||||
return -EINVAL;
|
||||
|
||||
/* install filters for each connected vif */
|
||||
spin_lock_bh(&ar->list_lock);
|
||||
list_for_each_entry(vif, &ar->vif_list, list) {
|
||||
if (!test_bit(CONNECTED, &vif->flags) ||
|
||||
!ath6kl_cfg80211_ready(vif))
|
||||
continue;
|
||||
connected = true;
|
||||
|
||||
ret = ath6kl_wow_suspend_vif(vif, wow, &filter);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&ar->list_lock);
|
||||
|
||||
if (!connected)
|
||||
return -ENOTCONN;
|
||||
else if (ret)
|
||||
return ret;
|
||||
|
||||
ar->state = ATH6KL_STATE_SUSPENDING;
|
||||
|
||||
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx,
|
||||
ATH6KL_WOW_MODE_ENABLE,
|
||||
filter,
|
||||
WOW_HOST_REQ_DELAY);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ath6kl_cfg80211_host_sleep(ar, vif);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return ath6kl_cfg80211_host_sleep(ar, first_vif);
|
||||
}
|
||||
|
||||
static int ath6kl_wow_resume(struct ath6kl *ar)
|
||||
static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
struct ath6kl *ar = vif->ar;
|
||||
int ret;
|
||||
|
||||
vif = ath6kl_vif_first(ar);
|
||||
if (!vif)
|
||||
return -EIO;
|
||||
|
||||
ar->state = ATH6KL_STATE_RESUMING;
|
||||
|
||||
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_HOST_MODE_AWAKE);
|
||||
if (ret) {
|
||||
ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
|
||||
ret);
|
||||
ar->state = ATH6KL_STATE_WOW;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (vif->nw_type != AP_NETWORK) {
|
||||
ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
|
||||
@ -2269,13 +2251,11 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
|
||||
if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&
|
||||
test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
|
||||
ar->fw_capabilities)) {
|
||||
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
|
||||
vif->fw_vif_idx, true);
|
||||
vif->fw_vif_idx, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -2285,6 +2265,48 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_wow_resume(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
int ret;
|
||||
|
||||
vif = ath6kl_vif_first(ar);
|
||||
if (WARN_ON(unlikely(!vif)) ||
|
||||
!ath6kl_cfg80211_ready(vif))
|
||||
return -EIO;
|
||||
|
||||
ar->state = ATH6KL_STATE_RESUMING;
|
||||
|
||||
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_HOST_MODE_AWAKE);
|
||||
if (ret) {
|
||||
ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
|
||||
ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->list_lock);
|
||||
list_for_each_entry(vif, &ar->vif_list, list) {
|
||||
if (!test_bit(CONNECTED, &vif->flags) ||
|
||||
!ath6kl_cfg80211_ready(vif))
|
||||
continue;
|
||||
ret = ath6kl_wow_resume_vif(vif);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&ar->list_lock);
|
||||
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
ar->state = ATH6KL_STATE_WOW;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
@ -2421,13 +2443,6 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
|
||||
|
||||
break;
|
||||
|
||||
case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
|
||||
/*
|
||||
* Nothing needed for schedule scan, firmware is already in
|
||||
* wow mode and sleeping most of the time.
|
||||
*/
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2475,9 +2490,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
|
||||
}
|
||||
break;
|
||||
|
||||
case ATH6KL_STATE_SCHED_SCAN:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2494,14 +2506,23 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
|
||||
{
|
||||
struct ath6kl *ar = wiphy_priv(wiphy);
|
||||
|
||||
ath6kl_recovery_suspend(ar);
|
||||
|
||||
return ath6kl_hif_suspend(ar, wow);
|
||||
}
|
||||
|
||||
static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
|
||||
{
|
||||
struct ath6kl *ar = wiphy_priv(wiphy);
|
||||
int err;
|
||||
|
||||
return ath6kl_hif_resume(ar);
|
||||
err = ath6kl_hif_resume(ar);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ath6kl_recovery_resume(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2738,6 +2759,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
int res;
|
||||
int i, ret;
|
||||
u16 rsn_capab = 0;
|
||||
int inactivity_timeout = 0;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
|
||||
|
||||
@ -2874,8 +2896,15 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
}
|
||||
|
||||
if (info->inactivity_timeout) {
|
||||
|
||||
inactivity_timeout = info->inactivity_timeout;
|
||||
|
||||
if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS)
|
||||
inactivity_timeout = DIV_ROUND_UP(inactivity_timeout,
|
||||
60);
|
||||
|
||||
res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx,
|
||||
info->inactivity_timeout);
|
||||
inactivity_timeout);
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
@ -2897,6 +2926,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
WLAN_EID_RSN, WMI_RSN_IE_CAPB,
|
||||
(const u8 *) &rsn_capab,
|
||||
sizeof(rsn_capab));
|
||||
vif->rsn_capab = rsn_capab;
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
@ -3210,7 +3240,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
u16 interval;
|
||||
int ret;
|
||||
int ret, rssi_thold;
|
||||
|
||||
if (ar->state != ATH6KL_STATE_ON)
|
||||
return -EIO;
|
||||
@ -3218,10 +3248,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
|
||||
if (vif->sme_state != SME_DISCONNECTED)
|
||||
return -EBUSY;
|
||||
|
||||
/* The FW currently can't support multi-vif WoW properly. */
|
||||
if (ar->num_vif > 1)
|
||||
return -EIO;
|
||||
|
||||
ath6kl_cfg80211_scan_complete_event(vif, true);
|
||||
|
||||
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
|
||||
@ -3243,6 +3269,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
|
||||
ar->fw_capabilities)) {
|
||||
if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
|
||||
rssi_thold = 0;
|
||||
else if (request->rssi_thold < -127)
|
||||
rssi_thold = -127;
|
||||
else
|
||||
rssi_thold = request->rssi_thold;
|
||||
|
||||
ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
rssi_thold);
|
||||
if (ret) {
|
||||
ath6kl_err("failed to set RSSI threshold for scan\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* fw uses seconds, also make sure that it's >0 */
|
||||
interval = max_t(u16, 1, request->interval / 1000);
|
||||
|
||||
@ -3250,15 +3293,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
|
||||
interval, interval,
|
||||
vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
|
||||
|
||||
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_WOW_MODE_ENABLE,
|
||||
WOW_FILTER_SSID,
|
||||
WOW_HOST_REQ_DELAY);
|
||||
if (ret) {
|
||||
ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* this also clears IE in fw if it's not set */
|
||||
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WMI_FRAME_PROBE_REQ,
|
||||
@ -3269,17 +3303,13 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_HOST_MODE_ASLEEP);
|
||||
if (ret) {
|
||||
ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
|
||||
ret);
|
||||
ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->state = ATH6KL_STATE_SCHED_SCAN;
|
||||
set_bit(SCHED_SCANNING, &vif->flags);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
|
||||
@ -3308,6 +3338,27 @@ static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
|
||||
mask);
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u32 rate, u32 pkts, u32 intvl)
|
||||
{
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
|
||||
if (vif->nw_type != INFRA_NETWORK ||
|
||||
!test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (vif->sme_state != SME_CONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
/* save this since the firmware won't report the interval */
|
||||
vif->txe_intvl = intvl;
|
||||
|
||||
return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx,
|
||||
rate, pkts, intvl);
|
||||
}
|
||||
|
||||
static const struct ieee80211_txrx_stypes
|
||||
ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
[NL80211_IFTYPE_STATION] = {
|
||||
@ -3374,6 +3425,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
|
||||
.sched_scan_start = ath6kl_cfg80211_sscan_start,
|
||||
.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
|
||||
.set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
|
||||
.set_cqm_txe_config = ath6kl_cfg80211_set_txe_config,
|
||||
};
|
||||
|
||||
void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
|
||||
@ -3394,16 +3446,22 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
|
||||
break;
|
||||
}
|
||||
|
||||
if (test_bit(CONNECTED, &vif->flags) ||
|
||||
test_bit(CONNECT_PEND, &vif->flags))
|
||||
if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
|
||||
(test_bit(CONNECTED, &vif->flags) ||
|
||||
test_bit(CONNECT_PEND, &vif->flags)))
|
||||
ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
|
||||
|
||||
vif->sme_state = SME_DISCONNECTED;
|
||||
clear_bit(CONNECTED, &vif->flags);
|
||||
clear_bit(CONNECT_PEND, &vif->flags);
|
||||
|
||||
/* Stop netdev queues, needed during recovery */
|
||||
netif_stop_queue(vif->ndev);
|
||||
netif_carrier_off(vif->ndev);
|
||||
|
||||
/* disable scanning */
|
||||
if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
|
||||
if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
|
||||
ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
|
||||
ath6kl_warn("failed to disable scan during stop\n");
|
||||
|
||||
@ -3415,7 +3473,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
|
||||
struct ath6kl_vif *vif;
|
||||
|
||||
vif = ath6kl_vif_first(ar);
|
||||
if (!vif) {
|
||||
if (!vif && ar->state != ATH6KL_STATE_RECOVERY) {
|
||||
/* save the current power mode before enabling power save */
|
||||
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
|
||||
|
||||
@ -3433,6 +3491,56 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
|
||||
ath6kl_cfg80211_stop(vif);
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
|
||||
struct regulatory_request *request)
|
||||
{
|
||||
struct ath6kl *ar = wiphy_priv(wiphy);
|
||||
u32 rates[IEEE80211_NUM_BANDS];
|
||||
int ret, i;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
|
||||
"cfg reg_notify %c%c%s%s initiator %d hint_type %d\n",
|
||||
request->alpha2[0], request->alpha2[1],
|
||||
request->intersect ? " intersect" : "",
|
||||
request->processed ? " processed" : "",
|
||||
request->initiator, request->user_reg_hint_type);
|
||||
|
||||
/*
|
||||
* As firmware is not able intersect regdoms, we can only listen to
|
||||
* cellular hints.
|
||||
*/
|
||||
if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
|
||||
if (ret) {
|
||||
ath6kl_err("failed to set regdomain: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Firmware will apply the regdomain change only after a scan is
|
||||
* issued and it will send a WMI_REGDOMAIN_EVENTID when it has been
|
||||
* changed.
|
||||
*/
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
|
||||
if (wiphy->bands[i])
|
||||
rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
|
||||
|
||||
|
||||
ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false,
|
||||
false, 0, ATH6KL_FG_SCAN_INTERVAL,
|
||||
0, NULL, false, rates);
|
||||
if (ret) {
|
||||
ath6kl_err("failed to start scan for a regdomain change: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
|
||||
{
|
||||
vif->aggr_cntxt = aggr_init(vif);
|
||||
@ -3505,9 +3613,13 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
|
||||
vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true;
|
||||
|
||||
memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
|
||||
if (fw_vif_idx != 0)
|
||||
if (fw_vif_idx != 0) {
|
||||
ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
|
||||
0x2;
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR,
|
||||
ar->fw_capabilities))
|
||||
ndev->dev_addr[4] ^= 0x80;
|
||||
}
|
||||
|
||||
init_netdev(ndev);
|
||||
|
||||
@ -3561,6 +3673,12 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT);
|
||||
}
|
||||
|
||||
if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) &&
|
||||
test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) {
|
||||
wiphy->reg_notifier = ath6kl_cfg80211_reg_notify;
|
||||
ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS;
|
||||
}
|
||||
|
||||
/* max num of ssids that can be probed during scanning */
|
||||
wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
|
||||
|
||||
@ -3606,7 +3724,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
|
||||
ath6kl_band_5ghz.ht_cap.ht_supported = false;
|
||||
}
|
||||
|
||||
if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) {
|
||||
if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) {
|
||||
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
|
||||
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
|
||||
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
|
||||
@ -3645,7 +3763,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
|
||||
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
|
||||
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities))
|
||||
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
|
||||
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
|
||||
|
@ -22,7 +22,6 @@ enum ath6kl_cfg_suspend_mode {
|
||||
ATH6KL_CFG_SUSPEND_DEEPSLEEP,
|
||||
ATH6KL_CFG_SUSPEND_CUTPOWER,
|
||||
ATH6KL_CFG_SUSPEND_WOW,
|
||||
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
|
||||
};
|
||||
|
||||
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
|
||||
|
@ -33,6 +33,8 @@ static unsigned int wow_mode;
|
||||
static unsigned int uart_debug;
|
||||
static unsigned int ath6kl_p2p;
|
||||
static unsigned int testmode;
|
||||
static unsigned int recovery_enable;
|
||||
static unsigned int heart_beat_poll;
|
||||
|
||||
module_param(debug_mask, uint, 0644);
|
||||
module_param(suspend_mode, uint, 0644);
|
||||
@ -40,6 +42,12 @@ module_param(wow_mode, uint, 0644);
|
||||
module_param(uart_debug, uint, 0644);
|
||||
module_param(ath6kl_p2p, uint, 0644);
|
||||
module_param(testmode, uint, 0644);
|
||||
module_param(recovery_enable, uint, 0644);
|
||||
module_param(heart_beat_poll, uint, 0644);
|
||||
MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error");
|
||||
MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \
|
||||
"polling. This also specifies the polling interval in" \
|
||||
"msecs. Set reocvery_enable for this to be effective");
|
||||
|
||||
void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
|
||||
{
|
||||
@ -202,6 +210,17 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
|
||||
__func__, wdev->netdev->name, wdev->netdev, ar);
|
||||
|
||||
ar->fw_recovery.enable = !!recovery_enable;
|
||||
if (!ar->fw_recovery.enable)
|
||||
return ret;
|
||||
|
||||
if (heart_beat_poll &&
|
||||
test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL,
|
||||
ar->fw_capabilities))
|
||||
ar->fw_recovery.hb_poll = heart_beat_poll;
|
||||
|
||||
ath6kl_recovery_init(ar);
|
||||
|
||||
return ret;
|
||||
|
||||
err_rxbuf_cleanup:
|
||||
@ -291,6 +310,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar)
|
||||
{
|
||||
ath6kl_hif_power_off(ar);
|
||||
|
||||
ath6kl_recovery_cleanup(ar);
|
||||
|
||||
destroy_workqueue(ar->ath6kl_wq);
|
||||
|
||||
if (ar->htc_target)
|
||||
|
@ -115,6 +115,27 @@ enum ath6kl_fw_capability {
|
||||
*/
|
||||
ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
|
||||
|
||||
/* Firmware supports filtering BSS results by RSSI */
|
||||
ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
|
||||
|
||||
/* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */
|
||||
ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR,
|
||||
|
||||
/* Firmware supports TX error rate notification */
|
||||
ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY,
|
||||
|
||||
/* supports WMI_SET_REGDOMAIN_CMDID command */
|
||||
ATH6KL_FW_CAPABILITY_REGDOMAIN,
|
||||
|
||||
/* Firmware supports sched scan decoupled from host sleep */
|
||||
ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2,
|
||||
|
||||
/*
|
||||
* Firmware capability for hang detection through heart beat
|
||||
* challenge messages.
|
||||
*/
|
||||
ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL,
|
||||
|
||||
/* this needs to be last */
|
||||
ATH6KL_FW_CAPABILITY_MAX,
|
||||
};
|
||||
@ -128,11 +149,15 @@ struct ath6kl_fw_ie {
|
||||
};
|
||||
|
||||
enum ath6kl_hw_flags {
|
||||
ATH6KL_HW_FLAG_64BIT_RATES = BIT(0),
|
||||
ATH6KL_HW_64BIT_RATES = BIT(0),
|
||||
ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1),
|
||||
ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2),
|
||||
ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3),
|
||||
};
|
||||
|
||||
#define ATH6KL_FW_API2_FILE "fw-2.bin"
|
||||
#define ATH6KL_FW_API3_FILE "fw-3.bin"
|
||||
#define ATH6KL_FW_API4_FILE "fw-4.bin"
|
||||
|
||||
/* AR6003 1.0 definitions */
|
||||
#define AR6003_HW_1_0_VERSION 0x300002ba
|
||||
@ -186,6 +211,13 @@ enum ath6kl_hw_flags {
|
||||
#define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \
|
||||
AR6004_HW_1_2_FW_DIR "/bdata.bin"
|
||||
|
||||
/* AR6004 1.3 definitions */
|
||||
#define AR6004_HW_1_3_VERSION 0x31c8088a
|
||||
#define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3"
|
||||
#define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin"
|
||||
#define AR6004_HW_1_3_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin"
|
||||
#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin"
|
||||
|
||||
/* Per STA data, used in AP mode */
|
||||
#define STA_PS_AWAKE BIT(0)
|
||||
#define STA_PS_SLEEP BIT(1)
|
||||
@ -536,6 +568,7 @@ enum ath6kl_vif_state {
|
||||
HOST_SLEEP_MODE_CMD_PROCESSED,
|
||||
NETDEV_MCAST_ALL_ON,
|
||||
NETDEV_MCAST_ALL_OFF,
|
||||
SCHED_SCANNING,
|
||||
};
|
||||
|
||||
struct ath6kl_vif {
|
||||
@ -580,11 +613,13 @@ struct ath6kl_vif {
|
||||
u16 assoc_bss_beacon_int;
|
||||
u16 listen_intvl_t;
|
||||
u16 bmiss_time_t;
|
||||
u32 txe_intvl;
|
||||
u16 bg_scan_period;
|
||||
u8 assoc_bss_dtim_period;
|
||||
struct net_device_stats net_stats;
|
||||
struct target_stats target_stats;
|
||||
struct wmi_connect_cmd profile;
|
||||
u16 rsn_capab;
|
||||
|
||||
struct list_head mc_filter;
|
||||
};
|
||||
@ -609,6 +644,7 @@ enum ath6kl_dev_state {
|
||||
SKIP_SCAN,
|
||||
ROAM_TBL_PEND,
|
||||
FIRST_BOOT,
|
||||
RECOVERY_CLEANUP,
|
||||
};
|
||||
|
||||
enum ath6kl_state {
|
||||
@ -619,7 +655,16 @@ enum ath6kl_state {
|
||||
ATH6KL_STATE_DEEPSLEEP,
|
||||
ATH6KL_STATE_CUTPOWER,
|
||||
ATH6KL_STATE_WOW,
|
||||
ATH6KL_STATE_SCHED_SCAN,
|
||||
ATH6KL_STATE_RECOVERY,
|
||||
};
|
||||
|
||||
/* Fw error recovery */
|
||||
#define ATH6KL_HB_RESP_MISS_THRES 5
|
||||
|
||||
enum ath6kl_fw_err {
|
||||
ATH6KL_FW_ASSERT,
|
||||
ATH6KL_FW_HB_RESP_FAILURE,
|
||||
ATH6KL_FW_EP_FULL,
|
||||
};
|
||||
|
||||
struct ath6kl {
|
||||
@ -679,6 +724,7 @@ struct ath6kl {
|
||||
struct ath6kl_req_key ap_mode_bkey;
|
||||
struct sk_buff_head mcastpsq;
|
||||
u32 want_ch_switch;
|
||||
u16 last_ch;
|
||||
|
||||
/*
|
||||
* FIXME: protects access to mcastpsq but is actually useless as
|
||||
@ -764,6 +810,17 @@ struct ath6kl {
|
||||
|
||||
bool wiphy_registered;
|
||||
|
||||
struct ath6kl_fw_recovery {
|
||||
struct work_struct recovery_work;
|
||||
unsigned long err_reason;
|
||||
unsigned long hb_poll;
|
||||
struct timer_list hb_timer;
|
||||
u32 seq_num;
|
||||
bool hb_pending;
|
||||
u8 hb_misscnt;
|
||||
bool enable;
|
||||
} fw_recovery;
|
||||
|
||||
#ifdef CONFIG_ATH6KL_DEBUG
|
||||
struct {
|
||||
struct sk_buff_head fwlog_queue;
|
||||
@ -899,4 +956,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type);
|
||||
void ath6kl_core_cleanup(struct ath6kl *ar);
|
||||
void ath6kl_core_destroy(struct ath6kl *ar);
|
||||
|
||||
/* Fw error recovery */
|
||||
void ath6kl_init_hw_restart(struct ath6kl *ar);
|
||||
void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason);
|
||||
void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie);
|
||||
void ath6kl_recovery_init(struct ath6kl *ar);
|
||||
void ath6kl_recovery_cleanup(struct ath6kl *ar);
|
||||
void ath6kl_recovery_suspend(struct ath6kl *ar);
|
||||
void ath6kl_recovery_resume(struct ath6kl *ar);
|
||||
#endif /* CORE_H */
|
||||
|
@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK {
|
||||
ATH6KL_DBG_SUSPEND = BIT(20),
|
||||
ATH6KL_DBG_USB = BIT(21),
|
||||
ATH6KL_DBG_USB_BULK = BIT(22),
|
||||
ATH6KL_DBG_RECOVERY = BIT(23),
|
||||
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
|
||||
};
|
||||
|
||||
|
@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
|
||||
|
||||
ath6kl_hif_dump_fw_crash(dev->ar);
|
||||
ath6kl_read_fwlogs(dev->ar);
|
||||
ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -693,11 +694,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
|
||||
ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
|
||||
dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
|
||||
|
||||
/* usb doesn't support enabling interrupts */
|
||||
/* FIXME: remove check once USB support is implemented */
|
||||
if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
|
||||
return 0;
|
||||
|
||||
status = ath6kl_hif_disable_intrs(dev);
|
||||
|
||||
fail_setup:
|
||||
|
@ -2492,7 +2492,8 @@ static int ath6kl_htc_mbox_conn_service(struct htc_target *target,
|
||||
max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz);
|
||||
}
|
||||
|
||||
if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) {
|
||||
if (WARN_ON_ONCE(assigned_ep == ENDPOINT_UNUSED ||
|
||||
assigned_ep >= ENDPOINT_MAX || !max_msg_sz)) {
|
||||
status = -ENOMEM;
|
||||
goto fail_tx;
|
||||
}
|
||||
@ -2655,12 +2656,6 @@ static int ath6kl_htc_mbox_wait_target(struct htc_target *target)
|
||||
struct htc_service_connect_resp resp;
|
||||
int status;
|
||||
|
||||
/* FIXME: remove once USB support is implemented */
|
||||
if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) {
|
||||
ath6kl_err("HTC doesn't support USB yet. Patience!\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* we should be getting 1 control message that the target is ready */
|
||||
packet = htc_wait_for_ctrl_msg(target);
|
||||
|
||||
@ -2890,9 +2885,7 @@ static void ath6kl_htc_mbox_cleanup(struct htc_target *target)
|
||||
{
|
||||
struct htc_packet *packet, *tmp_packet;
|
||||
|
||||
/* FIXME: remove check once USB support is implemented */
|
||||
if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB)
|
||||
ath6kl_hif_cleanup_scatter(target->dev->ar);
|
||||
ath6kl_hif_cleanup_scatter(target->dev->ar);
|
||||
|
||||
list_for_each_entry_safe(packet, tmp_packet,
|
||||
&target->free_ctrl_txbuf, list) {
|
||||
|
@ -374,9 +374,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
|
||||
packet = list_first_entry(txq,
|
||||
struct htc_packet,
|
||||
list);
|
||||
list_del(&packet->list);
|
||||
/* insert into local queue */
|
||||
list_add_tail(&packet->list, &send_queue);
|
||||
/* move to local queue */
|
||||
list_move_tail(&packet->list, &send_queue);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -399,11 +398,10 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
|
||||
* for cleanup */
|
||||
} else {
|
||||
/* callback wants to keep this packet,
|
||||
* remove from caller's queue */
|
||||
list_del(&packet->list);
|
||||
/* put it in the send queue */
|
||||
list_add_tail(&packet->list,
|
||||
&send_queue);
|
||||
* move from caller's queue to the send
|
||||
* queue */
|
||||
list_move_tail(&packet->list,
|
||||
&send_queue);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ static const struct ath6kl_hw hw_list[] = {
|
||||
.reserved_ram_size = 6912,
|
||||
.refclk_hz = 26000000,
|
||||
.uarttx_pin = 8,
|
||||
.flags = 0,
|
||||
.flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR,
|
||||
|
||||
/* hw2.0 needs override address hardcoded */
|
||||
.app_start_override_addr = 0x944C00,
|
||||
@ -68,7 +68,7 @@ static const struct ath6kl_hw hw_list[] = {
|
||||
.refclk_hz = 26000000,
|
||||
.uarttx_pin = 8,
|
||||
.testscript_addr = 0x57ef74,
|
||||
.flags = 0,
|
||||
.flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR,
|
||||
|
||||
.fw = {
|
||||
.dir = AR6003_HW_2_1_1_FW_DIR,
|
||||
@ -93,7 +93,8 @@ static const struct ath6kl_hw hw_list[] = {
|
||||
.board_addr = 0x433900,
|
||||
.refclk_hz = 26000000,
|
||||
.uarttx_pin = 11,
|
||||
.flags = ATH6KL_HW_FLAG_64BIT_RATES,
|
||||
.flags = ATH6KL_HW_64BIT_RATES |
|
||||
ATH6KL_HW_AP_INACTIVITY_MINS,
|
||||
|
||||
.fw = {
|
||||
.dir = AR6004_HW_1_0_FW_DIR,
|
||||
@ -113,8 +114,8 @@ static const struct ath6kl_hw hw_list[] = {
|
||||
.board_addr = 0x43d400,
|
||||
.refclk_hz = 40000000,
|
||||
.uarttx_pin = 11,
|
||||
.flags = ATH6KL_HW_FLAG_64BIT_RATES,
|
||||
|
||||
.flags = ATH6KL_HW_64BIT_RATES |
|
||||
ATH6KL_HW_AP_INACTIVITY_MINS,
|
||||
.fw = {
|
||||
.dir = AR6004_HW_1_1_FW_DIR,
|
||||
.fw = AR6004_HW_1_1_FIRMWARE_FILE,
|
||||
@ -133,7 +134,8 @@ static const struct ath6kl_hw hw_list[] = {
|
||||
.board_addr = 0x435c00,
|
||||
.refclk_hz = 40000000,
|
||||
.uarttx_pin = 11,
|
||||
.flags = ATH6KL_HW_FLAG_64BIT_RATES,
|
||||
.flags = ATH6KL_HW_64BIT_RATES |
|
||||
ATH6KL_HW_AP_INACTIVITY_MINS,
|
||||
|
||||
.fw = {
|
||||
.dir = AR6004_HW_1_2_FW_DIR,
|
||||
@ -142,6 +144,28 @@ static const struct ath6kl_hw hw_list[] = {
|
||||
.fw_board = AR6004_HW_1_2_BOARD_DATA_FILE,
|
||||
.fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE,
|
||||
},
|
||||
{
|
||||
.id = AR6004_HW_1_3_VERSION,
|
||||
.name = "ar6004 hw 1.3",
|
||||
.dataset_patch_addr = 0x437860,
|
||||
.app_load_addr = 0x1234,
|
||||
.board_ext_data_addr = 0x437000,
|
||||
.reserved_ram_size = 7168,
|
||||
.board_addr = 0x436400,
|
||||
.refclk_hz = 40000000,
|
||||
.uarttx_pin = 11,
|
||||
.flags = ATH6KL_HW_64BIT_RATES |
|
||||
ATH6KL_HW_AP_INACTIVITY_MINS |
|
||||
ATH6KL_HW_MAP_LP_ENDPOINT,
|
||||
|
||||
.fw = {
|
||||
.dir = AR6004_HW_1_3_FW_DIR,
|
||||
.fw = AR6004_HW_1_3_FIRMWARE_FILE,
|
||||
},
|
||||
|
||||
.fw_board = AR6004_HW_1_3_BOARD_DATA_FILE,
|
||||
.fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
@ -337,7 +361,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar)
|
||||
if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))
|
||||
return -EIO;
|
||||
|
||||
/* connect to Video service, map this to to HI PRI */
|
||||
/* connect to Video service, map this to HI PRI */
|
||||
connect.svc_id = WMI_DATA_VI_SVC;
|
||||
if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))
|
||||
return -EIO;
|
||||
@ -1088,6 +1112,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE);
|
||||
if (ret == 0) {
|
||||
ar->fw_api = 4;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);
|
||||
if (ret == 0) {
|
||||
ar->fw_api = 3;
|
||||
@ -1401,8 +1431,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
|
||||
return status;
|
||||
|
||||
/* WAR to avoid SDIO CRC err */
|
||||
if (ar->version.target_ver == AR6003_HW_2_0_VERSION ||
|
||||
ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
|
||||
if (ar->hw.flags & ATH6KL_HW_SDIO_CRC_ERROR_WAR) {
|
||||
ath6kl_err("temporary war to avoid sdio crc error\n");
|
||||
|
||||
param = 0x28;
|
||||
@ -1520,7 +1549,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ath6kl_init_hw_start(struct ath6kl *ar)
|
||||
static int __ath6kl_init_hw_start(struct ath6kl *ar)
|
||||
{
|
||||
long timeleft;
|
||||
int ret, i;
|
||||
@ -1616,8 +1645,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
|
||||
goto err_htc_stop;
|
||||
}
|
||||
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
|
||||
return 0;
|
||||
|
||||
err_htc_stop:
|
||||
@ -1630,7 +1657,18 @@ err_power_off:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath6kl_init_hw_stop(struct ath6kl *ar)
|
||||
int ath6kl_init_hw_start(struct ath6kl *ar)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __ath6kl_init_hw_start(ar);
|
||||
if (err)
|
||||
return err;
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __ath6kl_init_hw_stop(struct ath6kl *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -1646,11 +1684,37 @@ int ath6kl_init_hw_stop(struct ath6kl *ar)
|
||||
if (ret)
|
||||
ath6kl_warn("failed to power off hif: %d\n", ret);
|
||||
|
||||
ar->state = ATH6KL_STATE_OFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_init_hw_stop(struct ath6kl *ar)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __ath6kl_init_hw_stop(ar);
|
||||
if (err)
|
||||
return err;
|
||||
ar->state = ATH6KL_STATE_OFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath6kl_init_hw_restart(struct ath6kl *ar)
|
||||
{
|
||||
clear_bit(WMI_READY, &ar->flag);
|
||||
|
||||
ath6kl_cfg80211_stop_all(ar);
|
||||
|
||||
if (__ath6kl_init_hw_stop(ar)) {
|
||||
ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (__ath6kl_init_hw_start(ar)) {
|
||||
ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
|
||||
void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
|
||||
{
|
||||
|
@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
|
||||
}
|
||||
|
||||
address = TARG_VTOP(ar->target_type, debug_hdr_addr);
|
||||
ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
|
||||
ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
address = TARG_VTOP(ar->target_type,
|
||||
le32_to_cpu(debug_hdr.dbuf_addr));
|
||||
firstbuf = address;
|
||||
dropped = le32_to_cpu(debug_hdr.dropped);
|
||||
ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
|
||||
ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
loop = 100;
|
||||
|
||||
@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
|
||||
|
||||
address = TARG_VTOP(ar->target_type,
|
||||
le32_to_cpu(debug_buf.next));
|
||||
ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
|
||||
ret = ath6kl_diag_read(ar, address, &debug_buf,
|
||||
sizeof(debug_buf));
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@ -436,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) {
|
||||
ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
|
||||
if (ar->last_ch != channel)
|
||||
/* we actually don't know the phymode, default to HT20 */
|
||||
ath6kl_cfg80211_ch_switch_notify(vif, channel,
|
||||
WMI_11G_HT20);
|
||||
}
|
||||
ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20);
|
||||
|
||||
ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
|
||||
set_bit(CONNECTED, &vif->flags);
|
||||
@ -606,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
|
||||
|
||||
switch (vif->nw_type) {
|
||||
case AP_NETWORK:
|
||||
/*
|
||||
* reconfigure any saved RSN IE capabilites in the beacon /
|
||||
* probe response to stay in sync with the supplicant.
|
||||
*/
|
||||
if (vif->rsn_capab &&
|
||||
test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
|
||||
ar->fw_capabilities))
|
||||
ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WLAN_EID_RSN, WMI_RSN_IE_CAPB,
|
||||
(const u8 *) &vif->rsn_capab,
|
||||
sizeof(vif->rsn_capab));
|
||||
|
||||
return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
|
||||
&vif->profile);
|
||||
default:
|
||||
@ -628,6 +642,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
|
||||
if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
|
||||
res = ath6kl_commit_ch_switch(vif, channel);
|
||||
|
||||
/* if channel switch failed, oh well we tried */
|
||||
ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
|
||||
|
||||
if (res)
|
||||
ath6kl_err("channel switch failed nw_type %d res %d\n",
|
||||
vif->nw_type, res);
|
||||
@ -981,8 +998,25 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
|
||||
if (vif->nw_type == AP_NETWORK) {
|
||||
/* disconnect due to other STA vif switching channels */
|
||||
if (reason == BSS_DISCONNECTED &&
|
||||
prot_reason_status == WMI_AP_REASON_STA_ROAM)
|
||||
prot_reason_status == WMI_AP_REASON_STA_ROAM) {
|
||||
ar->want_ch_switch |= 1 << vif->fw_vif_idx;
|
||||
/* bail back to this channel if STA vif fails connect */
|
||||
ar->last_ch = le16_to_cpu(vif->profile.ch);
|
||||
}
|
||||
|
||||
if (prot_reason_status == WMI_AP_REASON_MAX_STA) {
|
||||
/* send max client reached notification to user space */
|
||||
cfg80211_conn_failed(vif->ndev, bssid,
|
||||
NL80211_CONN_FAIL_MAX_CLIENTS,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
if (prot_reason_status == WMI_AP_REASON_ACL) {
|
||||
/* send blocked client notification to user space */
|
||||
cfg80211_conn_failed(vif->ndev, bssid,
|
||||
NL80211_CONN_FAIL_BLOCKED_CLIENT,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
|
||||
return;
|
||||
@ -1041,6 +1075,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
|
||||
}
|
||||
}
|
||||
|
||||
/* restart disconnected concurrent vifs waiting for new channel */
|
||||
ath6kl_check_ch_switch(ar, ar->last_ch);
|
||||
|
||||
/* update connect & link status atomically */
|
||||
spin_lock_bh(&vif->if_lock);
|
||||
clear_bit(CONNECTED, &vif->flags);
|
||||
|
160
drivers/net/wireless/ath/ath6kl/recovery.c
Normal file
160
drivers/net/wireless/ath/ath6kl/recovery.c
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "cfg80211.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void ath6kl_recovery_work(struct work_struct *work)
|
||||
{
|
||||
struct ath6kl *ar = container_of(work, struct ath6kl,
|
||||
fw_recovery.recovery_work);
|
||||
|
||||
ar->state = ATH6KL_STATE_RECOVERY;
|
||||
|
||||
del_timer_sync(&ar->fw_recovery.hb_timer);
|
||||
|
||||
ath6kl_init_hw_restart(ar);
|
||||
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
clear_bit(WMI_CTRL_EP_FULL, &ar->flag);
|
||||
|
||||
ar->fw_recovery.err_reason = 0;
|
||||
|
||||
if (ar->fw_recovery.hb_poll)
|
||||
mod_timer(&ar->fw_recovery.hb_timer, jiffies +
|
||||
msecs_to_jiffies(ar->fw_recovery.hb_poll));
|
||||
}
|
||||
|
||||
void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason)
|
||||
{
|
||||
if (!ar->fw_recovery.enable)
|
||||
return;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n",
|
||||
reason);
|
||||
|
||||
set_bit(reason, &ar->fw_recovery.err_reason);
|
||||
|
||||
if (!test_bit(RECOVERY_CLEANUP, &ar->flag) &&
|
||||
ar->state != ATH6KL_STATE_RECOVERY)
|
||||
queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work);
|
||||
}
|
||||
|
||||
void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie)
|
||||
{
|
||||
if (cookie == ar->fw_recovery.seq_num)
|
||||
ar->fw_recovery.hb_pending = false;
|
||||
}
|
||||
|
||||
static void ath6kl_recovery_hb_timer(unsigned long data)
|
||||
{
|
||||
struct ath6kl *ar = (struct ath6kl *) data;
|
||||
int err;
|
||||
|
||||
if (test_bit(RECOVERY_CLEANUP, &ar->flag) ||
|
||||
(ar->state == ATH6KL_STATE_RECOVERY))
|
||||
return;
|
||||
|
||||
if (ar->fw_recovery.hb_pending)
|
||||
ar->fw_recovery.hb_misscnt++;
|
||||
else
|
||||
ar->fw_recovery.hb_misscnt = 0;
|
||||
|
||||
if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) {
|
||||
ar->fw_recovery.hb_misscnt = 0;
|
||||
ar->fw_recovery.seq_num = 0;
|
||||
ar->fw_recovery.hb_pending = false;
|
||||
ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
ar->fw_recovery.seq_num++;
|
||||
ar->fw_recovery.hb_pending = true;
|
||||
|
||||
err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi,
|
||||
ar->fw_recovery.seq_num, 0);
|
||||
if (err)
|
||||
ath6kl_warn("Failed to send hb challenge request, err:%d\n",
|
||||
err);
|
||||
|
||||
mod_timer(&ar->fw_recovery.hb_timer, jiffies +
|
||||
msecs_to_jiffies(ar->fw_recovery.hb_poll));
|
||||
}
|
||||
|
||||
void ath6kl_recovery_init(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_fw_recovery *recovery = &ar->fw_recovery;
|
||||
|
||||
clear_bit(RECOVERY_CLEANUP, &ar->flag);
|
||||
INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work);
|
||||
recovery->seq_num = 0;
|
||||
recovery->hb_misscnt = 0;
|
||||
ar->fw_recovery.hb_pending = false;
|
||||
ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer;
|
||||
ar->fw_recovery.hb_timer.data = (unsigned long) ar;
|
||||
init_timer_deferrable(&ar->fw_recovery.hb_timer);
|
||||
|
||||
if (ar->fw_recovery.hb_poll)
|
||||
mod_timer(&ar->fw_recovery.hb_timer, jiffies +
|
||||
msecs_to_jiffies(ar->fw_recovery.hb_poll));
|
||||
}
|
||||
|
||||
void ath6kl_recovery_cleanup(struct ath6kl *ar)
|
||||
{
|
||||
if (!ar->fw_recovery.enable)
|
||||
return;
|
||||
|
||||
set_bit(RECOVERY_CLEANUP, &ar->flag);
|
||||
|
||||
del_timer_sync(&ar->fw_recovery.hb_timer);
|
||||
cancel_work_sync(&ar->fw_recovery.recovery_work);
|
||||
}
|
||||
|
||||
void ath6kl_recovery_suspend(struct ath6kl *ar)
|
||||
{
|
||||
if (!ar->fw_recovery.enable)
|
||||
return;
|
||||
|
||||
ath6kl_recovery_cleanup(ar);
|
||||
|
||||
if (!ar->fw_recovery.err_reason)
|
||||
return;
|
||||
|
||||
/* Process pending fw error detection */
|
||||
ar->fw_recovery.err_reason = 0;
|
||||
WARN_ON(ar->state != ATH6KL_STATE_ON);
|
||||
ar->state = ATH6KL_STATE_RECOVERY;
|
||||
ath6kl_init_hw_restart(ar);
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
}
|
||||
|
||||
void ath6kl_recovery_resume(struct ath6kl *ar)
|
||||
{
|
||||
if (!ar->fw_recovery.enable)
|
||||
return;
|
||||
|
||||
clear_bit(RECOVERY_CLEANUP, &ar->flag);
|
||||
|
||||
if (!ar->fw_recovery.hb_poll)
|
||||
return;
|
||||
|
||||
ar->fw_recovery.hb_pending = false;
|
||||
ar->fw_recovery.seq_num = 0;
|
||||
ar->fw_recovery.hb_misscnt = 0;
|
||||
mod_timer(&ar->fw_recovery.hb_timer,
|
||||
jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll));
|
||||
}
|
@ -709,7 +709,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
struct htc_target *target = ar->htc_target;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
bool virt_scat = false;
|
||||
|
||||
if (ar_sdio->scatter_enabled)
|
||||
@ -844,22 +844,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
bool try_deepsleep = false;
|
||||
int ret;
|
||||
|
||||
if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
|
||||
ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n");
|
||||
|
||||
ret = ath6kl_set_sdio_pm_caps(ar);
|
||||
if (ret)
|
||||
goto cut_pwr;
|
||||
|
||||
ret = ath6kl_cfg80211_suspend(ar,
|
||||
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
|
||||
NULL);
|
||||
if (ret)
|
||||
goto cut_pwr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
|
||||
(!ar->suspend_mode && wow)) {
|
||||
|
||||
@ -942,14 +926,14 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
|
||||
case ATH6KL_STATE_WOW:
|
||||
break;
|
||||
|
||||
case ATH6KL_STATE_SCHED_SCAN:
|
||||
break;
|
||||
|
||||
case ATH6KL_STATE_SUSPENDING:
|
||||
break;
|
||||
|
||||
case ATH6KL_STATE_RESUMING:
|
||||
break;
|
||||
|
||||
case ATH6KL_STATE_RECOVERY:
|
||||
break;
|
||||
}
|
||||
|
||||
ath6kl_cfg80211_resume(ar);
|
||||
@ -1462,3 +1446,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE);
|
||||
|
@ -288,8 +288,16 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
|
||||
int status = 0;
|
||||
struct ath6kl_cookie *cookie = NULL;
|
||||
|
||||
if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW))
|
||||
if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) {
|
||||
dev_kfree_skb(skb);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(eid == ENDPOINT_UNUSED ||
|
||||
eid >= ENDPOINT_MAX)) {
|
||||
status = -EINVAL;
|
||||
goto fail_ctrl_tx;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->lock);
|
||||
|
||||
@ -591,6 +599,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
|
||||
*/
|
||||
set_bit(WMI_CTRL_EP_FULL, &ar->flag);
|
||||
ath6kl_err("wmi ctrl ep is full\n");
|
||||
ath6kl_recovery_err_notify(ar, ATH6KL_FW_EP_FULL);
|
||||
return action;
|
||||
}
|
||||
|
||||
@ -695,22 +704,31 @@ void ath6kl_tx_complete(struct htc_target *target,
|
||||
list);
|
||||
list_del(&packet->list);
|
||||
|
||||
if (WARN_ON_ONCE(packet->endpoint == ENDPOINT_UNUSED ||
|
||||
packet->endpoint >= ENDPOINT_MAX))
|
||||
continue;
|
||||
|
||||
ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt;
|
||||
if (!ath6kl_cookie)
|
||||
goto fatal;
|
||||
if (WARN_ON_ONCE(!ath6kl_cookie))
|
||||
continue;
|
||||
|
||||
status = packet->status;
|
||||
skb = ath6kl_cookie->skb;
|
||||
eid = packet->endpoint;
|
||||
map_no = ath6kl_cookie->map_no;
|
||||
|
||||
if (!skb || !skb->data)
|
||||
goto fatal;
|
||||
if (WARN_ON_ONCE(!skb || !skb->data)) {
|
||||
dev_kfree_skb(skb);
|
||||
ath6kl_free_cookie(ar, ath6kl_cookie);
|
||||
continue;
|
||||
}
|
||||
|
||||
__skb_queue_tail(&skb_queue, skb);
|
||||
|
||||
if (!status && (packet->act_len != skb->len))
|
||||
goto fatal;
|
||||
if (WARN_ON_ONCE(!status && (packet->act_len != skb->len))) {
|
||||
ath6kl_free_cookie(ar, ath6kl_cookie);
|
||||
continue;
|
||||
}
|
||||
|
||||
ar->tx_pending[eid]--;
|
||||
|
||||
@ -792,11 +810,6 @@ void ath6kl_tx_complete(struct htc_target *target,
|
||||
wake_up(&ar->event_wq);
|
||||
|
||||
return;
|
||||
|
||||
fatal:
|
||||
WARN_ON(1);
|
||||
spin_unlock_bh(&ar->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
void ath6kl_tx_data_cleanup(struct ath6kl *ar)
|
||||
@ -885,8 +898,11 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
|
||||
break;
|
||||
|
||||
packet = (struct htc_packet *) skb->head;
|
||||
if (!IS_ALIGNED((unsigned long) skb->data, 4))
|
||||
if (!IS_ALIGNED((unsigned long) skb->data, 4)) {
|
||||
size_t len = skb_headlen(skb);
|
||||
skb->data = PTR_ALIGN(skb->data - 4, 4);
|
||||
skb_set_tail_pointer(skb, len);
|
||||
}
|
||||
set_htc_rxpkt_info(packet, skb, skb->data,
|
||||
ATH6KL_BUFFER_SIZE, endpoint);
|
||||
packet->skb = skb;
|
||||
@ -908,8 +924,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
|
||||
return;
|
||||
|
||||
packet = (struct htc_packet *) skb->head;
|
||||
if (!IS_ALIGNED((unsigned long) skb->data, 4))
|
||||
if (!IS_ALIGNED((unsigned long) skb->data, 4)) {
|
||||
size_t len = skb_headlen(skb);
|
||||
skb->data = PTR_ALIGN(skb->data - 4, 4);
|
||||
skb_set_tail_pointer(skb, len);
|
||||
}
|
||||
set_htc_rxpkt_info(packet, skb, skb->data,
|
||||
ATH6KL_AMSDU_BUFFER_SIZE, 0);
|
||||
packet->skb = skb;
|
||||
|
@ -185,9 +185,10 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
|
||||
for (i = 0; i < urb_cnt; i++) {
|
||||
urb_context = kzalloc(sizeof(struct ath6kl_urb_context),
|
||||
GFP_KERNEL);
|
||||
if (urb_context == NULL)
|
||||
/* FIXME: set status to -ENOMEM */
|
||||
break;
|
||||
if (urb_context == NULL) {
|
||||
status = -ENOMEM;
|
||||
goto fail_alloc_pipe_resources;
|
||||
}
|
||||
|
||||
urb_context->pipe = pipe;
|
||||
|
||||
@ -204,6 +205,7 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
|
||||
pipe->logical_pipe_num, pipe->usb_pipe_handle,
|
||||
pipe->urb_alloc);
|
||||
|
||||
fail_alloc_pipe_resources:
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -803,7 +805,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
|
||||
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
|
||||
break;
|
||||
case WMI_DATA_VI_SVC:
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
|
||||
|
||||
if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
|
||||
else
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
|
||||
/*
|
||||
* Disable rxdata2 directly, it will be enabled
|
||||
* if FW enable rxdata2
|
||||
@ -811,7 +817,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
|
||||
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
|
||||
break;
|
||||
case WMI_DATA_VO_SVC:
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP;
|
||||
|
||||
if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
|
||||
else
|
||||
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
|
||||
/*
|
||||
* Disable rxdata2 directly, it will be enabled
|
||||
* if FW enable rxdata2
|
||||
@ -1196,7 +1206,14 @@ static struct usb_driver ath6kl_usb_driver = {
|
||||
|
||||
static int ath6kl_usb_init(void)
|
||||
{
|
||||
usb_register(&ath6kl_usb_driver);
|
||||
int ret;
|
||||
|
||||
ret = usb_register(&ath6kl_usb_driver);
|
||||
if (ret) {
|
||||
ath6kl_err("usb registration failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1220,3 +1237,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE);
|
||||
|
@ -936,8 +936,12 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
|
||||
|
||||
regpair = ath6kl_get_regpair((u16) reg_code);
|
||||
country = ath6kl_regd_find_country_by_rd((u16) reg_code);
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
|
||||
regpair->regDmnEnum);
|
||||
if (regpair)
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
|
||||
regpair->regDmnEnum);
|
||||
else
|
||||
ath6kl_warn("Regpair not found reg_code 0x%0x\n",
|
||||
reg_code);
|
||||
}
|
||||
|
||||
if (country && wmi->parent_dev->wiphy_registered) {
|
||||
@ -1116,7 +1120,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
* the timer would not ever fire if the scan interval is short
|
||||
* enough.
|
||||
*/
|
||||
if (ar->state == ATH6KL_STATE_SCHED_SCAN &&
|
||||
if (test_bit(SCHED_SCANNING, &vif->flags) &&
|
||||
!timer_pending(&vif->sched_scan_timer)) {
|
||||
mod_timer(&vif->sched_scan_timer, jiffies +
|
||||
msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
|
||||
@ -1170,6 +1174,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
|
||||
rate = RATE_AUTO;
|
||||
} else {
|
||||
index = reply->rate_index & 0x7f;
|
||||
if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1)))
|
||||
return -EINVAL;
|
||||
|
||||
sgi = (reply->rate_index & 0x80) ? 1 : 0;
|
||||
rate = wmi_rate_tbl[index][sgi];
|
||||
}
|
||||
@ -1531,6 +1538,68 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
struct ath6kl_vif *vif)
|
||||
{
|
||||
struct wmi_txe_notify_event *ev;
|
||||
u32 rate, pkts;
|
||||
|
||||
if (len < sizeof(*ev))
|
||||
return -EINVAL;
|
||||
|
||||
if (vif->sme_state != SME_CONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
ev = (struct wmi_txe_notify_event *) datap;
|
||||
rate = le32_to_cpu(ev->rate);
|
||||
pkts = le32_to_cpu(ev->pkts);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d% pkts %d intvl %ds\n",
|
||||
vif->bssid, rate, pkts, vif->txe_intvl);
|
||||
|
||||
cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts,
|
||||
rate, vif->txe_intvl, GFP_KERNEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
|
||||
u32 rate, u32 pkts, u32 intvl)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct wmi_txe_notify_cmd *cmd;
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_txe_notify_cmd *) skb->data;
|
||||
cmd->rate = cpu_to_le32(rate);
|
||||
cmd->pkts = cpu_to_le32(pkts);
|
||||
cmd->intvl = cpu_to_le32(intvl);
|
||||
|
||||
return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID,
|
||||
NO_SYNC_WMIFLAG);
|
||||
}
|
||||
|
||||
int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct wmi_set_rssi_filter_cmd *cmd;
|
||||
int ret;
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_set_rssi_filter_cmd *) skb->data;
|
||||
cmd->rssi = rssi;
|
||||
|
||||
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID,
|
||||
NO_SYNC_WMIFLAG);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
|
||||
struct wmi_snr_threshold_params_cmd *snr_cmd)
|
||||
{
|
||||
@ -1677,8 +1746,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
|
||||
int ret;
|
||||
u16 info1;
|
||||
|
||||
if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1))))
|
||||
if (WARN_ON(skb == NULL ||
|
||||
(if_idx > (wmi->parent_dev->vif_max - 1)))) {
|
||||
dev_kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
|
||||
cmd_id, skb->len, sync_flag);
|
||||
@ -1833,6 +1905,59 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
|
||||
* ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
|
||||
* mgmt operations using station interface.
|
||||
*/
|
||||
static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
enum wmi_scan_type scan_type,
|
||||
u32 force_fgscan, u32 is_legacy,
|
||||
u32 home_dwell_time,
|
||||
u32 force_scan_interval,
|
||||
s8 num_chan, u16 *ch_list)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct wmi_start_scan_cmd *sc;
|
||||
s8 size;
|
||||
int i, ret;
|
||||
|
||||
size = sizeof(struct wmi_start_scan_cmd);
|
||||
|
||||
if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
|
||||
return -EINVAL;
|
||||
|
||||
if (num_chan > WMI_MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
if (num_chan)
|
||||
size += sizeof(u16) * (num_chan - 1);
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(size);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
sc = (struct wmi_start_scan_cmd *) skb->data;
|
||||
sc->scan_type = scan_type;
|
||||
sc->force_fg_scan = cpu_to_le32(force_fgscan);
|
||||
sc->is_legacy = cpu_to_le32(is_legacy);
|
||||
sc->home_dwell_time = cpu_to_le32(home_dwell_time);
|
||||
sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
|
||||
sc->num_ch = num_chan;
|
||||
|
||||
for (i = 0; i < num_chan; i++)
|
||||
sc->ch_list[i] = cpu_to_le16(ch_list[i]);
|
||||
|
||||
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID,
|
||||
NO_SYNC_WMIFLAG);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* beginscan supports (compared to old startscan) P2P mgmt operations using
|
||||
* station interface, send additional information like supported rates to
|
||||
* advertise and xmit rates for probe requests
|
||||
*/
|
||||
int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
enum wmi_scan_type scan_type,
|
||||
u32 force_fgscan, u32 is_legacy,
|
||||
@ -1848,6 +1973,15 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
int num_rates;
|
||||
u32 ratemask;
|
||||
|
||||
if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
|
||||
ar->fw_capabilities)) {
|
||||
return ath6kl_wmi_startscan_cmd(wmi, if_idx,
|
||||
scan_type, force_fgscan,
|
||||
is_legacy, home_dwell_time,
|
||||
force_scan_interval,
|
||||
num_chan, ch_list);
|
||||
}
|
||||
|
||||
size = sizeof(struct wmi_begin_scan_cmd);
|
||||
|
||||
if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
|
||||
@ -1900,50 +2034,24 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
|
||||
* ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
|
||||
* mgmt operations using station interface.
|
||||
*/
|
||||
int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
enum wmi_scan_type scan_type,
|
||||
u32 force_fgscan, u32 is_legacy,
|
||||
u32 home_dwell_time, u32 force_scan_interval,
|
||||
s8 num_chan, u16 *ch_list)
|
||||
int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct wmi_start_scan_cmd *sc;
|
||||
s8 size;
|
||||
int i, ret;
|
||||
struct wmi_enable_sched_scan_cmd *sc;
|
||||
int ret;
|
||||
|
||||
size = sizeof(struct wmi_start_scan_cmd);
|
||||
|
||||
if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
|
||||
return -EINVAL;
|
||||
|
||||
if (num_chan > WMI_MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
if (num_chan)
|
||||
size += sizeof(u16) * (num_chan - 1);
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(size);
|
||||
skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
sc = (struct wmi_start_scan_cmd *) skb->data;
|
||||
sc->scan_type = scan_type;
|
||||
sc->force_fg_scan = cpu_to_le32(force_fgscan);
|
||||
sc->is_legacy = cpu_to_le32(is_legacy);
|
||||
sc->home_dwell_time = cpu_to_le32(home_dwell_time);
|
||||
sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
|
||||
sc->num_ch = num_chan;
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n",
|
||||
enable ? "enabling" : "disabling", if_idx);
|
||||
sc = (struct wmi_enable_sched_scan_cmd *) skb->data;
|
||||
sc->enable = enable ? 1 : 0;
|
||||
|
||||
for (i = 0; i < num_chan; i++)
|
||||
sc->ch_list[i] = cpu_to_le16(ch_list[i]);
|
||||
|
||||
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID,
|
||||
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
|
||||
WMI_ENABLE_SCHED_SCAN_CMDID,
|
||||
NO_SYNC_WMIFLAG);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2275,8 +2383,10 @@ static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,
|
||||
struct wmi_data_hdr *data_hdr;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(skb == NULL || ep_id == wmi->ep_id))
|
||||
if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) {
|
||||
dev_kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
skb_push(skb, sizeof(struct wmi_data_hdr));
|
||||
|
||||
@ -2313,10 +2423,8 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
|
||||
spin_unlock_bh(&wmi->lock);
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
goto free_skb;
|
||||
}
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_sync_cmd *) skb->data;
|
||||
|
||||
@ -2339,7 +2447,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
|
||||
* then do not send the Synchronize cmd on the control ep
|
||||
*/
|
||||
if (ret)
|
||||
goto free_skb;
|
||||
goto free_cmd_skb;
|
||||
|
||||
/*
|
||||
* Send sync cmd followed by sync data messages on all
|
||||
@ -2349,15 +2457,12 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
|
||||
NO_SYNC_WMIFLAG);
|
||||
|
||||
if (ret)
|
||||
goto free_skb;
|
||||
|
||||
/* cmd buffer sent, we no longer own it */
|
||||
skb = NULL;
|
||||
goto free_data_skb;
|
||||
|
||||
for (index = 0; index < num_pri_streams; index++) {
|
||||
|
||||
if (WARN_ON(!data_sync_bufs[index].skb))
|
||||
break;
|
||||
goto free_data_skb;
|
||||
|
||||
ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,
|
||||
data_sync_bufs[index].
|
||||
@ -2366,17 +2471,20 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
|
||||
ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,
|
||||
ep_id, if_idx);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
data_sync_bufs[index].skb = NULL;
|
||||
|
||||
if (ret)
|
||||
goto free_data_skb;
|
||||
}
|
||||
|
||||
free_skb:
|
||||
return 0;
|
||||
|
||||
free_cmd_skb:
|
||||
/* free up any resources left over (possibly due to an error) */
|
||||
if (skb)
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
free_data_skb:
|
||||
for (index = 0; index < num_pri_streams; index++) {
|
||||
if (data_sync_bufs[index].skb != NULL) {
|
||||
dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].
|
||||
@ -2618,11 +2726,13 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret, mode, band;
|
||||
u64 mcsrate, ratemask[IEEE80211_NUM_BANDS];
|
||||
u64 mcsrate, ratemask[ATH6KL_NUM_BANDS];
|
||||
struct wmi_set_tx_select_rates64_cmd *cmd;
|
||||
|
||||
memset(&ratemask, 0, sizeof(ratemask));
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
|
||||
/* only check 2.4 and 5 GHz bands, skip the rest */
|
||||
for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {
|
||||
/* copy legacy rate mask */
|
||||
ratemask[band] = mask->control[band].legacy;
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
@ -2668,11 +2778,13 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret, mode, band;
|
||||
u32 mcsrate, ratemask[IEEE80211_NUM_BANDS];
|
||||
u32 mcsrate, ratemask[ATH6KL_NUM_BANDS];
|
||||
struct wmi_set_tx_select_rates32_cmd *cmd;
|
||||
|
||||
memset(&ratemask, 0, sizeof(ratemask));
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
|
||||
/* only check 2.4 and 5 GHz bands, skip the rest */
|
||||
for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {
|
||||
/* copy legacy rate mask */
|
||||
ratemask[band] = mask->control[band].legacy;
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
@ -2716,7 +2828,7 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
|
||||
{
|
||||
struct ath6kl *ar = wmi->parent_dev;
|
||||
|
||||
if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES)
|
||||
if (ar->hw.flags & ATH6KL_HW_64BIT_RATES)
|
||||
return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
|
||||
else
|
||||
return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
|
||||
@ -3139,12 +3251,40 @@ int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct wmi_set_regdomain_cmd *cmd;
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_set_regdomain_cmd *) skb->data;
|
||||
memcpy(cmd->iso_name, alpha2, 2);
|
||||
|
||||
return ath6kl_wmi_cmd_send(wmi, 0, skb,
|
||||
WMI_SET_REGDOMAIN_CMDID,
|
||||
NO_SYNC_WMIFLAG);
|
||||
}
|
||||
|
||||
s32 ath6kl_wmi_get_rate(s8 rate_index)
|
||||
{
|
||||
u8 sgi = 0;
|
||||
|
||||
if (rate_index == RATE_AUTO)
|
||||
return 0;
|
||||
|
||||
return wmi_rate_tbl[(u32) rate_index][0];
|
||||
/* SGI is stored as the MSB of the rate_index */
|
||||
if (rate_index & RATE_INDEX_MSB) {
|
||||
rate_index &= RATE_INDEX_WITHOUT_SGI_MASK;
|
||||
sgi = 1;
|
||||
}
|
||||
|
||||
if (WARN_ON(rate_index > RATE_MCS_7_40))
|
||||
rate_index = RATE_MCS_7_40;
|
||||
|
||||
return wmi_rate_tbl[(u32) rate_index][sgi];
|
||||
}
|
||||
|
||||
static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
|
||||
@ -3634,6 +3774,19 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout)
|
||||
NO_SYNC_WMIFLAG);
|
||||
}
|
||||
|
||||
static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap,
|
||||
int len)
|
||||
{
|
||||
struct wmix_hb_challenge_resp_cmd *cmd;
|
||||
|
||||
if (len < sizeof(struct wmix_hb_challenge_resp_cmd))
|
||||
return;
|
||||
|
||||
cmd = (struct wmix_hb_challenge_resp_cmd *) datap;
|
||||
ath6kl_recovery_hb_event(wmi->parent_dev,
|
||||
le32_to_cpu(cmd->cookie));
|
||||
}
|
||||
|
||||
static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
|
||||
{
|
||||
struct wmix_cmd_hdr *cmd;
|
||||
@ -3658,6 +3811,7 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
|
||||
switch (id) {
|
||||
case WMIX_HB_CHALLENGE_RESP_EVENTID:
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n");
|
||||
ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len);
|
||||
break;
|
||||
case WMIX_DBGLOG_EVENTID:
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len);
|
||||
@ -3750,6 +3904,9 @@ static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,
|
||||
case WMI_RX_ACTION_EVENTID:
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
|
||||
return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
|
||||
case WMI_TXE_NOTIFY_EVENTID:
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n");
|
||||
return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif);
|
||||
default:
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);
|
||||
return -EINVAL;
|
||||
|
@ -48,7 +48,7 @@
|
||||
|
||||
#define A_BAND_24GHZ 0
|
||||
#define A_BAND_5GHZ 1
|
||||
#define A_NUM_BANDS 2
|
||||
#define ATH6KL_NUM_BANDS 2
|
||||
|
||||
/* in ms */
|
||||
#define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000
|
||||
@ -628,6 +628,20 @@ enum wmi_cmd_id {
|
||||
WMI_SET_MCASTRATE,
|
||||
|
||||
WMI_STA_BMISS_ENHANCE_CMDID,
|
||||
|
||||
WMI_SET_REGDOMAIN_CMDID,
|
||||
|
||||
WMI_SET_RSSI_FILTER_CMDID,
|
||||
|
||||
WMI_SET_KEEP_ALIVE_EXT,
|
||||
|
||||
WMI_VOICE_DETECTION_ENABLE_CMDID,
|
||||
|
||||
WMI_SET_TXE_NOTIFY_CMDID,
|
||||
|
||||
WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/
|
||||
|
||||
WMI_ENABLE_SCHED_SCAN_CMDID,
|
||||
};
|
||||
|
||||
enum wmi_mgmt_frame_type {
|
||||
@ -843,7 +857,7 @@ struct wmi_begin_scan_cmd {
|
||||
u8 scan_type;
|
||||
|
||||
/* Supported rates to advertise in the probe request frames */
|
||||
struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS];
|
||||
struct wmi_supp_rates supp_rates[ATH6KL_NUM_BANDS];
|
||||
|
||||
/* how many channels follow */
|
||||
u8 num_ch;
|
||||
@ -941,6 +955,11 @@ struct wmi_scan_params_cmd {
|
||||
__le32 max_dfsch_act_time;
|
||||
} __packed;
|
||||
|
||||
/* WMI_ENABLE_SCHED_SCAN_CMDID */
|
||||
struct wmi_enable_sched_scan_cmd {
|
||||
u8 enable;
|
||||
} __packed;
|
||||
|
||||
/* WMI_SET_BSS_FILTER_CMDID */
|
||||
enum wmi_bss_filter {
|
||||
/* no beacons forwarded */
|
||||
@ -1032,6 +1051,11 @@ struct wmi_sta_bmiss_enhance_cmd {
|
||||
u8 enable;
|
||||
} __packed;
|
||||
|
||||
struct wmi_set_regdomain_cmd {
|
||||
u8 length;
|
||||
u8 iso_name[2];
|
||||
} __packed;
|
||||
|
||||
/* WMI_SET_POWER_MODE_CMDID */
|
||||
enum wmi_power_mode {
|
||||
REC_POWER = 0x01,
|
||||
@ -1276,6 +1300,11 @@ struct wmi_snr_threshold_params_cmd {
|
||||
u8 reserved[3];
|
||||
} __packed;
|
||||
|
||||
/* Don't report BSSs with signal (RSSI) below this threshold */
|
||||
struct wmi_set_rssi_filter_cmd {
|
||||
s8 rssi;
|
||||
} __packed;
|
||||
|
||||
enum wmi_preamble_policy {
|
||||
WMI_IGNORE_BARKER_IN_ERP = 0,
|
||||
WMI_FOLLOW_BARKER_IN_ERP,
|
||||
@ -1455,6 +1484,20 @@ enum wmi_event_id {
|
||||
WMI_P2P_CAPABILITIES_EVENTID,
|
||||
WMI_RX_ACTION_EVENTID,
|
||||
WMI_P2P_INFO_EVENTID,
|
||||
|
||||
/* WPS Events */
|
||||
WMI_WPS_GET_STATUS_EVENTID,
|
||||
WMI_WPS_PROFILE_EVENTID,
|
||||
|
||||
/* more P2P events */
|
||||
WMI_NOA_INFO_EVENTID,
|
||||
WMI_OPPPS_INFO_EVENTID,
|
||||
WMI_PORT_STATUS_EVENTID,
|
||||
|
||||
/* 802.11w */
|
||||
WMI_GET_RSN_CAP_EVENTID,
|
||||
|
||||
WMI_TXE_NOTIFY_EVENTID,
|
||||
};
|
||||
|
||||
struct wmi_ready_event_2 {
|
||||
@ -1749,6 +1792,9 @@ struct rx_stats {
|
||||
a_sle32 ucast_rate;
|
||||
} __packed;
|
||||
|
||||
#define RATE_INDEX_WITHOUT_SGI_MASK 0x7f
|
||||
#define RATE_INDEX_MSB 0x80
|
||||
|
||||
struct tkip_ccmp_stats {
|
||||
__le32 tkip_local_mic_fail;
|
||||
__le32 tkip_cnter_measures_invoked;
|
||||
@ -2019,7 +2065,6 @@ struct wmi_set_ie_cmd {
|
||||
|
||||
#define WOW_MAX_FILTERS_PER_LIST 4
|
||||
#define WOW_PATTERN_SIZE 64
|
||||
#define WOW_MASK_SIZE 64
|
||||
|
||||
#define MAC_MAX_FILTERS_PER_LIST 4
|
||||
|
||||
@ -2028,7 +2073,7 @@ struct wow_filter {
|
||||
u8 wow_filter_id;
|
||||
u8 wow_filter_size;
|
||||
u8 wow_filter_offset;
|
||||
u8 wow_filter_mask[WOW_MASK_SIZE];
|
||||
u8 wow_filter_mask[WOW_PATTERN_SIZE];
|
||||
u8 wow_filter_pattern[WOW_PATTERN_SIZE];
|
||||
} __packed;
|
||||
|
||||
@ -2087,6 +2132,19 @@ struct wmi_del_wow_pattern_cmd {
|
||||
__le16 filter_id;
|
||||
} __packed;
|
||||
|
||||
/* WMI_SET_TXE_NOTIFY_CMDID */
|
||||
struct wmi_txe_notify_cmd {
|
||||
__le32 rate;
|
||||
__le32 pkts;
|
||||
__le32 intvl;
|
||||
} __packed;
|
||||
|
||||
/* WMI_TXE_NOTIFY_EVENTID */
|
||||
struct wmi_txe_notify_event {
|
||||
__le32 rate;
|
||||
__le32 pkts;
|
||||
} __packed;
|
||||
|
||||
/* WMI_SET_AKMP_PARAMS_CMD */
|
||||
|
||||
struct wmi_pmkid {
|
||||
@ -2505,11 +2563,6 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
|
||||
int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,
|
||||
u16 channel);
|
||||
int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx);
|
||||
int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
enum wmi_scan_type scan_type,
|
||||
u32 force_fgscan, u32 is_legacy,
|
||||
u32 home_dwell_time, u32 force_scan_interval,
|
||||
s8 num_chan, u16 *ch_list);
|
||||
|
||||
int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
enum wmi_scan_type scan_type,
|
||||
@ -2517,6 +2570,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
u32 home_dwell_time, u32 force_scan_interval,
|
||||
s8 num_chan, u16 *ch_list, u32 no_cck,
|
||||
u32 *rates);
|
||||
int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable);
|
||||
|
||||
int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec,
|
||||
u16 fg_end_sec, u16 bg_sec,
|
||||
@ -2592,6 +2646,7 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
|
||||
const u8 *mask);
|
||||
int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
|
||||
u16 list_id, u16 filter_id);
|
||||
int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi);
|
||||
int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
|
||||
int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
|
||||
int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
|
||||
@ -2600,6 +2655,9 @@ int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
|
||||
int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
|
||||
u8 *filter, bool add_filter);
|
||||
int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable);
|
||||
int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
|
||||
u32 rate, u32 pkts, u32 intvl);
|
||||
int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2);
|
||||
|
||||
/* AP mode uAPSD */
|
||||
int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable);
|
||||
@ -2658,6 +2716,8 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout);
|
||||
|
||||
void ath6kl_wmi_sscan_timer(unsigned long ptr);
|
||||
|
||||
int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source);
|
||||
|
||||
struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);
|
||||
void *ath6kl_wmi_init(struct ath6kl *devt);
|
||||
void ath6kl_wmi_shutdown(struct wmi *wmi);
|
||||
|
Loading…
Reference in New Issue
Block a user