提交 01a28298 编写于 作者: J John W. Linville

Merge branch 'master' of...

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem

Conflicts:
	drivers/net/wireless/ath/ath9k/hw.c
#
# This outlines the Linux authentication/association and
# deauthentication/disassociation flows.
#
# This can be converted into a diagram using the service
# at http://www.websequencediagrams.com/
#
participant userspace
participant mac80211
participant driver
alt authentication needed (not FT)
userspace->mac80211: authenticate
alt authenticated/authenticating already
mac80211->driver: sta_state(AP, not-exists)
mac80211->driver: bss_info_changed(clear BSSID)
else associated
note over mac80211,driver
like deauth/disassoc, without sending the
BA session stop & deauth/disassoc frames
end note
end
mac80211->driver: config(channel, non-HT)
mac80211->driver: bss_info_changed(set BSSID, basic rate bitmap)
mac80211->driver: sta_state(AP, exists)
alt no probe request data known
mac80211->driver: TX directed probe request
driver->mac80211: RX probe response
end
mac80211->driver: TX auth frame
driver->mac80211: RX auth frame
alt WEP shared key auth
mac80211->driver: TX auth frame
driver->mac80211: RX auth frame
end
mac80211->driver: sta_state(AP, authenticated)
mac80211->userspace: RX auth frame
end
userspace->mac80211: associate
alt authenticated or associated
note over mac80211,driver: cleanup like for authenticate
end
alt not previously authenticated (FT)
mac80211->driver: config(channel, non-HT)
mac80211->driver: bss_info_changed(set BSSID, basic rate bitmap)
mac80211->driver: sta_state(AP, exists)
mac80211->driver: sta_state(AP, authenticated)
end
mac80211->driver: TX assoc
driver->mac80211: RX assoc response
note over mac80211: init rate control
mac80211->driver: sta_state(AP, associated)
alt not using WPA
mac80211->driver: sta_state(AP, authorized)
end
mac80211->driver: set up QoS parameters
alt is HT channel
mac80211->driver: config(channel, HT params)
end
mac80211->driver: bss_info_changed(QoS, HT, associated with AID)
mac80211->userspace: associated
note left of userspace: associated now
alt using WPA
note over userspace
do 4-way-handshake
(data frames)
end note
userspace->mac80211: authorized
mac80211->driver: sta_state(AP, authorized)
end
userspace->mac80211: deauthenticate/disassociate
mac80211->driver: stop BA sessions
mac80211->driver: TX deauth/disassoc
mac80211->driver: flush frames
mac80211->driver: sta_state(AP,associated)
mac80211->driver: sta_state(AP,authenticated)
mac80211->driver: sta_state(AP,exists)
mac80211->driver: sta_state(AP,not-exists)
mac80211->driver: turn off powersave
mac80211->driver: bss_info_changed(clear BSSID, not associated, no QoS, ...)
mac80211->driver: config(non-HT channel type)
mac80211->userspace: disconnected
...@@ -174,28 +174,24 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry); ...@@ -174,28 +174,24 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry);
void ath_hw_cycle_counters_update(struct ath_common *common); void ath_hw_cycle_counters_update(struct ath_common *common);
int32_t ath_hw_get_listen_time(struct ath_common *common); int32_t ath_hw_get_listen_time(struct ath_common *common);
extern __printf(2, 3) void ath_printk(const char *level, const char *fmt, ...); __printf(3, 4)
void ath_printk(const char *level, const struct ath_common *common,
#define _ath_printk(level, common, fmt, ...) \ const char *fmt, ...);
do { \
__always_unused struct ath_common *unused = common; \
ath_printk(level, fmt, ##__VA_ARGS__); \
} while (0)
#define ath_emerg(common, fmt, ...) \ #define ath_emerg(common, fmt, ...) \
_ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__) ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__)
#define ath_alert(common, fmt, ...) \ #define ath_alert(common, fmt, ...) \
_ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__) ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__)
#define ath_crit(common, fmt, ...) \ #define ath_crit(common, fmt, ...) \
_ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__) ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__)
#define ath_err(common, fmt, ...) \ #define ath_err(common, fmt, ...) \
_ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__) ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__)
#define ath_warn(common, fmt, ...) \ #define ath_warn(common, fmt, ...) \
_ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__) ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__)
#define ath_notice(common, fmt, ...) \ #define ath_notice(common, fmt, ...) \
_ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__) ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__)
#define ath_info(common, fmt, ...) \ #define ath_info(common, fmt, ...) \
_ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__) ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__)
/** /**
* enum ath_debug_level - atheros wireless debug level * enum ath_debug_level - atheros wireless debug level
...@@ -256,7 +252,7 @@ enum ATH_DEBUG { ...@@ -256,7 +252,7 @@ enum ATH_DEBUG {
#define ath_dbg(common, dbg_mask, fmt, ...) \ #define ath_dbg(common, dbg_mask, fmt, ...) \
do { \ do { \
if ((common)->debug_mask & ATH_DBG_##dbg_mask) \ if ((common)->debug_mask & ATH_DBG_##dbg_mask) \
_ath_printk(KERN_DEBUG, common, fmt, ##__VA_ARGS__); \ ath_printk(KERN_DEBUG, common, fmt, ##__VA_ARGS__); \
} while (0) } while (0)
#define ATH_DBG_WARN(foo, arg...) WARN(foo, arg) #define ATH_DBG_WARN(foo, arg...) WARN(foo, arg)
......
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# Copyright (c) 2004-2010 Atheros Communications Inc. # Copyright (c) 2004-2011 Atheros Communications Inc.
# Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
# All rights reserved. # All rights reserved.
# #
# #
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -105,7 +106,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, ...@@ -105,7 +106,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
} }
ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n", ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n",
targ_info->version, targ_info->type); targ_info->version, targ_info->type);
return 0; return 0;
} }
...@@ -192,7 +193,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) ...@@ -192,7 +193,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header); memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header);
ath6kl_dbg(ATH6KL_DBG_BMI, ath6kl_dbg(ATH6KL_DBG_BMI,
"bmi write memory: addr: 0x%x, len: %d\n", addr, len); "bmi write memory: addr: 0x%x, len: %d\n", addr, len);
len_remain = len; len_remain = len;
while (len_remain) { while (len_remain) {
...@@ -434,7 +435,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len) ...@@ -434,7 +435,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
offset += sizeof(tx_len); offset += sizeof(tx_len);
memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain], memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain],
tx_len); tx_len);
offset += tx_len; offset += tx_len;
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -222,6 +223,29 @@ struct ath6kl_bmi_target_info { ...@@ -222,6 +223,29 @@ struct ath6kl_bmi_target_info {
__le32 type; /* target type */ __le32 type; /* target type */
} __packed; } __packed;
#define ath6kl_bmi_write_hi32(ar, item, val) \
({ \
u32 addr; \
__le32 v; \
\
addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \
v = cpu_to_le32(val); \
ath6kl_bmi_write(ar, addr, (u8 *) &v, sizeof(v)); \
})
#define ath6kl_bmi_read_hi32(ar, item, val) \
({ \
u32 addr, *check_type = val; \
__le32 tmp; \
int ret; \
\
(void) (check_type == val); \
addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \
ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \
*val = le32_to_cpu(tmp); \
ret; \
})
int ath6kl_bmi_init(struct ath6kl *ar); int ath6kl_bmi_init(struct ath6kl *ar);
void ath6kl_bmi_cleanup(struct ath6kl *ar); void ath6kl_bmi_cleanup(struct ath6kl *ar);
void ath6kl_bmi_reset(struct ath6kl *ar); void ath6kl_bmi_reset(struct ath6kl *ar);
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -68,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = { ...@@ -68,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = {
#define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates (ath6kl_rates + 0)
#define ath6kl_g_rates_size 12 #define ath6kl_g_rates_size 12
#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_20 | \
IEEE80211_HT_CAP_SGI_40)
static struct ieee80211_channel ath6kl_2ghz_channels[] = { static struct ieee80211_channel ath6kl_2ghz_channels[] = {
CHAN2G(1, 2412, 0), CHAN2G(1, 2412, 0),
CHAN2G(2, 2417, 0), CHAN2G(2, 2417, 0),
...@@ -112,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = { ...@@ -112,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = {
.channels = ath6kl_2ghz_channels, .channels = ath6kl_2ghz_channels,
.n_bitrates = ath6kl_g_rates_size, .n_bitrates = ath6kl_g_rates_size,
.bitrates = ath6kl_g_rates, .bitrates = ath6kl_g_rates,
.ht_cap.cap = ath6kl_g_htcap,
.ht_cap.ht_supported = true,
}; };
static struct ieee80211_supported_band ath6kl_band_5ghz = { static struct ieee80211_supported_band ath6kl_band_5ghz = {
...@@ -119,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { ...@@ -119,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
.channels = ath6kl_5ghz_a_channels, .channels = ath6kl_5ghz_a_channels,
.n_bitrates = ath6kl_a_rates_size, .n_bitrates = ath6kl_a_rates_size,
.bitrates = ath6kl_a_rates, .bitrates = ath6kl_a_rates,
.ht_cap.cap = ath6kl_g_htcap,
.ht_cap.ht_supported = true,
}; };
#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
...@@ -381,7 +390,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, ...@@ -381,7 +390,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
return false; return false;
if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) && if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
ar->num_vif)) ar->num_vif))
return false; return false;
if (type == NL80211_IFTYPE_STATION || if (type == NL80211_IFTYPE_STATION ||
...@@ -407,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, ...@@ -407,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
return false; return false;
} }
static bool ath6kl_is_tx_pending(struct ath6kl *ar)
{
return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
}
static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme) struct cfg80211_connect_params *sme)
{ {
...@@ -414,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -414,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev);
int status; int status;
u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
u16 interval;
ath6kl_cfg80211_sscan_disable(vif); ath6kl_cfg80211_sscan_disable(vif);
...@@ -450,8 +466,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -450,8 +466,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
* sleep until the command queue drains * sleep until the command queue drains
*/ */
wait_event_interruptible_timeout(ar->event_wq, wait_event_interruptible_timeout(ar->event_wq,
ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0, ath6kl_is_tx_pending(ar),
WMI_TIMEOUT); WMI_TIMEOUT);
if (signal_pending(current)) { if (signal_pending(current)) {
ath6kl_err("cmd queue drain timeout\n"); ath6kl_err("cmd queue drain timeout\n");
up(&ar->sem); up(&ar->sem);
...@@ -546,7 +562,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -546,7 +562,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
if (!ar->usr_bss_filter) { if (!ar->usr_bss_filter) {
clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
ALL_BSS_FILTER, 0) != 0) { ALL_BSS_FILTER, 0) != 0) {
ath6kl_err("couldn't set bss filtering\n"); ath6kl_err("couldn't set bss filtering\n");
up(&ar->sem); up(&ar->sem);
return -EIO; return -EIO;
...@@ -568,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -568,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
vif->grp_crypto_len, vif->ch_hint); vif->grp_crypto_len, vif->ch_hint);
vif->reconnect_flag = 0; vif->reconnect_flag = 0;
if (vif->nw_type == INFRA_NETWORK) {
interval = max_t(u16, vif->listen_intvl_t,
ATH6KL_MAX_WOW_LISTEN_INTL);
status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
interval,
0);
if (status) {
ath6kl_err("couldn't set listen intervel\n");
up(&ar->sem);
return status;
}
}
status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
vif->dot11_auth_mode, vif->auth_mode, vif->dot11_auth_mode, vif->auth_mode,
vif->prwise_crypto, vif->prwise_crypto,
...@@ -590,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -590,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
} }
if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
((vif->auth_mode == WPA_PSK_AUTH) ((vif->auth_mode == WPA_PSK_AUTH) ||
|| (vif->auth_mode == WPA2_PSK_AUTH))) { (vif->auth_mode == WPA2_PSK_AUTH))) {
mod_timer(&vif->disconnect_timer, mod_timer(&vif->disconnect_timer,
jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
} }
...@@ -824,13 +854,13 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, ...@@ -824,13 +854,13 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
if (vif->sme_state == SME_CONNECTING) { if (vif->sme_state == SME_CONNECTING) {
cfg80211_connect_result(vif->ndev, cfg80211_connect_result(vif->ndev,
bssid, NULL, 0, bssid, NULL, 0,
NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL); GFP_KERNEL);
} else if (vif->sme_state == SME_CONNECTED) { } else if (vif->sme_state == SME_CONNECTED) {
cfg80211_disconnected(vif->ndev, reason, cfg80211_disconnected(vif->ndev, reason,
NULL, 0, GFP_KERNEL); NULL, 0, GFP_KERNEL);
} }
vif->sme_state = SME_DISCONNECTED; vif->sme_state = SME_DISCONNECTED;
...@@ -876,19 +906,14 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ...@@ -876,19 +906,14 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
request->ssids[i].ssid); request->ssids[i].ssid);
} }
/* /* this also clears IE in fw if it's not set */
* FIXME: we should clear the IE in fw if it's not set so just ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
* remove the check altogether WMI_FRAME_PROBE_REQ,
*/ request->ie, request->ie_len);
if (request->ie) { if (ret) {
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_err("failed to set Probe Request appie for "
WMI_FRAME_PROBE_REQ, "scan");
request->ie, request->ie_len); return ret;
if (ret) {
ath6kl_err("failed to set Probe Request appie for "
"scan");
return ret;
}
} }
/* /*
...@@ -917,7 +942,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ...@@ -917,7 +942,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
force_fg_scan = 1; force_fg_scan = 1;
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
ar->fw_capabilities)) { ar->fw_capabilities)) {
/* /*
* If capable of doing P2P mgmt operations using * If capable of doing P2P mgmt operations using
* station interface, send additional information like * station interface, send additional information like
...@@ -926,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ...@@ -926,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
*/ */
ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
WMI_LONG_SCAN, force_fg_scan, WMI_LONG_SCAN, force_fg_scan,
false, 0, 0, n_channels, false, 0,
channels, request->no_cck, ATH6KL_FG_SCAN_INTERVAL,
n_channels, channels,
request->no_cck,
request->rates); request->rates);
} else { } else {
ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
WMI_LONG_SCAN, force_fg_scan, WMI_LONG_SCAN, force_fg_scan,
false, 0, 0, n_channels, false, 0,
channels); ATH6KL_FG_SCAN_INTERVAL,
n_channels, channels);
} }
if (ret) if (ret)
ath6kl_err("wmi_startscan_cmd failed\n"); ath6kl_err("wmi_startscan_cmd failed\n");
...@@ -1046,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, ...@@ -1046,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
return -ENOTSUPP; return -ENOTSUPP;
} }
if (((vif->auth_mode == WPA_PSK_AUTH) if (((vif->auth_mode == WPA_PSK_AUTH) ||
|| (vif->auth_mode == WPA2_PSK_AUTH)) (vif->auth_mode == WPA2_PSK_AUTH)) &&
&& (key_usage & GROUP_USAGE)) (key_usage & GROUP_USAGE))
del_timer(&vif->disconnect_timer); del_timer(&vif->disconnect_timer);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
...@@ -1058,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, ...@@ -1058,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
if (vif->nw_type == AP_NETWORK && !pairwise && if (vif->nw_type == AP_NETWORK && !pairwise &&
(key_type == TKIP_CRYPT || key_type == AES_CRYPT || (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
key_type == WAPI_CRYPT) && params) { key_type == WAPI_CRYPT)) {
ar->ap_mode_bkey.valid = true; ar->ap_mode_bkey.valid = true;
ar->ap_mode_bkey.key_index = key_index; ar->ap_mode_bkey.key_index = key_index;
ar->ap_mode_bkey.key_type = key_type; ar->ap_mode_bkey.key_type = key_type;
...@@ -1263,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, ...@@ -1263,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
{ {
struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
struct ath6kl_vif *vif; struct ath6kl_vif *vif;
u8 ath6kl_dbm;
int dbm = MBM_TO_DBM(mbm); int dbm = MBM_TO_DBM(mbm);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
...@@ -1280,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, ...@@ -1280,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
case NL80211_TX_POWER_AUTOMATIC: case NL80211_TX_POWER_AUTOMATIC:
return 0; return 0;
case NL80211_TX_POWER_LIMITED: case NL80211_TX_POWER_LIMITED:
ar->tx_pwr = ath6kl_dbm = dbm; ar->tx_pwr = dbm;
break; break;
default: default:
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
...@@ -1288,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, ...@@ -1288,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm); ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm);
return 0; return 0;
} }
...@@ -1349,7 +1376,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, ...@@ -1349,7 +1376,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
} }
if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx, if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
mode.pwr_mode) != 0) { mode.pwr_mode) != 0) {
ath6kl_err("wmi_powermode_cmd failed\n"); ath6kl_err("wmi_powermode_cmd failed\n");
return -EIO; return -EIO;
} }
...@@ -1904,7 +1931,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) ...@@ -1904,7 +1931,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
struct ath6kl_vif *vif; struct ath6kl_vif *vif;
int ret, left; int ret, left;
u32 filter = 0; u32 filter = 0;
u16 i; u16 i, bmiss_time;
u8 index = 0; u8 index = 0;
__be32 ips[MAX_IP_ADDRS]; __be32 ips[MAX_IP_ADDRS];
...@@ -1941,6 +1968,34 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) ...@@ -1941,6 +1968,34 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
if (ret) if (ret)
return ret; return ret;
netif_stop_queue(vif->ndev);
if (vif->nw_type != AP_NETWORK) {
ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_MAX_WOW_LISTEN_INTL,
0);
if (ret)
return ret;
/* Set listen interval x 15 times as bmiss time */
bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15;
if (bmiss_time > ATH6KL_MAX_BMISS_TIME)
bmiss_time = ATH6KL_MAX_BMISS_TIME;
ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
bmiss_time, 0);
if (ret)
return ret;
ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
0xFFFF, 0, 0xFFFF, 0, 0, 0,
0, 0, 0, 0);
if (ret)
return ret;
}
ar->state = ATH6KL_STATE_SUSPENDING;
/* Setup own IP addr for ARP agent. */ /* Setup own IP addr for ARP agent. */
in_dev = __in_dev_get_rtnl(vif->ndev); in_dev = __in_dev_get_rtnl(vif->ndev);
if (!in_dev) if (!in_dev)
...@@ -2019,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar) ...@@ -2019,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
if (!vif) if (!vif)
return -EIO; return -EIO;
ar->state = ATH6KL_STATE_RESUMING;
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE); ATH6KL_HOST_MODE_AWAKE);
return ret; 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);
if (ret)
return ret;
ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
vif->listen_intvl_t, 0);
if (ret)
return ret;
ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
vif->bmiss_time_t, 0);
if (ret)
return ret;
}
ar->state = ATH6KL_STATE_ON;
netif_wake_queue(vif->ndev);
return 0;
} }
int ath6kl_cfg80211_suspend(struct ath6kl *ar, int ath6kl_cfg80211_suspend(struct ath6kl *ar,
enum ath6kl_cfg_suspend_mode mode, enum ath6kl_cfg_suspend_mode mode,
struct cfg80211_wowlan *wow) struct cfg80211_wowlan *wow)
{ {
enum ath6kl_state prev_state;
int ret; int ret;
switch (mode) { switch (mode) {
...@@ -2038,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, ...@@ -2038,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
/* Flush all non control pkts in TX path */ /* Flush all non control pkts in TX path */
ath6kl_tx_data_cleanup(ar); ath6kl_tx_data_cleanup(ar);
prev_state = ar->state;
ret = ath6kl_wow_suspend(ar, wow); ret = ath6kl_wow_suspend(ar, wow);
if (ret) { if (ret) {
ath6kl_err("wow suspend failed: %d\n", ret); ar->state = prev_state;
return ret; return ret;
} }
ar->state = ATH6KL_STATE_WOW; ar->state = ATH6KL_STATE_WOW;
break; break;
...@@ -2114,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) ...@@ -2114,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
return ret; return ret;
} }
ar->state = ATH6KL_STATE_ON;
break; break;
case ATH6KL_STATE_DEEPSLEEP: case ATH6KL_STATE_DEEPSLEEP:
...@@ -2188,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) ...@@ -2188,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
*/ */
void ath6kl_check_wow_status(struct ath6kl *ar) void ath6kl_check_wow_status(struct ath6kl *ar)
{ {
if (ar->state == ATH6KL_STATE_SUSPENDING)
return;
if (ar->state == ATH6KL_STATE_WOW) if (ar->state == ATH6KL_STATE_WOW)
ath6kl_cfg80211_resume(ar); ath6kl_cfg80211_resume(ar);
} }
...@@ -2275,30 +2366,27 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, ...@@ -2275,30 +2366,27 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
struct ath6kl *ar = vif->ar; struct ath6kl *ar = vif->ar;
int res; int res;
if (info->beacon_ies) { /* this also clears IE in fw if it's not set */
res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_BEACON, WMI_FRAME_BEACON,
info->beacon_ies, info->beacon_ies,
info->beacon_ies_len); info->beacon_ies_len);
if (res) if (res)
return res; return res;
}
if (info->proberesp_ies) { /* this also clears IE in fw if it's not set */
res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
info->proberesp_ies_len); info->proberesp_ies_len);
if (res) if (res)
return res; return res;
}
if (info->assocresp_ies) { /* this also clears IE in fw if it's not set */
res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_ASSOC_RESP, WMI_FRAME_ASSOC_RESP,
info->assocresp_ies, info->assocresp_ies,
info->assocresp_ies_len); info->assocresp_ies_len);
if (res) if (res)
return res; return res;
}
return 0; return 0;
} }
...@@ -2309,6 +2397,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -2309,6 +2397,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev);
struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt;
bool hidden = false;
u8 *ies; u8 *ies;
int ies_len; int ies_len;
struct wmi_connect_cmd p; struct wmi_connect_cmd p;
...@@ -2345,7 +2434,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -2345,7 +2434,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
memcpy(vif->ssid, info->ssid, info->ssid_len); memcpy(vif->ssid, info->ssid, info->ssid_len);
vif->ssid_len = info->ssid_len; vif->ssid_len = info->ssid_len;
if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
return -EOPNOTSUPP; /* TODO */ hidden = true;
res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden);
if (res)
return res;
ret = ath6kl_set_auth_type(vif, info->auth_type); ret = ath6kl_set_auth_type(vif, info->auth_type);
if (ret) if (ret)
...@@ -2584,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif, ...@@ -2584,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
return ret; return ret;
} }
static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
u32 id,
u32 freq,
u32 wait,
const u8 *buf,
size_t len,
bool *more_data,
bool no_cck)
{
struct ieee80211_mgmt *mgmt;
struct ath6kl_sta *conn;
bool is_psq_empty = false;
struct ath6kl_mgmt_buff *mgmt_buf;
size_t mgmt_buf_size;
struct ath6kl *ar = vif->ar;
mgmt = (struct ieee80211_mgmt *) buf;
if (is_multicast_ether_addr(mgmt->da))
return false;
conn = ath6kl_find_sta(vif, mgmt->da);
if (!conn)
return false;
if (conn->sta_flags & STA_PS_SLEEP) {
if (!(conn->sta_flags & STA_PS_POLLED)) {
/* Queue the frames if the STA is sleeping */
mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff);
mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL);
if (!mgmt_buf)
return false;
INIT_LIST_HEAD(&mgmt_buf->list);
mgmt_buf->id = id;
mgmt_buf->freq = freq;
mgmt_buf->wait = wait;
mgmt_buf->len = len;
mgmt_buf->no_cck = no_cck;
memcpy(mgmt_buf->buf, buf, len);
spin_lock_bh(&conn->psq_lock);
is_psq_empty = skb_queue_empty(&conn->psq) &&
(conn->mgmt_psq_len == 0);
list_add_tail(&mgmt_buf->list, &conn->mgmt_psq);
conn->mgmt_psq_len++;
spin_unlock_bh(&conn->psq_lock);
/*
* If this is the first pkt getting queued
* for this STA, update the PVB for this
* STA.
*/
if (is_psq_empty)
ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx,
conn->aid, 1);
return true;
}
/*
* This tx is because of a PsPoll.
* Determine if MoreData bit has to be set.
*/
spin_lock_bh(&conn->psq_lock);
if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0))
*more_data = true;
spin_unlock_bh(&conn->psq_lock);
}
return false;
}
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
...@@ -2595,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, ...@@ -2595,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev);
u32 id; u32 id;
const struct ieee80211_mgmt *mgmt; const struct ieee80211_mgmt *mgmt;
bool more_data, queued;
mgmt = (const struct ieee80211_mgmt *) buf; mgmt = (const struct ieee80211_mgmt *) buf;
if (buf + len >= mgmt->u.probe_resp.variable && if (buf + len >= mgmt->u.probe_resp.variable &&
...@@ -2620,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, ...@@ -2620,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
*cookie = id; *cookie = id;
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, /* AP mode Power saving processing */
ar->fw_capabilities)) { if (vif->nw_type == AP_NETWORK) {
/* queued = ath6kl_mgmt_powersave_ap(vif,
* If capable of doing P2P mgmt operations using id, chan->center_freq,
* station interface, send additional information like wait, buf,
* supported rates to advertise and xmit rates for len, &more_data, no_cck);
* probe requests if (queued)
*/ return 0;
return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
chan->center_freq, wait,
buf, len, no_cck);
} else {
return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
chan->center_freq, wait,
buf, len);
} }
return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
chan->center_freq, wait,
buf, len, no_cck);
} }
static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
...@@ -2929,7 +3090,10 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, ...@@ -2929,7 +3090,10 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
vif->wdev.netdev = ndev; vif->wdev.netdev = ndev;
vif->wdev.iftype = type; vif->wdev.iftype = type;
vif->fw_vif_idx = fw_vif_idx; vif->fw_vif_idx = fw_vif_idx;
vif->nw_type = vif->next_mode = nw_type; vif->nw_type = nw_type;
vif->next_mode = nw_type;
vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
if (fw_vif_idx != 0) if (fw_vif_idx != 0)
...@@ -3009,18 +3173,36 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) ...@@ -3009,18 +3173,36 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
wiphy->max_sched_scan_ssids = 10; wiphy->max_sched_scan_ssids = 10;
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
ar->wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
ret = wiphy_register(wiphy); ret = wiphy_register(wiphy);
if (ret < 0) { if (ret < 0) {
ath6kl_err("couldn't register wiphy device\n"); ath6kl_err("couldn't register wiphy device\n");
return ret; return ret;
} }
ar->wiphy_registered = true;
return 0; return 0;
} }
void ath6kl_cfg80211_cleanup(struct ath6kl *ar) void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
{ {
wiphy_unregister(ar->wiphy); wiphy_unregister(ar->wiphy);
ar->wiphy_registered = false;
} }
struct ath6kl *ath6kl_cfg80211_create(void) struct ath6kl *ath6kl_cfg80211_create(void)
......
/* /*
* Copyright (c) 2011 Atheros Communications Inc. * Copyright (c) 2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
......
/* /*
* Copyright (c) 2010-2011 Atheros Communications Inc. * Copyright (c) 2010-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -26,12 +27,14 @@ ...@@ -26,12 +27,14 @@
unsigned int debug_mask; unsigned int debug_mask;
static unsigned int suspend_mode; static unsigned int suspend_mode;
static unsigned int wow_mode;
static unsigned int uart_debug; static unsigned int uart_debug;
static unsigned int ath6kl_p2p; static unsigned int ath6kl_p2p;
static unsigned int testmode; static unsigned int testmode;
module_param(debug_mask, uint, 0644); module_param(debug_mask, uint, 0644);
module_param(suspend_mode, uint, 0644); module_param(suspend_mode, uint, 0644);
module_param(wow_mode, uint, 0644);
module_param(uart_debug, uint, 0644); module_param(uart_debug, uint, 0644);
module_param(ath6kl_p2p, uint, 0644); module_param(ath6kl_p2p, uint, 0644);
module_param(testmode, uint, 0644); module_param(testmode, uint, 0644);
...@@ -97,48 +100,12 @@ int ath6kl_core_init(struct ath6kl *ar) ...@@ -97,48 +100,12 @@ int ath6kl_core_init(struct ath6kl *ar)
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi);
ret = ath6kl_cfg80211_init(ar);
if (ret)
goto err_node_cleanup;
ret = ath6kl_debug_init(ar);
if (ret) {
wiphy_unregister(ar->wiphy);
goto err_node_cleanup;
}
for (i = 0; i < ar->vif_max; i++)
ar->avail_idx_map |= BIT(i);
rtnl_lock();
/* Add an initial station interface */
ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
INFRA_NETWORK);
rtnl_unlock();
if (!ndev) {
ath6kl_err("Failed to instantiate a network device\n");
ret = -ENOMEM;
wiphy_unregister(ar->wiphy);
goto err_debug_init;
}
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
__func__, ndev->name, ndev, ar);
/* setup access class priority mappings */ /* setup access class priority mappings */
ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */
ar->ac_stream_pri_map[WMM_AC_BE] = 1; ar->ac_stream_pri_map[WMM_AC_BE] = 1;
ar->ac_stream_pri_map[WMM_AC_VI] = 2; ar->ac_stream_pri_map[WMM_AC_VI] = 2;
ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */
/* give our connected endpoints some buffers */
ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
/* allocate some buffers that handle larger AMSDU frames */ /* allocate some buffers that handle larger AMSDU frames */
ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS);
...@@ -148,32 +115,25 @@ int ath6kl_core_init(struct ath6kl *ar) ...@@ -148,32 +115,25 @@ int ath6kl_core_init(struct ath6kl *ar)
ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
if (suspend_mode && if (suspend_mode &&
suspend_mode >= WLAN_POWER_STATE_CUT_PWR && suspend_mode >= WLAN_POWER_STATE_CUT_PWR &&
suspend_mode <= WLAN_POWER_STATE_WOW) suspend_mode <= WLAN_POWER_STATE_WOW)
ar->suspend_mode = suspend_mode; ar->suspend_mode = suspend_mode;
else else
ar->suspend_mode = 0; ar->suspend_mode = 0;
if (suspend_mode == WLAN_POWER_STATE_WOW &&
(wow_mode == WLAN_POWER_STATE_CUT_PWR ||
wow_mode == WLAN_POWER_STATE_DEEP_SLEEP))
ar->wow_suspend_mode = wow_mode;
else
ar->wow_suspend_mode = 0;
if (uart_debug) if (uart_debug)
ar->conf_flags |= ATH6KL_CONF_UART_DEBUG; ar->conf_flags |= ATH6KL_CONF_UART_DEBUG;
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
ar->wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
set_bit(FIRST_BOOT, &ar->flag); set_bit(FIRST_BOOT, &ar->flag);
ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; ath6kl_debug_init(ar);
ret = ath6kl_init_hw_start(ar); ret = ath6kl_init_hw_start(ar);
if (ret) { if (ret) {
...@@ -181,24 +141,47 @@ int ath6kl_core_init(struct ath6kl *ar) ...@@ -181,24 +141,47 @@ int ath6kl_core_init(struct ath6kl *ar)
goto err_rxbuf_cleanup; goto err_rxbuf_cleanup;
} }
/* /* give our connected endpoints some buffers */
* Set mac address which is received in ready event ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
* FIXME: Move to ath6kl_interface_add() ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
*/
memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); ret = ath6kl_cfg80211_init(ar);
if (ret)
goto err_rxbuf_cleanup;
ret = ath6kl_debug_init_fs(ar);
if (ret) {
wiphy_unregister(ar->wiphy);
goto err_rxbuf_cleanup;
}
for (i = 0; i < ar->vif_max; i++)
ar->avail_idx_map |= BIT(i);
rtnl_lock();
/* Add an initial station interface */
ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
INFRA_NETWORK);
rtnl_unlock();
if (!ndev) {
ath6kl_err("Failed to instantiate a network device\n");
ret = -ENOMEM;
wiphy_unregister(ar->wiphy);
goto err_rxbuf_cleanup;
}
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
__func__, ndev->name, ndev, ar);
return ret; return ret;
err_rxbuf_cleanup: err_rxbuf_cleanup:
ath6kl_debug_cleanup(ar);
ath6kl_htc_flush_rx_buf(ar->htc_target); ath6kl_htc_flush_rx_buf(ar->htc_target);
ath6kl_cleanup_amsdu_rxbufs(ar); ath6kl_cleanup_amsdu_rxbufs(ar);
rtnl_lock();
ath6kl_cfg80211_vif_cleanup(netdev_priv(ndev));
rtnl_unlock();
wiphy_unregister(ar->wiphy);
err_debug_init:
ath6kl_debug_cleanup(ar);
err_node_cleanup:
ath6kl_wmi_shutdown(ar->wmi); ath6kl_wmi_shutdown(ar->wmi);
clear_bit(WMI_ENABLED, &ar->flag); clear_bit(WMI_ENABLED, &ar->flag);
ar->wmi = NULL; ar->wmi = NULL;
...@@ -245,9 +228,7 @@ struct ath6kl *ath6kl_core_create(struct device *dev) ...@@ -245,9 +228,7 @@ struct ath6kl *ath6kl_core_create(struct device *dev)
clear_bit(SKIP_SCAN, &ar->flag); clear_bit(SKIP_SCAN, &ar->flag);
clear_bit(DESTROY_IN_PROGRESS, &ar->flag); clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
ar->listen_intvl_b = A_DEFAULT_LISTEN_INTERVAL;
ar->tx_pwr = 0; ar->tx_pwr = 0;
ar->intra_bss = 1; ar->intra_bss = 1;
ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
...@@ -261,6 +242,8 @@ struct ath6kl *ath6kl_core_create(struct device *dev) ...@@ -261,6 +242,8 @@ struct ath6kl *ath6kl_core_create(struct device *dev)
spin_lock_init(&ar->sta_list[ctr].psq_lock); spin_lock_init(&ar->sta_list[ctr].psq_lock);
skb_queue_head_init(&ar->sta_list[ctr].psq); skb_queue_head_init(&ar->sta_list[ctr].psq);
skb_queue_head_init(&ar->sta_list[ctr].apsdq); skb_queue_head_init(&ar->sta_list[ctr].apsdq);
ar->sta_list[ctr].mgmt_psq_len = 0;
INIT_LIST_HEAD(&ar->sta_list[ctr].mgmt_psq);
ar->sta_list[ctr].aggr_conn = ar->sta_list[ctr].aggr_conn =
kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL);
if (!ar->sta_list[ctr].aggr_conn) { if (!ar->sta_list[ctr].aggr_conn) {
......
/* /*
* Copyright (c) 2010-2011 Atheros Communications Inc. * Copyright (c) 2010-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -59,8 +60,9 @@ ...@@ -59,8 +60,9 @@
#define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC) #define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC)
#define DISCON_TIMER_INTVAL 10000 /* in msec */ #define DISCON_TIMER_INTVAL 10000 /* in msec */
#define A_DEFAULT_LISTEN_INTERVAL 1 /* beacon intervals */
#define A_MAX_WOW_LISTEN_INTERVAL 1000 /* Channel dwell time in fg scan */
#define ATH6KL_FG_SCAN_INTERVAL 50 /* in ms */
/* includes also the null byte */ /* includes also the null byte */
#define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL" #define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL"
...@@ -183,6 +185,11 @@ struct ath6kl_fw_ie { ...@@ -183,6 +185,11 @@ struct ath6kl_fw_ie {
#define MBOX_YIELD_LIMIT 99 #define MBOX_YIELD_LIMIT 99
#define ATH6KL_DEFAULT_LISTEN_INTVAL 100 /* in TUs */
#define ATH6KL_DEFAULT_BMISS_TIME 1500
#define ATH6KL_MAX_WOW_LISTEN_INTL 300 /* in TUs */
#define ATH6KL_MAX_BMISS_TIME 5000
/* configuration lags */ /* configuration lags */
/* /*
* ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in * ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in
...@@ -226,6 +233,12 @@ struct rxtid { ...@@ -226,6 +233,12 @@ struct rxtid {
u32 hold_q_sz; u32 hold_q_sz;
struct skb_hold_q *hold_q; struct skb_hold_q *hold_q;
struct sk_buff_head q; struct sk_buff_head q;
/*
* FIXME: No clue what this should protect. Apparently it should
* protect some of the fields above but they are also accessed
* without taking the lock.
*/
spinlock_t lock; spinlock_t lock;
}; };
...@@ -285,6 +298,16 @@ struct ath6kl_cookie { ...@@ -285,6 +298,16 @@ struct ath6kl_cookie {
struct ath6kl_cookie *arc_list_next; struct ath6kl_cookie *arc_list_next;
}; };
struct ath6kl_mgmt_buff {
struct list_head list;
u32 freq;
u32 wait;
u32 id;
bool no_cck;
size_t len;
u8 buf[0];
};
struct ath6kl_sta { struct ath6kl_sta {
u16 sta_flags; u16 sta_flags;
u8 mac[ETH_ALEN]; u8 mac[ETH_ALEN];
...@@ -294,7 +317,12 @@ struct ath6kl_sta { ...@@ -294,7 +317,12 @@ struct ath6kl_sta {
u8 auth; u8 auth;
u8 wpa_ie[ATH6KL_MAX_IE]; u8 wpa_ie[ATH6KL_MAX_IE];
struct sk_buff_head psq; struct sk_buff_head psq;
/* protects psq, mgmt_psq, apsdq, and mgmt_psq_len fields */
spinlock_t psq_lock; spinlock_t psq_lock;
struct list_head mgmt_psq;
size_t mgmt_psq_len;
u8 apsd_info; u8 apsd_info;
struct sk_buff_head apsdq; struct sk_buff_head apsdq;
struct aggr_info_conn *aggr_conn; struct aggr_info_conn *aggr_conn;
...@@ -494,6 +522,8 @@ struct ath6kl_vif { ...@@ -494,6 +522,8 @@ struct ath6kl_vif {
bool probe_req_report; bool probe_req_report;
u16 next_chan; u16 next_chan;
u16 assoc_bss_beacon_int; u16 assoc_bss_beacon_int;
u16 listen_intvl_t;
u16 bmiss_time_t;
u8 assoc_bss_dtim_period; u8 assoc_bss_dtim_period;
struct net_device_stats net_stats; struct net_device_stats net_stats;
struct target_stats target_stats; struct target_stats target_stats;
...@@ -521,6 +551,8 @@ enum ath6kl_dev_state { ...@@ -521,6 +551,8 @@ enum ath6kl_dev_state {
enum ath6kl_state { enum ath6kl_state {
ATH6KL_STATE_OFF, ATH6KL_STATE_OFF,
ATH6KL_STATE_ON, ATH6KL_STATE_ON,
ATH6KL_STATE_SUSPENDING,
ATH6KL_STATE_RESUMING,
ATH6KL_STATE_DEEPSLEEP, ATH6KL_STATE_DEEPSLEEP,
ATH6KL_STATE_CUTPOWER, ATH6KL_STATE_CUTPOWER,
ATH6KL_STATE_WOW, ATH6KL_STATE_WOW,
...@@ -549,9 +581,14 @@ struct ath6kl { ...@@ -549,9 +581,14 @@ struct ath6kl {
unsigned int vif_max; unsigned int vif_max;
u8 max_norm_iface; u8 max_norm_iface;
u8 avail_idx_map; u8 avail_idx_map;
/*
* Protects at least amsdu_rx_buffer_queue, ath6kl_alloc_cookie()
* calls, tx_pending and total_tx_data_pend.
*/
spinlock_t lock; spinlock_t lock;
struct semaphore sem; struct semaphore sem;
u16 listen_intvl_b;
u8 lrssi_roam_threshold; u8 lrssi_roam_threshold;
struct ath6kl_version version; struct ath6kl_version version;
u32 target_type; u32 target_type;
...@@ -577,7 +614,13 @@ struct ath6kl { ...@@ -577,7 +614,13 @@ struct ath6kl {
u8 sta_list_index; u8 sta_list_index;
struct ath6kl_req_key ap_mode_bkey; struct ath6kl_req_key ap_mode_bkey;
struct sk_buff_head mcastpsq; struct sk_buff_head mcastpsq;
/*
* FIXME: protects access to mcastpsq but is actually useless as
* all skbe_queue_*() functions provide serialisation themselves
*/
spinlock_t mcastpsq_lock; spinlock_t mcastpsq_lock;
u8 intra_bss; u8 intra_bss;
struct wmi_ap_mode_stat ap_stats; struct wmi_ap_mode_stat ap_stats;
u8 ap_country_code[3]; u8 ap_country_code[3];
...@@ -620,6 +663,7 @@ struct ath6kl { ...@@ -620,6 +663,7 @@ struct ath6kl {
u16 conf_flags; u16 conf_flags;
u16 suspend_mode; u16 suspend_mode;
u16 wow_suspend_mode;
wait_queue_head_t event_wq; wait_queue_head_t event_wq;
struct ath6kl_mbox_info mbox_info; struct ath6kl_mbox_info mbox_info;
...@@ -650,12 +694,16 @@ struct ath6kl { ...@@ -650,12 +694,16 @@ struct ath6kl {
bool p2p; bool p2p;
bool wiphy_registered;
#ifdef CONFIG_ATH6KL_DEBUG #ifdef CONFIG_ATH6KL_DEBUG
struct { struct {
struct circ_buf fwlog_buf; struct sk_buff_head fwlog_queue;
spinlock_t fwlog_lock; struct completion fwlog_completion;
void *fwlog_tmp; bool fwlog_open;
u32 fwlog_mask; u32 fwlog_mask;
unsigned int dbgfs_diag_reg; unsigned int dbgfs_diag_reg;
u32 diag_reg_addr_wr; u32 diag_reg_addr_wr;
u32 diag_reg_val_wr; u32 diag_reg_val_wr;
...@@ -727,10 +775,10 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target, ...@@ -727,10 +775,10 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
void aggr_module_destroy(struct aggr_info *aggr_info); void aggr_module_destroy(struct aggr_info *aggr_info);
void aggr_reset_state(struct aggr_info_conn *aggr_conn); void aggr_reset_state(struct aggr_info_conn *aggr_conn);
struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 * node_addr); struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr);
struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver); void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver);
int ath6kl_control_tx(void *devt, struct sk_buff *skb, int ath6kl_control_tx(void *devt, struct sk_buff *skb,
enum htc_endpoint_id eid); enum htc_endpoint_id eid);
void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel,
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -16,7 +17,7 @@ ...@@ -16,7 +17,7 @@
#include "core.h" #include "core.h"
#include <linux/circ_buf.h> #include <linux/skbuff.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/export.h> #include <linux/export.h>
...@@ -32,9 +33,8 @@ struct ath6kl_fwlog_slot { ...@@ -32,9 +33,8 @@ struct ath6kl_fwlog_slot {
u8 payload[0]; u8 payload[0];
}; };
#define ATH6KL_FWLOG_SIZE 32768 #define ATH6KL_FWLOG_MAX_ENTRIES 20
#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \
ATH6KL_FWLOG_PAYLOAD_SIZE)
#define ATH6KL_FWLOG_VALID_MASK 0x1ffff #define ATH6KL_FWLOG_VALID_MASK 0x1ffff
int ath6kl_printk(const char *level, const char *fmt, ...) int ath6kl_printk(const char *level, const char *fmt, ...)
...@@ -119,29 +119,29 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, ...@@ -119,29 +119,29 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
if (irq_proc_reg != NULL) { if (irq_proc_reg != NULL) {
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"Host Int status: 0x%x\n", "Host Int status: 0x%x\n",
irq_proc_reg->host_int_status); irq_proc_reg->host_int_status);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"CPU Int status: 0x%x\n", "CPU Int status: 0x%x\n",
irq_proc_reg->cpu_int_status); irq_proc_reg->cpu_int_status);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"Error Int status: 0x%x\n", "Error Int status: 0x%x\n",
irq_proc_reg->error_int_status); irq_proc_reg->error_int_status);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"Counter Int status: 0x%x\n", "Counter Int status: 0x%x\n",
irq_proc_reg->counter_int_status); irq_proc_reg->counter_int_status);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"Mbox Frame: 0x%x\n", "Mbox Frame: 0x%x\n",
irq_proc_reg->mbox_frame); irq_proc_reg->mbox_frame);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"Rx Lookahead Valid: 0x%x\n", "Rx Lookahead Valid: 0x%x\n",
irq_proc_reg->rx_lkahd_valid); irq_proc_reg->rx_lkahd_valid);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"Rx Lookahead 0: 0x%x\n", "Rx Lookahead 0: 0x%x\n",
irq_proc_reg->rx_lkahd[0]); irq_proc_reg->rx_lkahd[0]);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"Rx Lookahead 1: 0x%x\n", "Rx Lookahead 1: 0x%x\n",
irq_proc_reg->rx_lkahd[1]); irq_proc_reg->rx_lkahd[1]);
if (dev->ar->mbox_info.gmbox_addr != 0) { if (dev->ar->mbox_info.gmbox_addr != 0) {
/* /*
...@@ -149,27 +149,27 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, ...@@ -149,27 +149,27 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
* additional state. * additional state.
*/ */
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"GMBOX Host Int status 2: 0x%x\n", "GMBOX Host Int status 2: 0x%x\n",
irq_proc_reg->host_int_status2); irq_proc_reg->host_int_status2);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"GMBOX RX Avail: 0x%x\n", "GMBOX RX Avail: 0x%x\n",
irq_proc_reg->gmbox_rx_avail); irq_proc_reg->gmbox_rx_avail);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"GMBOX lookahead alias 0: 0x%x\n", "GMBOX lookahead alias 0: 0x%x\n",
irq_proc_reg->rx_gmbox_lkahd_alias[0]); irq_proc_reg->rx_gmbox_lkahd_alias[0]);
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"GMBOX lookahead alias 1: 0x%x\n", "GMBOX lookahead alias 1: 0x%x\n",
irq_proc_reg->rx_gmbox_lkahd_alias[1]); irq_proc_reg->rx_gmbox_lkahd_alias[1]);
} }
} }
if (irq_enable_reg != NULL) { if (irq_enable_reg != NULL) {
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"Int status Enable: 0x%x\n", "Int status Enable: 0x%x\n",
irq_enable_reg->int_status_en); irq_enable_reg->int_status_en);
ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n", ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n",
irq_enable_reg->cntr_int_status_en); irq_enable_reg->cntr_int_status_en);
} }
ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n"); ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n");
} }
...@@ -268,105 +268,103 @@ static const struct file_operations fops_war_stats = { ...@@ -268,105 +268,103 @@ static const struct file_operations fops_war_stats = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
size_t buf_len)
{ {
struct circ_buf *fwlog = &ar->debug.fwlog_buf; struct ath6kl_fwlog_slot *slot;
size_t space; struct sk_buff *skb;
int i; size_t slot_len;
/* entries must all be equal size */ if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE))
return; return;
space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE;
if (space < buf_len)
/* discard oldest slot */
fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) &
(ATH6KL_FWLOG_SIZE - 1);
for (i = 0; i < buf_len; i += space) { skb = alloc_skb(slot_len, GFP_KERNEL);
space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, if (!skb)
ATH6KL_FWLOG_SIZE); return;
if ((size_t) space > buf_len - i) slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len);
space = buf_len - i; slot->timestamp = cpu_to_le32(jiffies);
slot->length = cpu_to_le32(len);
memcpy(slot->payload, buf, len);
memcpy(&fwlog->buf[fwlog->head], buf, space); /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */
fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len);
}
} spin_lock(&ar->debug.fwlog_queue.lock);
void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) __skb_queue_tail(&ar->debug.fwlog_queue, skb);
{ complete(&ar->debug.fwlog_completion);
struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp;
size_t slot_len;
if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) /* drop oldest entries */
return; while (skb_queue_len(&ar->debug.fwlog_queue) >
ATH6KL_FWLOG_MAX_ENTRIES) {
skb = __skb_dequeue(&ar->debug.fwlog_queue);
kfree_skb(skb);
}
spin_lock_bh(&ar->debug.fwlog_lock); spin_unlock(&ar->debug.fwlog_queue.lock);
slot->timestamp = cpu_to_le32(jiffies); return;
slot->length = cpu_to_le32(len); }
memcpy(slot->payload, buf, len);
slot_len = sizeof(*slot) + len; static int ath6kl_fwlog_open(struct inode *inode, struct file *file)
{
struct ath6kl *ar = inode->i_private;
if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) if (ar->debug.fwlog_open)
memset(slot->payload + len, 0, return -EBUSY;
ATH6KL_FWLOG_SLOT_SIZE - slot_len);
ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); ar->debug.fwlog_open = true;
spin_unlock_bh(&ar->debug.fwlog_lock); file->private_data = inode->i_private;
return 0;
} }
static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) static int ath6kl_fwlog_release(struct inode *inode, struct file *file)
{ {
return CIRC_CNT(ar->debug.fwlog_buf.head, struct ath6kl *ar = inode->i_private;
ar->debug.fwlog_buf.tail,
ATH6KL_FWLOG_SLOT_SIZE) == 0; ar->debug.fwlog_open = false;
return 0;
} }
static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath6kl *ar = file->private_data; struct ath6kl *ar = file->private_data;
struct circ_buf *fwlog = &ar->debug.fwlog_buf; struct sk_buff *skb;
size_t len = 0, buf_len = count;
ssize_t ret_cnt; ssize_t ret_cnt;
size_t len = 0;
char *buf; char *buf;
int ccnt;
buf = vmalloc(buf_len); buf = vmalloc(count);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
/* read undelivered logs from firmware */ /* read undelivered logs from firmware */
ath6kl_read_fwlogs(ar); ath6kl_read_fwlogs(ar);
spin_lock_bh(&ar->debug.fwlog_lock); spin_lock(&ar->debug.fwlog_queue.lock);
while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, if (skb->len > count - len) {
ATH6KL_FWLOG_SIZE); /* not enough space, put skb back and leave */
__skb_queue_head(&ar->debug.fwlog_queue, skb);
break;
}
if ((size_t) ccnt > buf_len - len)
ccnt = buf_len - len;
memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); memcpy(buf + len, skb->data, skb->len);
len += ccnt; len += skb->len;
fwlog->tail = (fwlog->tail + ccnt) & kfree_skb(skb);
(ATH6KL_FWLOG_SIZE - 1);
} }
spin_unlock_bh(&ar->debug.fwlog_lock); spin_unlock(&ar->debug.fwlog_queue.lock);
if (WARN_ON(len > buf_len)) /* FIXME: what to do if len == 0? */
len = buf_len;
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
...@@ -376,12 +374,87 @@ static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, ...@@ -376,12 +374,87 @@ static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
} }
static const struct file_operations fops_fwlog = { static const struct file_operations fops_fwlog = {
.open = ath6kl_debugfs_open, .open = ath6kl_fwlog_open,
.release = ath6kl_fwlog_release,
.read = ath6kl_fwlog_read, .read = ath6kl_fwlog_read,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t ath6kl_fwlog_block_read(struct file *file,
char __user *user_buf,
size_t count,
loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
struct sk_buff *skb;
ssize_t ret_cnt;
size_t len = 0, not_copied;
char *buf;
int ret;
buf = vmalloc(count);
if (!buf)
return -ENOMEM;
spin_lock(&ar->debug.fwlog_queue.lock);
if (skb_queue_len(&ar->debug.fwlog_queue) == 0) {
/* we must init under queue lock */
init_completion(&ar->debug.fwlog_completion);
spin_unlock(&ar->debug.fwlog_queue.lock);
ret = wait_for_completion_interruptible(
&ar->debug.fwlog_completion);
if (ret == -ERESTARTSYS)
return ret;
spin_lock(&ar->debug.fwlog_queue.lock);
}
while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
if (skb->len > count - len) {
/* not enough space, put skb back and leave */
__skb_queue_head(&ar->debug.fwlog_queue, skb);
break;
}
memcpy(buf + len, skb->data, skb->len);
len += skb->len;
kfree_skb(skb);
}
spin_unlock(&ar->debug.fwlog_queue.lock);
/* FIXME: what to do if len == 0? */
not_copied = copy_to_user(user_buf, buf, len);
if (not_copied != 0) {
ret_cnt = -EFAULT;
goto out;
}
*ppos = *ppos + len;
ret_cnt = len;
out:
vfree(buf);
return ret_cnt;
}
static const struct file_operations fops_fwlog_block = {
.open = ath6kl_fwlog_open,
.release = ath6kl_fwlog_release,
.read = ath6kl_fwlog_block_read,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
...@@ -667,9 +740,13 @@ static ssize_t ath6kl_endpoint_stats_read(struct file *file, ...@@ -667,9 +740,13 @@ static ssize_t ath6kl_endpoint_stats_read(struct file *file,
return -ENOMEM; return -ENOMEM;
#define EPSTAT(name) \ #define EPSTAT(name) \
len = print_endpoint_stat(target, buf, buf_len, len, \ do { \
offsetof(struct htc_endpoint_stats, name), \ len = print_endpoint_stat(target, buf, buf_len, len, \
#name) offsetof(struct htc_endpoint_stats, \
name), \
#name); \
} while (0)
EPSTAT(cred_low_indicate); EPSTAT(cred_low_indicate);
EPSTAT(tx_issued); EPSTAT(tx_issued);
EPSTAT(tx_pkt_bundled); EPSTAT(tx_pkt_bundled);
...@@ -779,17 +856,9 @@ static ssize_t ath6kl_regread_write(struct file *file, ...@@ -779,17 +856,9 @@ static ssize_t ath6kl_regread_write(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath6kl *ar = file->private_data; struct ath6kl *ar = file->private_data;
u8 buf[50];
unsigned int len;
unsigned long reg_addr; unsigned long reg_addr;
len = min(count, sizeof(buf) - 1); if (kstrtoul_from_user(user_buf, count, 0, &reg_addr))
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &reg_addr))
return -EINVAL; return -EINVAL;
if ((reg_addr % 4) != 0) if ((reg_addr % 4) != 0)
...@@ -903,15 +972,8 @@ static ssize_t ath6kl_lrssi_roam_write(struct file *file, ...@@ -903,15 +972,8 @@ static ssize_t ath6kl_lrssi_roam_write(struct file *file,
{ {
struct ath6kl *ar = file->private_data; struct ath6kl *ar = file->private_data;
unsigned long lrssi_roam_threshold; unsigned long lrssi_roam_threshold;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1); if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold))
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &lrssi_roam_threshold))
return -EINVAL; return -EINVAL;
ar->lrssi_roam_threshold = lrssi_roam_threshold; ar->lrssi_roam_threshold = lrssi_roam_threshold;
...@@ -1558,12 +1620,12 @@ static ssize_t ath6kl_listen_int_write(struct file *file, ...@@ -1558,12 +1620,12 @@ static ssize_t ath6kl_listen_int_write(struct file *file,
if (kstrtou16(buf, 0, &listen_interval)) if (kstrtou16(buf, 0, &listen_interval))
return -EINVAL; return -EINVAL;
if ((listen_interval < 1) || (listen_interval > 50)) if ((listen_interval < 15) || (listen_interval > 3000))
return -EINVAL; return -EINVAL;
ar->listen_intvl_b = listen_interval; vif->listen_intvl_t = listen_interval;
ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, 0, ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
ar->listen_intvl_b); vif->listen_intvl_t, 0);
return count; return count;
} }
...@@ -1573,10 +1635,15 @@ static ssize_t ath6kl_listen_int_read(struct file *file, ...@@ -1573,10 +1635,15 @@ static ssize_t ath6kl_listen_int_read(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath6kl *ar = file->private_data; struct ath6kl *ar = file->private_data;
struct ath6kl_vif *vif;
char buf[32]; char buf[32];
int len; int len;
len = scnprintf(buf, sizeof(buf), "%u\n", ar->listen_intvl_b); vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
len = scnprintf(buf, sizeof(buf), "%u\n", vif->listen_intvl_t);
return simple_read_from_buffer(user_buf, count, ppos, buf, len); return simple_read_from_buffer(user_buf, count, ppos, buf, len);
} }
...@@ -1649,33 +1716,29 @@ static const struct file_operations fops_power_params = { ...@@ -1649,33 +1716,29 @@ static const struct file_operations fops_power_params = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
int ath6kl_debug_init(struct ath6kl *ar) void ath6kl_debug_init(struct ath6kl *ar)
{ {
ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); skb_queue_head_init(&ar->debug.fwlog_queue);
if (ar->debug.fwlog_buf.buf == NULL) init_completion(&ar->debug.fwlog_completion);
return -ENOMEM;
ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL);
if (ar->debug.fwlog_tmp == NULL) {
vfree(ar->debug.fwlog_buf.buf);
return -ENOMEM;
}
spin_lock_init(&ar->debug.fwlog_lock);
/* /*
* Actually we are lying here but don't know how to read the mask * Actually we are lying here but don't know how to read the mask
* value from the firmware. * value from the firmware.
*/ */
ar->debug.fwlog_mask = 0; ar->debug.fwlog_mask = 0;
}
/*
* Initialisation needs to happen in two stages as fwlog events can come
* before cfg80211 is initialised, and debugfs depends on cfg80211
* initialisation.
*/
int ath6kl_debug_init_fs(struct ath6kl *ar)
{
ar->debugfs_phy = debugfs_create_dir("ath6kl", ar->debugfs_phy = debugfs_create_dir("ath6kl",
ar->wiphy->debugfsdir); ar->wiphy->debugfsdir);
if (!ar->debugfs_phy) { if (!ar->debugfs_phy)
vfree(ar->debug.fwlog_buf.buf);
kfree(ar->debug.fwlog_tmp);
return -ENOMEM; return -ENOMEM;
}
debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
&fops_tgt_stats); &fops_tgt_stats);
...@@ -1689,6 +1752,9 @@ int ath6kl_debug_init(struct ath6kl *ar) ...@@ -1689,6 +1752,9 @@ int ath6kl_debug_init(struct ath6kl *ar)
debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
&fops_fwlog); &fops_fwlog);
debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar,
&fops_fwlog_block);
debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy,
ar, &fops_fwlog_mask); ar, &fops_fwlog_mask);
...@@ -1723,27 +1789,26 @@ int ath6kl_debug_init(struct ath6kl *ar) ...@@ -1723,27 +1789,26 @@ int ath6kl_debug_init(struct ath6kl *ar)
ar->debugfs_phy, ar, &fops_disconnect_timeout); ar->debugfs_phy, ar, &fops_disconnect_timeout);
debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar, debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar,
&fops_create_qos); &fops_create_qos);
debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar, debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar,
&fops_delete_qos); &fops_delete_qos);
debugfs_create_file("bgscan_interval", S_IWUSR, debugfs_create_file("bgscan_interval", S_IWUSR,
ar->debugfs_phy, ar, &fops_bgscan_int); ar->debugfs_phy, ar, &fops_bgscan_int);
debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR, debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR,
ar->debugfs_phy, ar, &fops_listen_int); ar->debugfs_phy, ar, &fops_listen_int);
debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar, debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar,
&fops_power_params); &fops_power_params);
return 0; return 0;
} }
void ath6kl_debug_cleanup(struct ath6kl *ar) void ath6kl_debug_cleanup(struct ath6kl *ar)
{ {
vfree(ar->debug.fwlog_buf.buf); skb_queue_purge(&ar->debug.fwlog_queue);
kfree(ar->debug.fwlog_tmp);
kfree(ar->debug.roam_tbl); kfree(ar->debug.roam_tbl);
} }
......
/* /*
* Copyright (c) 2011 Atheros Communications Inc. * Copyright (c) 2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -77,7 +78,8 @@ int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf, ...@@ -77,7 +78,8 @@ int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
size_t len); size_t len);
void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive); void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive);
void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout); void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout);
int ath6kl_debug_init(struct ath6kl *ar); void ath6kl_debug_init(struct ath6kl *ar);
int ath6kl_debug_init_fs(struct ath6kl *ar);
void ath6kl_debug_cleanup(struct ath6kl *ar); void ath6kl_debug_cleanup(struct ath6kl *ar);
#else #else
...@@ -127,7 +129,11 @@ static inline void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, ...@@ -127,7 +129,11 @@ static inline void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar,
{ {
} }
static inline int ath6kl_debug_init(struct ath6kl *ar) static inline void ath6kl_debug_init(struct ath6kl *ar)
{
}
static inline int ath6kl_debug_init_fs(struct ath6kl *ar)
{ {
return 0; return 0;
} }
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
......
/* /*
* Copyright (c) 2007-2011 Atheros Communications Inc. * Copyright (c) 2007-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -89,7 +90,7 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) ...@@ -89,7 +90,7 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
} }
ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n", ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n",
regdump_addr); regdump_addr);
regdump_addr = TARG_VTOP(ar->target_type, regdump_addr); regdump_addr = TARG_VTOP(ar->target_type, regdump_addr);
/* fetch register dump data */ /* fetch register dump data */
...@@ -106,9 +107,9 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) ...@@ -106,9 +107,9 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4); BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4);
for (i = 0; i < REG_DUMP_COUNT_AR6003 / 4; i++) { for (i = 0; i < REG_DUMP_COUNT_AR6003; i += 4) {
ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
4 * i, i,
le32_to_cpu(regdump_val[i]), le32_to_cpu(regdump_val[i]),
le32_to_cpu(regdump_val[i + 1]), le32_to_cpu(regdump_val[i + 1]),
le32_to_cpu(regdump_val[i + 2]), le32_to_cpu(regdump_val[i + 2]),
...@@ -134,6 +135,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) ...@@ -134,6 +135,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
ath6kl_warn("Failed to clear debug interrupt: %d\n", ret); ath6kl_warn("Failed to clear debug interrupt: %d\n", ret);
ath6kl_hif_dump_fw_crash(dev->ar); ath6kl_hif_dump_fw_crash(dev->ar);
ath6kl_read_fwlogs(dev->ar);
return ret; return ret;
} }
...@@ -283,7 +285,7 @@ static int ath6kl_hif_proc_counter_intr(struct ath6kl_device *dev) ...@@ -283,7 +285,7 @@ static int ath6kl_hif_proc_counter_intr(struct ath6kl_device *dev)
dev->irq_en_reg.cntr_int_status_en; dev->irq_en_reg.cntr_int_status_en;
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
counter_int_status); counter_int_status);
/* /*
...@@ -358,7 +360,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev) ...@@ -358,7 +360,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev)
} }
ath6kl_dbg(ATH6KL_DBG_IRQ, ath6kl_dbg(ATH6KL_DBG_IRQ,
"valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
cpu_int_status); cpu_int_status);
/* Clear the interrupt */ /* Clear the interrupt */
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -197,6 +198,8 @@ struct hif_scatter_req { ...@@ -197,6 +198,8 @@ struct hif_scatter_req {
u8 *virt_dma_buf; u8 *virt_dma_buf;
struct hif_scatter_item scat_list[1]; struct hif_scatter_item scat_list[1];
u32 scat_q_depth;
}; };
struct ath6kl_irq_proc_registers { struct ath6kl_irq_proc_registers {
...@@ -220,6 +223,7 @@ struct ath6kl_irq_enable_reg { ...@@ -220,6 +223,7 @@ struct ath6kl_irq_enable_reg {
} __packed; } __packed;
struct ath6kl_device { struct ath6kl_device {
/* protects irq_proc_reg and irq_en_reg below */
spinlock_t lock; spinlock_t lock;
struct ath6kl_irq_proc_registers irq_proc_reg; struct ath6kl_irq_proc_registers irq_proc_reg;
struct ath6kl_irq_enable_reg irq_en_reg; struct ath6kl_irq_enable_reg irq_en_reg;
......
/* /*
* Copyright (c) 2007-2011 Atheros Communications Inc. * Copyright (c) 2007-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -22,6 +23,9 @@ ...@@ -22,6 +23,9 @@
#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask))
/* threshold to re-enable Tx bundling for an AC*/
#define TX_RESUME_BUNDLE_THRESHOLD 1500
/* Functions for Tx credit handling */ /* Functions for Tx credit handling */
static void ath6kl_credit_deposit(struct ath6kl_htc_credit_info *cred_info, static void ath6kl_credit_deposit(struct ath6kl_htc_credit_info *cred_info,
struct htc_endpoint_credit_dist *ep_dist, struct htc_endpoint_credit_dist *ep_dist,
...@@ -168,31 +172,29 @@ static void ath6kl_credit_reduce(struct ath6kl_htc_credit_info *cred_info, ...@@ -168,31 +172,29 @@ static void ath6kl_credit_reduce(struct ath6kl_htc_credit_info *cred_info,
static void ath6kl_credit_update(struct ath6kl_htc_credit_info *cred_info, static void ath6kl_credit_update(struct ath6kl_htc_credit_info *cred_info,
struct list_head *epdist_list) struct list_head *epdist_list)
{ {
struct htc_endpoint_credit_dist *cur_dist_list; struct htc_endpoint_credit_dist *cur_list;
list_for_each_entry(cur_dist_list, epdist_list, list) { list_for_each_entry(cur_list, epdist_list, list) {
if (cur_dist_list->endpoint == ENDPOINT_0) if (cur_list->endpoint == ENDPOINT_0)
continue; continue;
if (cur_dist_list->cred_to_dist > 0) { if (cur_list->cred_to_dist > 0) {
cur_dist_list->credits += cur_list->credits += cur_list->cred_to_dist;
cur_dist_list->cred_to_dist; cur_list->cred_to_dist = 0;
cur_dist_list->cred_to_dist = 0;
if (cur_dist_list->credits > if (cur_list->credits > cur_list->cred_assngd)
cur_dist_list->cred_assngd)
ath6kl_credit_reduce(cred_info, ath6kl_credit_reduce(cred_info,
cur_dist_list, cur_list,
cur_dist_list->cred_assngd); cur_list->cred_assngd);
if (cur_dist_list->credits > if (cur_list->credits > cur_list->cred_norm)
cur_dist_list->cred_norm) ath6kl_credit_reduce(cred_info, cur_list,
ath6kl_credit_reduce(cred_info, cur_dist_list, cur_list->cred_norm);
cur_dist_list->cred_norm);
if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) { if (!(cur_list->dist_flags & HTC_EP_ACTIVE)) {
if (cur_dist_list->txq_depth == 0) if (cur_list->txq_depth == 0)
ath6kl_credit_reduce(cred_info, ath6kl_credit_reduce(cred_info,
cur_dist_list, 0); cur_list, 0);
} }
} }
} }
...@@ -460,8 +462,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target, ...@@ -460,8 +462,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target,
INIT_LIST_HEAD(&tx_compq); INIT_LIST_HEAD(&tx_compq);
ath6kl_dbg(ATH6KL_DBG_HTC, ath6kl_dbg(ATH6KL_DBG_HTC,
"htc tx scat complete len %d entries %d\n", "htc tx scat complete len %d entries %d\n",
scat_req->len, scat_req->scat_entries); scat_req->len, scat_req->scat_entries);
if (scat_req->status) if (scat_req->status)
ath6kl_err("send scatter req failed: %d\n", scat_req->status); ath6kl_err("send scatter req failed: %d\n", scat_req->status);
...@@ -599,8 +601,8 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target, ...@@ -599,8 +601,8 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target,
list); list);
ath6kl_dbg(ATH6KL_DBG_HTC, ath6kl_dbg(ATH6KL_DBG_HTC,
"htc tx got packet 0x%p queue depth %d\n", "htc tx got packet 0x%p queue depth %d\n",
packet, get_queue_depth(&endpoint->txq)); packet, get_queue_depth(&endpoint->txq));
len = CALC_TXRX_PADDED_LEN(target, len = CALC_TXRX_PADDED_LEN(target,
packet->act_len + HTC_HDR_LENGTH); packet->act_len + HTC_HDR_LENGTH);
...@@ -670,6 +672,7 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, ...@@ -670,6 +672,7 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target,
struct htc_packet *packet; struct htc_packet *packet;
int i, len, rem_scat, cred_pad; int i, len, rem_scat, cred_pad;
int status = 0; int status = 0;
u8 flags;
rem_scat = target->max_tx_bndl_sz; rem_scat = target->max_tx_bndl_sz;
...@@ -696,9 +699,9 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, ...@@ -696,9 +699,9 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target,
scat_req->scat_list[i].packet = packet; scat_req->scat_list[i].packet = packet;
/* prepare packet and flag message as part of a send bundle */ /* prepare packet and flag message as part of a send bundle */
ath6kl_htc_tx_prep_pkt(packet, flags = packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE;
packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE, ath6kl_htc_tx_prep_pkt(packet, flags,
cred_pad, packet->info.tx.seqno); cred_pad, packet->info.tx.seqno);
/* Make sure the buffer is 4-byte aligned */ /* Make sure the buffer is 4-byte aligned */
ath6kl_htc_tx_buf_align(&packet->buf, ath6kl_htc_tx_buf_align(&packet->buf,
packet->act_len + HTC_HDR_LENGTH); packet->act_len + HTC_HDR_LENGTH);
...@@ -744,6 +747,12 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, ...@@ -744,6 +747,12 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
struct hif_scatter_req *scat_req = NULL; struct hif_scatter_req *scat_req = NULL;
int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0;
int status; int status;
u32 txb_mask;
u8 ac = WMM_NUM_AC;
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
(WMI_CONTROL_SVC != endpoint->svc_id))
ac = target->dev->ar->ep2ac_map[endpoint->eid];
while (true) { while (true) {
status = 0; status = 0;
...@@ -759,10 +768,35 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, ...@@ -759,10 +768,35 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
if (!scat_req) { if (!scat_req) {
/* no scatter resources */ /* no scatter resources */
ath6kl_dbg(ATH6KL_DBG_HTC, ath6kl_dbg(ATH6KL_DBG_HTC,
"htc tx no more scatter resources\n"); "htc tx no more scatter resources\n");
break; break;
} }
if ((ac < WMM_NUM_AC) && (ac != WMM_AC_BK)) {
if (WMM_AC_BE == ac)
/*
* BE, BK have priorities and bit
* positions reversed
*/
txb_mask = (1 << WMM_AC_BK);
else
/*
* any AC with priority lower than
* itself
*/
txb_mask = ((1 << ac) - 1);
/*
* when the scatter request resources drop below a
* certain threshold, disable Tx bundling for all
* AC's with priority lower than the current requesting
* AC. Otherwise re-enable Tx bundling for them
*/
if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS)
target->tx_bndl_mask &= ~txb_mask;
else
target->tx_bndl_mask |= txb_mask;
}
ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n", ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n",
n_scat); n_scat);
...@@ -806,6 +840,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, ...@@ -806,6 +840,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
struct htc_packet *packet; struct htc_packet *packet;
int bundle_sent; int bundle_sent;
int n_pkts_bundle; int n_pkts_bundle;
u8 ac = WMM_NUM_AC;
spin_lock_bh(&target->tx_lock); spin_lock_bh(&target->tx_lock);
...@@ -823,6 +858,10 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, ...@@ -823,6 +858,10 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
*/ */
INIT_LIST_HEAD(&txq); INIT_LIST_HEAD(&txq);
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
(WMI_CONTROL_SVC != endpoint->svc_id))
ac = target->dev->ar->ep2ac_map[endpoint->eid];
while (true) { while (true) {
if (list_empty(&endpoint->txq)) if (list_empty(&endpoint->txq))
...@@ -840,15 +879,18 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, ...@@ -840,15 +879,18 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
while (true) { while (true) {
/* try to send a bundle on each pass */ /* try to send a bundle on each pass */
if ((target->tx_bndl_enable) && if ((target->tx_bndl_mask) &&
(get_queue_depth(&txq) >= (get_queue_depth(&txq) >=
HTC_MIN_HTC_MSGS_TO_BUNDLE)) { HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
int temp1 = 0, temp2 = 0; int temp1 = 0, temp2 = 0;
ath6kl_htc_tx_bundle(endpoint, &txq, /* check if bundling is enabled for an AC */
&temp1, &temp2); if (target->tx_bndl_mask & (1 << ac)) {
bundle_sent += temp1; ath6kl_htc_tx_bundle(endpoint, &txq,
n_pkts_bundle += temp2; &temp1, &temp2);
bundle_sent += temp1;
n_pkts_bundle += temp2;
}
} }
if (list_empty(&txq)) if (list_empty(&txq))
...@@ -867,6 +909,26 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, ...@@ -867,6 +909,26 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
endpoint->ep_st.tx_bundles += bundle_sent; endpoint->ep_st.tx_bundles += bundle_sent;
endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle; endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle;
/*
* if an AC has bundling disabled and no tx bundling
* has occured continously for a certain number of TX,
* enable tx bundling for this AC
*/
if (!bundle_sent) {
if (!(target->tx_bndl_mask & (1 << ac)) &&
(ac < WMM_NUM_AC)) {
if (++target->ac_tx_count[ac] >=
TX_RESUME_BUNDLE_THRESHOLD) {
target->ac_tx_count[ac] = 0;
target->tx_bndl_mask |= (1 << ac);
}
}
} else {
/* tx bundling will reset the counter */
if (ac < WMM_NUM_AC)
target->ac_tx_count[ac] = 0;
}
} }
endpoint->tx_proc_cnt = 0; endpoint->tx_proc_cnt = 0;
...@@ -979,8 +1041,8 @@ static int htc_setup_tx_complete(struct htc_target *target) ...@@ -979,8 +1041,8 @@ static int htc_setup_tx_complete(struct htc_target *target)
memcpy(&setup_comp_ext->flags, &flags, memcpy(&setup_comp_ext->flags, &flags,
sizeof(setup_comp_ext->flags)); sizeof(setup_comp_ext->flags));
set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext, set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext,
sizeof(struct htc_setup_comp_ext_msg), sizeof(struct htc_setup_comp_ext_msg),
ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
} else { } else {
struct htc_setup_comp_msg *setup_comp; struct htc_setup_comp_msg *setup_comp;
...@@ -988,8 +1050,8 @@ static int htc_setup_tx_complete(struct htc_target *target) ...@@ -988,8 +1050,8 @@ static int htc_setup_tx_complete(struct htc_target *target)
memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg)); memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg));
setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID); setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID);
set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp, set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp,
sizeof(struct htc_setup_comp_msg), sizeof(struct htc_setup_comp_msg),
ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
} }
/* we want synchronous operation */ /* we want synchronous operation */
...@@ -1088,9 +1150,9 @@ void ath6kl_htc_flush_txep(struct htc_target *target, ...@@ -1088,9 +1150,9 @@ void ath6kl_htc_flush_txep(struct htc_target *target,
packet->status = -ECANCELED; packet->status = -ECANCELED;
list_del(&packet->list); list_del(&packet->list);
ath6kl_dbg(ATH6KL_DBG_HTC, ath6kl_dbg(ATH6KL_DBG_HTC,
"htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n", "htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n",
packet, packet->act_len, packet, packet->act_len,
packet->endpoint, packet->info.tx.tag); packet->endpoint, packet->info.tx.tag);
INIT_LIST_HEAD(&container); INIT_LIST_HEAD(&container);
list_add_tail(&packet->list, &container); list_add_tail(&packet->list, &container);
...@@ -1490,7 +1552,7 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) ...@@ -1490,7 +1552,7 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets)
if (packets->act_len > 0) { if (packets->act_len > 0) {
ath6kl_err("htc_ctrl_rx, got message with len:%zu\n", ath6kl_err("htc_ctrl_rx, got message with len:%zu\n",
packets->act_len + HTC_HDR_LENGTH); packets->act_len + HTC_HDR_LENGTH);
ath6kl_dbg_dump(ATH6KL_DBG_HTC, ath6kl_dbg_dump(ATH6KL_DBG_HTC,
"htc rx unexpected endpoint 0 message", "", "htc rx unexpected endpoint 0 message", "",
...@@ -1609,8 +1671,8 @@ static int htc_parse_trailer(struct htc_target *target, ...@@ -1609,8 +1671,8 @@ static int htc_parse_trailer(struct htc_target *target,
} }
lk_ahd = (struct htc_lookahead_report *) record_buf; lk_ahd = (struct htc_lookahead_report *) record_buf;
if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) &&
&& next_lk_ahds) { next_lk_ahds) {
ath6kl_dbg(ATH6KL_DBG_HTC, ath6kl_dbg(ATH6KL_DBG_HTC,
"htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n", "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n",
...@@ -2038,13 +2100,13 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target, ...@@ -2038,13 +2100,13 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target,
list_for_each_entry_safe(packet, tmp_pkt, rx_pktq, list) { list_for_each_entry_safe(packet, tmp_pkt, rx_pktq, list) {
list_del(&packet->list); list_del(&packet->list);
htc_reclaim_rxbuf(target, packet, htc_reclaim_rxbuf(target, packet,
&target->endpoint[packet->endpoint]); &target->endpoint[packet->endpoint]);
} }
list_for_each_entry_safe(packet, tmp_pkt, &tmp_rxq, list) { list_for_each_entry_safe(packet, tmp_pkt, &tmp_rxq, list) {
list_del(&packet->list); list_del(&packet->list);
htc_reclaim_rxbuf(target, packet, htc_reclaim_rxbuf(target, packet,
&target->endpoint[packet->endpoint]); &target->endpoint[packet->endpoint]);
} }
return status; return status;
...@@ -2176,11 +2238,11 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) ...@@ -2176,11 +2238,11 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
u32 look_ahead; u32 look_ahead;
if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead, if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead,
HTC_TARGET_RESPONSE_TIMEOUT)) HTC_TARGET_RESPONSE_TIMEOUT))
return NULL; return NULL;
ath6kl_dbg(ATH6KL_DBG_HTC, ath6kl_dbg(ATH6KL_DBG_HTC,
"htc rx wait ctrl look_ahead 0x%X\n", look_ahead); "htc rx wait ctrl look_ahead 0x%X\n", look_ahead);
htc_hdr = (struct htc_frame_hdr *)&look_ahead; htc_hdr = (struct htc_frame_hdr *)&look_ahead;
...@@ -2245,7 +2307,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, ...@@ -2245,7 +2307,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
depth = get_queue_depth(pkt_queue); depth = get_queue_depth(pkt_queue);
ath6kl_dbg(ATH6KL_DBG_HTC, ath6kl_dbg(ATH6KL_DBG_HTC,
"htc rx add multiple ep id %d cnt %d len %d\n", "htc rx add multiple ep id %d cnt %d len %d\n",
first_pkt->endpoint, depth, first_pkt->buf_len); first_pkt->endpoint, depth, first_pkt->buf_len);
endpoint = &target->endpoint[first_pkt->endpoint]; endpoint = &target->endpoint[first_pkt->endpoint];
...@@ -2271,8 +2333,8 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, ...@@ -2271,8 +2333,8 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) {
if (target->ep_waiting == first_pkt->endpoint) { if (target->ep_waiting == first_pkt->endpoint) {
ath6kl_dbg(ATH6KL_DBG_HTC, ath6kl_dbg(ATH6KL_DBG_HTC,
"htc rx blocked on ep %d, unblocking\n", "htc rx blocked on ep %d, unblocking\n",
target->ep_waiting); target->ep_waiting);
target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS; target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS;
target->ep_waiting = ENDPOINT_MAX; target->ep_waiting = ENDPOINT_MAX;
rx_unblock = true; rx_unblock = true;
...@@ -2309,7 +2371,21 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target) ...@@ -2309,7 +2371,21 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target)
"htc rx flush pkt 0x%p len %d ep %d\n", "htc rx flush pkt 0x%p len %d ep %d\n",
packet, packet->buf_len, packet, packet->buf_len,
packet->endpoint); packet->endpoint);
dev_kfree_skb(packet->pkt_cntxt); /*
* packets in rx_bufq of endpoint 0 have originally
* been queued from target->free_ctrl_rxbuf where
* packet and packet->buf_start are allocated
* separately using kmalloc(). For other endpoint
* rx_bufq, it is allocated as skb where packet is
* skb->head. Take care of this difference while freeing
* the memory.
*/
if (packet->endpoint == ENDPOINT_0) {
kfree(packet->buf_start);
kfree(packet);
} else {
dev_kfree_skb(packet->pkt_cntxt);
}
spin_lock_bh(&target->rx_lock); spin_lock_bh(&target->rx_lock);
} }
spin_unlock_bh(&target->rx_lock); spin_unlock_bh(&target->rx_lock);
...@@ -2328,6 +2404,7 @@ int ath6kl_htc_conn_service(struct htc_target *target, ...@@ -2328,6 +2404,7 @@ int ath6kl_htc_conn_service(struct htc_target *target,
enum htc_endpoint_id assigned_ep = ENDPOINT_MAX; enum htc_endpoint_id assigned_ep = ENDPOINT_MAX;
unsigned int max_msg_sz = 0; unsigned int max_msg_sz = 0;
int status = 0; int status = 0;
u16 msg_id;
ath6kl_dbg(ATH6KL_DBG_HTC, ath6kl_dbg(ATH6KL_DBG_HTC,
"htc connect service target 0x%p service id 0x%x\n", "htc connect service target 0x%p service id 0x%x\n",
...@@ -2371,9 +2448,10 @@ int ath6kl_htc_conn_service(struct htc_target *target, ...@@ -2371,9 +2448,10 @@ int ath6kl_htc_conn_service(struct htc_target *target,
} }
resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf; resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf;
msg_id = le16_to_cpu(resp_msg->msg_id);
if ((le16_to_cpu(resp_msg->msg_id) != HTC_MSG_CONN_SVC_RESP_ID) if ((msg_id != HTC_MSG_CONN_SVC_RESP_ID) ||
|| (rx_pkt->act_len < sizeof(*resp_msg))) { (rx_pkt->act_len < sizeof(*resp_msg))) {
status = -ENOMEM; status = -ENOMEM;
goto fail_tx; goto fail_tx;
} }
...@@ -2420,6 +2498,15 @@ int ath6kl_htc_conn_service(struct htc_target *target, ...@@ -2420,6 +2498,15 @@ int ath6kl_htc_conn_service(struct htc_target *target,
endpoint->cred_dist.endpoint = assigned_ep; endpoint->cred_dist.endpoint = assigned_ep;
endpoint->cred_dist.cred_sz = target->tgt_cred_sz; endpoint->cred_dist.cred_sz = target->tgt_cred_sz;
switch (endpoint->svc_id) {
case WMI_DATA_BK_SVC:
endpoint->tx_drop_packet_threshold = MAX_DEF_COOKIE_NUM / 3;
break;
default:
endpoint->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM;
break;
}
if (conn_req->max_rxmsg_sz) { if (conn_req->max_rxmsg_sz) {
/* /*
* Override cred_per_msg calculation, this optimizes * Override cred_per_msg calculation, this optimizes
...@@ -2517,7 +2604,8 @@ static void htc_setup_msg_bndl(struct htc_target *target) ...@@ -2517,7 +2604,8 @@ static void htc_setup_msg_bndl(struct htc_target *target)
target->max_rx_bndl_sz, target->max_tx_bndl_sz); target->max_rx_bndl_sz, target->max_tx_bndl_sz);
if (target->max_tx_bndl_sz) if (target->max_tx_bndl_sz)
target->tx_bndl_enable = true; /* tx_bndl_mask is enabled per AC, each has 1 bit */
target->tx_bndl_mask = (1 << WMM_NUM_AC) - 1;
if (target->max_rx_bndl_sz) if (target->max_rx_bndl_sz)
target->rx_bndl_enable = true; target->rx_bndl_enable = true;
...@@ -2532,7 +2620,7 @@ static void htc_setup_msg_bndl(struct htc_target *target) ...@@ -2532,7 +2620,7 @@ static void htc_setup_msg_bndl(struct htc_target *target)
* padding will spill into the next credit buffer * padding will spill into the next credit buffer
* which is fatal. * which is fatal.
*/ */
target->tx_bndl_enable = false; target->tx_bndl_mask = 0;
} }
} }
...@@ -2589,8 +2677,8 @@ int ath6kl_htc_wait_target(struct htc_target *target) ...@@ -2589,8 +2677,8 @@ int ath6kl_htc_wait_target(struct htc_target *target)
} }
ath6kl_dbg(ATH6KL_DBG_BOOT, "htc using protocol %s (%d)\n", ath6kl_dbg(ATH6KL_DBG_BOOT, "htc using protocol %s (%d)\n",
(target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1",
target->htc_tgt_ver); target->htc_tgt_ver);
if (target->msg_per_bndl_max > 0) if (target->msg_per_bndl_max > 0)
htc_setup_msg_bndl(target); htc_setup_msg_bndl(target);
...@@ -2784,14 +2872,14 @@ void ath6kl_htc_cleanup(struct htc_target *target) ...@@ -2784,14 +2872,14 @@ void ath6kl_htc_cleanup(struct htc_target *target)
ath6kl_hif_cleanup_scatter(target->dev->ar); ath6kl_hif_cleanup_scatter(target->dev->ar);
list_for_each_entry_safe(packet, tmp_packet, list_for_each_entry_safe(packet, tmp_packet,
&target->free_ctrl_txbuf, list) { &target->free_ctrl_txbuf, list) {
list_del(&packet->list); list_del(&packet->list);
kfree(packet->buf_start); kfree(packet->buf_start);
kfree(packet); kfree(packet);
} }
list_for_each_entry_safe(packet, tmp_packet, list_for_each_entry_safe(packet, tmp_packet,
&target->free_ctrl_rxbuf, list) { &target->free_ctrl_rxbuf, list) {
list_del(&packet->list); list_del(&packet->list);
kfree(packet->buf_start); kfree(packet->buf_start);
kfree(packet); kfree(packet);
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -87,6 +88,8 @@ ...@@ -87,6 +88,8 @@
#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4) #define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4)
#define WMI_MAX_SERVICES 5 #define WMI_MAX_SERVICES 5
#define WMM_NUM_AC 4
/* reserved and used to flush ALL packets */ /* reserved and used to flush ALL packets */
#define HTC_TX_PACKET_TAG_ALL 0 #define HTC_TX_PACKET_TAG_ALL 0
#define HTC_SERVICE_TX_PACKET_TAG 1 #define HTC_SERVICE_TX_PACKET_TAG 1
...@@ -498,6 +501,7 @@ struct htc_endpoint { ...@@ -498,6 +501,7 @@ struct htc_endpoint {
u8 seqno; u8 seqno;
u32 conn_flags; u32 conn_flags;
struct htc_endpoint_stats ep_st; struct htc_endpoint_stats ep_st;
u16 tx_drop_packet_threshold;
}; };
struct htc_control_buffer { struct htc_control_buffer {
...@@ -519,9 +523,16 @@ struct htc_target { ...@@ -519,9 +523,16 @@ struct htc_target {
struct ath6kl_htc_credit_info *credit_info; struct ath6kl_htc_credit_info *credit_info;
int tgt_creds; int tgt_creds;
unsigned int tgt_cred_sz; unsigned int tgt_cred_sz;
/* protects free_ctrl_txbuf and free_ctrl_rxbuf */
spinlock_t htc_lock; spinlock_t htc_lock;
/* FIXME: does this protext rx_bufq and endpoint structures or what? */
spinlock_t rx_lock; spinlock_t rx_lock;
/* protects endpoint->txq */
spinlock_t tx_lock; spinlock_t tx_lock;
struct ath6kl_device *dev; struct ath6kl_device *dev;
u32 htc_flags; u32 htc_flags;
u32 rx_st_flags; u32 rx_st_flags;
...@@ -531,7 +542,7 @@ struct htc_target { ...@@ -531,7 +542,7 @@ struct htc_target {
/* max messages per bundle for HTC */ /* max messages per bundle for HTC */
int msg_per_bndl_max; int msg_per_bndl_max;
bool tx_bndl_enable; u32 tx_bndl_mask;
int rx_bndl_enable; int rx_bndl_enable;
int max_rx_bndl_sz; int max_rx_bndl_sz;
int max_tx_bndl_sz; int max_tx_bndl_sz;
...@@ -543,6 +554,9 @@ struct htc_target { ...@@ -543,6 +554,9 @@ struct htc_target {
int max_xfer_szper_scatreq; int max_xfer_szper_scatreq;
int chk_irq_status_cnt; int chk_irq_status_cnt;
/* counts the number of Tx without bundling continously per AC */
u32 ac_tx_count[WMM_NUM_AC];
}; };
void *ath6kl_htc_create(struct ath6kl *ar); void *ath6kl_htc_create(struct ath6kl *ar);
......
/* /*
* Copyright (c) 2011 Atheros Communications Inc. * Copyright (c) 2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -74,7 +75,7 @@ static const struct ath6kl_hw hw_list[] = { ...@@ -74,7 +75,7 @@ static const struct ath6kl_hw hw_list[] = {
}, },
.fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE, .fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE,
.fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
}, },
{ {
.id = AR6004_HW_1_0_VERSION, .id = AR6004_HW_1_0_VERSION,
...@@ -351,11 +352,7 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, ...@@ -351,11 +352,7 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
blk_size |= ((u32)htc_ctrl_buf) << 16; blk_size |= ((u32)htc_ctrl_buf) << 16;
/* set the host interest area for the block size */ /* set the host interest area for the block size */
status = ath6kl_bmi_write(ar, status = ath6kl_bmi_write_hi32(ar, hi_mbox_io_block_sz, blk_size);
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_mbox_io_block_sz)),
(u8 *)&blk_size,
4);
if (status) { if (status) {
ath6kl_err("bmi_write_memory for IO block size failed\n"); ath6kl_err("bmi_write_memory for IO block size failed\n");
goto out; goto out;
...@@ -367,11 +364,8 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, ...@@ -367,11 +364,8 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
if (mbox_isr_yield_val) { if (mbox_isr_yield_val) {
/* set the host interest area for the mbox ISR yield limit */ /* set the host interest area for the mbox ISR yield limit */
status = ath6kl_bmi_write(ar, status = ath6kl_bmi_write_hi32(ar, hi_mbox_isr_yield_limit,
ath6kl_get_hi_item_addr(ar, mbox_isr_yield_val);
HI_ITEM(hi_mbox_isr_yield_limit)),
(u8 *)&mbox_isr_yield_val,
4);
if (status) { if (status) {
ath6kl_err("bmi_write_memory for yield limit failed\n"); ath6kl_err("bmi_write_memory for yield limit failed\n");
goto out; goto out;
...@@ -384,7 +378,6 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, ...@@ -384,7 +378,6 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
{ {
int status = 0;
int ret; int ret;
/* /*
...@@ -392,43 +385,54 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) ...@@ -392,43 +385,54 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
* default values. Required if checksum offload is needed. Set * default values. Required if checksum offload is needed. Set
* RxMetaVersion to 2. * RxMetaVersion to 2.
*/ */
if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx, ret = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx,
ar->rx_meta_ver, 0, 0)) { ar->rx_meta_ver, 0, 0);
ath6kl_err("unable to set the rx frame format\n"); if (ret) {
status = -EIO; ath6kl_err("unable to set the rx frame format: %d\n", ret);
return ret;
} }
if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) {
if ((ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1, ret = ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1,
IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) { IGNORE_PS_FAIL_DURING_SCAN);
ath6kl_err("unable to set power save fail event policy\n"); if (ret) {
status = -EIO; ath6kl_err("unable to set power save fail event policy: %d\n",
ret);
return ret;
} }
}
if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) {
if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0, ret = ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0,
WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) { WMI_FOLLOW_BARKER_IN_ERP);
ath6kl_err("unable to set barker preamble policy\n"); if (ret) {
status = -EIO; ath6kl_err("unable to set barker preamble policy: %d\n",
ret);
return ret;
} }
}
if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx, ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx,
WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) { WLAN_CONFIG_KEEP_ALIVE_INTERVAL);
ath6kl_err("unable to set keep alive interval\n"); if (ret) {
status = -EIO; ath6kl_err("unable to set keep alive interval: %d\n", ret);
return ret;
} }
if (ath6kl_wmi_disctimeout_cmd(ar->wmi, idx, ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, idx,
WLAN_CONFIG_DISCONNECT_TIMEOUT)) { WLAN_CONFIG_DISCONNECT_TIMEOUT);
ath6kl_err("unable to set disconnect timeout\n"); if (ret) {
status = -EIO; ath6kl_err("unable to set disconnect timeout: %d\n", ret);
return ret;
} }
if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) {
if (ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED)) { ret = ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED);
ath6kl_err("unable to set txop bursting\n"); if (ret) {
status = -EIO; ath6kl_err("unable to set txop bursting: %d\n", ret);
return ret;
} }
}
if (ar->p2p && (ar->vif_max == 1 || idx)) { if (ar->p2p && (ar->vif_max == 1 || idx)) {
ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx, ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx,
...@@ -452,7 +456,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) ...@@ -452,7 +456,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
} }
} }
return status; return ret;
} }
int ath6kl_configure_target(struct ath6kl *ar) int ath6kl_configure_target(struct ath6kl *ar)
...@@ -462,8 +466,7 @@ int ath6kl_configure_target(struct ath6kl *ar) ...@@ -462,8 +466,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
int i, status; int i, status;
param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG); param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG);
if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, if (ath6kl_bmi_write_hi32(ar, hi_serial_enable, param)) {
HI_ITEM(hi_serial_enable)), (u8 *)&param, 4)) {
ath6kl_err("bmi_write_memory for uart debug failed\n"); ath6kl_err("bmi_write_memory for uart debug failed\n");
return -EIO; return -EIO;
} }
...@@ -499,11 +502,8 @@ int ath6kl_configure_target(struct ath6kl *ar) ...@@ -499,11 +502,8 @@ int ath6kl_configure_target(struct ath6kl *ar)
if (ar->p2p && ar->vif_max == 1) if (ar->p2p && ar->vif_max == 1)
fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
param = HTC_PROTOCOL_VERSION; if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest,
if (ath6kl_bmi_write(ar, HTC_PROTOCOL_VERSION) != 0) {
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_app_host_interest)),
(u8 *)&param, 4) != 0) {
ath6kl_err("bmi_write_memory for htc version failed\n"); ath6kl_err("bmi_write_memory for htc version failed\n");
return -EIO; return -EIO;
} }
...@@ -511,10 +511,7 @@ int ath6kl_configure_target(struct ath6kl *ar) ...@@ -511,10 +511,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
/* set the firmware mode to STA/IBSS/AP */ /* set the firmware mode to STA/IBSS/AP */
param = 0; param = 0;
if (ath6kl_bmi_read(ar, if (ath6kl_bmi_read_hi32(ar, hi_option_flag, &param) != 0) {
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_option_flag)),
(u8 *)&param, 4) != 0) {
ath6kl_err("bmi_read_memory for setting fwmode failed\n"); ath6kl_err("bmi_read_memory for setting fwmode failed\n");
return -EIO; return -EIO;
} }
...@@ -526,11 +523,7 @@ int ath6kl_configure_target(struct ath6kl *ar) ...@@ -526,11 +523,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);
if (ath6kl_bmi_write(ar, if (ath6kl_bmi_write_hi32(ar, hi_option_flag, param) != 0) {
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_option_flag)),
(u8 *)&param,
4) != 0) {
ath6kl_err("bmi_write_memory for setting fwmode failed\n"); ath6kl_err("bmi_write_memory for setting fwmode failed\n");
return -EIO; return -EIO;
} }
...@@ -549,16 +542,13 @@ int ath6kl_configure_target(struct ath6kl *ar) ...@@ -549,16 +542,13 @@ int ath6kl_configure_target(struct ath6kl *ar)
param = ar->hw.board_ext_data_addr; param = ar->hw.board_ext_data_addr;
ram_reserved_size = ar->hw.reserved_ram_size; ram_reserved_size = ar->hw.reserved_ram_size;
if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) {
HI_ITEM(hi_board_ext_data)),
(u8 *)&param, 4) != 0) {
ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
return -EIO; return -EIO;
} }
if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz,
HI_ITEM(hi_end_ram_reserve_sz)), ram_reserved_size) != 0) {
(u8 *)&ram_reserved_size, 4) != 0) {
ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
return -EIO; return -EIO;
} }
...@@ -569,20 +559,13 @@ int ath6kl_configure_target(struct ath6kl *ar) ...@@ -569,20 +559,13 @@ int ath6kl_configure_target(struct ath6kl *ar)
return -EIO; return -EIO;
/* Configure GPIO AR600x UART */ /* Configure GPIO AR600x UART */
param = ar->hw.uarttx_pin; status = ath6kl_bmi_write_hi32(ar, hi_dbg_uart_txpin,
status = ath6kl_bmi_write(ar, ar->hw.uarttx_pin);
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_dbg_uart_txpin)),
(u8 *)&param, 4);
if (status) if (status)
return status; return status;
/* Configure target refclk_hz */ /* Configure target refclk_hz */
param = ar->hw.refclk_hz; status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, ar->hw.refclk_hz);
status = ath6kl_bmi_write(ar,
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_refclk_hz)),
(u8 *)&param, 4);
if (status) if (status)
return status; return status;
...@@ -832,13 +815,13 @@ static int ath6kl_fetch_testscript_file(struct ath6kl *ar) ...@@ -832,13 +815,13 @@ static int ath6kl_fetch_testscript_file(struct ath6kl *ar)
return 0; return 0;
snprintf(filename, sizeof(filename), "%s/%s", snprintf(filename, sizeof(filename), "%s/%s",
ar->hw.fw.dir, ar->hw.fw.testscript); ar->hw.fw.dir, ar->hw.fw.testscript);
ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript, ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript,
&ar->fw_testscript_len); &ar->fw_testscript_len);
if (ret) { if (ret) {
ath6kl_err("Failed to get testscript file %s: %d\n", ath6kl_err("Failed to get testscript file %s: %d\n",
filename, ret); filename, ret);
return ret; return ret;
} }
...@@ -922,7 +905,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ...@@ -922,7 +905,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
switch (ie_id) { switch (ie_id) {
case ATH6KL_FW_IE_OTP_IMAGE: case ATH6KL_FW_IE_OTP_IMAGE:
ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",
ie_len); ie_len);
ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);
...@@ -935,7 +918,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ...@@ -935,7 +918,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
break; break;
case ATH6KL_FW_IE_FW_IMAGE: case ATH6KL_FW_IE_FW_IMAGE:
ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n",
ie_len); ie_len);
/* in testmode we already might have a fw file */ /* in testmode we already might have a fw file */
if (ar->fw != NULL) if (ar->fw != NULL)
...@@ -952,7 +935,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ...@@ -952,7 +935,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
break; break;
case ATH6KL_FW_IE_PATCH_IMAGE: case ATH6KL_FW_IE_PATCH_IMAGE:
ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n", ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n",
ie_len); ie_len);
ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);
...@@ -1096,22 +1079,14 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) ...@@ -1096,22 +1079,14 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
*/ */
if (ar->hw.board_addr != 0) { if (ar->hw.board_addr != 0) {
board_address = ar->hw.board_addr; board_address = ar->hw.board_addr;
ath6kl_bmi_write(ar, ath6kl_bmi_write_hi32(ar, hi_board_data,
ath6kl_get_hi_item_addr(ar, board_address);
HI_ITEM(hi_board_data)),
(u8 *) &board_address, 4);
} else { } else {
ath6kl_bmi_read(ar, ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address);
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_board_data)),
(u8 *) &board_address, 4);
} }
/* determine where in target ram to write extended board data */ /* determine where in target ram to write extended board data */
ath6kl_bmi_read(ar, ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address);
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_board_ext_data)),
(u8 *) &board_ext_address, 4);
if (ar->target_type == TARGET_TYPE_AR6003 && if (ar->target_type == TARGET_TYPE_AR6003 &&
board_ext_address == 0) { board_ext_address == 0) {
...@@ -1123,6 +1098,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) ...@@ -1123,6 +1098,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
case TARGET_TYPE_AR6003: case TARGET_TYPE_AR6003:
board_data_size = AR6003_BOARD_DATA_SZ; board_data_size = AR6003_BOARD_DATA_SZ;
board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ; board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ;
if (ar->fw_board_len > (board_data_size + board_ext_data_size))
board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ_V2;
break; break;
case TARGET_TYPE_AR6004: case TARGET_TYPE_AR6004:
board_data_size = AR6004_BOARD_DATA_SZ; board_data_size = AR6004_BOARD_DATA_SZ;
...@@ -1154,10 +1131,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) ...@@ -1154,10 +1131,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
/* record that extended board data is initialized */ /* record that extended board data is initialized */
param = (board_ext_data_size << 16) | 1; param = (board_ext_data_size << 16) | 1;
ath6kl_bmi_write(ar, ath6kl_bmi_write_hi32(ar, hi_board_ext_data_config, param);
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_board_ext_data_config)),
(unsigned char *) &param, 4);
} }
if (ar->fw_board_len < board_data_size) { if (ar->fw_board_len < board_data_size) {
...@@ -1178,11 +1152,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) ...@@ -1178,11 +1152,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
} }
/* record the fact that Board Data IS initialized */ /* record the fact that Board Data IS initialized */
param = 1; ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, 1);
ath6kl_bmi_write(ar,
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_board_data_initialized)),
(u8 *)&param, 4);
return ret; return ret;
} }
...@@ -1209,10 +1179,7 @@ static int ath6kl_upload_otp(struct ath6kl *ar) ...@@ -1209,10 +1179,7 @@ static int ath6kl_upload_otp(struct ath6kl *ar)
} }
/* read firmware start address */ /* read firmware start address */
ret = ath6kl_bmi_read(ar, ret = ath6kl_bmi_read_hi32(ar, hi_app_start, &address);
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_app_start)),
(u8 *) &address, sizeof(address));
if (ret) { if (ret) {
ath6kl_err("Failed to read hi_app_start: %d\n", ret); ath6kl_err("Failed to read hi_app_start: %d\n", ret);
...@@ -1270,7 +1237,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar) ...@@ -1270,7 +1237,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar)
static int ath6kl_upload_patch(struct ath6kl *ar) static int ath6kl_upload_patch(struct ath6kl *ar)
{ {
u32 address, param; u32 address;
int ret; int ret;
if (ar->fw_patch == NULL) if (ar->fw_patch == NULL)
...@@ -1287,18 +1254,14 @@ static int ath6kl_upload_patch(struct ath6kl *ar) ...@@ -1287,18 +1254,14 @@ static int ath6kl_upload_patch(struct ath6kl *ar)
return ret; return ret;
} }
param = address; ath6kl_bmi_write_hi32(ar, hi_dset_list_head, address);
ath6kl_bmi_write(ar,
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_dset_list_head)),
(unsigned char *) &param, 4);
return 0; return 0;
} }
static int ath6kl_upload_testscript(struct ath6kl *ar) static int ath6kl_upload_testscript(struct ath6kl *ar)
{ {
u32 address, param; u32 address;
int ret; int ret;
if (ar->testmode != 2) if (ar->testmode != 2)
...@@ -1310,7 +1273,7 @@ static int ath6kl_upload_testscript(struct ath6kl *ar) ...@@ -1310,7 +1273,7 @@ static int ath6kl_upload_testscript(struct ath6kl *ar)
address = ar->hw.testscript_addr; address = ar->hw.testscript_addr;
ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n", ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n",
address, ar->fw_testscript_len); address, ar->fw_testscript_len);
ret = ath6kl_bmi_write(ar, address, ar->fw_testscript, ret = ath6kl_bmi_write(ar, address, ar->fw_testscript,
ar->fw_testscript_len); ar->fw_testscript_len);
...@@ -1319,23 +1282,9 @@ static int ath6kl_upload_testscript(struct ath6kl *ar) ...@@ -1319,23 +1282,9 @@ static int ath6kl_upload_testscript(struct ath6kl *ar)
return ret; return ret;
} }
param = address; ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address);
ath6kl_bmi_write(ar, ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096);
ath6kl_get_hi_item_addr(ar, ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1);
HI_ITEM(hi_ota_testscript)),
(unsigned char *) &param, 4);
param = 4096;
ath6kl_bmi_write(ar,
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_end_ram_reserve_sz)),
(unsigned char *) &param, 4);
param = 1;
ath6kl_bmi_write(ar,
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_test_apps_related)),
(unsigned char *) &param, 4);
return 0; return 0;
} }
...@@ -1346,7 +1295,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) ...@@ -1346,7 +1295,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
int status = 0; int status = 0;
if (ar->target_type != TARGET_TYPE_AR6003 && if (ar->target_type != TARGET_TYPE_AR6003 &&
ar->target_type != TARGET_TYPE_AR6004) ar->target_type != TARGET_TYPE_AR6004)
return -EINVAL; return -EINVAL;
/* temporarily disable system sleep */ /* temporarily disable system sleep */
...@@ -1403,7 +1352,8 @@ static int ath6kl_init_upload(struct ath6kl *ar) ...@@ -1403,7 +1352,8 @@ static int ath6kl_init_upload(struct ath6kl *ar)
return status; return status;
/* WAR to avoid SDIO CRC err */ /* WAR to avoid SDIO CRC err */
if (ar->version.target_ver == AR6003_HW_2_0_VERSION) { if (ar->version.target_ver == AR6003_HW_2_0_VERSION ||
ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
ath6kl_err("temporary war to avoid sdio crc error\n"); ath6kl_err("temporary war to avoid sdio crc error\n");
param = 0x20; param = 0x20;
...@@ -1726,9 +1676,11 @@ void ath6kl_stop_txrx(struct ath6kl *ar) ...@@ -1726,9 +1676,11 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
* configure NOT to reset the target during a debug session. * configure NOT to reset the target during a debug session.
*/ */
ath6kl_dbg(ATH6KL_DBG_TRC, ath6kl_dbg(ATH6KL_DBG_TRC,
"attempting to reset target on instance destroy\n"); "attempting to reset target on instance destroy\n");
ath6kl_reset_device(ar, ar->target_type, true, true); ath6kl_reset_device(ar, ar->target_type, true, true);
clear_bit(WLAN_ENABLED, &ar->flag); clear_bit(WLAN_ENABLED, &ar->flag);
up(&ar->sem);
} }
EXPORT_SYMBOL(ath6kl_stop_txrx); EXPORT_SYMBOL(ath6kl_stop_txrx);
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -80,11 +81,21 @@ static void ath6kl_add_new_sta(struct ath6kl_vif *vif, u8 *mac, u16 aid, ...@@ -80,11 +81,21 @@ static void ath6kl_add_new_sta(struct ath6kl_vif *vif, u8 *mac, u16 aid,
static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
{ {
struct ath6kl_sta *sta = &ar->sta_list[i]; struct ath6kl_sta *sta = &ar->sta_list[i];
struct ath6kl_mgmt_buff *entry, *tmp;
/* empty the queued pkts in the PS queue if any */ /* empty the queued pkts in the PS queue if any */
spin_lock_bh(&sta->psq_lock); spin_lock_bh(&sta->psq_lock);
skb_queue_purge(&sta->psq); skb_queue_purge(&sta->psq);
skb_queue_purge(&sta->apsdq); skb_queue_purge(&sta->apsdq);
if (sta->mgmt_psq_len != 0) {
list_for_each_entry_safe(entry, tmp, &sta->mgmt_psq, list) {
kfree(entry);
}
INIT_LIST_HEAD(&sta->mgmt_psq);
sta->mgmt_psq_len = 0;
}
spin_unlock_bh(&sta->psq_lock); spin_unlock_bh(&sta->psq_lock);
memset(&ar->ap_stats.sta[sta->aid - 1], 0, memset(&ar->ap_stats.sta[sta->aid - 1], 0,
...@@ -339,7 +350,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, ...@@ -339,7 +350,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
__le32 data; __le32 data;
if (target_type != TARGET_TYPE_AR6003 && if (target_type != TARGET_TYPE_AR6003 &&
target_type != TARGET_TYPE_AR6004) target_type != TARGET_TYPE_AR6004)
return; return;
data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) : data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) :
...@@ -588,11 +599,9 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, ...@@ -588,11 +599,9 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
memcpy(vif->bssid, bssid, sizeof(vif->bssid)); memcpy(vif->bssid, bssid, sizeof(vif->bssid));
vif->bss_ch = channel; vif->bss_ch = channel;
if ((vif->nw_type == INFRA_NETWORK)) { if ((vif->nw_type == INFRA_NETWORK))
ar->listen_intvl_b = listen_int;
ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
0, ar->listen_intvl_b); vif->listen_intvl_t, 0);
}
netif_wake_queue(vif->ndev); netif_wake_queue(vif->ndev);
...@@ -810,6 +819,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) ...@@ -810,6 +819,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid)
struct sk_buff *skb; struct sk_buff *skb;
bool psq_empty = false; bool psq_empty = false;
struct ath6kl *ar = vif->ar; struct ath6kl *ar = vif->ar;
struct ath6kl_mgmt_buff *mgmt_buf;
conn = ath6kl_find_sta_by_aid(ar, aid); conn = ath6kl_find_sta_by_aid(ar, aid);
...@@ -820,7 +830,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) ...@@ -820,7 +830,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid)
* becomes empty update the PVB for this station. * becomes empty update the PVB for this station.
*/ */
spin_lock_bh(&conn->psq_lock); spin_lock_bh(&conn->psq_lock);
psq_empty = skb_queue_empty(&conn->psq); psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0);
spin_unlock_bh(&conn->psq_lock); spin_unlock_bh(&conn->psq_lock);
if (psq_empty) if (psq_empty)
...@@ -828,15 +838,31 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) ...@@ -828,15 +838,31 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid)
return; return;
spin_lock_bh(&conn->psq_lock); spin_lock_bh(&conn->psq_lock);
skb = skb_dequeue(&conn->psq); if (conn->mgmt_psq_len > 0) {
spin_unlock_bh(&conn->psq_lock); mgmt_buf = list_first_entry(&conn->mgmt_psq,
struct ath6kl_mgmt_buff, list);
list_del(&mgmt_buf->list);
conn->mgmt_psq_len--;
spin_unlock_bh(&conn->psq_lock);
conn->sta_flags |= STA_PS_POLLED;
ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx,
mgmt_buf->id, mgmt_buf->freq,
mgmt_buf->wait, mgmt_buf->buf,
mgmt_buf->len, mgmt_buf->no_cck);
conn->sta_flags &= ~STA_PS_POLLED;
kfree(mgmt_buf);
} else {
skb = skb_dequeue(&conn->psq);
spin_unlock_bh(&conn->psq_lock);
conn->sta_flags |= STA_PS_POLLED; conn->sta_flags |= STA_PS_POLLED;
ath6kl_data_tx(skb, vif->ndev); ath6kl_data_tx(skb, vif->ndev);
conn->sta_flags &= ~STA_PS_POLLED; conn->sta_flags &= ~STA_PS_POLLED;
}
spin_lock_bh(&conn->psq_lock); spin_lock_bh(&conn->psq_lock);
psq_empty = skb_queue_empty(&conn->psq); psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0);
spin_unlock_bh(&conn->psq_lock); spin_unlock_bh(&conn->psq_lock);
if (psq_empty) if (psq_empty)
...@@ -922,8 +948,8 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, ...@@ -922,8 +948,8 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
} }
ath6kl_cfg80211_disconnect_event(vif, reason, bssid, ath6kl_cfg80211_disconnect_event(vif, reason, bssid,
assoc_resp_len, assoc_info, assoc_resp_len, assoc_info,
prot_reason_status); prot_reason_status);
aggr_reset_state(vif->aggr_cntxt->aggr_conn); aggr_reset_state(vif->aggr_cntxt->aggr_conn);
...@@ -943,9 +969,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, ...@@ -943,9 +969,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
} else { } else {
set_bit(CONNECT_PEND, &vif->flags); set_bit(CONNECT_PEND, &vif->flags);
if (((reason == ASSOC_FAILED) && if (((reason == ASSOC_FAILED) &&
(prot_reason_status == 0x11)) || (prot_reason_status == 0x11)) ||
((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) &&
&& (vif->reconnect_flag == 1))) { (vif->reconnect_flag == 1))) {
set_bit(CONNECTED, &vif->flags); set_bit(CONNECTED, &vif->flags);
return; return;
} }
...@@ -1079,7 +1105,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) ...@@ -1079,7 +1105,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
if (mc_all_on || mc_all_off) { if (mc_all_on || mc_all_off) {
/* Enable/disable all multicast */ /* Enable/disable all multicast */
ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n",
mc_all_on ? "enabling" : "disabling"); mc_all_on ? "enabling" : "disabling");
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
mc_all_on); mc_all_on);
if (ret) if (ret)
...@@ -1092,7 +1118,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) ...@@ -1092,7 +1118,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
found = false; found = false;
netdev_for_each_mc_addr(ha, ndev) { netdev_for_each_mc_addr(ha, ndev) {
if (memcmp(ha->addr, mc_filter->hw_addr, if (memcmp(ha->addr, mc_filter->hw_addr,
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
found = true; found = true;
break; break;
} }
...@@ -1111,7 +1137,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) ...@@ -1111,7 +1137,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
false); false);
if (ret) { if (ret) {
ath6kl_warn("Failed to remove multicast filter:%pM\n", ath6kl_warn("Failed to remove multicast filter:%pM\n",
mc_filter->hw_addr); mc_filter->hw_addr);
return; return;
} }
...@@ -1126,7 +1152,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) ...@@ -1126,7 +1152,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
found = false; found = false;
list_for_each_entry(mc_filter, &vif->mc_filter, list) { list_for_each_entry(mc_filter, &vif->mc_filter, list) {
if (memcmp(ha->addr, mc_filter->hw_addr, if (memcmp(ha->addr, mc_filter->hw_addr,
ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
found = true; found = true;
break; break;
} }
...@@ -1151,7 +1177,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) ...@@ -1151,7 +1177,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
true); true);
if (ret) { if (ret) {
ath6kl_warn("Failed to add multicast filter :%pM\n", ath6kl_warn("Failed to add multicast filter :%pM\n",
mc_filter->hw_addr); mc_filter->hw_addr);
kfree(mc_filter); kfree(mc_filter);
goto out; goto out;
} }
...@@ -1184,5 +1210,7 @@ void init_netdev(struct net_device *dev) ...@@ -1184,5 +1210,7 @@ void init_netdev(struct net_device *dev)
sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH
+ WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES; + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES;
dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
return; return;
} }
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -31,6 +32,7 @@ ...@@ -31,6 +32,7 @@
struct ath6kl_sdio { struct ath6kl_sdio {
struct sdio_func *func; struct sdio_func *func;
/* protects access to bus_req_freeq */
spinlock_t lock; spinlock_t lock;
/* free list */ /* free list */
...@@ -49,16 +51,20 @@ struct ath6kl_sdio { ...@@ -49,16 +51,20 @@ struct ath6kl_sdio {
/* scatter request list head */ /* scatter request list head */
struct list_head scat_req; struct list_head scat_req;
/* Avoids disabling irq while the interrupts being handled */ atomic_t irq_handling;
struct mutex mtx_irq; wait_queue_head_t irq_wq;
/* protects access to scat_req */
spinlock_t scat_lock; spinlock_t scat_lock;
bool scatter_enabled; bool scatter_enabled;
bool is_disabled; bool is_disabled;
const struct sdio_device_id *id; const struct sdio_device_id *id;
struct work_struct wr_async_work; struct work_struct wr_async_work;
struct list_head wr_asyncq; struct list_head wr_asyncq;
/* protects access to wr_asyncq */
spinlock_t wr_async_lock; spinlock_t wr_async_lock;
}; };
...@@ -404,7 +410,10 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, ...@@ -404,7 +410,10 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
return -ENOMEM; return -ENOMEM;
mutex_lock(&ar_sdio->dma_buffer_mutex); mutex_lock(&ar_sdio->dma_buffer_mutex);
tbuf = ar_sdio->dma_buffer; tbuf = ar_sdio->dma_buffer;
memcpy(tbuf, buf, len);
if (request & HIF_WRITE)
memcpy(tbuf, buf, len);
bounced = true; bounced = true;
} else } else
tbuf = buf; tbuf = buf;
...@@ -462,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) ...@@ -462,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");
ar_sdio = sdio_get_drvdata(func); ar_sdio = sdio_get_drvdata(func);
mutex_lock(&ar_sdio->mtx_irq); atomic_set(&ar_sdio->irq_handling, 1);
/* /*
* Release the host during interrups so we can pick it back up when * Release the host during interrups so we can pick it back up when
* we process commands. * we process commands.
...@@ -471,7 +480,10 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) ...@@ -471,7 +480,10 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); status = ath6kl_hif_intr_bh_handler(ar_sdio->ar);
sdio_claim_host(ar_sdio->func); sdio_claim_host(ar_sdio->func);
mutex_unlock(&ar_sdio->mtx_irq);
atomic_set(&ar_sdio->irq_handling, 0);
wake_up(&ar_sdio->irq_wq);
WARN_ON(status && status != -ECANCELED); WARN_ON(status && status != -ECANCELED);
} }
...@@ -572,6 +584,13 @@ static void ath6kl_sdio_irq_enable(struct ath6kl *ar) ...@@ -572,6 +584,13 @@ static void ath6kl_sdio_irq_enable(struct ath6kl *ar)
sdio_release_host(ar_sdio->func); sdio_release_host(ar_sdio->func);
} }
static bool ath6kl_sdio_is_on_irq(struct ath6kl *ar)
{
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
return !atomic_read(&ar_sdio->irq_handling);
}
static void ath6kl_sdio_irq_disable(struct ath6kl *ar) static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
{ {
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
...@@ -579,14 +598,21 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar) ...@@ -579,14 +598,21 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
sdio_claim_host(ar_sdio->func); sdio_claim_host(ar_sdio->func);
mutex_lock(&ar_sdio->mtx_irq); if (atomic_read(&ar_sdio->irq_handling)) {
sdio_release_host(ar_sdio->func);
ret = wait_event_interruptible(ar_sdio->irq_wq,
ath6kl_sdio_is_on_irq(ar));
if (ret)
return;
sdio_claim_host(ar_sdio->func);
}
ret = sdio_release_irq(ar_sdio->func); ret = sdio_release_irq(ar_sdio->func);
if (ret) if (ret)
ath6kl_err("Failed to release sdio irq: %d\n", ret); ath6kl_err("Failed to release sdio irq: %d\n", ret);
mutex_unlock(&ar_sdio->mtx_irq);
sdio_release_host(ar_sdio->func); sdio_release_host(ar_sdio->func);
} }
...@@ -601,6 +627,8 @@ static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar) ...@@ -601,6 +627,8 @@ static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar)
node = list_first_entry(&ar_sdio->scat_req, node = list_first_entry(&ar_sdio->scat_req,
struct hif_scatter_req, list); struct hif_scatter_req, list);
list_del(&node->list); list_del(&node->list);
node->scat_q_depth = get_queue_depth(&ar_sdio->scat_req);
} }
spin_unlock_bh(&ar_sdio->scat_lock); spin_unlock_bh(&ar_sdio->scat_lock);
...@@ -633,8 +661,8 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar, ...@@ -633,8 +661,8 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,
return -EINVAL; return -EINVAL;
ath6kl_dbg(ATH6KL_DBG_SCATTER, ath6kl_dbg(ATH6KL_DBG_SCATTER,
"hif-scatter: total len: %d scatter entries: %d\n", "hif-scatter: total len: %d scatter entries: %d\n",
scat_req->len, scat_req->scat_entries); scat_req->len, scat_req->scat_entries);
if (request & HIF_SYNCHRONOUS) if (request & HIF_SYNCHRONOUS)
status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest);
...@@ -813,6 +841,7 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) ...@@ -813,6 +841,7 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
struct sdio_func *func = ar_sdio->func; struct sdio_func *func = ar_sdio->func;
mmc_pm_flag_t flags; mmc_pm_flag_t flags;
bool try_deepsleep = false;
int ret; int ret;
if (ar->state == ATH6KL_STATE_SCHED_SCAN) { if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
...@@ -839,14 +868,22 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) ...@@ -839,14 +868,22 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
goto cut_pwr; goto cut_pwr;
ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
if (ret) if (ret && ret != -ENOTCONN)
ath6kl_err("wow suspend failed: %d\n", ret);
if (ret &&
(!ar->wow_suspend_mode ||
ar->wow_suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP))
try_deepsleep = true;
else if (ret &&
ar->wow_suspend_mode == WLAN_POWER_STATE_CUT_PWR)
goto cut_pwr; goto cut_pwr;
if (!ret)
return 0; return 0;
} }
if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP || if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP ||
!ar->suspend_mode) { !ar->suspend_mode || try_deepsleep) {
flags = sdio_get_host_pm_caps(func); flags = sdio_get_host_pm_caps(func);
if (!(flags & MMC_PM_KEEP_POWER)) if (!(flags & MMC_PM_KEEP_POWER))
...@@ -901,8 +938,15 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) ...@@ -901,8 +938,15 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
case ATH6KL_STATE_WOW: case ATH6KL_STATE_WOW:
break; break;
case ATH6KL_STATE_SCHED_SCAN: case ATH6KL_STATE_SCHED_SCAN:
break; break;
case ATH6KL_STATE_SUSPENDING:
break;
case ATH6KL_STATE_RESUMING:
break;
} }
ath6kl_cfg80211_resume(ar); ath6kl_cfg80211_resume(ar);
...@@ -981,7 +1025,7 @@ static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data) ...@@ -981,7 +1025,7 @@ static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
(u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC); (u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC);
if (status) { if (status) {
ath6kl_err("%s: failed to read from window data addr\n", ath6kl_err("%s: failed to read from window data addr\n",
__func__); __func__);
return status; return status;
} }
...@@ -1285,7 +1329,6 @@ static int ath6kl_sdio_probe(struct sdio_func *func, ...@@ -1285,7 +1329,6 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
spin_lock_init(&ar_sdio->scat_lock); spin_lock_init(&ar_sdio->scat_lock);
spin_lock_init(&ar_sdio->wr_async_lock); spin_lock_init(&ar_sdio->wr_async_lock);
mutex_init(&ar_sdio->dma_buffer_mutex); mutex_init(&ar_sdio->dma_buffer_mutex);
mutex_init(&ar_sdio->mtx_irq);
INIT_LIST_HEAD(&ar_sdio->scat_req); INIT_LIST_HEAD(&ar_sdio->scat_req);
INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
...@@ -1293,6 +1336,8 @@ static int ath6kl_sdio_probe(struct sdio_func *func, ...@@ -1293,6 +1336,8 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work); INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work);
init_waitqueue_head(&ar_sdio->irq_wq);
for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) for (count = 0; count < BUS_REQUEST_MAX_NUM; count++)
ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]);
......
/* /*
* Copyright (c) 2004-2010 Atheros Communications Inc. * Copyright (c) 2004-2010 Atheros Communications Inc.
* Copyright (c) 2011 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
#define AR6003_BOARD_DATA_SZ 1024 #define AR6003_BOARD_DATA_SZ 1024
#define AR6003_BOARD_EXT_DATA_SZ 768 #define AR6003_BOARD_EXT_DATA_SZ 768
#define AR6003_BOARD_EXT_DATA_SZ_V2 1024
#define AR6004_BOARD_DATA_SZ 6144 #define AR6004_BOARD_DATA_SZ 6144
#define AR6004_BOARD_EXT_DATA_SZ 0 #define AR6004_BOARD_EXT_DATA_SZ 0
......
/* /*
* Copyright (c) 2010-2011 Atheros Communications Inc. * Copyright (c) 2010-2011 Atheros Communications Inc.
* Copyright (c) 2011 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
......
/* /*
* Copyright (c) 2010-2011 Atheros Communications Inc. * Copyright (c) 2010-2011 Atheros Communications Inc.
* Copyright (c) 2011 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -158,8 +159,8 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn, ...@@ -158,8 +159,8 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn,
*/ */
if (is_apsdq_empty) { if (is_apsdq_empty) {
ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi,
vif->fw_vif_idx, vif->fw_vif_idx,
conn->aid, 1, 0); conn->aid, 1, 0);
} }
*flags |= WMI_DATA_HDR_FLAGS_UAPSD; *flags |= WMI_DATA_HDR_FLAGS_UAPSD;
...@@ -284,6 +285,9 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, ...@@ -284,6 +285,9 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
int status = 0; int status = 0;
struct ath6kl_cookie *cookie = NULL; struct ath6kl_cookie *cookie = NULL;
if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW))
return -EACCES;
spin_lock_bh(&ar->lock); spin_lock_bh(&ar->lock);
ath6kl_dbg(ATH6KL_DBG_WLAN_TX, ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
...@@ -359,6 +363,11 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -359,6 +363,11 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) {
dev_kfree_skb(skb);
return 0;
}
if (!test_bit(WMI_READY, &ar->flag)) if (!test_bit(WMI_READY, &ar->flag))
goto fail_tx; goto fail_tx;
...@@ -370,7 +379,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -370,7 +379,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
if (test_bit(WMI_ENABLED, &ar->flag)) { if (test_bit(WMI_ENABLED, &ar->flag)) {
if ((dev->features & NETIF_F_IP_CSUM) && if ((dev->features & NETIF_F_IP_CSUM) &&
(csum == CHECKSUM_PARTIAL)) { (csum == CHECKSUM_PARTIAL)) {
csum_start = skb->csum_start - csum_start = skb->csum_start -
(skb_network_header(skb) - skb->head) + (skb_network_header(skb) - skb->head) +
sizeof(struct ath6kl_llc_snap_hdr); sizeof(struct ath6kl_llc_snap_hdr);
...@@ -394,7 +403,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -394,7 +403,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
} }
if ((dev->features & NETIF_F_IP_CSUM) && if ((dev->features & NETIF_F_IP_CSUM) &&
(csum == CHECKSUM_PARTIAL)) { (csum == CHECKSUM_PARTIAL)) {
meta_v2.csum_start = csum_start; meta_v2.csum_start = csum_start;
meta_v2.csum_dest = csum_dest; meta_v2.csum_dest = csum_dest;
...@@ -419,7 +428,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -419,7 +428,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
} }
if ((vif->nw_type == ADHOC_NETWORK) && if ((vif->nw_type == ADHOC_NETWORK) &&
ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags)) ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags))
chk_adhoc_ps_mapping = true; chk_adhoc_ps_mapping = true;
else { else {
/* get the stream mapping */ /* get the stream mapping */
...@@ -593,7 +602,8 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, ...@@ -593,7 +602,8 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
*/ */
if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] < if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] <
ar->hiac_stream_active_pri && ar->hiac_stream_active_pri &&
ar->cookie_count <= MAX_HI_COOKIE_NUM) ar->cookie_count <=
target->endpoint[endpoint].tx_drop_packet_threshold)
/* /*
* Give preference to the highest priority stream by * Give preference to the highest priority stream by
* dropping the packets which overflowed. * dropping the packets which overflowed.
...@@ -876,7 +886,7 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) ...@@ -876,7 +886,7 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
if (!IS_ALIGNED((unsigned long) skb->data, 4)) if (!IS_ALIGNED((unsigned long) skb->data, 4))
skb->data = PTR_ALIGN(skb->data - 4, 4); skb->data = PTR_ALIGN(skb->data - 4, 4);
set_htc_rxpkt_info(packet, skb, skb->data, set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_BUFFER_SIZE, endpoint); ATH6KL_BUFFER_SIZE, endpoint);
list_add_tail(&packet->list, &queue); list_add_tail(&packet->list, &queue);
} }
...@@ -1256,8 +1266,8 @@ static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif, ...@@ -1256,8 +1266,8 @@ static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif,
flags = 0; flags = 0;
ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi,
vif->fw_vif_idx, vif->fw_vif_idx,
conn->aid, 0, flags); conn->aid, 0, flags);
} }
return; return;
...@@ -1296,7 +1306,15 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ...@@ -1296,7 +1306,15 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
skb_put(skb, packet->act_len + HTC_HDR_LENGTH); skb_put(skb, packet->act_len + HTC_HDR_LENGTH);
skb_pull(skb, HTC_HDR_LENGTH); skb_pull(skb, HTC_HDR_LENGTH);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ",
skb->data, skb->len);
if (ept == ar->ctrl_ep) { if (ept == ar->ctrl_ep) {
if (test_bit(WMI_ENABLED, &ar->flag)) {
ath6kl_check_wow_status(ar);
ath6kl_wmi_control_rx(ar->wmi, skb);
return;
}
if_idx = if_idx =
wmi_cmd_hdr_get_if_idx((struct wmi_cmd_hdr *) skb->data); wmi_cmd_hdr_get_if_idx((struct wmi_cmd_hdr *) skb->data);
} else { } else {
...@@ -1321,10 +1339,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ...@@ -1321,10 +1339,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
spin_unlock_bh(&vif->if_lock); spin_unlock_bh(&vif->if_lock);
ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ",
skb->data, skb->len);
skb->dev = vif->ndev; skb->dev = vif->ndev;
if (!test_bit(WMI_ENABLED, &ar->flag)) { if (!test_bit(WMI_ENABLED, &ar->flag)) {
...@@ -1336,11 +1350,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ...@@ -1336,11 +1350,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
ath6kl_check_wow_status(ar); ath6kl_check_wow_status(ar);
if (ept == ar->ctrl_ep) {
ath6kl_wmi_control_rx(ar->wmi, skb);
return;
}
min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) + min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) +
sizeof(struct ath6kl_llc_snap_hdr); sizeof(struct ath6kl_llc_snap_hdr);
...@@ -1416,8 +1425,33 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ...@@ -1416,8 +1425,33 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
if (!(conn->sta_flags & STA_PS_SLEEP)) { if (!(conn->sta_flags & STA_PS_SLEEP)) {
struct sk_buff *skbuff = NULL; struct sk_buff *skbuff = NULL;
bool is_apsdq_empty; bool is_apsdq_empty;
struct ath6kl_mgmt_buff *mgmt;
u8 idx;
spin_lock_bh(&conn->psq_lock); spin_lock_bh(&conn->psq_lock);
while (conn->mgmt_psq_len > 0) {
mgmt = list_first_entry(
&conn->mgmt_psq,
struct ath6kl_mgmt_buff,
list);
list_del(&mgmt->list);
conn->mgmt_psq_len--;
spin_unlock_bh(&conn->psq_lock);
idx = vif->fw_vif_idx;
ath6kl_wmi_send_mgmt_cmd(ar->wmi,
idx,
mgmt->id,
mgmt->freq,
mgmt->wait,
mgmt->buf,
mgmt->len,
mgmt->no_cck);
kfree(mgmt);
spin_lock_bh(&conn->psq_lock);
}
conn->mgmt_psq_len = 0;
while ((skbuff = skb_dequeue(&conn->psq))) { while ((skbuff = skb_dequeue(&conn->psq))) {
spin_unlock_bh(&conn->psq_lock); spin_unlock_bh(&conn->psq_lock);
ath6kl_data_tx(skbuff, vif->ndev); ath6kl_data_tx(skbuff, vif->ndev);
...@@ -1541,7 +1575,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ...@@ -1541,7 +1575,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
aggr_conn = vif->aggr_cntxt->aggr_conn; aggr_conn = vif->aggr_cntxt->aggr_conn;
if (aggr_process_recv_frm(aggr_conn, tid, seq_no, if (aggr_process_recv_frm(aggr_conn, tid, seq_no,
is_amsdu, skb)) { is_amsdu, skb)) {
/* aggregation code will handle the skb */ /* aggregation code will handle the skb */
return; return;
} }
......
/* /*
* Copyright (c) 2007-2011 Atheros Communications Inc. * Copyright (c) 2007-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
......
/* /*
* Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -126,7 +127,7 @@ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb) ...@@ -126,7 +127,7 @@ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)
if (!is_ethertype(be16_to_cpu(type))) { if (!is_ethertype(be16_to_cpu(type))) {
ath6kl_dbg(ATH6KL_DBG_WMI, ath6kl_dbg(ATH6KL_DBG_WMI,
"%s: pkt is already in 802.3 format\n", __func__); "%s: pkt is already in 802.3 format\n", __func__);
return 0; return 0;
} }
...@@ -827,8 +828,8 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, ...@@ -827,8 +828,8 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 && if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&
pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) { pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {
/* WMM OUT (00:50:F2) */ /* WMM OUT (00:50:F2) */
if (pie[1] > 5 if (pie[1] > 5 &&
&& pie[6] == WMM_PARAM_OUI_SUBTYPE) pie[6] == WMM_PARAM_OUI_SUBTYPE)
wmi->is_wmm_enabled = true; wmi->is_wmm_enabled = true;
} }
break; break;
...@@ -912,17 +913,17 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) ...@@ -912,17 +913,17 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
regpair = ath6kl_get_regpair((u16) reg_code); regpair = ath6kl_get_regpair((u16) reg_code);
country = ath6kl_regd_find_country_by_rd((u16) reg_code); country = ath6kl_regd_find_country_by_rd((u16) reg_code);
ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
regpair->regDmnEnum); regpair->regDmnEnum);
} }
if (country) { if (country && wmi->parent_dev->wiphy_registered) {
alpha2[0] = country->isoName[0]; alpha2[0] = country->isoName[0];
alpha2[1] = country->isoName[1]; alpha2[1] = country->isoName[1];
regulatory_hint(wmi->parent_dev->wiphy, alpha2); regulatory_hint(wmi->parent_dev->wiphy, alpha2);
ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n", ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n",
alpha2[0], alpha2[1]); alpha2[0], alpha2[1]);
} }
} }
...@@ -1033,8 +1034,9 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, ...@@ -1033,8 +1034,9 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
if (len < 8 + 2 + 2) if (len < 8 + 2 + 2)
return -EINVAL; return -EINVAL;
if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &vif->flags) if (bih->frame_type == BEACON_FTYPE &&
&& memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) { test_bit(CONNECTED, &vif->flags) &&
memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) {
const u8 *tim; const u8 *tim;
tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2, tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2,
len - 8 - 2 - 2); len - 8 - 2 - 2);
...@@ -1366,8 +1368,8 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, ...@@ -1366,8 +1368,8 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
/* Upper threshold breached */ /* Upper threshold breached */
if (rssi < sq_thresh->upper_threshold[0]) { if (rssi < sq_thresh->upper_threshold[0]) {
ath6kl_dbg(ATH6KL_DBG_WMI, ath6kl_dbg(ATH6KL_DBG_WMI,
"spurious upper rssi threshold event: %d\n", "spurious upper rssi threshold event: %d\n",
rssi); rssi);
} else if ((rssi < sq_thresh->upper_threshold[1]) && } else if ((rssi < sq_thresh->upper_threshold[1]) &&
(rssi >= sq_thresh->upper_threshold[0])) { (rssi >= sq_thresh->upper_threshold[0])) {
new_threshold = WMI_RSSI_THRESHOLD1_ABOVE; new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;
...@@ -1390,7 +1392,7 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, ...@@ -1390,7 +1392,7 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
/* Lower threshold breached */ /* Lower threshold breached */
if (rssi > sq_thresh->lower_threshold[0]) { if (rssi > sq_thresh->lower_threshold[0]) {
ath6kl_dbg(ATH6KL_DBG_WMI, ath6kl_dbg(ATH6KL_DBG_WMI,
"spurious lower rssi threshold event: %d %d\n", "spurious lower rssi threshold event: %d %d\n",
rssi, sq_thresh->lower_threshold[0]); rssi, sq_thresh->lower_threshold[0]);
} else if ((rssi > sq_thresh->lower_threshold[1]) && } else if ((rssi > sq_thresh->lower_threshold[1]) &&
(rssi <= sq_thresh->lower_threshold[0])) { (rssi <= sq_thresh->lower_threshold[0])) {
...@@ -1551,8 +1553,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, ...@@ -1551,8 +1553,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
/* Upper threshold breached */ /* Upper threshold breached */
if (snr < sq_thresh->upper_threshold[0]) { if (snr < sq_thresh->upper_threshold[0]) {
ath6kl_dbg(ATH6KL_DBG_WMI, ath6kl_dbg(ATH6KL_DBG_WMI,
"spurious upper snr threshold event: %d\n", "spurious upper snr threshold event: %d\n",
snr); snr);
} else if ((snr < sq_thresh->upper_threshold[1]) && } else if ((snr < sq_thresh->upper_threshold[1]) &&
(snr >= sq_thresh->upper_threshold[0])) { (snr >= sq_thresh->upper_threshold[0])) {
new_threshold = WMI_SNR_THRESHOLD1_ABOVE; new_threshold = WMI_SNR_THRESHOLD1_ABOVE;
...@@ -1569,8 +1571,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, ...@@ -1569,8 +1571,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
/* Lower threshold breached */ /* Lower threshold breached */
if (snr > sq_thresh->lower_threshold[0]) { if (snr > sq_thresh->lower_threshold[0]) {
ath6kl_dbg(ATH6KL_DBG_WMI, ath6kl_dbg(ATH6KL_DBG_WMI,
"spurious lower snr threshold event: %d\n", "spurious lower snr threshold event: %d\n",
sq_thresh->lower_threshold[0]); sq_thresh->lower_threshold[0]);
} else if ((snr > sq_thresh->lower_threshold[1]) && } else if ((snr > sq_thresh->lower_threshold[1]) &&
(snr <= sq_thresh->lower_threshold[0])) { (snr <= sq_thresh->lower_threshold[0])) {
new_threshold = WMI_SNR_THRESHOLD4_BELOW; new_threshold = WMI_SNR_THRESHOLD4_BELOW;
...@@ -2028,6 +2030,26 @@ int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx, ...@@ -2028,6 +2030,26 @@ int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx,
return ret; return ret;
} }
int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx,
u16 bmiss_time, u16 num_beacons)
{
struct sk_buff *skb;
struct wmi_bmiss_time_cmd *cmd;
int ret;
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_bmiss_time_cmd *) skb->data;
cmd->bmiss_time = cpu_to_le16(bmiss_time);
cmd->num_beacons = cpu_to_le16(num_beacons);
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BMISS_TIME_CMDID,
NO_SYNC_WMIFLAG);
return ret;
}
int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode) int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -2613,7 +2635,7 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, ...@@ -2613,7 +2635,7 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
int ret; int ret;
if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) && if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) &&
wow_mode != ATH6KL_WOW_MODE_DISABLE) { wow_mode != ATH6KL_WOW_MODE_DISABLE) {
ath6kl_err("invalid wow mode: %d\n", wow_mode); ath6kl_err("invalid wow mode: %d\n", wow_mode);
return -EINVAL; return -EINVAL;
} }
...@@ -3014,6 +3036,22 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac, ...@@ -3014,6 +3036,22 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,
NO_SYNC_WMIFLAG); NO_SYNC_WMIFLAG);
} }
int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable)
{
struct sk_buff *skb;
struct wmi_ap_hidden_ssid_cmd *cmd;
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_ap_hidden_ssid_cmd *) skb->data;
cmd->hidden_ssid = enable ? 1 : 0;
return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_HIDDEN_SSID_CMDID,
NO_SYNC_WMIFLAG);
}
/* This command will be used to enable/disable AP uAPSD feature */ /* This command will be used to enable/disable AP uAPSD feature */
int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable) int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable)
{ {
...@@ -3183,8 +3221,9 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur) ...@@ -3183,8 +3221,9 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)
* ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P
* mgmt operations using station interface. * mgmt operations using station interface.
*/ */
int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id,
u32 wait, const u8 *data, u16 data_len) u32 freq, u32 wait, const u8 *data,
u16 data_len)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct wmi_send_action_cmd *p; struct wmi_send_action_cmd *p;
...@@ -3220,9 +3259,9 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, ...@@ -3220,9 +3259,9 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
NO_SYNC_WMIFLAG); NO_SYNC_WMIFLAG);
} }
int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id,
u32 wait, const u8 *data, u16 data_len, u32 freq, u32 wait, const u8 *data,
u32 no_cck) u16 data_len, u32 no_cck)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct wmi_send_mgmt_cmd *p; struct wmi_send_mgmt_cmd *p;
...@@ -3259,6 +3298,32 @@ int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, ...@@ -3259,6 +3298,32 @@ int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
NO_SYNC_WMIFLAG); NO_SYNC_WMIFLAG);
} }
int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
u32 wait, const u8 *data, u16 data_len,
u32 no_cck)
{
int status;
struct ath6kl *ar = wmi->parent_dev;
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
*/
status = __ath6kl_wmi_send_mgmt_cmd(ar->wmi, if_idx, id, freq,
wait, data, data_len,
no_cck);
} else {
status = ath6kl_wmi_send_action_cmd(ar->wmi, if_idx, id, freq,
wait, data, data_len);
}
return status;
}
int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq, int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
const u8 *dst, const u8 *data, const u8 *dst, const u8 *data,
u16 data_len) u16 data_len)
...@@ -3370,32 +3435,101 @@ static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len) ...@@ -3370,32 +3435,101 @@ static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len)
return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len); return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len);
} }
/* Control Path */ /* Process interface specific wmi events, caller would free the datap */
int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,
u8 *datap, u32 len)
{ {
struct wmi_cmd_hdr *cmd;
struct ath6kl_vif *vif; struct ath6kl_vif *vif;
u32 len;
u16 id;
u8 if_idx;
u8 *datap;
int ret = 0;
if (WARN_ON(skb == NULL)) vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx);
if (!vif) {
ath6kl_dbg(ATH6KL_DBG_WMI,
"Wmi event for unavailable vif, vif_index:%d\n",
if_idx);
return -EINVAL; return -EINVAL;
}
if (skb->len < sizeof(struct wmi_cmd_hdr)) { switch (cmd_id) {
ath6kl_err("bad packet 1\n"); case WMI_CONNECT_EVENTID:
dev_kfree_skb(skb); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
return ath6kl_wmi_connect_event_rx(wmi, datap, len, vif);
case WMI_DISCONNECT_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
return ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif);
case WMI_TKIP_MICERR_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
return ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif);
case WMI_BSSINFO_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
return ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif);
case WMI_NEIGHBOR_REPORT_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
return ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,
vif);
case WMI_SCAN_COMPLETE_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
return ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);
case WMI_REPORT_STATISTICS_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
return ath6kl_wmi_stats_event_rx(wmi, datap, len, vif);
case WMI_CAC_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
return ath6kl_wmi_cac_event_rx(wmi, datap, len, vif);
case WMI_PSPOLL_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
return ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif);
case WMI_DTIMEXPIRY_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
return ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif);
case WMI_ADDBA_REQ_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
return ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif);
case WMI_DELBA_REQ_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
return ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif);
case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI,
"WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID");
return ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif);
case WMI_REMAIN_ON_CHNL_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
return ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);
case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI,
"WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
return ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
len, vif);
case WMI_TX_STATUS_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
return ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif);
case WMI_RX_PROBE_REQ_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
return ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif);
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);
default:
ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);
return -EINVAL; return -EINVAL;
} }
return 0;
}
static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd;
int ret = 0;
u32 len;
u16 id;
u8 if_idx;
u8 *datap;
cmd = (struct wmi_cmd_hdr *) skb->data; cmd = (struct wmi_cmd_hdr *) skb->data;
id = le16_to_cpu(cmd->cmd_id); id = le16_to_cpu(cmd->cmd_id);
if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK; if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK;
skb_pull(skb, sizeof(struct wmi_cmd_hdr)); skb_pull(skb, sizeof(struct wmi_cmd_hdr));
datap = skb->data; datap = skb->data;
len = skb->len; len = skb->len;
...@@ -3403,15 +3537,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ...@@ -3403,15 +3537,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ", ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ",
datap, len); datap, len);
vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx);
if (!vif) {
ath6kl_dbg(ATH6KL_DBG_WMI,
"Wmi event for unavailable vif, vif_index:%d\n",
if_idx);
dev_kfree_skb(skb);
return -EINVAL;
}
switch (id) { switch (id) {
case WMI_GET_BITRATE_CMDID: case WMI_GET_BITRATE_CMDID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n");
...@@ -3429,26 +3554,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ...@@ -3429,26 +3554,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n");
ret = ath6kl_wmi_ready_event_rx(wmi, datap, len); ret = ath6kl_wmi_ready_event_rx(wmi, datap, len);
break; break;
case WMI_CONNECT_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
ret = ath6kl_wmi_connect_event_rx(wmi, datap, len, vif);
break;
case WMI_DISCONNECT_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif);
break;
case WMI_PEER_NODE_EVENTID: case WMI_PEER_NODE_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n");
ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len); ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len);
break; break;
case WMI_TKIP_MICERR_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif);
break;
case WMI_BSSINFO_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif);
break;
case WMI_REGDOMAIN_EVENTID: case WMI_REGDOMAIN_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n");
ath6kl_wmi_regdomain_event(wmi, datap, len); ath6kl_wmi_regdomain_event(wmi, datap, len);
...@@ -3457,23 +3566,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ...@@ -3457,23 +3566,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n");
ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len); ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len);
break; break;
case WMI_NEIGHBOR_REPORT_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,
vif);
break;
case WMI_SCAN_COMPLETE_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);
break;
case WMI_CMDERROR_EVENTID: case WMI_CMDERROR_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n");
ret = ath6kl_wmi_error_event_rx(wmi, datap, len); ret = ath6kl_wmi_error_event_rx(wmi, datap, len);
break; break;
case WMI_REPORT_STATISTICS_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
ret = ath6kl_wmi_stats_event_rx(wmi, datap, len, vif);
break;
case WMI_RSSI_THRESHOLD_EVENTID: case WMI_RSSI_THRESHOLD_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n");
ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len); ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len);
...@@ -3493,10 +3589,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ...@@ -3493,10 +3589,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");
ret = ath6kl_wmi_control_rx_xtnd(wmi, skb); ret = ath6kl_wmi_control_rx_xtnd(wmi, skb);
break; break;
case WMI_CAC_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
ret = ath6kl_wmi_cac_event_rx(wmi, datap, len, vif);
break;
case WMI_CHANNEL_CHANGE_EVENTID: case WMI_CHANNEL_CHANGE_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n");
break; break;
...@@ -3536,28 +3628,12 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ...@@ -3536,28 +3628,12 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");
ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len); ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len);
break; break;
case WMI_PSPOLL_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif);
break;
case WMI_DTIMEXPIRY_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif);
break;
case WMI_SET_PARAMS_REPLY_EVENTID: case WMI_SET_PARAMS_REPLY_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n");
break; break;
case WMI_ADDBA_REQ_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif);
break;
case WMI_ADDBA_RESP_EVENTID: case WMI_ADDBA_RESP_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n");
break; break;
case WMI_DELBA_REQ_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif);
break;
case WMI_REPORT_BTCOEX_CONFIG_EVENTID: case WMI_REPORT_BTCOEX_CONFIG_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, ath6kl_dbg(ATH6KL_DBG_WMI,
"WMI_REPORT_BTCOEX_CONFIG_EVENTID\n"); "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n");
...@@ -3570,52 +3646,39 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ...@@ -3570,52 +3646,39 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
ret = ath6kl_wmi_tx_complete_event_rx(datap, len); ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
break; break;
case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI,
"WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID");
ret = ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif);
break;
case WMI_REMAIN_ON_CHNL_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);
break;
case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI,
"WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
len, vif);
break;
case WMI_TX_STATUS_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif);
break;
case WMI_RX_PROBE_REQ_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif);
break;
case WMI_P2P_CAPABILITIES_EVENTID: case WMI_P2P_CAPABILITIES_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n");
ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len); ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len);
break; break;
case WMI_RX_ACTION_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
break;
case WMI_P2P_INFO_EVENTID: case WMI_P2P_INFO_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n"); ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n");
ret = ath6kl_wmi_p2p_info_event_rx(datap, len); ret = ath6kl_wmi_p2p_info_event_rx(datap, len);
break; break;
default: default:
ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id); /* may be the event is interface specific */
ret = -EINVAL; ret = ath6kl_wmi_proc_events_vif(wmi, if_idx, id, datap, len);
break; break;
} }
dev_kfree_skb(skb); dev_kfree_skb(skb);
return ret; return ret;
} }
/* Control Path */
int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
{
if (WARN_ON(skb == NULL))
return -EINVAL;
if (skb->len < sizeof(struct wmi_cmd_hdr)) {
ath6kl_err("bad packet 1\n");
dev_kfree_skb(skb);
return -EINVAL;
}
return ath6kl_wmi_proc_events(wmi, skb);
}
void ath6kl_wmi_reset(struct wmi *wmi) void ath6kl_wmi_reset(struct wmi *wmi)
{ {
spin_lock_bh(&wmi->lock); spin_lock_bh(&wmi->lock);
......
/* /*
* Copyright (c) 2010-2011 Atheros Communications Inc. * Copyright (c) 2010-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -110,6 +111,8 @@ struct wmi { ...@@ -110,6 +111,8 @@ struct wmi {
u8 fat_pipe_exist; u8 fat_pipe_exist;
struct ath6kl *parent_dev; struct ath6kl *parent_dev;
u8 pwr_mode; u8 pwr_mode;
/* protects fat_pipe_exist and stream_exist_for_ac */
spinlock_t lock; spinlock_t lock;
enum htc_endpoint_id ep_id; enum htc_endpoint_id ep_id;
struct sq_threshold_params struct sq_threshold_params
...@@ -997,6 +1000,12 @@ struct wmi_listen_int_cmd { ...@@ -997,6 +1000,12 @@ struct wmi_listen_int_cmd {
__le16 num_beacons; __le16 num_beacons;
} __packed; } __packed;
/* WMI_SET_BMISS_TIME_CMDID */
struct wmi_bmiss_time_cmd {
__le16 bmiss_time;
__le16 num_beacons;
};
/* WMI_SET_POWER_MODE_CMDID */ /* WMI_SET_POWER_MODE_CMDID */
enum wmi_power_mode { enum wmi_power_mode {
REC_POWER = 0x01, REC_POWER = 0x01,
...@@ -1014,7 +1023,7 @@ struct wmi_power_mode_cmd { ...@@ -1014,7 +1023,7 @@ struct wmi_power_mode_cmd {
*/ */
enum power_save_fail_event_policy { enum power_save_fail_event_policy {
SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1, SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1,
IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2, IGNORE_PS_FAIL_DURING_SCAN = 2,
}; };
struct wmi_power_params_cmd { struct wmi_power_params_cmd {
...@@ -1212,7 +1221,7 @@ struct wmi_snr_threshold_params_cmd { ...@@ -1212,7 +1221,7 @@ struct wmi_snr_threshold_params_cmd {
enum wmi_preamble_policy { enum wmi_preamble_policy {
WMI_IGNORE_BARKER_IN_ERP = 0, WMI_IGNORE_BARKER_IN_ERP = 0,
WMI_DONOT_IGNORE_BARKER_IN_ERP WMI_FOLLOW_BARKER_IN_ERP,
}; };
struct wmi_set_lpreamble_cmd { struct wmi_set_lpreamble_cmd {
...@@ -2128,6 +2137,10 @@ struct wmi_rx_frame_format_cmd { ...@@ -2128,6 +2137,10 @@ struct wmi_rx_frame_format_cmd {
u8 reserved[1]; u8 reserved[1];
} __packed; } __packed;
struct wmi_ap_hidden_ssid_cmd {
u8 hidden_ssid;
} __packed;
/* AP mode events */ /* AP mode events */
struct wmi_ap_set_apsd_cmd { struct wmi_ap_set_apsd_cmd {
u8 enable; u8 enable;
...@@ -2413,6 +2426,8 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag, ...@@ -2413,6 +2426,8 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag,
int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx,
u16 listen_interval, u16 listen_interval,
u16 listen_beacons); u16 listen_beacons);
int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx,
u16 bmiss_time, u16 num_beacons);
int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode); int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode);
int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u8 if_idx, u16 idle_period, int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u8 if_idx, u16 idle_period,
u16 ps_poll_num, u16 dtim_policy, u16 ps_poll_num, u16 dtim_policy,
...@@ -2484,6 +2499,7 @@ u8 ath6kl_wmi_get_traffic_class(u8 user_priority); ...@@ -2484,6 +2499,7 @@ u8 ath6kl_wmi_get_traffic_class(u8 user_priority);
u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri); u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri);
/* AP mode */ /* AP mode */
int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable);
int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx, int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx,
struct wmi_connect_cmd *p); struct wmi_connect_cmd *p);
...@@ -2505,9 +2521,6 @@ int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); ...@@ -2505,9 +2521,6 @@ int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable);
int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
u32 dur); u32 dur);
int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
u32 wait, const u8 *data, u16 data_len);
int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
u32 wait, const u8 *data, u16 data_len, u32 wait, const u8 *data, u16 data_len,
u32 no_cck); u32 no_cck);
......
...@@ -834,9 +834,10 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, ...@@ -834,9 +834,10 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
AR_SREV_9287_11_OR_LATER(ah)) AR_SREV_9287_11_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
if (AR_SREV_9271_10(ah)) if (AR_SREV_9271_10(ah)) {
REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only, REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENA);
modesIndex, regWrites); REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_ADC_ON, 0xa);
}
ENABLE_REGWRITE_BUFFER(ah); ENABLE_REGWRITE_BUFFER(ah);
...@@ -858,21 +859,11 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, ...@@ -858,21 +859,11 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
REGWRITE_BUFFER_FLUSH(ah); REGWRITE_BUFFER_FLUSH(ah);
if (AR_SREV_9271(ah)) {
if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1)
REG_WRITE_ARRAY(&ah->iniModes_high_power_tx_gain_9271,
modesIndex, regWrites);
else
REG_WRITE_ARRAY(&ah->iniModes_normal_power_tx_gain_9271,
modesIndex, regWrites);
}
REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites);
if (IS_CHAN_A_FAST_CLOCK(ah, chan)) { if (IS_CHAN_A_FAST_CLOCK(ah, chan))
REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, REG_WRITE_ARRAY(&ah->iniModesFastClock, modesIndex,
regWrites); regWrites);
}
ar5008_hw_override_ini(ah, chan); ar5008_hw_override_ini(ah, chan);
ar5008_hw_set_channel_regs(ah, chan); ar5008_hw_set_channel_regs(ah, chan);
......
...@@ -34,23 +34,8 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ...@@ -34,23 +34,8 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
ARRAY_SIZE(ar9271Modes_9271), 5); ARRAY_SIZE(ar9271Modes_9271), 5);
INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271,
ARRAY_SIZE(ar9271Common_9271), 2); ARRAY_SIZE(ar9271Common_9271), 2);
INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271,
ar9287Common_normal_cck_fir_coeff_9287_1_1,
ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_9287_1_1), 2);
INIT_INI_ARRAY(&ah->iniCommon_japan_2484_cck_fir_coeff_9271,
ar9287Common_japan_2484_cck_fir_coeff_9287_1_1,
ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_9287_1_1), 2);
INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only,
ar9271Modes_9271_1_0_only,
ARRAY_SIZE(ar9271Modes_9271_1_0_only), 5);
INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg, INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg,
ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 5); ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 5);
INIT_INI_ARRAY(&ah->iniModes_high_power_tx_gain_9271,
ar9271Modes_high_power_tx_gain_9271,
ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 5);
INIT_INI_ARRAY(&ah->iniModes_normal_power_tx_gain_9271,
ar9271Modes_normal_power_tx_gain_9271,
ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 5);
return; return;
} }
...@@ -79,7 +64,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ...@@ -79,7 +64,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2,
ARRAY_SIZE(ar9280Common_9280_2), 2); ARRAY_SIZE(ar9280Common_9280_2), 2);
INIT_INI_ARRAY(&ah->iniModesAdditional, INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9280Modes_fast_clock_9280_2, ar9280Modes_fast_clock_9280_2,
ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
} else if (AR_SREV_9160_10_OR_LATER(ah)) { } else if (AR_SREV_9160_10_OR_LATER(ah)) {
...@@ -160,11 +145,6 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ...@@ -160,11 +145,6 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
INI_RA(addac, 31,1) = 0; INI_RA(addac, 31,1) = 0;
} }
} }
}
/* Support for Japan ch.14 (2484) spread */
void ar9002_hw_cck_chan14_spread(struct ath_hw *ah)
{
if (AR_SREV_9287_11_OR_LATER(ah)) { if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniCckfirNormal, INIT_INI_ARRAY(&ah->iniCckfirNormal,
ar9287Common_normal_cck_fir_coeff_9287_1_1, ar9287Common_normal_cck_fir_coeff_9287_1_1,
...@@ -204,14 +184,10 @@ static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah) ...@@ -204,14 +184,10 @@ static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
} }
} }
static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah) static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type)
{ {
u32 txgain_type;
if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >=
AR5416_EEP_MINOR_VER_19) { AR5416_EEP_MINOR_VER_19) {
txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
INIT_INI_ARRAY(&ah->iniModesTxGain, INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9280Modes_high_power_tx_gain_9280_2, ar9280Modes_high_power_tx_gain_9280_2,
...@@ -227,8 +203,22 @@ static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah) ...@@ -227,8 +203,22 @@ static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah)
} }
} }
static void ar9271_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type)
{
if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9271Modes_high_power_tx_gain_9271,
ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 5);
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9271Modes_normal_power_tx_gain_9271,
ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 5);
}
static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
{ {
u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
if (AR_SREV_9287_11_OR_LATER(ah)) if (AR_SREV_9287_11_OR_LATER(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain, INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9287Modes_rx_gain_9287_1_1, ar9287Modes_rx_gain_9287_1_1,
...@@ -236,15 +226,15 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) ...@@ -236,15 +226,15 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
else if (AR_SREV_9280_20(ah)) else if (AR_SREV_9280_20(ah))
ar9280_20_hw_init_rxgain_ini(ah); ar9280_20_hw_init_rxgain_ini(ah);
if (AR_SREV_9287_11_OR_LATER(ah)) { if (AR_SREV_9271(ah)) {
ar9271_hw_init_txgain_ini(ah, txgain_type);
} else if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModesTxGain, INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9287Modes_tx_gain_9287_1_1, ar9287Modes_tx_gain_9287_1_1,
ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 5); ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 5);
} else if (AR_SREV_9280_20(ah)) { } else if (AR_SREV_9280_20(ah)) {
ar9280_20_hw_init_txgain_ini(ah); ar9280_20_hw_init_txgain_ini(ah, txgain_type);
} else if (AR_SREV_9285_12_OR_LATER(ah)) { } else if (AR_SREV_9285_12_OR_LATER(ah)) {
u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
/* txgain table */ /* txgain table */
if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) {
if (AR_SREV_9285E_20(ah)) { if (AR_SREV_9285E_20(ah)) {
......
...@@ -3092,12 +3092,6 @@ static const u32 ar9271Common_9271[][2] = { ...@@ -3092,12 +3092,6 @@ static const u32 ar9271Common_9271[][2] = {
{0x0000d384, 0xf3307ff0}, {0x0000d384, 0xf3307ff0},
}; };
static const u32 ar9271Modes_9271_1_0_only[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311},
{0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
};
static const u32 ar9271Modes_9271_ANI_reg[][5] = { static const u32 ar9271Modes_9271_ANI_reg[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2}, {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
......
...@@ -347,15 +347,12 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, ...@@ -347,15 +347,12 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags) u32 size, u32 flags)
{ {
struct ar5416_desc *ads = AR5416DESC(ds); struct ar5416_desc *ads = AR5416DESC(ds);
struct ath9k_hw_capabilities *pCap = &ah->caps;
ads->ds_ctl1 = size & AR_BufLen; ads->ds_ctl1 = size & AR_BufLen;
if (flags & ATH9K_RXDESC_INTREQ) if (flags & ATH9K_RXDESC_INTREQ)
ads->ds_ctl1 |= AR_RxIntrReq; ads->ds_ctl1 |= AR_RxIntrReq;
ads->ds_rxstatus8 &= ~AR_RxDone; memset(&ads->u.rx, 0, sizeof(ads->u.rx));
if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
memset(&(ads->u), 0, sizeof(ads->u));
} }
EXPORT_SYMBOL(ath9k_hw_setuprxdesc); EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
......
...@@ -60,6 +60,8 @@ ...@@ -60,6 +60,8 @@
#define AR_PHY_RF_CTL3 0x9828 #define AR_PHY_RF_CTL3 0x9828
#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 #define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000
#define AR_PHY_TX_END_TO_A2_RX_ON_S 16 #define AR_PHY_TX_END_TO_A2_RX_ON_S 16
#define AR_PHY_TX_END_TO_ADC_ON 0xFF000000
#define AR_PHY_TX_END_TO_ADC_ON_S 24
#define AR_PHY_ADC_CTL 0x982C #define AR_PHY_ADC_CTL 0x982C
#define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003 #define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003
......
...@@ -295,266 +295,6 @@ static const u32 ar9300_2p2_radio_core[][2] = { ...@@ -295,266 +295,6 @@ static const u32 ar9300_2p2_radio_core[][2] = {
{0x00016bd4, 0x00000000}, {0x00016bd4, 0x00000000},
}; };
static const u32 ar9300Common_rx_gain_table_merlin_2p2[][2] = {
/* Addr allmodes */
{0x0000a000, 0x02000101},
{0x0000a004, 0x02000102},
{0x0000a008, 0x02000103},
{0x0000a00c, 0x02000104},
{0x0000a010, 0x02000200},
{0x0000a014, 0x02000201},
{0x0000a018, 0x02000202},
{0x0000a01c, 0x02000203},
{0x0000a020, 0x02000204},
{0x0000a024, 0x02000205},
{0x0000a028, 0x02000208},
{0x0000a02c, 0x02000302},
{0x0000a030, 0x02000303},
{0x0000a034, 0x02000304},
{0x0000a038, 0x02000400},
{0x0000a03c, 0x02010300},
{0x0000a040, 0x02010301},
{0x0000a044, 0x02010302},
{0x0000a048, 0x02000500},
{0x0000a04c, 0x02010400},
{0x0000a050, 0x02020300},
{0x0000a054, 0x02020301},
{0x0000a058, 0x02020302},
{0x0000a05c, 0x02020303},
{0x0000a060, 0x02020400},
{0x0000a064, 0x02030300},
{0x0000a068, 0x02030301},
{0x0000a06c, 0x02030302},
{0x0000a070, 0x02030303},
{0x0000a074, 0x02030400},
{0x0000a078, 0x02040300},
{0x0000a07c, 0x02040301},
{0x0000a080, 0x02040302},
{0x0000a084, 0x02040303},
{0x0000a088, 0x02030500},
{0x0000a08c, 0x02040400},
{0x0000a090, 0x02050203},
{0x0000a094, 0x02050204},
{0x0000a098, 0x02050205},
{0x0000a09c, 0x02040500},
{0x0000a0a0, 0x02050301},
{0x0000a0a4, 0x02050302},
{0x0000a0a8, 0x02050303},
{0x0000a0ac, 0x02050400},
{0x0000a0b0, 0x02050401},
{0x0000a0b4, 0x02050402},
{0x0000a0b8, 0x02050403},
{0x0000a0bc, 0x02050500},
{0x0000a0c0, 0x02050501},
{0x0000a0c4, 0x02050502},
{0x0000a0c8, 0x02050503},
{0x0000a0cc, 0x02050504},
{0x0000a0d0, 0x02050600},
{0x0000a0d4, 0x02050601},
{0x0000a0d8, 0x02050602},
{0x0000a0dc, 0x02050603},
{0x0000a0e0, 0x02050604},
{0x0000a0e4, 0x02050700},
{0x0000a0e8, 0x02050701},
{0x0000a0ec, 0x02050702},
{0x0000a0f0, 0x02050703},
{0x0000a0f4, 0x02050704},
{0x0000a0f8, 0x02050705},
{0x0000a0fc, 0x02050708},
{0x0000a100, 0x02050709},
{0x0000a104, 0x0205070a},
{0x0000a108, 0x0205070b},
{0x0000a10c, 0x0205070c},
{0x0000a110, 0x0205070d},
{0x0000a114, 0x02050710},
{0x0000a118, 0x02050711},
{0x0000a11c, 0x02050712},
{0x0000a120, 0x02050713},
{0x0000a124, 0x02050714},
{0x0000a128, 0x02050715},
{0x0000a12c, 0x02050730},
{0x0000a130, 0x02050731},
{0x0000a134, 0x02050732},
{0x0000a138, 0x02050733},
{0x0000a13c, 0x02050734},
{0x0000a140, 0x02050735},
{0x0000a144, 0x02050750},
{0x0000a148, 0x02050751},
{0x0000a14c, 0x02050752},
{0x0000a150, 0x02050753},
{0x0000a154, 0x02050754},
{0x0000a158, 0x02050755},
{0x0000a15c, 0x02050770},
{0x0000a160, 0x02050771},
{0x0000a164, 0x02050772},
{0x0000a168, 0x02050773},
{0x0000a16c, 0x02050774},
{0x0000a170, 0x02050775},
{0x0000a174, 0x00000776},
{0x0000a178, 0x00000776},
{0x0000a17c, 0x00000776},
{0x0000a180, 0x00000776},
{0x0000a184, 0x00000776},
{0x0000a188, 0x00000776},
{0x0000a18c, 0x00000776},
{0x0000a190, 0x00000776},
{0x0000a194, 0x00000776},
{0x0000a198, 0x00000776},
{0x0000a19c, 0x00000776},
{0x0000a1a0, 0x00000776},
{0x0000a1a4, 0x00000776},
{0x0000a1a8, 0x00000776},
{0x0000a1ac, 0x00000776},
{0x0000a1b0, 0x00000776},
{0x0000a1b4, 0x00000776},
{0x0000a1b8, 0x00000776},
{0x0000a1bc, 0x00000776},
{0x0000a1c0, 0x00000776},
{0x0000a1c4, 0x00000776},
{0x0000a1c8, 0x00000776},
{0x0000a1cc, 0x00000776},
{0x0000a1d0, 0x00000776},
{0x0000a1d4, 0x00000776},
{0x0000a1d8, 0x00000776},
{0x0000a1dc, 0x00000776},
{0x0000a1e0, 0x00000776},
{0x0000a1e4, 0x00000776},
{0x0000a1e8, 0x00000776},
{0x0000a1ec, 0x00000776},
{0x0000a1f0, 0x00000776},
{0x0000a1f4, 0x00000776},
{0x0000a1f8, 0x00000776},
{0x0000a1fc, 0x00000776},
{0x0000b000, 0x02000101},
{0x0000b004, 0x02000102},
{0x0000b008, 0x02000103},
{0x0000b00c, 0x02000104},
{0x0000b010, 0x02000200},
{0x0000b014, 0x02000201},
{0x0000b018, 0x02000202},
{0x0000b01c, 0x02000203},
{0x0000b020, 0x02000204},
{0x0000b024, 0x02000205},
{0x0000b028, 0x02000208},
{0x0000b02c, 0x02000302},
{0x0000b030, 0x02000303},
{0x0000b034, 0x02000304},
{0x0000b038, 0x02000400},
{0x0000b03c, 0x02010300},
{0x0000b040, 0x02010301},
{0x0000b044, 0x02010302},
{0x0000b048, 0x02000500},
{0x0000b04c, 0x02010400},
{0x0000b050, 0x02020300},
{0x0000b054, 0x02020301},
{0x0000b058, 0x02020302},
{0x0000b05c, 0x02020303},
{0x0000b060, 0x02020400},
{0x0000b064, 0x02030300},
{0x0000b068, 0x02030301},
{0x0000b06c, 0x02030302},
{0x0000b070, 0x02030303},
{0x0000b074, 0x02030400},
{0x0000b078, 0x02040300},
{0x0000b07c, 0x02040301},
{0x0000b080, 0x02040302},
{0x0000b084, 0x02040303},
{0x0000b088, 0x02030500},
{0x0000b08c, 0x02040400},
{0x0000b090, 0x02050203},
{0x0000b094, 0x02050204},
{0x0000b098, 0x02050205},
{0x0000b09c, 0x02040500},
{0x0000b0a0, 0x02050301},
{0x0000b0a4, 0x02050302},
{0x0000b0a8, 0x02050303},
{0x0000b0ac, 0x02050400},
{0x0000b0b0, 0x02050401},
{0x0000b0b4, 0x02050402},
{0x0000b0b8, 0x02050403},
{0x0000b0bc, 0x02050500},
{0x0000b0c0, 0x02050501},
{0x0000b0c4, 0x02050502},
{0x0000b0c8, 0x02050503},
{0x0000b0cc, 0x02050504},
{0x0000b0d0, 0x02050600},
{0x0000b0d4, 0x02050601},
{0x0000b0d8, 0x02050602},
{0x0000b0dc, 0x02050603},
{0x0000b0e0, 0x02050604},
{0x0000b0e4, 0x02050700},
{0x0000b0e8, 0x02050701},
{0x0000b0ec, 0x02050702},
{0x0000b0f0, 0x02050703},
{0x0000b0f4, 0x02050704},
{0x0000b0f8, 0x02050705},
{0x0000b0fc, 0x02050708},
{0x0000b100, 0x02050709},
{0x0000b104, 0x0205070a},
{0x0000b108, 0x0205070b},
{0x0000b10c, 0x0205070c},
{0x0000b110, 0x0205070d},
{0x0000b114, 0x02050710},
{0x0000b118, 0x02050711},
{0x0000b11c, 0x02050712},
{0x0000b120, 0x02050713},
{0x0000b124, 0x02050714},
{0x0000b128, 0x02050715},
{0x0000b12c, 0x02050730},
{0x0000b130, 0x02050731},
{0x0000b134, 0x02050732},
{0x0000b138, 0x02050733},
{0x0000b13c, 0x02050734},
{0x0000b140, 0x02050735},
{0x0000b144, 0x02050750},
{0x0000b148, 0x02050751},
{0x0000b14c, 0x02050752},
{0x0000b150, 0x02050753},
{0x0000b154, 0x02050754},
{0x0000b158, 0x02050755},
{0x0000b15c, 0x02050770},
{0x0000b160, 0x02050771},
{0x0000b164, 0x02050772},
{0x0000b168, 0x02050773},
{0x0000b16c, 0x02050774},
{0x0000b170, 0x02050775},
{0x0000b174, 0x00000776},
{0x0000b178, 0x00000776},
{0x0000b17c, 0x00000776},
{0x0000b180, 0x00000776},
{0x0000b184, 0x00000776},
{0x0000b188, 0x00000776},
{0x0000b18c, 0x00000776},
{0x0000b190, 0x00000776},
{0x0000b194, 0x00000776},
{0x0000b198, 0x00000776},
{0x0000b19c, 0x00000776},
{0x0000b1a0, 0x00000776},
{0x0000b1a4, 0x00000776},
{0x0000b1a8, 0x00000776},
{0x0000b1ac, 0x00000776},
{0x0000b1b0, 0x00000776},
{0x0000b1b4, 0x00000776},
{0x0000b1b8, 0x00000776},
{0x0000b1bc, 0x00000776},
{0x0000b1c0, 0x00000776},
{0x0000b1c4, 0x00000776},
{0x0000b1c8, 0x00000776},
{0x0000b1cc, 0x00000776},
{0x0000b1d0, 0x00000776},
{0x0000b1d4, 0x00000776},
{0x0000b1d8, 0x00000776},
{0x0000b1dc, 0x00000776},
{0x0000b1e0, 0x00000776},
{0x0000b1e4, 0x00000776},
{0x0000b1e8, 0x00000776},
{0x0000b1ec, 0x00000776},
{0x0000b1f0, 0x00000776},
{0x0000b1f4, 0x00000776},
{0x0000b1f8, 0x00000776},
{0x0000b1fc, 0x00000776},
};
static const u32 ar9300_2p2_mac_postamble[][5] = { static const u32 ar9300_2p2_mac_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
...@@ -572,48 +312,6 @@ static const u32 ar9300_2p2_soc_postamble[][5] = { ...@@ -572,48 +312,6 @@ static const u32 ar9300_2p2_soc_postamble[][5] = {
{0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
}; };
static const u32 ar9200_merlin_2p2_radio_core[][2] = {
/* Addr allmodes */
{0x00007800, 0x00040000},
{0x00007804, 0xdb005012},
{0x00007808, 0x04924914},
{0x0000780c, 0x21084210},
{0x00007810, 0x6d801300},
{0x00007814, 0x0019beff},
{0x00007818, 0x07e41000},
{0x0000781c, 0x00392000},
{0x00007820, 0x92592480},
{0x00007824, 0x00040000},
{0x00007828, 0xdb005012},
{0x0000782c, 0x04924914},
{0x00007830, 0x21084210},
{0x00007834, 0x6d801300},
{0x00007838, 0x0019beff},
{0x0000783c, 0x07e40000},
{0x00007840, 0x00392000},
{0x00007844, 0x92592480},
{0x00007848, 0x00100000},
{0x0000784c, 0x773f0567},
{0x00007850, 0x54214514},
{0x00007854, 0x12035828},
{0x00007858, 0x92592692},
{0x0000785c, 0x00000000},
{0x00007860, 0x56400000},
{0x00007864, 0x0a8e370e},
{0x00007868, 0xc0102850},
{0x0000786c, 0x812d4000},
{0x00007870, 0x807ec400},
{0x00007874, 0x001b6db0},
{0x00007878, 0x00376b63},
{0x0000787c, 0x06db6db6},
{0x00007880, 0x006d8000},
{0x00007884, 0xffeffffe},
{0x00007888, 0xffeffffe},
{0x0000788c, 0x00010000},
{0x00007890, 0x02060aeb},
{0x00007894, 0x5a108000},
};
static const u32 ar9300_2p2_baseband_postamble[][5] = { static const u32 ar9300_2p2_baseband_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
......
...@@ -87,11 +87,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ...@@ -87,11 +87,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
/* additional clock settings */ /* additional clock settings */
if (ah->is_clk_25mhz) if (ah->is_clk_25mhz)
INIT_INI_ARRAY(&ah->iniModesAdditional, INIT_INI_ARRAY(&ah->iniAdditional,
ar9331_1p1_xtal_25M, ar9331_1p1_xtal_25M,
ARRAY_SIZE(ar9331_1p1_xtal_25M), 2); ARRAY_SIZE(ar9331_1p1_xtal_25M), 2);
else else
INIT_INI_ARRAY(&ah->iniModesAdditional, INIT_INI_ARRAY(&ah->iniAdditional,
ar9331_1p1_xtal_40M, ar9331_1p1_xtal_40M,
ARRAY_SIZE(ar9331_1p1_xtal_40M), 2); ARRAY_SIZE(ar9331_1p1_xtal_40M), 2);
} else if (AR_SREV_9330_12(ah)) { } else if (AR_SREV_9330_12(ah)) {
...@@ -140,11 +140,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ...@@ -140,11 +140,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
/* additional clock settings */ /* additional clock settings */
if (ah->is_clk_25mhz) if (ah->is_clk_25mhz)
INIT_INI_ARRAY(&ah->iniModesAdditional, INIT_INI_ARRAY(&ah->iniAdditional,
ar9331_1p2_xtal_25M, ar9331_1p2_xtal_25M,
ARRAY_SIZE(ar9331_1p2_xtal_25M), 2); ARRAY_SIZE(ar9331_1p2_xtal_25M), 2);
else else
INIT_INI_ARRAY(&ah->iniModesAdditional, INIT_INI_ARRAY(&ah->iniAdditional,
ar9331_1p2_xtal_40M, ar9331_1p2_xtal_40M,
ARRAY_SIZE(ar9331_1p2_xtal_40M), 2); ARRAY_SIZE(ar9331_1p2_xtal_40M), 2);
} else if (AR_SREV_9340(ah)) { } else if (AR_SREV_9340(ah)) {
...@@ -194,15 +194,16 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ...@@ -194,15 +194,16 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0), ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0),
5); 5);
INIT_INI_ARRAY(&ah->iniModesAdditional, INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9340Modes_fast_clock_1p0, ar9340Modes_fast_clock_1p0,
ARRAY_SIZE(ar9340Modes_fast_clock_1p0), ARRAY_SIZE(ar9340Modes_fast_clock_1p0),
3); 3);
INIT_INI_ARRAY(&ah->iniModesAdditional_40M, if (!ah->is_clk_25mhz)
ar9340_1p0_radio_core_40M, INIT_INI_ARRAY(&ah->iniAdditional,
ARRAY_SIZE(ar9340_1p0_radio_core_40M), ar9340_1p0_radio_core_40M,
2); ARRAY_SIZE(ar9340_1p0_radio_core_40M),
2);
} else if (AR_SREV_9485_11(ah)) { } else if (AR_SREV_9485_11(ah)) {
/* mac */ /* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
...@@ -321,7 +322,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ...@@ -321,7 +322,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
2); 2);
/* Fast clock modal settings */ /* Fast clock modal settings */
INIT_INI_ARRAY(&ah->iniModesAdditional, INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9462_modes_fast_clock_2p0, ar9462_modes_fast_clock_2p0,
ARRAY_SIZE(ar9462_modes_fast_clock_2p0), 3); ARRAY_SIZE(ar9462_modes_fast_clock_2p0), 3);
...@@ -378,7 +379,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ...@@ -378,7 +379,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table), ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table),
5); 5);
INIT_INI_ARRAY(&ah->iniModesAdditional, INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9580_1p0_modes_fast_clock, ar9580_1p0_modes_fast_clock,
ARRAY_SIZE(ar9580_1p0_modes_fast_clock), ARRAY_SIZE(ar9580_1p0_modes_fast_clock),
3); 3);
...@@ -445,7 +446,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ...@@ -445,7 +446,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
2); 2);
/* Fast clock modal settings */ /* Fast clock modal settings */
INIT_INI_ARRAY(&ah->iniModesAdditional, INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9300Modes_fast_clock_2p2, ar9300Modes_fast_clock_2p2,
ARRAY_SIZE(ar9300Modes_fast_clock_2p2), ARRAY_SIZE(ar9300Modes_fast_clock_2p2),
3); 3);
......
...@@ -679,18 +679,17 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, ...@@ -679,18 +679,17 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
* different modal values. * different modal values.
*/ */
if (IS_CHAN_A_FAST_CLOCK(ah, chan)) if (IS_CHAN_A_FAST_CLOCK(ah, chan))
REG_WRITE_ARRAY(&ah->iniModesAdditional, REG_WRITE_ARRAY(&ah->iniModesFastClock,
modesIndex, regWrites); modesIndex, regWrites);
if (AR_SREV_9330(ah)) REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites);
REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites);
if (AR_SREV_9340(ah) && !ah->is_clk_25mhz)
REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites);
if (AR_SREV_9462(ah)) if (AR_SREV_9462(ah))
ar9003_hw_prog_ini(ah, &ah->ini_BTCOEX_MAX_TXPWR, 1); ar9003_hw_prog_ini(ah, &ah->ini_BTCOEX_MAX_TXPWR, 1);
if (chan->channel == 2484)
ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1);
ah->modes_index = modesIndex; ah->modes_index = modesIndex;
ar9003_hw_override_ini(ah); ar9003_hw_override_ini(ah);
ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_channel_regs(ah, chan);
...@@ -1320,13 +1319,9 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, ...@@ -1320,13 +1319,9 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
* different modal values. * different modal values.
*/ */
if (IS_CHAN_A_FAST_CLOCK(ah, chan)) if (IS_CHAN_A_FAST_CLOCK(ah, chan))
REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); REG_WRITE_ARRAY(&ah->iniModesFastClock, modesIndex, regWrites);
if (AR_SREV_9330(ah))
REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites);
if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites);
REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites);
ah->modes_index = modesIndex; ah->modes_index = modesIndex;
*ini_reloaded = true; *ini_reloaded = true;
......
...@@ -583,19 +583,13 @@ struct ath_ant_comb { ...@@ -583,19 +583,13 @@ struct ath_ant_comb {
#define SC_OP_INVALID BIT(0) #define SC_OP_INVALID BIT(0)
#define SC_OP_BEACONS BIT(1) #define SC_OP_BEACONS BIT(1)
#define SC_OP_RXAGGR BIT(2) #define SC_OP_OFFCHANNEL BIT(2)
#define SC_OP_TXAGGR BIT(3) #define SC_OP_RXFLUSH BIT(3)
#define SC_OP_OFFCHANNEL BIT(4) #define SC_OP_TSF_RESET BIT(4)
#define SC_OP_PREAMBLE_SHORT BIT(5) #define SC_OP_BT_PRIORITY_DETECTED BIT(5)
#define SC_OP_PROTECT_ENABLE BIT(6) #define SC_OP_BT_SCAN BIT(6)
#define SC_OP_RXFLUSH BIT(7) #define SC_OP_ANI_RUN BIT(7)
#define SC_OP_LED_ASSOCIATED BIT(8) #define SC_OP_PRIM_STA_VIF BIT(8)
#define SC_OP_LED_ON BIT(9)
#define SC_OP_TSF_RESET BIT(11)
#define SC_OP_BT_PRIORITY_DETECTED BIT(12)
#define SC_OP_BT_SCAN BIT(13)
#define SC_OP_ANI_RUN BIT(14)
#define SC_OP_PRIM_STA_VIF BIT(15)
/* Powersave flags */ /* Powersave flags */
#define PS_WAIT_FOR_BEACON BIT(0) #define PS_WAIT_FOR_BEACON BIT(0)
...@@ -617,15 +611,12 @@ struct ath9k_vif_iter_data { ...@@ -617,15 +611,12 @@ struct ath9k_vif_iter_data {
int nstations; /* number of station vifs */ int nstations; /* number of station vifs */
int nwds; /* number of WDS vifs */ int nwds; /* number of WDS vifs */
int nadhocs; /* number of adhoc vifs */ int nadhocs; /* number of adhoc vifs */
int nothers; /* number of vifs not specified above. */
}; };
struct ath_softc { struct ath_softc {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct device *dev; struct device *dev;
int chan_idx;
int chan_is_ht;
struct survey_info *cur_survey; struct survey_info *cur_survey;
struct survey_info survey[ATH9K_NUM_CHANNELS]; struct survey_info survey[ATH9K_NUM_CHANNELS];
......
...@@ -67,7 +67,7 @@ int ath_beaconq_config(struct ath_softc *sc) ...@@ -67,7 +67,7 @@ int ath_beaconq_config(struct ath_softc *sc)
* up rate codes, and channel flags. Beacons are always sent out at the * up rate codes, and channel flags. Beacons are always sent out at the
* lowest rate, and are not retried. * lowest rate, and are not retried.
*/ */
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
struct ath_buf *bf, int rateidx) struct ath_buf *bf, int rateidx)
{ {
struct sk_buff *skb = bf->bf_mpdu; struct sk_buff *skb = bf->bf_mpdu;
...@@ -82,7 +82,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, ...@@ -82,7 +82,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
sband = &sc->sbands[common->hw->conf.channel->band]; sband = &sc->sbands[common->hw->conf.channel->band];
rate = sband->bitrates[rateidx].hw_value; rate = sband->bitrates[rateidx].hw_value;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) if (vif->bss_conf.use_short_preamble)
rate |= sband->bitrates[rateidx].hw_value_short; rate |= sband->bitrates[rateidx].hw_value_short;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
...@@ -209,7 +209,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, ...@@ -209,7 +209,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
} }
} }
ath_beacon_setup(sc, avp, bf, info->control.rates[0].idx); ath_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
while (skb) { while (skb) {
ath_tx_cabq(hw, skb); ath_tx_cabq(hw, skb);
......
...@@ -738,9 +738,9 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, ...@@ -738,9 +738,9 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len, len += snprintf(buf + len, sizeof(buf) - len,
"VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i" "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i"
" ADHOC: %i OTHER: %i TOTAL: %hi BEACON-VIF: %hi\n", " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
iter_data.naps, iter_data.nstations, iter_data.nmeshes, iter_data.naps, iter_data.nstations, iter_data.nmeshes,
iter_data.nwds, iter_data.nadhocs, iter_data.nothers, iter_data.nwds, iter_data.nadhocs,
sc->nvifs, sc->nbcnvifs); sc->nvifs, sc->nbcnvifs);
if (len > sizeof(buf)) if (len > sizeof(buf))
......
...@@ -362,7 +362,8 @@ void ath9k_stop_btcoex(struct ath_softc *sc) ...@@ -362,7 +362,8 @@ void ath9k_stop_btcoex(struct ath_softc *sc)
ath9k_hw_btcoex_disable(ah); ath9k_hw_btcoex_disable(ah);
if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
ath9k_btcoex_timer_pause(sc); ath9k_btcoex_timer_pause(sc);
ath_mci_flush_profile(&sc->btcoex.mci); if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI)
ath_mci_flush_profile(&sc->btcoex.mci);
} }
} }
......
...@@ -919,7 +919,6 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ...@@ -919,7 +919,6 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
/* setup initial channel */ /* setup initial channel */
init_channel = ath9k_cmn_get_curchannel(hw, ah); init_channel = ath9k_cmn_get_curchannel(hw, ah);
ath9k_hw_htc_resetinit(ah);
ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false); ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
if (ret) { if (ret) {
ath_err(common, ath_err(common,
......
...@@ -449,6 +449,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ...@@ -449,6 +449,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
ah->slottime = ATH9K_SLOT_TIME_9; ah->slottime = ATH9K_SLOT_TIME_9;
ah->globaltxtimeout = (u32) -1; ah->globaltxtimeout = (u32) -1;
ah->power_mode = ATH9K_PM_UNDEFINED; ah->power_mode = ATH9K_PM_UNDEFINED;
ah->htc_reset_init = true;
} }
static int ath9k_hw_init_macaddr(struct ath_hw *ah) static int ath9k_hw_init_macaddr(struct ath_hw *ah)
...@@ -555,7 +556,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) ...@@ -555,7 +556,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
return -EIO; return -EIO;
} }
if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
((AR_SREV_9160(ah) || AR_SREV_9280(ah)) && ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) &&
!ah->is_pciexpress)) { !ah->is_pciexpress)) {
...@@ -619,9 +620,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) ...@@ -619,9 +620,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
if (!ah->is_pciexpress) if (!ah->is_pciexpress)
ath9k_hw_disablepcie(ah); ath9k_hw_disablepcie(ah);
if (!AR_SREV_9300_20_OR_LATER(ah))
ar9002_hw_cck_chan14_spread(ah);
r = ath9k_hw_post_init(ah); r = ath9k_hw_post_init(ah);
if (r) if (r)
return r; return r;
...@@ -1521,17 +1519,81 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) ...@@ -1521,17 +1519,81 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
} }
EXPORT_SYMBOL(ath9k_hw_check_alive); EXPORT_SYMBOL(ath9k_hw_check_alive);
/*
* Fast channel change:
* (Change synthesizer based on channel freq without resetting chip)
*
* Don't do FCC when
* - Flag is not set
* - Chip is just coming out of full sleep
* - Channel to be set is same as current channel
* - Channel flags are different, (eg.,moving from 2GHz to 5GHz channel)
*/
static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
int ret;
if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI)
goto fail;
if (ah->chip_fullsleep)
goto fail;
if (!ah->curchan)
goto fail;
if (chan->channel == ah->curchan->channel)
goto fail;
if ((chan->channelFlags & CHANNEL_ALL) !=
(ah->curchan->channelFlags & CHANNEL_ALL))
goto fail;
if (!ath9k_hw_check_alive(ah))
goto fail;
/*
* For AR9462, make sure that calibration data for
* re-using are present.
*/
if (AR_SREV_9462(ah) && (!ah->caldata ||
!ah->caldata->done_txiqcal_once ||
!ah->caldata->done_txclcal_once ||
!ah->caldata->rtt_hist.num_readings))
goto fail;
ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n",
ah->curchan->channel, chan->channel);
ret = ath9k_hw_channel_change(ah, chan);
if (!ret)
goto fail;
ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah, true);
if ((ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && ar9003_mci_is_ready(ah))
ar9003_mci_2g5g_switch(ah, true);
if (AR_SREV_9271(ah))
ar9002_hw_load_ani_reg(ah, chan);
return 0;
fail:
return -EINVAL;
}
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool bChannelChange) struct ath9k_hw_cal_data *caldata, bool fastcc)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
u32 saveLedState; u32 saveLedState;
struct ath9k_channel *curchan = ah->curchan;
u32 saveDefAntenna; u32 saveDefAntenna;
u32 macStaId1; u32 macStaId1;
u64 tsf = 0; u64 tsf = 0;
int i, r; int i, r;
bool allow_fbs = false, start_mci_reset = false; bool start_mci_reset = false;
bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI); bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
bool save_fullsleep = ah->chip_fullsleep; bool save_fullsleep = ah->chip_fullsleep;
...@@ -1544,8 +1606,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -1544,8 +1606,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
return -EIO; return -EIO;
if (curchan && !ah->chip_fullsleep) if (ah->curchan && !ah->chip_fullsleep)
ath9k_hw_getnf(ah, curchan); ath9k_hw_getnf(ah, ah->curchan);
ah->caldata = caldata; ah->caldata = caldata;
if (caldata && if (caldata &&
...@@ -1558,32 +1620,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -1558,32 +1620,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
} }
ah->noise = ath9k_hw_getchan_noise(ah, chan); ah->noise = ath9k_hw_getchan_noise(ah, chan);
if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) if (fastcc) {
bChannelChange = false; r = ath9k_hw_do_fastcc(ah, chan);
if (!r)
if (caldata && return r;
caldata->done_txiqcal_once &&
caldata->done_txclcal_once &&
caldata->rtt_hist.num_readings)
allow_fbs = true;
if (bChannelChange &&
(!ah->chip_fullsleep) &&
(ah->curchan != NULL) &&
(chan->channel != ah->curchan->channel) &&
(allow_fbs ||
((chan->channelFlags & CHANNEL_ALL) ==
(ah->curchan->channelFlags & CHANNEL_ALL)))) {
if (ath9k_hw_channel_change(ah, chan)) {
ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah, true);
if (mci && ar9003_mci_is_ready(ah))
ar9003_mci_2g5g_switch(ah, true);
if (AR_SREV_9271(ah))
ar9002_hw_load_ani_reg(ah, chan);
return 0;
}
} }
if (mci) if (mci)
...@@ -2389,8 +2429,17 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ...@@ -2389,8 +2429,17 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9485_OR_LATER(ah)) if (AR_SREV_9485_OR_LATER(ah))
ah->enabled_cals |= TX_IQ_ON_AGC_CAL; ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
} }
if (AR_SREV_9462(ah))
pCap->hw_caps |= ATH9K_HW_CAP_RTT | ATH9K_HW_CAP_MCI; if (AR_SREV_9462(ah)) {
if (!(ah->ent_mode & AR_ENT_OTP_49GHZ_DISABLE))
pCap->hw_caps |= ATH9K_HW_CAP_MCI;
if (AR_SREV_9462_20(ah))
pCap->hw_caps |= ATH9K_HW_CAP_RTT;
}
return 0; return 0;
} }
...@@ -2516,12 +2565,6 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) ...@@ -2516,12 +2565,6 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
} }
EXPORT_SYMBOL(ath9k_hw_set_gpio); EXPORT_SYMBOL(ath9k_hw_set_gpio);
u32 ath9k_hw_getdefantenna(struct ath_hw *ah)
{
return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
}
EXPORT_SYMBOL(ath9k_hw_getdefantenna);
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna) void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
{ {
REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
...@@ -2579,6 +2622,7 @@ bool ath9k_hw_phy_disable(struct ath_hw *ah) ...@@ -2579,6 +2622,7 @@ bool ath9k_hw_phy_disable(struct ath_hw *ah)
return false; return false;
ath9k_hw_init_pll(ah, NULL); ath9k_hw_init_pll(ah, NULL);
ah->htc_reset_init = true;
return true; return true;
} }
EXPORT_SYMBOL(ath9k_hw_phy_disable); EXPORT_SYMBOL(ath9k_hw_phy_disable);
...@@ -2939,12 +2983,6 @@ EXPORT_SYMBOL(ath_gen_timer_isr); ...@@ -2939,12 +2983,6 @@ EXPORT_SYMBOL(ath_gen_timer_isr);
/* HTC */ /* HTC */
/********/ /********/
void ath9k_hw_htc_resetinit(struct ath_hw *ah)
{
ah->htc_reset_init = true;
}
EXPORT_SYMBOL(ath9k_hw_htc_resetinit);
static struct { static struct {
u32 version; u32 version;
const char * name; const char * name;
......
...@@ -827,19 +827,14 @@ struct ath_hw { ...@@ -827,19 +827,14 @@ struct ath_hw {
struct ar5416IniArray iniAddac; struct ar5416IniArray iniAddac;
struct ar5416IniArray iniPcieSerdes; struct ar5416IniArray iniPcieSerdes;
struct ar5416IniArray iniPcieSerdesLowPower; struct ar5416IniArray iniPcieSerdesLowPower;
struct ar5416IniArray iniModesAdditional; struct ar5416IniArray iniModesFastClock;
struct ar5416IniArray iniModesAdditional_40M; struct ar5416IniArray iniAdditional;
struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesRxGain;
struct ar5416IniArray iniModesTxGain; struct ar5416IniArray iniModesTxGain;
struct ar5416IniArray iniModes_9271_1_0_only;
struct ar5416IniArray iniCckfirNormal; struct ar5416IniArray iniCckfirNormal;
struct ar5416IniArray iniCckfirJapan2484; struct ar5416IniArray iniCckfirJapan2484;
struct ar5416IniArray ini_japan2484; struct ar5416IniArray ini_japan2484;
struct ar5416IniArray iniCommon_normal_cck_fir_coeff_9271;
struct ar5416IniArray iniCommon_japan_2484_cck_fir_coeff_9271;
struct ar5416IniArray iniModes_9271_ANI_reg; struct ar5416IniArray iniModes_9271_ANI_reg;
struct ar5416IniArray iniModes_high_power_tx_gain_9271;
struct ar5416IniArray iniModes_normal_power_tx_gain_9271;
struct ar5416IniArray ini_radio_post_sys2ant; struct ar5416IniArray ini_radio_post_sys2ant;
struct ar5416IniArray ini_BTCOEX_MAX_TXPWR; struct ar5416IniArray ini_BTCOEX_MAX_TXPWR;
...@@ -924,7 +919,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid); ...@@ -924,7 +919,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid);
void ath9k_hw_deinit(struct ath_hw *ah); void ath9k_hw_deinit(struct ath_hw *ah);
int ath9k_hw_init(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah);
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool bChannelChange); struct ath9k_hw_cal_data *caldata, bool fastcc);
int ath9k_hw_fill_cap_info(struct ath_hw *ah); int ath9k_hw_fill_cap_info(struct ath_hw *ah);
u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan); u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
...@@ -934,7 +929,6 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio); ...@@ -934,7 +929,6 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio);
void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
u32 ah_signal_type); u32 ah_signal_type);
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
/* General Operation */ /* General Operation */
...@@ -988,9 +982,6 @@ void ath_gen_timer_isr(struct ath_hw *hw); ...@@ -988,9 +982,6 @@ void ath_gen_timer_isr(struct ath_hw *hw);
void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len); void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len);
/* HTC */
void ath9k_hw_htc_resetinit(struct ath_hw *ah);
/* PHY */ /* PHY */
void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
u32 *coef_mantissa, u32 *coef_exponent); u32 *coef_mantissa, u32 *coef_exponent);
...@@ -1000,7 +991,6 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan); ...@@ -1000,7 +991,6 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan);
* Code Specific to AR5008, AR9001 or AR9002, * Code Specific to AR5008, AR9001 or AR9002,
* we stuff these here to avoid callbacks for AR9003. * we stuff these here to avoid callbacks for AR9003.
*/ */
void ar9002_hw_cck_chan14_spread(struct ath_hw *ah);
int ar9002_hw_rf_claim(struct ath_hw *ah); int ar9002_hw_rf_claim(struct ath_hw *ah);
void ar9002_hw_enable_async_fifo(struct ath_hw *ah); void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
......
...@@ -172,7 +172,7 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) ...@@ -172,7 +172,7 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath_softc *sc = (struct ath_softc *) common->priv; struct ath_softc *sc = (struct ath_softc *) common->priv;
if (ah->config.serialize_regmode == SER_REG_MODE_ON) { if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&sc->sc_serial_rw, flags); spin_lock_irqsave(&sc->sc_serial_rw, flags);
iowrite32(val, sc->mem + reg_offset); iowrite32(val, sc->mem + reg_offset);
...@@ -188,7 +188,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) ...@@ -188,7 +188,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
struct ath_softc *sc = (struct ath_softc *) common->priv; struct ath_softc *sc = (struct ath_softc *) common->priv;
u32 val; u32 val;
if (ah->config.serialize_regmode == SER_REG_MODE_ON) { if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&sc->sc_serial_rw, flags); spin_lock_irqsave(&sc->sc_serial_rw, flags);
val = ioread32(sc->mem + reg_offset); val = ioread32(sc->mem + reg_offset);
...@@ -219,7 +219,7 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl ...@@ -219,7 +219,7 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl
unsigned long uninitialized_var(flags); unsigned long uninitialized_var(flags);
u32 val; u32 val;
if (ah->config.serialize_regmode == SER_REG_MODE_ON) { if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) {
spin_lock_irqsave(&sc->sc_serial_rw, flags); spin_lock_irqsave(&sc->sc_serial_rw, flags);
val = __ath9k_reg_rmw(sc, reg_offset, set, clr); val = __ath9k_reg_rmw(sc, reg_offset, set, clr);
spin_unlock_irqrestore(&sc->sc_serial_rw, flags); spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
...@@ -484,19 +484,11 @@ static void ath9k_init_misc(struct ath_softc *sc) ...@@ -484,19 +484,11 @@ static void ath9k_init_misc(struct ath_softc *sc)
{ {
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int i = 0; int i = 0;
setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
sc->config.txpowlimit = ATH_TXPOWER_MAX; sc->config.txpowlimit = ATH_TXPOWER_MAX;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
sc->sc_flags |= SC_OP_TXAGGR;
sc->sc_flags |= SC_OP_RXAGGR;
}
sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9; sc->beacon.slottime = ATH9K_SLOT_TIME_9;
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
......
...@@ -185,13 +185,6 @@ bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q) ...@@ -185,13 +185,6 @@ bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q)
} }
EXPORT_SYMBOL(ath9k_hw_stop_dma_queue); EXPORT_SYMBOL(ath9k_hw_stop_dma_queue);
void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
{
*txqs &= ah->intr_txqs;
ah->intr_txqs &= ~(*txqs);
}
EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs);
bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
const struct ath9k_tx_queue_info *qinfo) const struct ath9k_tx_queue_info *qinfo)
{ {
...@@ -340,6 +333,15 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, ...@@ -340,6 +333,15 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
} }
EXPORT_SYMBOL(ath9k_hw_setuptxqueue); EXPORT_SYMBOL(ath9k_hw_setuptxqueue);
static void ath9k_hw_clear_queue_interrupts(struct ath_hw *ah, u32 q)
{
ah->txok_interrupt_mask &= ~(1 << q);
ah->txerr_interrupt_mask &= ~(1 << q);
ah->txdesc_interrupt_mask &= ~(1 << q);
ah->txeol_interrupt_mask &= ~(1 << q);
ah->txurn_interrupt_mask &= ~(1 << q);
}
bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
...@@ -354,11 +356,7 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) ...@@ -354,11 +356,7 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
ath_dbg(common, QUEUE, "Release TX queue: %u\n", q); ath_dbg(common, QUEUE, "Release TX queue: %u\n", q);
qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
ah->txok_interrupt_mask &= ~(1 << q); ath9k_hw_clear_queue_interrupts(ah, q);
ah->txerr_interrupt_mask &= ~(1 << q);
ah->txdesc_interrupt_mask &= ~(1 << q);
ah->txeol_interrupt_mask &= ~(1 << q);
ah->txurn_interrupt_mask &= ~(1 << q);
ath9k_hw_set_txq_interrupts(ah, qi); ath9k_hw_set_txq_interrupts(ah, qi);
return true; return true;
...@@ -510,26 +508,17 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) ...@@ -510,26 +508,17 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
if (AR_SREV_9300_20_OR_LATER(ah)) if (AR_SREV_9300_20_OR_LATER(ah))
REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN); REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN);
if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) ath9k_hw_clear_queue_interrupts(ah, q);
if (qi->tqi_qflags & TXQ_FLAG_TXINT_ENABLE) {
ah->txok_interrupt_mask |= 1 << q; ah->txok_interrupt_mask |= 1 << q;
else
ah->txok_interrupt_mask &= ~(1 << q);
if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
ah->txerr_interrupt_mask |= 1 << q; ah->txerr_interrupt_mask |= 1 << q;
else }
ah->txerr_interrupt_mask &= ~(1 << q);
if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
ah->txdesc_interrupt_mask |= 1 << q; ah->txdesc_interrupt_mask |= 1 << q;
else
ah->txdesc_interrupt_mask &= ~(1 << q);
if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
ah->txeol_interrupt_mask |= 1 << q; ah->txeol_interrupt_mask |= 1 << q;
else
ah->txeol_interrupt_mask &= ~(1 << q);
if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
ah->txurn_interrupt_mask |= 1 << q; ah->txurn_interrupt_mask |= 1 << q;
else
ah->txurn_interrupt_mask &= ~(1 << q);
ath9k_hw_set_txq_interrupts(ah, qi); ath9k_hw_set_txq_interrupts(ah, qi);
return true; return true;
...@@ -747,8 +736,7 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah) ...@@ -747,8 +736,7 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah)
qi.tqi_cwmax = 0; qi.tqi_cwmax = 0;
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE | qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE;
TXQ_FLAG_TXERRINT_ENABLE;
return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
} }
......
...@@ -583,8 +583,7 @@ enum ath9k_tx_queue { ...@@ -583,8 +583,7 @@ enum ath9k_tx_queue {
#define ATH9K_WME_UPSD 4 #define ATH9K_WME_UPSD 4
enum ath9k_tx_queue_flags { enum ath9k_tx_queue_flags {
TXQ_FLAG_TXOKINT_ENABLE = 0x0001, TXQ_FLAG_TXINT_ENABLE = 0x0001,
TXQ_FLAG_TXERRINT_ENABLE = 0x0001,
TXQ_FLAG_TXDESCINT_ENABLE = 0x0002, TXQ_FLAG_TXDESCINT_ENABLE = 0x0002,
TXQ_FLAG_TXEOLINT_ENABLE = 0x0004, TXQ_FLAG_TXEOLINT_ENABLE = 0x0004,
TXQ_FLAG_TXURNINT_ENABLE = 0x0008, TXQ_FLAG_TXURNINT_ENABLE = 0x0008,
...@@ -714,7 +713,6 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); ...@@ -714,7 +713,6 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q); bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q);
void ath9k_hw_abort_tx_dma(struct ath_hw *ah); void ath9k_hw_abort_tx_dma(struct ath_hw *ah);
void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
const struct ath9k_tx_queue_info *qinfo); const struct ath9k_tx_queue_info *qinfo);
bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
......
...@@ -118,13 +118,15 @@ void ath9k_ps_restore(struct ath_softc *sc) ...@@ -118,13 +118,15 @@ void ath9k_ps_restore(struct ath_softc *sc)
if (--sc->ps_usecount != 0) if (--sc->ps_usecount != 0)
goto unlock; goto unlock;
if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK)) if (sc->ps_flags & PS_WAIT_FOR_TX_ACK)
goto unlock;
if (sc->ps_idle)
mode = ATH9K_PM_FULL_SLEEP; mode = ATH9K_PM_FULL_SLEEP;
else if (sc->ps_enabled && else if (sc->ps_enabled &&
!(sc->ps_flags & (PS_WAIT_FOR_BEACON | !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB | PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA | PS_WAIT_FOR_PSPOLL_DATA)))
PS_WAIT_FOR_TX_ACK)))
mode = ATH9K_PM_NETWORK_SLEEP; mode = ATH9K_PM_NETWORK_SLEEP;
else else
goto unlock; goto unlock;
...@@ -332,10 +334,6 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, ...@@ -332,10 +334,6 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
hchan = ah->curchan; hchan = ah->curchan;
} }
if (fastcc && (ah->chip_fullsleep ||
!ath9k_hw_check_alive(ah)))
fastcc = false;
if (!ath_prepare_reset(sc, retry_tx, flush)) if (!ath_prepare_reset(sc, retry_tx, flush))
fastcc = false; fastcc = false;
...@@ -641,7 +639,8 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, ...@@ -641,7 +639,8 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
#endif #endif
an->sta = sta; an->sta = sta;
an->vif = vif; an->vif = vif;
if (sc->sc_flags & SC_OP_TXAGGR) {
if (sta->ht_cap.ht_supported) {
ath_tx_node_init(sc, an); ath_tx_node_init(sc, an);
an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor); sta->ht_cap.ampdu_factor);
...@@ -660,7 +659,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) ...@@ -660,7 +659,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
an->sta = NULL; an->sta = NULL;
#endif #endif
if (sc->sc_flags & SC_OP_TXAGGR) if (sta->ht_cap.ht_supported)
ath_tx_node_cleanup(sc, an); ath_tx_node_cleanup(sc, an);
} }
...@@ -993,12 +992,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ...@@ -993,12 +992,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
curchan->center_freq); curchan->center_freq);
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
/* setup initial channel */
sc->chan_idx = curchan->hw_value;
init_channel = ath9k_cmn_get_curchannel(hw, ah); init_channel = ath9k_cmn_get_curchannel(hw, ah);
/* Reset SERDES registers */ /* Reset SERDES registers */
...@@ -1047,9 +1042,6 @@ static int ath9k_start(struct ieee80211_hw *hw) ...@@ -1047,9 +1042,6 @@ static int ath9k_start(struct ieee80211_hw *hw)
sc->sc_flags &= ~SC_OP_INVALID; sc->sc_flags &= ~SC_OP_INVALID;
sc->sc_ah->is_monitoring = false; sc->sc_ah->is_monitoring = false;
/* Disable BMISS interrupt when we're not associated */
ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
if (!ath_complete_reset(sc, false)) { if (!ath_complete_reset(sc, false)) {
r = -EIO; r = -EIO;
spin_unlock_bh(&sc->sc_pcu_lock); spin_unlock_bh(&sc->sc_pcu_lock);
...@@ -1277,7 +1269,6 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) ...@@ -1277,7 +1269,6 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
iter_data->nwds++; iter_data->nwds++;
break; break;
default: default:
iter_data->nothers++;
break; break;
} }
} }
...@@ -1761,7 +1752,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, ...@@ -1761,7 +1752,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_node *an = (struct ath_node *) sta->drv_priv; struct ath_node *an = (struct ath_node *) sta->drv_priv;
if (!(sc->sc_flags & SC_OP_TXAGGR)) if (!sta->ht_cap.ht_supported)
return; return;
switch (cmd) { switch (cmd) {
...@@ -1973,7 +1964,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1973,7 +1964,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
if (changed & BSS_CHANGED_BSSID) { if (changed & BSS_CHANGED_ASSOC) {
ath9k_config_bss(sc, vif); ath9k_config_bss(sc, vif);
ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n", ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n",
...@@ -2053,25 +2044,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2053,25 +2044,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ath_beacon_config(sc, vif); ath_beacon_config(sc, vif);
} }
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
ath_dbg(common, CONFIG, "BSS Changed PREAMBLE %d\n",
bss_conf->use_short_preamble);
if (bss_conf->use_short_preamble)
sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
else
sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT;
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
ath_dbg(common, CONFIG, "BSS Changed CTS PROT %d\n",
bss_conf->use_cts_prot);
if (bss_conf->use_cts_prot &&
hw->conf.channel->band != IEEE80211_BAND_5GHZ)
sc->sc_flags |= SC_OP_PROTECT_ENABLE;
else
sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
}
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
} }
...@@ -2129,15 +2101,10 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ...@@ -2129,15 +2101,10 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
switch (action) { switch (action) {
case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_START:
if (!(sc->sc_flags & SC_OP_RXAGGR))
ret = -ENOTSUPP;
break; break;
case IEEE80211_AMPDU_RX_STOP: case IEEE80211_AMPDU_RX_STOP:
break; break;
case IEEE80211_AMPDU_TX_START: case IEEE80211_AMPDU_TX_START:
if (!(sc->sc_flags & SC_OP_TXAGGR))
return -EOPNOTSUPP;
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
ret = ath_tx_aggr_start(sc, sta, tid, ssn); ret = ath_tx_aggr_start(sc, sta, tid, ssn);
if (!ret) if (!ret)
......
此差异已折叠。
...@@ -982,8 +982,6 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, ...@@ -982,8 +982,6 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
{ {
struct ath_hw *ah = common->ah; struct ath_hw *ah = common->ah;
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
/* /*
* everything but the rate is checked here, the rate check is done * everything but the rate is checked here, the rate check is done
* separately to avoid doing two lookups for a rate for each frame. * separately to avoid doing two lookups for a rate for each frame.
...@@ -1841,6 +1839,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ...@@ -1841,6 +1839,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if (sc->sc_flags & SC_OP_RXFLUSH) if (sc->sc_flags & SC_OP_RXFLUSH)
goto requeue_drop_frag; goto requeue_drop_frag;
memset(rxs, 0, sizeof(struct ieee80211_rx_status));
rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
if (rs.rs_tstamp > tsf_lower && if (rs.rs_tstamp > tsf_lower &&
unlikely(rs.rs_tstamp - tsf_lower > 0x10000000)) unlikely(rs.rs_tstamp - tsf_lower > 0x10000000))
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册