Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
commit
0440507bbc
|
@ -249,15 +249,6 @@ Who: Ravikiran Thirumalai <kiran@scalex86.org>
|
|||
|
||||
---------------------------
|
||||
|
||||
What: Code that is now under CONFIG_WIRELESS_EXT_SYSFS
|
||||
(in net/core/net-sysfs.c)
|
||||
When: 3.5
|
||||
Why: Over 1K .text/.data size reduction, data is available in other
|
||||
ways (ioctls)
|
||||
Who: Johannes Berg <johannes@sipsolutions.net>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: sysfs ui for changing p4-clockmod parameters
|
||||
When: September 2009
|
||||
Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
|
||||
|
@ -434,6 +425,19 @@ Who: Hans Verkuil <hans.verkuil@cisco.com>
|
|||
|
||||
----------------------------
|
||||
|
||||
What: CONFIG_CFG80211_WEXT
|
||||
When: as soon as distributions ship new wireless tools, ie. wpa_supplicant 1.0
|
||||
and NetworkManager/connman/etc. that are able to use nl80211
|
||||
Why: Wireless extensions are deprecated, and userland tools are moving to
|
||||
using nl80211. New drivers are no longer using wireless extensions,
|
||||
and while there might still be old drivers, both new drivers and new
|
||||
userland no longer needs them and they can't be used for an feature
|
||||
developed in the past couple of years. As such, compatibility with
|
||||
wireless extensions in new drivers will be removed.
|
||||
Who: Johannes Berg <johannes@sipsolutions.net>
|
||||
|
||||
----------------------------
|
||||
|
||||
What: g_file_storage driver
|
||||
When: 3.8
|
||||
Why: This driver has been superseded by g_mass_storage.
|
||||
|
|
18
MAINTAINERS
18
MAINTAINERS
|
@ -329,7 +329,7 @@ F: drivers/hwmon/adm1029.c
|
|||
|
||||
ADM8211 WIRELESS DRIVER
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://linuxwireless.org/
|
||||
W: http://wireless.kernel.org/
|
||||
S: Orphan
|
||||
F: drivers/net/wireless/adm8211.*
|
||||
|
||||
|
@ -1423,7 +1423,7 @@ B43 WIRELESS DRIVER
|
|||
M: Stefano Brivio <stefano.brivio@polimi.it>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: b43-dev@lists.infradead.org
|
||||
W: http://linuxwireless.org/en/users/Drivers/b43
|
||||
W: http://wireless.kernel.org/en/users/Drivers/b43
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/b43/
|
||||
|
||||
|
@ -1432,7 +1432,7 @@ M: Larry Finger <Larry.Finger@lwfinger.net>
|
|||
M: Stefano Brivio <stefano.brivio@polimi.it>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: b43-dev@lists.infradead.org
|
||||
W: http://linuxwireless.org/en/users/Drivers/b43
|
||||
W: http://wireless.kernel.org/en/users/Drivers/b43
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/b43legacy/
|
||||
|
||||
|
@ -4339,7 +4339,7 @@ F: arch/m68k/hp300/
|
|||
MAC80211
|
||||
M: Johannes Berg <johannes@sipsolutions.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://linuxwireless.org/
|
||||
W: http://wireless.kernel.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
|
||||
S: Maintained
|
||||
F: Documentation/networking/mac80211-injection.txt
|
||||
|
@ -4350,7 +4350,7 @@ MAC80211 PID RATE CONTROL
|
|||
M: Stefano Brivio <stefano.brivio@polimi.it>
|
||||
M: Mattias Nissler <mattias.nissler@gmx.de>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID
|
||||
W: http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
|
||||
S: Maintained
|
||||
F: net/mac80211/rc80211_pid*
|
||||
|
@ -5027,7 +5027,7 @@ F: fs/ocfs2/
|
|||
|
||||
ORINOCO DRIVER
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://linuxwireless.org/en/users/Drivers/orinoco
|
||||
W: http://wireless.kernel.org/en/users/Drivers/orinoco
|
||||
W: http://www.nongnu.org/orinoco/
|
||||
S: Orphan
|
||||
F: drivers/net/wireless/orinoco/
|
||||
|
@ -5729,7 +5729,7 @@ F: net/rose/
|
|||
RTL8180 WIRELESS DRIVER
|
||||
M: "John W. Linville" <linville@tuxdriver.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://linuxwireless.org/
|
||||
W: http://wireless.kernel.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/rtl818x/rtl8180/
|
||||
|
@ -5739,7 +5739,7 @@ M: Herton Ronaldo Krzesinski <herton@canonical.com>
|
|||
M: Hin-Tak Leung <htl10@users.sourceforge.net>
|
||||
M: Larry Finger <Larry.Finger@lwfinger.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://linuxwireless.org/
|
||||
W: http://wireless.kernel.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/rtl818x/rtl8187/
|
||||
|
@ -5748,7 +5748,7 @@ RTL8192CE WIRELESS DRIVER
|
|||
M: Larry Finger <Larry.Finger@lwfinger.net>
|
||||
M: Chaoming Li <chaoming_li@realsil.com.cn>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://linuxwireless.org/
|
||||
W: http://wireless.kernel.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/rtlwifi/
|
||||
|
|
|
@ -2585,35 +2585,6 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
|
||||
/*
|
||||
* 'dev' could be NULL if a channel change is required for the hardware
|
||||
* device itself, instead of a particular VIF.
|
||||
*
|
||||
* FIXME: To be handled properly when monitor mode is supported.
|
||||
*/
|
||||
if (!dev)
|
||||
return -EBUSY;
|
||||
|
||||
vif = netdev_priv(dev);
|
||||
|
||||
if (!ath6kl_cfg80211_ready(vif))
|
||||
return -EIO;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
|
||||
__func__, chan->center_freq, chan->hw_value);
|
||||
vif->next_chan = chan->center_freq;
|
||||
vif->next_ch_type = channel_type;
|
||||
vif->next_ch_band = chan->band;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
|
||||
u8 *rsn_capab)
|
||||
{
|
||||
|
@ -2791,7 +2762,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
p.ssid_len = vif->ssid_len;
|
||||
memcpy(p.ssid, vif->ssid, vif->ssid_len);
|
||||
p.dot11_auth_mode = vif->dot11_auth_mode;
|
||||
p.ch = cpu_to_le16(vif->next_chan);
|
||||
p.ch = cpu_to_le16(info->channel->center_freq);
|
||||
|
||||
/* Enable uAPSD support by default */
|
||||
res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
|
||||
|
@ -2815,8 +2786,8 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
return res;
|
||||
}
|
||||
|
||||
if (ath6kl_set_htcap(vif, vif->next_ch_band,
|
||||
vif->next_ch_type != NL80211_CHAN_NO_HT))
|
||||
if (ath6kl_set_htcap(vif, info->channel->band,
|
||||
info->channel_type != NL80211_CHAN_NO_HT))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
|
@ -3271,7 +3242,6 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
|
|||
.suspend = __ath6kl_cfg80211_suspend,
|
||||
.resume = __ath6kl_cfg80211_resume,
|
||||
#endif
|
||||
.set_channel = ath6kl_set_channel,
|
||||
.start_ap = ath6kl_start_ap,
|
||||
.change_beacon = ath6kl_change_beacon,
|
||||
.stop_ap = ath6kl_stop_ap,
|
||||
|
|
|
@ -553,9 +553,6 @@ struct ath6kl_vif {
|
|||
u32 last_cancel_roc_id;
|
||||
u32 send_action_id;
|
||||
bool probe_req_report;
|
||||
u16 next_chan;
|
||||
enum nl80211_channel_type next_ch_type;
|
||||
enum ieee80211_band next_ch_band;
|
||||
u16 assoc_bss_beacon_int;
|
||||
u16 listen_intvl_t;
|
||||
u16 bmiss_time_t;
|
||||
|
|
|
@ -598,7 +598,6 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
|
|||
|
||||
struct ath6kl *ar = vif->ar;
|
||||
|
||||
vif->next_chan = channel;
|
||||
vif->profile.ch = cpu_to_le16(channel);
|
||||
|
||||
switch (vif->nw_type) {
|
||||
|
|
|
@ -3,7 +3,9 @@ ath9k-y += beacon.o \
|
|||
init.o \
|
||||
main.o \
|
||||
recv.o \
|
||||
xmit.o
|
||||
xmit.o \
|
||||
link.o \
|
||||
antenna.o
|
||||
|
||||
ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
|
||||
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
|
||||
|
|
|
@ -126,7 +126,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
|
|||
sc->irq = irq;
|
||||
|
||||
/* Will be cleared in ath9k_start() */
|
||||
sc->sc_flags |= SC_OP_INVALID;
|
||||
set_bit(SC_OP_INVALID, &sc->sc_flags);
|
||||
|
||||
ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
|
||||
if (ret) {
|
||||
|
|
|
@ -0,0 +1,776 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ath9k.h"
|
||||
|
||||
static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
|
||||
int mindelta, int main_rssi_avg,
|
||||
int alt_rssi_avg, int pkt_count)
|
||||
{
|
||||
return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
|
||||
(alt_rssi_avg > main_rssi_avg + maxdelta)) ||
|
||||
(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
|
||||
}
|
||||
|
||||
static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
|
||||
int curr_main_set, int curr_alt_set,
|
||||
int alt_rssi_avg, int main_rssi_avg)
|
||||
{
|
||||
bool result = false;
|
||||
switch (div_group) {
|
||||
case 0:
|
||||
if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
|
||||
result = true;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
|
||||
(curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
|
||||
(alt_rssi_avg >= (main_rssi_avg - 5))) ||
|
||||
((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
|
||||
(curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
|
||||
(alt_rssi_avg >= (main_rssi_avg - 2)))) &&
|
||||
(alt_rssi_avg >= 4))
|
||||
result = true;
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
|
||||
struct ath_hw_antcomb_conf ant_conf,
|
||||
int main_rssi_avg)
|
||||
{
|
||||
antcomb->quick_scan_cnt = 0;
|
||||
|
||||
if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
|
||||
antcomb->rssi_lna2 = main_rssi_avg;
|
||||
else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
|
||||
antcomb->rssi_lna1 = main_rssi_avg;
|
||||
|
||||
switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
|
||||
case 0x10: /* LNA2 A-B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
|
||||
struct ath_hw_antcomb_conf *div_ant_conf,
|
||||
int main_rssi_avg, int alt_rssi_avg,
|
||||
int alt_ratio)
|
||||
{
|
||||
/* alt_good */
|
||||
switch (antcomb->quick_scan_cnt) {
|
||||
case 0:
|
||||
/* set alt to main, and alt to first conf */
|
||||
div_ant_conf->main_lna_conf = antcomb->main_conf;
|
||||
div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
|
||||
break;
|
||||
case 1:
|
||||
/* set alt to main, and alt to first conf */
|
||||
div_ant_conf->main_lna_conf = antcomb->main_conf;
|
||||
div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
|
||||
antcomb->rssi_first = main_rssi_avg;
|
||||
antcomb->rssi_second = alt_rssi_avg;
|
||||
|
||||
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
|
||||
/* main is LNA1 */
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->first_ratio = true;
|
||||
else
|
||||
antcomb->first_ratio = false;
|
||||
} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->first_ratio = true;
|
||||
else
|
||||
antcomb->first_ratio = false;
|
||||
} else {
|
||||
if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
|
||||
(alt_rssi_avg > main_rssi_avg +
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
|
||||
(alt_rssi_avg > main_rssi_avg)) &&
|
||||
(antcomb->total_pkt_count > 50))
|
||||
antcomb->first_ratio = true;
|
||||
else
|
||||
antcomb->first_ratio = false;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
antcomb->alt_good = false;
|
||||
antcomb->scan_not_start = false;
|
||||
antcomb->scan = false;
|
||||
antcomb->rssi_first = main_rssi_avg;
|
||||
antcomb->rssi_third = alt_rssi_avg;
|
||||
|
||||
if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
|
||||
antcomb->rssi_lna1 = alt_rssi_avg;
|
||||
else if (antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
antcomb->rssi_lna2 = alt_rssi_avg;
|
||||
else if (antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
|
||||
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
|
||||
antcomb->rssi_lna2 = main_rssi_avg;
|
||||
else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
|
||||
antcomb->rssi_lna1 = main_rssi_avg;
|
||||
}
|
||||
|
||||
if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
|
||||
ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
|
||||
div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
|
||||
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->second_ratio = true;
|
||||
else
|
||||
antcomb->second_ratio = false;
|
||||
} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->second_ratio = true;
|
||||
else
|
||||
antcomb->second_ratio = false;
|
||||
} else {
|
||||
if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
|
||||
(alt_rssi_avg > main_rssi_avg +
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
|
||||
(alt_rssi_avg > main_rssi_avg)) &&
|
||||
(antcomb->total_pkt_count > 50))
|
||||
antcomb->second_ratio = true;
|
||||
else
|
||||
antcomb->second_ratio = false;
|
||||
}
|
||||
|
||||
/* set alt to the conf with maximun ratio */
|
||||
if (antcomb->first_ratio && antcomb->second_ratio) {
|
||||
if (antcomb->rssi_second > antcomb->rssi_third) {
|
||||
/* first alt*/
|
||||
if ((antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2*/
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->first_quick_scan_conf;
|
||||
} else if ((antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)) {
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
} else {
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->second_quick_scan_conf;
|
||||
}
|
||||
} else if (antcomb->first_ratio) {
|
||||
/* first alt */
|
||||
if ((antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->first_quick_scan_conf;
|
||||
} else if (antcomb->second_ratio) {
|
||||
/* second alt */
|
||||
if ((antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->second_quick_scan_conf;
|
||||
} else {
|
||||
/* main is largest */
|
||||
if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf = antcomb->main_conf;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
||||
struct ath_ant_comb *antcomb,
|
||||
int alt_ratio)
|
||||
{
|
||||
if (ant_conf->div_group == 0) {
|
||||
/* Adjust the fast_div_bias based on main and alt lna conf */
|
||||
switch ((ant_conf->main_lna_conf << 4) |
|
||||
ant_conf->alt_lna_conf) {
|
||||
case 0x01: /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x3b;
|
||||
break;
|
||||
case 0x02: /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x3d;
|
||||
break;
|
||||
case 0x03: /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
case 0x10: /* LNA2 A-B */
|
||||
ant_conf->fast_div_bias = 0x7;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
ant_conf->fast_div_bias = 0x7;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
ant_conf->fast_div_bias = 0x6;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x0;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
ant_conf->fast_div_bias = 0x6;
|
||||
break;
|
||||
case 0x30: /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
case 0x31: /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x3b;
|
||||
break;
|
||||
case 0x32: /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x3d;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (ant_conf->div_group == 1) {
|
||||
/* Adjust the fast_div_bias based on main and alt_lna_conf */
|
||||
switch ((ant_conf->main_lna_conf << 4) |
|
||||
ant_conf->alt_lna_conf) {
|
||||
case 0x01: /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x02: /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x03: /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x10: /* LNA2 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x30: /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x31: /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x32: /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (ant_conf->div_group == 2) {
|
||||
/* Adjust the fast_div_bias based on main and alt_lna_conf */
|
||||
switch ((ant_conf->main_lna_conf << 4) |
|
||||
ant_conf->alt_lna_conf) {
|
||||
case 0x01: /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x02: /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x03: /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x10: /* LNA2 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x30: /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x31: /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x32: /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
|
||||
{
|
||||
struct ath_hw_antcomb_conf div_ant_conf;
|
||||
struct ath_ant_comb *antcomb = &sc->ant_comb;
|
||||
int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
|
||||
int curr_main_set;
|
||||
int main_rssi = rs->rs_rssi_ctl0;
|
||||
int alt_rssi = rs->rs_rssi_ctl1;
|
||||
int rx_ant_conf, main_ant_conf;
|
||||
bool short_scan = false;
|
||||
|
||||
rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
|
||||
ATH_ANT_RX_MASK;
|
||||
main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
|
||||
ATH_ANT_RX_MASK;
|
||||
|
||||
/* Record packet only when both main_rssi and alt_rssi is positive */
|
||||
if (main_rssi > 0 && alt_rssi > 0) {
|
||||
antcomb->total_pkt_count++;
|
||||
antcomb->main_total_rssi += main_rssi;
|
||||
antcomb->alt_total_rssi += alt_rssi;
|
||||
if (main_ant_conf == rx_ant_conf)
|
||||
antcomb->main_recv_cnt++;
|
||||
else
|
||||
antcomb->alt_recv_cnt++;
|
||||
}
|
||||
|
||||
/* Short scan check */
|
||||
if (antcomb->scan && antcomb->alt_good) {
|
||||
if (time_after(jiffies, antcomb->scan_start_time +
|
||||
msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
|
||||
short_scan = true;
|
||||
else
|
||||
if (antcomb->total_pkt_count ==
|
||||
ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
|
||||
alt_ratio = ((antcomb->alt_recv_cnt * 100) /
|
||||
antcomb->total_pkt_count);
|
||||
if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
|
||||
short_scan = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
|
||||
rs->rs_moreaggr) && !short_scan)
|
||||
return;
|
||||
|
||||
if (antcomb->total_pkt_count) {
|
||||
alt_ratio = ((antcomb->alt_recv_cnt * 100) /
|
||||
antcomb->total_pkt_count);
|
||||
main_rssi_avg = (antcomb->main_total_rssi /
|
||||
antcomb->total_pkt_count);
|
||||
alt_rssi_avg = (antcomb->alt_total_rssi /
|
||||
antcomb->total_pkt_count);
|
||||
}
|
||||
|
||||
|
||||
ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
|
||||
curr_alt_set = div_ant_conf.alt_lna_conf;
|
||||
curr_main_set = div_ant_conf.main_lna_conf;
|
||||
|
||||
antcomb->count++;
|
||||
|
||||
if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
|
||||
if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
|
||||
ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
|
||||
main_rssi_avg);
|
||||
antcomb->alt_good = true;
|
||||
} else {
|
||||
antcomb->alt_good = false;
|
||||
}
|
||||
|
||||
antcomb->count = 0;
|
||||
antcomb->scan = true;
|
||||
antcomb->scan_not_start = true;
|
||||
}
|
||||
|
||||
if (!antcomb->scan) {
|
||||
if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
|
||||
alt_ratio, curr_main_set, curr_alt_set,
|
||||
alt_rssi_avg, main_rssi_avg)) {
|
||||
if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
|
||||
/* Switch main and alt LNA */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
} else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
}
|
||||
|
||||
goto div_comb_done;
|
||||
} else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
|
||||
(curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
|
||||
/* Set alt to another LNA */
|
||||
if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
|
||||
goto div_comb_done;
|
||||
}
|
||||
|
||||
if ((alt_rssi_avg < (main_rssi_avg +
|
||||
div_ant_conf.lna1_lna2_delta)))
|
||||
goto div_comb_done;
|
||||
}
|
||||
|
||||
if (!antcomb->scan_not_start) {
|
||||
switch (curr_alt_set) {
|
||||
case ATH_ANT_DIV_COMB_LNA2:
|
||||
antcomb->rssi_lna2 = alt_rssi_avg;
|
||||
antcomb->rssi_lna1 = main_rssi_avg;
|
||||
antcomb->scan = true;
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case ATH_ANT_DIV_COMB_LNA1:
|
||||
antcomb->rssi_lna1 = alt_rssi_avg;
|
||||
antcomb->rssi_lna2 = main_rssi_avg;
|
||||
antcomb->scan = true;
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
|
||||
antcomb->rssi_add = alt_rssi_avg;
|
||||
antcomb->scan = true;
|
||||
/* set to A-B */
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
break;
|
||||
case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
|
||||
antcomb->rssi_sub = alt_rssi_avg;
|
||||
antcomb->scan = false;
|
||||
if (antcomb->rssi_lna2 >
|
||||
(antcomb->rssi_lna1 +
|
||||
ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
|
||||
/* use LNA2 as main LNA */
|
||||
if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
|
||||
(antcomb->rssi_add > antcomb->rssi_sub)) {
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
} else if (antcomb->rssi_sub >
|
||||
antcomb->rssi_lna1) {
|
||||
/* set to A-B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
} else {
|
||||
/* set to LNA1 */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
}
|
||||
} else {
|
||||
/* use LNA1 as main LNA */
|
||||
if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
|
||||
(antcomb->rssi_add > antcomb->rssi_sub)) {
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
} else if (antcomb->rssi_sub >
|
||||
antcomb->rssi_lna1) {
|
||||
/* set to A-B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
} else {
|
||||
/* set to LNA2 */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!antcomb->alt_good) {
|
||||
antcomb->scan_not_start = false;
|
||||
/* Set alt to another LNA */
|
||||
if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
} else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
}
|
||||
goto div_comb_done;
|
||||
}
|
||||
}
|
||||
|
||||
ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
alt_ratio);
|
||||
|
||||
antcomb->quick_scan_cnt++;
|
||||
|
||||
div_comb_done:
|
||||
ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
|
||||
ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
|
||||
|
||||
antcomb->scan_start_time = jiffies;
|
||||
antcomb->total_pkt_count = 0;
|
||||
antcomb->main_total_rssi = 0;
|
||||
antcomb->alt_total_rssi = 0;
|
||||
antcomb->main_recv_cnt = 0;
|
||||
antcomb->alt_recv_cnt = 0;
|
||||
}
|
||||
|
||||
void ath_ant_comb_update(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_hw_antcomb_conf div_ant_conf;
|
||||
u8 lna_conf;
|
||||
|
||||
ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
|
||||
|
||||
if (sc->ant_rx == 1)
|
||||
lna_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
lna_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
|
||||
div_ant_conf.main_lna_conf = lna_conf;
|
||||
div_ant_conf.alt_lna_conf = lna_conf;
|
||||
|
||||
ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
|
||||
}
|
|
@ -653,7 +653,6 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
|
|||
}
|
||||
|
||||
static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
|
||||
u8 num_chains,
|
||||
struct coeff *coeff,
|
||||
bool is_reusable)
|
||||
{
|
||||
|
@ -677,7 +676,9 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
|
|||
}
|
||||
|
||||
/* Load the average of 2 passes */
|
||||
for (i = 0; i < num_chains; i++) {
|
||||
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
|
||||
if (!(ah->txchainmask & (1 << i)))
|
||||
continue;
|
||||
nmeasurement = REG_READ_FIELD(ah,
|
||||
AR_PHY_TX_IQCAL_STATUS_B0,
|
||||
AR_PHY_CALIBRATED_GAINS_0);
|
||||
|
@ -767,16 +768,13 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
|
|||
};
|
||||
struct coeff coeff;
|
||||
s32 iq_res[6];
|
||||
u8 num_chains = 0;
|
||||
int i, im, j;
|
||||
int nmeasurement;
|
||||
|
||||
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
|
||||
if (ah->txchainmask & (1 << i))
|
||||
num_chains++;
|
||||
}
|
||||
if (!(ah->txchainmask & (1 << i)))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < num_chains; i++) {
|
||||
nmeasurement = REG_READ_FIELD(ah,
|
||||
AR_PHY_TX_IQCAL_STATUS_B0,
|
||||
AR_PHY_CALIBRATED_GAINS_0);
|
||||
|
@ -839,8 +837,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
|
|||
coeff.phs_coeff[i][im] -= 128;
|
||||
}
|
||||
}
|
||||
ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains,
|
||||
&coeff, is_reusable);
|
||||
ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
|
||||
|
||||
return;
|
||||
|
||||
|
@ -901,7 +898,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
|
|||
bool is_reusable = true, status = true;
|
||||
bool run_rtt_cal = false, run_agc_cal;
|
||||
bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
|
||||
bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
|
||||
u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
|
||||
AR_PHY_AGC_CONTROL_FLTR_CAL |
|
||||
AR_PHY_AGC_CONTROL_PKDET_CAL;
|
||||
|
@ -970,7 +966,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
|
|||
} else if (caldata && !caldata->done_txiqcal_once)
|
||||
run_agc_cal = true;
|
||||
|
||||
if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
|
||||
if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
|
||||
ar9003_mci_init_cal_req(ah, &is_reusable);
|
||||
|
||||
if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
|
||||
|
@ -993,7 +989,7 @@ skip_tx_iqcal:
|
|||
0, AH_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
|
||||
if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
|
||||
ar9003_mci_init_cal_done(ah);
|
||||
|
||||
if (rtt && !run_rtt_cal) {
|
||||
|
|
|
@ -3412,11 +3412,11 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
|||
if (!dump_base_hdr) {
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "2GHz modal Header");
|
||||
len += ar9003_dump_modal_eeprom(buf, len, size,
|
||||
len = ar9003_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader2G);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "5GHz modal Header");
|
||||
len += ar9003_dump_modal_eeprom(buf, len, size,
|
||||
len = ar9003_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader5G);
|
||||
goto out;
|
||||
}
|
||||
|
@ -3613,6 +3613,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
|
|||
value = ar9003_switch_com_spdt_get(ah, is2ghz);
|
||||
REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
|
||||
AR_SWITCH_TABLE_COM_SPDT_ALL, value);
|
||||
REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_SPDT_ENABLE);
|
||||
}
|
||||
|
||||
value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
|
||||
|
|
|
@ -35,31 +35,30 @@ static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,
|
|||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
while (time_out) {
|
||||
if (REG_READ(ah, address) & bit_position) {
|
||||
REG_WRITE(ah, address, bit_position);
|
||||
if (!(REG_READ(ah, address) & bit_position)) {
|
||||
udelay(10);
|
||||
time_out -= 10;
|
||||
|
||||
if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) {
|
||||
if (bit_position &
|
||||
AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
|
||||
ar9003_mci_reset_req_wakeup(ah);
|
||||
|
||||
if (bit_position &
|
||||
(AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
|
||||
AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
|
||||
AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
|
||||
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG);
|
||||
}
|
||||
break;
|
||||
if (time_out < 0)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
REG_WRITE(ah, address, bit_position);
|
||||
|
||||
udelay(10);
|
||||
time_out -= 10;
|
||||
|
||||
if (time_out < 0)
|
||||
if (address != AR_MCI_INTERRUPT_RX_MSG_RAW)
|
||||
break;
|
||||
|
||||
if (bit_position & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
|
||||
ar9003_mci_reset_req_wakeup(ah);
|
||||
|
||||
if (bit_position & (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
|
||||
AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
|
||||
AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
|
||||
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_RX_MSG);
|
||||
break;
|
||||
}
|
||||
|
||||
if (time_out <= 0) {
|
||||
|
@ -127,14 +126,13 @@ static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,
|
|||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
u32 payload[4] = {0, 0, 0, 0};
|
||||
|
||||
if (!mci->bt_version_known &&
|
||||
(mci->bt_state != MCI_BT_SLEEP)) {
|
||||
MCI_GPM_SET_TYPE_OPCODE(payload,
|
||||
MCI_GPM_COEX_AGENT,
|
||||
MCI_GPM_COEX_VERSION_QUERY);
|
||||
ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
|
||||
wait_done, true);
|
||||
}
|
||||
if (mci->bt_version_known ||
|
||||
(mci->bt_state == MCI_BT_SLEEP))
|
||||
return;
|
||||
|
||||
MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
|
||||
MCI_GPM_COEX_VERSION_QUERY);
|
||||
ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
|
||||
}
|
||||
|
||||
static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
|
||||
|
@ -158,15 +156,14 @@ static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
|
|||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
u32 *payload = &mci->wlan_channels[0];
|
||||
|
||||
if ((mci->wlan_channels_update == true) &&
|
||||
(mci->bt_state != MCI_BT_SLEEP)) {
|
||||
MCI_GPM_SET_TYPE_OPCODE(payload,
|
||||
MCI_GPM_COEX_AGENT,
|
||||
MCI_GPM_COEX_WLAN_CHANNELS);
|
||||
ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
|
||||
wait_done, true);
|
||||
MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
|
||||
}
|
||||
if (!mci->wlan_channels_update ||
|
||||
(mci->bt_state == MCI_BT_SLEEP))
|
||||
return;
|
||||
|
||||
MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
|
||||
MCI_GPM_COEX_WLAN_CHANNELS);
|
||||
ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
|
||||
MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
|
||||
}
|
||||
|
||||
static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
|
||||
|
@ -174,29 +171,30 @@ static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
|
|||
{
|
||||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
u32 payload[4] = {0, 0, 0, 0};
|
||||
bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
|
||||
MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
|
||||
bool query_btinfo;
|
||||
|
||||
if (mci->bt_state != MCI_BT_SLEEP) {
|
||||
if (mci->bt_state == MCI_BT_SLEEP)
|
||||
return;
|
||||
|
||||
MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
|
||||
MCI_GPM_COEX_STATUS_QUERY);
|
||||
query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
|
||||
MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
|
||||
MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
|
||||
MCI_GPM_COEX_STATUS_QUERY);
|
||||
|
||||
*(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
|
||||
|
||||
/*
|
||||
* If bt_status_query message is not sent successfully,
|
||||
* then need_flush_btinfo should be set again.
|
||||
*/
|
||||
if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
|
||||
wait_done, true)) {
|
||||
if (query_btinfo)
|
||||
mci->need_flush_btinfo = true;
|
||||
}
|
||||
*(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
|
||||
|
||||
/*
|
||||
* If bt_status_query message is not sent successfully,
|
||||
* then need_flush_btinfo should be set again.
|
||||
*/
|
||||
if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
|
||||
wait_done, true)) {
|
||||
if (query_btinfo)
|
||||
mci->query_bt = false;
|
||||
mci->need_flush_btinfo = true;
|
||||
}
|
||||
|
||||
if (query_btinfo)
|
||||
mci->query_bt = false;
|
||||
}
|
||||
|
||||
static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
|
||||
|
@ -241,73 +239,73 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah)
|
|||
ar9003_mci_remote_reset(ah, true);
|
||||
ar9003_mci_send_req_wake(ah, true);
|
||||
|
||||
if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
|
||||
if (!ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500))
|
||||
goto clear_redunt;
|
||||
|
||||
mci->bt_state = MCI_BT_AWAKE;
|
||||
mci->bt_state = MCI_BT_AWAKE;
|
||||
|
||||
/*
|
||||
* we don't need to send more remote_reset at this moment.
|
||||
* If BT receive first remote_reset, then BT HW will
|
||||
* be cleaned up and will be able to receive req_wake
|
||||
* and BT HW will respond sys_waking.
|
||||
* In this case, WLAN will receive BT's HW sys_waking.
|
||||
* Otherwise, if BT SW missed initial remote_reset,
|
||||
* that remote_reset will still clean up BT MCI RX,
|
||||
* and the req_wake will wake BT up,
|
||||
* and BT SW will respond this req_wake with a remote_reset and
|
||||
* sys_waking. In this case, WLAN will receive BT's SW
|
||||
* sys_waking. In either case, BT's RX is cleaned up. So we
|
||||
* don't need to reply BT's remote_reset now, if any.
|
||||
* Similarly, if in any case, WLAN can receive BT's sys_waking,
|
||||
* that means WLAN's RX is also fine.
|
||||
*/
|
||||
ar9003_mci_send_sys_waking(ah, true);
|
||||
udelay(10);
|
||||
/*
|
||||
* we don't need to send more remote_reset at this moment.
|
||||
* If BT receive first remote_reset, then BT HW will
|
||||
* be cleaned up and will be able to receive req_wake
|
||||
* and BT HW will respond sys_waking.
|
||||
* In this case, WLAN will receive BT's HW sys_waking.
|
||||
* Otherwise, if BT SW missed initial remote_reset,
|
||||
* that remote_reset will still clean up BT MCI RX,
|
||||
* and the req_wake will wake BT up,
|
||||
* and BT SW will respond this req_wake with a remote_reset and
|
||||
* sys_waking. In this case, WLAN will receive BT's SW
|
||||
* sys_waking. In either case, BT's RX is cleaned up. So we
|
||||
* don't need to reply BT's remote_reset now, if any.
|
||||
* Similarly, if in any case, WLAN can receive BT's sys_waking,
|
||||
* that means WLAN's RX is also fine.
|
||||
*/
|
||||
ar9003_mci_send_sys_waking(ah, true);
|
||||
udelay(10);
|
||||
|
||||
/*
|
||||
* Set BT priority interrupt value to be 0xff to
|
||||
* avoid having too many BT PRIORITY interrupts.
|
||||
*/
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
|
||||
/*
|
||||
* Set BT priority interrupt value to be 0xff to
|
||||
* avoid having too many BT PRIORITY interrupts.
|
||||
*/
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
|
||||
REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
|
||||
|
||||
/*
|
||||
* A contention reset will be received after send out
|
||||
* sys_waking. Also BT priority interrupt bits will be set.
|
||||
* Clear those bits before the next step.
|
||||
*/
|
||||
/*
|
||||
* A contention reset will be received after send out
|
||||
* sys_waking. Also BT priority interrupt bits will be set.
|
||||
* Clear those bits before the next step.
|
||||
*/
|
||||
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
|
||||
AR_MCI_INTERRUPT_BT_PRI);
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI);
|
||||
|
||||
if (mci->is_2g) {
|
||||
ar9003_mci_send_lna_transfer(ah, true);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if ((mci->is_2g && !mci->update_2g5g)) {
|
||||
if (ar9003_mci_wait_for_interrupt(ah,
|
||||
AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
|
||||
mci_timeout))
|
||||
ath_dbg(common, MCI,
|
||||
"MCI WLAN has control over the LNA & BT obeys it\n");
|
||||
else
|
||||
ath_dbg(common, MCI,
|
||||
"MCI BT didn't respond to LNA_TRANS\n");
|
||||
}
|
||||
if (mci->is_2g) {
|
||||
ar9003_mci_send_lna_transfer(ah, true);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if ((mci->is_2g && !mci->update_2g5g)) {
|
||||
if (ar9003_mci_wait_for_interrupt(ah,
|
||||
AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
|
||||
mci_timeout))
|
||||
ath_dbg(common, MCI,
|
||||
"MCI WLAN has control over the LNA & BT obeys it\n");
|
||||
else
|
||||
ath_dbg(common, MCI,
|
||||
"MCI BT didn't respond to LNA_TRANS\n");
|
||||
}
|
||||
|
||||
clear_redunt:
|
||||
/* Clear the extra redundant SYS_WAKING from BT */
|
||||
if ((mci->bt_state == MCI_BT_AWAKE) &&
|
||||
(REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
|
||||
(REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
|
||||
(REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
|
@ -330,7 +328,6 @@ void ar9003_mci_set_full_sleep(struct ath_hw *ah)
|
|||
}
|
||||
|
||||
mci->ready = false;
|
||||
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
|
||||
}
|
||||
|
||||
static void ar9003_mci_disable_interrupt(struct ath_hw *ah)
|
||||
|
@ -615,9 +612,9 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
|
|||
}
|
||||
break;
|
||||
}
|
||||
} else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) {
|
||||
} else if ((recv_type == gpm_type) &&
|
||||
(recv_opcode == gpm_opcode))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if it's cal_grant
|
||||
|
@ -731,38 +728,38 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP))
|
||||
goto exit;
|
||||
|
||||
if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
|
||||
ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
|
||||
if (!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) &&
|
||||
!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE))
|
||||
goto exit;
|
||||
|
||||
/*
|
||||
* BT is sleeping. Check if BT wakes up during
|
||||
* WLAN calibration. If BT wakes up during
|
||||
* WLAN calibration, need to go through all
|
||||
* message exchanges again and recal.
|
||||
*/
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
|
||||
AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
|
||||
/*
|
||||
* BT is sleeping. Check if BT wakes up during
|
||||
* WLAN calibration. If BT wakes up during
|
||||
* WLAN calibration, need to go through all
|
||||
* message exchanges again and recal.
|
||||
*/
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
|
||||
(AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
|
||||
AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE));
|
||||
|
||||
ar9003_mci_remote_reset(ah, true);
|
||||
ar9003_mci_send_sys_waking(ah, true);
|
||||
udelay(1);
|
||||
ar9003_mci_remote_reset(ah, true);
|
||||
ar9003_mci_send_sys_waking(ah, true);
|
||||
udelay(1);
|
||||
|
||||
if (IS_CHAN_2GHZ(chan))
|
||||
ar9003_mci_send_lna_transfer(ah, true);
|
||||
if (IS_CHAN_2GHZ(chan))
|
||||
ar9003_mci_send_lna_transfer(ah, true);
|
||||
|
||||
mci_hw->bt_state = MCI_BT_AWAKE;
|
||||
|
||||
if (caldata) {
|
||||
caldata->done_txiqcal_once = false;
|
||||
caldata->done_txclcal_once = false;
|
||||
caldata->rtt_done = false;
|
||||
}
|
||||
|
||||
if (!ath9k_hw_init_cal(ah, chan))
|
||||
return -EIO;
|
||||
mci_hw->bt_state = MCI_BT_AWAKE;
|
||||
|
||||
if (caldata) {
|
||||
caldata->done_txiqcal_once = false;
|
||||
caldata->done_txclcal_once = false;
|
||||
caldata->rtt_done = false;
|
||||
}
|
||||
|
||||
if (!ath9k_hw_init_cal(ah, chan))
|
||||
return -EIO;
|
||||
|
||||
exit:
|
||||
ar9003_mci_enable_interrupt(ah);
|
||||
return 0;
|
||||
|
@ -798,29 +795,27 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)
|
|||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
u32 thresh;
|
||||
|
||||
if (enable) {
|
||||
REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
|
||||
AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
|
||||
REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
|
||||
AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
|
||||
|
||||
if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
|
||||
thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
|
||||
REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
|
||||
REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
|
||||
} else {
|
||||
REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
|
||||
}
|
||||
|
||||
REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
|
||||
} else {
|
||||
if (!enable) {
|
||||
REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
|
||||
return;
|
||||
}
|
||||
REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
|
||||
REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
|
||||
AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
|
||||
|
||||
if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
|
||||
thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
|
||||
REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
|
||||
REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
|
||||
} else
|
||||
REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
|
||||
|
||||
REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
|
||||
}
|
||||
|
||||
void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
|
||||
|
@ -943,26 +938,27 @@ static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
|
|||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
u32 new_flags, to_set, to_clear;
|
||||
|
||||
if (mci->update_2g5g && (mci->bt_state != MCI_BT_SLEEP)) {
|
||||
if (mci->is_2g) {
|
||||
new_flags = MCI_2G_FLAGS;
|
||||
to_clear = MCI_2G_FLAGS_CLEAR_MASK;
|
||||
to_set = MCI_2G_FLAGS_SET_MASK;
|
||||
} else {
|
||||
new_flags = MCI_5G_FLAGS;
|
||||
to_clear = MCI_5G_FLAGS_CLEAR_MASK;
|
||||
to_set = MCI_5G_FLAGS_SET_MASK;
|
||||
}
|
||||
if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP))
|
||||
return;
|
||||
|
||||
if (to_clear)
|
||||
ar9003_mci_send_coex_bt_flags(ah, wait_done,
|
||||
if (mci->is_2g) {
|
||||
new_flags = MCI_2G_FLAGS;
|
||||
to_clear = MCI_2G_FLAGS_CLEAR_MASK;
|
||||
to_set = MCI_2G_FLAGS_SET_MASK;
|
||||
} else {
|
||||
new_flags = MCI_5G_FLAGS;
|
||||
to_clear = MCI_5G_FLAGS_CLEAR_MASK;
|
||||
to_set = MCI_5G_FLAGS_SET_MASK;
|
||||
}
|
||||
|
||||
if (to_clear)
|
||||
ar9003_mci_send_coex_bt_flags(ah, wait_done,
|
||||
MCI_GPM_COEX_BT_FLAGS_CLEAR,
|
||||
to_clear);
|
||||
if (to_set)
|
||||
ar9003_mci_send_coex_bt_flags(ah, wait_done,
|
||||
if (to_set)
|
||||
ar9003_mci_send_coex_bt_flags(ah, wait_done,
|
||||
MCI_GPM_COEX_BT_FLAGS_SET,
|
||||
to_set);
|
||||
}
|
||||
}
|
||||
|
||||
static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
|
||||
|
@ -1018,34 +1014,34 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
|
|||
{
|
||||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
|
||||
if (mci->update_2g5g) {
|
||||
if (mci->is_2g) {
|
||||
ar9003_mci_send_2g5g_status(ah, true);
|
||||
ar9003_mci_send_lna_transfer(ah, true);
|
||||
udelay(5);
|
||||
if (!mci->update_2g5g)
|
||||
return;
|
||||
|
||||
REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
|
||||
AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
|
||||
REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
|
||||
AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
|
||||
if (mci->is_2g) {
|
||||
ar9003_mci_send_2g5g_status(ah, true);
|
||||
ar9003_mci_send_lna_transfer(ah, true);
|
||||
udelay(5);
|
||||
|
||||
if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
|
||||
REG_SET_BIT(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
|
||||
}
|
||||
} else {
|
||||
ar9003_mci_send_lna_take(ah, true);
|
||||
udelay(5);
|
||||
REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
|
||||
AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
|
||||
REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
|
||||
AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
|
||||
|
||||
REG_SET_BIT(ah, AR_MCI_TX_CTRL,
|
||||
AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
|
||||
REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
|
||||
AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
|
||||
REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
|
||||
if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
|
||||
REG_SET_BIT(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
|
||||
} else {
|
||||
ar9003_mci_send_lna_take(ah, true);
|
||||
udelay(5);
|
||||
|
||||
ar9003_mci_send_2g5g_status(ah, true);
|
||||
}
|
||||
REG_SET_BIT(ah, AR_MCI_TX_CTRL,
|
||||
AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
|
||||
REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
|
||||
AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
|
||||
REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
|
||||
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
|
||||
|
||||
ar9003_mci_send_2g5g_status(ah, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1132,7 +1128,7 @@ void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
|
|||
if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {
|
||||
ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n");
|
||||
} else {
|
||||
is_reusable = false;
|
||||
*is_reusable = false;
|
||||
ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n");
|
||||
}
|
||||
}
|
||||
|
@ -1259,12 +1255,12 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
|
|||
}
|
||||
if (p_data)
|
||||
*p_data = more_gpm;
|
||||
}
|
||||
}
|
||||
|
||||
if (value != MCI_GPM_INVALID)
|
||||
value <<= 4;
|
||||
if (value != MCI_GPM_INVALID)
|
||||
value <<= 4;
|
||||
|
||||
break;
|
||||
break;
|
||||
case MCI_STATE_LAST_SCHD_MSG_OFFSET:
|
||||
value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
|
||||
AR_MCI_RX_LAST_SCHD_MSG_INDEX);
|
||||
|
@ -1359,24 +1355,22 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
|
|||
ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
|
||||
break;
|
||||
case MCI_STATE_NEED_FLUSH_BT_INFO:
|
||||
/*
|
||||
* btcoex_hw.mci.unhalt_bt_gpm means whether it's
|
||||
* needed to send UNHALT message. It's set whenever
|
||||
* there's a request to send HALT message.
|
||||
* mci_halted_bt_gpm means whether HALT message is sent
|
||||
* out successfully.
|
||||
*
|
||||
* Checking (mci_unhalt_bt_gpm == false) instead of
|
||||
* checking (ah->mci_halted_bt_gpm == false) will make
|
||||
* sure currently is in UNHALT-ed mode and BT can
|
||||
* respond to status query.
|
||||
*/
|
||||
value = (!mci->unhalt_bt_gpm &&
|
||||
mci->need_flush_btinfo) ? 1 : 0;
|
||||
if (p_data)
|
||||
mci->need_flush_btinfo =
|
||||
(*p_data != 0) ? true : false;
|
||||
break;
|
||||
/*
|
||||
* btcoex_hw.mci.unhalt_bt_gpm means whether it's
|
||||
* needed to send UNHALT message. It's set whenever
|
||||
* there's a request to send HALT message.
|
||||
* mci_halted_bt_gpm means whether HALT message is sent
|
||||
* out successfully.
|
||||
*
|
||||
* Checking (mci_unhalt_bt_gpm == false) instead of
|
||||
* checking (ah->mci_halted_bt_gpm == false) will make
|
||||
* sure currently is in UNHALT-ed mode and BT can
|
||||
* respond to status query.
|
||||
*/
|
||||
value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0;
|
||||
if (p_data)
|
||||
mci->need_flush_btinfo = (*p_data != 0) ? true : false;
|
||||
break;
|
||||
case MCI_STATE_RECOVER_RX:
|
||||
ar9003_mci_prep_interface(ah);
|
||||
mci->query_bt = true;
|
||||
|
@ -1387,9 +1381,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
|
|||
case MCI_STATE_NEED_FTP_STOMP:
|
||||
value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
|
||||
break;
|
||||
case MCI_STATE_NEED_TUNING:
|
||||
value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1397,3 +1388,19 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
|
|||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL(ar9003_mci_state);
|
||||
|
||||
void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
|
||||
ath_dbg(common, MCI, "Give LNA and SPDT control to BT\n");
|
||||
|
||||
REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
|
||||
mci->is_2g = false;
|
||||
mci->update_2g5g = true;
|
||||
ar9003_mci_send_2g5g_status(ah, true);
|
||||
|
||||
/* Force another 2g5g update at next scanning */
|
||||
mci->update_2g5g = true;
|
||||
}
|
||||
|
|
|
@ -212,7 +212,6 @@ enum mci_state_type {
|
|||
MCI_STATE_SET_CONCUR_TX_PRI,
|
||||
MCI_STATE_RECOVER_RX,
|
||||
MCI_STATE_NEED_FTP_STOMP,
|
||||
MCI_STATE_NEED_TUNING,
|
||||
MCI_STATE_DEBUG,
|
||||
MCI_STATE_MAX
|
||||
};
|
||||
|
@ -266,6 +265,7 @@ void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
|
|||
void ar9003_mci_cleanup(struct ath_hw *ah);
|
||||
void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
|
||||
u32 *rx_msg_intr);
|
||||
void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
|
||||
|
||||
/*
|
||||
* These functions are used by ath9k_hw.
|
||||
|
@ -273,10 +273,6 @@ void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
|
|||
|
||||
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
|
||||
|
||||
static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
|
||||
{
|
||||
return ah->btcoex_hw.mci.ready;
|
||||
}
|
||||
void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep);
|
||||
void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable);
|
||||
void ar9003_mci_init_cal_done(struct ath_hw *ah);
|
||||
|
@ -292,10 +288,6 @@ void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
|
|||
|
||||
#else
|
||||
|
||||
static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -676,6 +676,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
|
|||
if (chan->channel == 2484)
|
||||
ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1);
|
||||
|
||||
if (AR_SREV_9462(ah))
|
||||
REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
|
||||
AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
|
||||
|
||||
ah->modes_index = modesIndex;
|
||||
ar9003_hw_override_ini(ah);
|
||||
ar9003_hw_set_channel_regs(ah, chan);
|
||||
|
|
|
@ -820,18 +820,26 @@
|
|||
#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001
|
||||
#define AR_PHY_RX_DELAY_DELAY 0x00003FFF
|
||||
#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010
|
||||
#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x00000001
|
||||
#define AR_PHY_SPECTRAL_SCAN_ENABLE_S 0
|
||||
#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002
|
||||
#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1
|
||||
#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0
|
||||
#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4
|
||||
#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00
|
||||
#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8
|
||||
#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000
|
||||
#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16
|
||||
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000
|
||||
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
|
||||
|
||||
#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x00000001
|
||||
#define AR_PHY_SPECTRAL_SCAN_ENABLE_S 0
|
||||
#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002
|
||||
#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1
|
||||
#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0
|
||||
#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4
|
||||
#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00
|
||||
#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8
|
||||
#define AR_PHY_SPECTRAL_SCAN_COUNT 0x0FFF0000
|
||||
#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16
|
||||
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x10000000
|
||||
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 28
|
||||
#define AR_PHY_SPECTRAL_SCAN_PRIORITY 0x20000000
|
||||
#define AR_PHY_SPECTRAL_SCAN_PRIORITY_S 29
|
||||
#define AR_PHY_SPECTRAL_SCAN_USE_ERR5 0x40000000
|
||||
#define AR_PHY_SPECTRAL_SCAN_USE_ERR5_S 30
|
||||
#define AR_PHY_SPECTRAL_SCAN_COMPRESSED_RPT 0x80000000
|
||||
#define AR_PHY_SPECTRAL_SCAN_COMPRESSED_RPT_S 31
|
||||
|
||||
#define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004
|
||||
#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION 0x00000001
|
||||
#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION_S 0
|
||||
|
|
|
@ -958,7 +958,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
|
|||
{0x0001604c, 0x2699e04f},
|
||||
{0x00016050, 0x6db6db6c},
|
||||
{0x00016058, 0x6c200000},
|
||||
{0x00016080, 0x00040000},
|
||||
{0x00016080, 0x000c0000},
|
||||
{0x00016084, 0x9a68048c},
|
||||
{0x00016088, 0x54214514},
|
||||
{0x0001608c, 0x1203040b},
|
||||
|
@ -981,7 +981,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
|
|||
{0x00016144, 0x02084080},
|
||||
{0x00016148, 0x000080c0},
|
||||
{0x00016280, 0x050a0001},
|
||||
{0x00016284, 0x3d841400},
|
||||
{0x00016284, 0x3d841418},
|
||||
{0x00016288, 0x00000000},
|
||||
{0x0001628c, 0xe3000000},
|
||||
{0x00016290, 0xa1005080},
|
||||
|
@ -1007,6 +1007,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
|
|||
|
||||
static const u32 ar9462_2p0_soc_preamble[][2] = {
|
||||
/* Addr allmodes */
|
||||
{0x000040a4 ,0x00a0c1c9},
|
||||
{0x00007020, 0x00000000},
|
||||
{0x00007034, 0x00000002},
|
||||
{0x00007038, 0x000004c2},
|
||||
|
|
|
@ -307,6 +307,7 @@ struct ath_rx {
|
|||
u8 defant;
|
||||
u8 rxotherant;
|
||||
u32 *rxlink;
|
||||
u32 num_pkts;
|
||||
unsigned int rxfilter;
|
||||
spinlock_t rxbuflock;
|
||||
struct list_head rxbuf;
|
||||
|
@ -325,6 +326,9 @@ int ath_rx_init(struct ath_softc *sc, int nbufs);
|
|||
void ath_rx_cleanup(struct ath_softc *sc);
|
||||
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp);
|
||||
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
|
||||
void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq);
|
||||
void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
|
||||
void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
|
||||
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
|
||||
bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
|
||||
void ath_draintxq(struct ath_softc *sc,
|
||||
|
@ -414,9 +418,9 @@ int ath_beaconq_config(struct ath_softc *sc);
|
|||
void ath_set_beacon(struct ath_softc *sc);
|
||||
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
|
||||
|
||||
/*******/
|
||||
/* ANI */
|
||||
/*******/
|
||||
/*******************/
|
||||
/* Link Monitoring */
|
||||
/*******************/
|
||||
|
||||
#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */
|
||||
#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */
|
||||
|
@ -427,7 +431,9 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
|
|||
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
|
||||
|
||||
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
|
||||
#define ATH_PLL_WORK_INTERVAL 100
|
||||
|
||||
void ath_tx_complete_poll_work(struct work_struct *work);
|
||||
void ath_reset_work(struct work_struct *work);
|
||||
void ath_hw_check(struct work_struct *work);
|
||||
void ath_hw_pll_work(struct work_struct *work);
|
||||
|
@ -436,22 +442,31 @@ void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
|
|||
void ath_paprd_calibrate(struct work_struct *work);
|
||||
void ath_ani_calibrate(unsigned long data);
|
||||
void ath_start_ani(struct ath_common *common);
|
||||
int ath_update_survey_stats(struct ath_softc *sc);
|
||||
void ath_update_survey_nf(struct ath_softc *sc, int channel);
|
||||
|
||||
/**********/
|
||||
/* BTCOEX */
|
||||
/**********/
|
||||
|
||||
enum bt_op_flags {
|
||||
BT_OP_PRIORITY_DETECTED,
|
||||
BT_OP_SCAN,
|
||||
};
|
||||
|
||||
struct ath_btcoex {
|
||||
bool hw_timer_enabled;
|
||||
spinlock_t btcoex_lock;
|
||||
struct timer_list period_timer; /* Timer for BT period */
|
||||
u32 bt_priority_cnt;
|
||||
unsigned long bt_priority_time;
|
||||
unsigned long op_flags;
|
||||
int bt_stomp_type; /* Types of BT stomping */
|
||||
u32 btcoex_no_stomp; /* in usec */
|
||||
u32 btcoex_period; /* in usec */
|
||||
u32 btscan_no_stomp; /* in usec */
|
||||
u32 duty_cycle;
|
||||
u32 bt_wait_time;
|
||||
struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
|
||||
struct ath_mci_profile mci;
|
||||
};
|
||||
|
@ -513,8 +528,10 @@ static inline void ath_deinit_leds(struct ath_softc *sc)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************/
|
||||
/* Antenna diversity/combining */
|
||||
/*******************************/
|
||||
|
||||
#define ATH_ANT_RX_CURRENT_SHIFT 4
|
||||
#define ATH_ANT_RX_MAIN_SHIFT 2
|
||||
#define ATH_ANT_RX_MASK 0x3
|
||||
|
@ -567,6 +584,9 @@ struct ath_ant_comb {
|
|||
unsigned long scan_start_time;
|
||||
};
|
||||
|
||||
void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
|
||||
void ath_ant_comb_update(struct ath_softc *sc);
|
||||
|
||||
/********************/
|
||||
/* Main driver core */
|
||||
/********************/
|
||||
|
@ -584,15 +604,15 @@ struct ath_ant_comb {
|
|||
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
|
||||
#define ATH_RATE_DUMMY_MARKER 0
|
||||
|
||||
#define SC_OP_INVALID BIT(0)
|
||||
#define SC_OP_BEACONS BIT(1)
|
||||
#define SC_OP_OFFCHANNEL BIT(2)
|
||||
#define SC_OP_RXFLUSH BIT(3)
|
||||
#define SC_OP_TSF_RESET BIT(4)
|
||||
#define SC_OP_BT_PRIORITY_DETECTED BIT(5)
|
||||
#define SC_OP_BT_SCAN BIT(6)
|
||||
#define SC_OP_ANI_RUN BIT(7)
|
||||
#define SC_OP_PRIM_STA_VIF BIT(8)
|
||||
enum sc_op_flags {
|
||||
SC_OP_INVALID,
|
||||
SC_OP_BEACONS,
|
||||
SC_OP_RXFLUSH,
|
||||
SC_OP_TSF_RESET,
|
||||
SC_OP_ANI_RUN,
|
||||
SC_OP_PRIM_STA_VIF,
|
||||
SC_OP_HW_RESET,
|
||||
};
|
||||
|
||||
/* Powersave flags */
|
||||
#define PS_WAIT_FOR_BEACON BIT(0)
|
||||
|
@ -638,9 +658,9 @@ struct ath_softc {
|
|||
struct completion paprd_complete;
|
||||
|
||||
unsigned int hw_busy_count;
|
||||
unsigned long sc_flags;
|
||||
|
||||
u32 intrstatus;
|
||||
u32 sc_flags; /* SC_OP_* */
|
||||
u16 ps_flags; /* PS_* */
|
||||
u16 curtxpow;
|
||||
bool ps_enabled;
|
||||
|
@ -736,5 +756,4 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
struct ath9k_vif_iter_data *iter_data);
|
||||
|
||||
|
||||
#endif /* ATH9K_H */
|
||||
|
|
|
@ -48,7 +48,10 @@ int ath_beaconq_config(struct ath_softc *sc)
|
|||
txq = sc->tx.txq_map[WME_AC_BE];
|
||||
ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
|
||||
qi.tqi_aifs = qi_be.tqi_aifs;
|
||||
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
|
||||
if (ah->slottime == ATH9K_SLOT_TIME_20)
|
||||
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
|
||||
else
|
||||
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
|
||||
qi.tqi_cwmax = qi_be.tqi_cwmax;
|
||||
}
|
||||
|
||||
|
@ -387,7 +390,7 @@ void ath_beacon_tasklet(unsigned long data)
|
|||
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
|
||||
ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
|
||||
sc->beacon.bmisscnt = 0;
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
}
|
||||
|
||||
|
@ -477,16 +480,16 @@ static void ath9k_beacon_init(struct ath_softc *sc,
|
|||
u32 next_beacon,
|
||||
u32 beacon_period)
|
||||
{
|
||||
if (sc->sc_flags & SC_OP_TSF_RESET) {
|
||||
if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath9k_hw_reset_tsf(sc->sc_ah);
|
||||
}
|
||||
|
||||
ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
|
||||
|
||||
if (sc->sc_flags & SC_OP_TSF_RESET) {
|
||||
if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
|
||||
ath9k_ps_restore(sc);
|
||||
sc->sc_flags &= ~SC_OP_TSF_RESET;
|
||||
clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,7 +519,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
|
|||
/* Set the computed AP beacon timers */
|
||||
|
||||
ath9k_hw_disable_interrupts(ah);
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
ath9k_beacon_init(sc, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(ah);
|
||||
|
@ -659,7 +662,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
|||
u32 tsf, intval, nexttbtt;
|
||||
|
||||
ath9k_reset_beacon_status(sc);
|
||||
if (!(sc->sc_flags & SC_OP_BEACONS))
|
||||
if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
|
||||
ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
|
||||
|
||||
intval = TU_TO_USEC(conf->beacon_interval);
|
||||
|
@ -724,7 +727,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
|
|||
*/
|
||||
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
|
||||
(vif->type == NL80211_IFTYPE_STATION) &&
|
||||
(sc->sc_flags & SC_OP_BEACONS) &&
|
||||
test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
|
||||
!avp->primary_sta_vif) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"Beacon already configured for a station interface\n");
|
||||
|
@ -810,7 +813,7 @@ void ath_set_beacon(struct ath_softc *sc)
|
|||
return;
|
||||
}
|
||||
|
||||
sc->sc_flags |= SC_OP_BEACONS;
|
||||
set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
}
|
||||
|
||||
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
|
||||
|
@ -818,7 +821,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
|
|||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
if (!ath_has_valid_bslot(sc)) {
|
||||
sc->sc_flags &= ~SC_OP_BEACONS;
|
||||
clear_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -336,10 +336,16 @@ static void ar9003_btcoex_bt_stomp(struct ath_hw *ah,
|
|||
enum ath_stomp_type stomp_type)
|
||||
{
|
||||
struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
|
||||
const u32 *weight = AR_SREV_9462(ah) ? ar9003_wlan_weights[stomp_type] :
|
||||
ar9462_wlan_weights[stomp_type];
|
||||
const u32 *weight = ar9003_wlan_weights[stomp_type];
|
||||
int i;
|
||||
|
||||
if (AR_SREV_9462(ah)) {
|
||||
if ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
|
||||
btcoex->mci.stomp_ftp)
|
||||
stomp_type = ATH_BTCOEX_STOMP_LOW_FTP;
|
||||
weight = ar9462_wlan_weights[stomp_type];
|
||||
}
|
||||
|
||||
for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
|
||||
btcoex->bt_weight[i] = AR9300_BT_WGHT;
|
||||
btcoex->wlan_weight[i] = weight[i];
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
#define ATH_BT_CNT_THRESHOLD 3
|
||||
#define ATH_BT_CNT_SCAN_THRESHOLD 15
|
||||
|
||||
#define ATH_BTCOEX_RX_WAIT_TIME 100
|
||||
#define ATH_BTCOEX_STOMP_FTP_THRESH 5
|
||||
|
||||
#define AR9300_NUM_BT_WEIGHTS 4
|
||||
#define AR9300_NUM_WLAN_WEIGHTS 4
|
||||
/* Defines the BT AR_BT_COEX_WGHT used */
|
||||
|
@ -80,6 +83,7 @@ struct ath9k_hw_mci {
|
|||
u8 bt_ver_major;
|
||||
u8 bt_ver_minor;
|
||||
u8 bt_state;
|
||||
u8 stomp_ftp;
|
||||
};
|
||||
|
||||
struct ath_btcoex_hw {
|
||||
|
|
|
@ -205,10 +205,10 @@ static ssize_t write_file_disable_ani(struct file *file,
|
|||
common->disable_ani = !!disable_ani;
|
||||
|
||||
if (disable_ani) {
|
||||
sc->sc_flags &= ~SC_OP_ANI_RUN;
|
||||
clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
||||
del_timer_sync(&common->ani.timer);
|
||||
} else {
|
||||
sc->sc_flags |= SC_OP_ANI_RUN;
|
||||
set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
||||
ath_start_ani(common);
|
||||
}
|
||||
|
||||
|
@ -374,6 +374,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
|
|||
sc->debug.stats.istats.dtim++;
|
||||
if (status & ATH9K_INT_TSFOOR)
|
||||
sc->debug.stats.istats.tsfoor++;
|
||||
if (status & ATH9K_INT_MCI)
|
||||
sc->debug.stats.istats.mci++;
|
||||
}
|
||||
|
||||
static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
|
||||
|
@ -418,6 +420,7 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
|
|||
PR_IS("DTIMSYNC", dtimsync);
|
||||
PR_IS("DTIM", dtim);
|
||||
PR_IS("TSFOOR", tsfoor);
|
||||
PR_IS("MCI", mci);
|
||||
PR_IS("TOTAL", total);
|
||||
|
||||
len += snprintf(buf + len, mxlen - len,
|
||||
|
@ -1318,7 +1321,7 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
|
|||
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
|
||||
u8 nread;
|
||||
|
||||
if (sc->sc_flags & SC_OP_INVALID)
|
||||
if (test_bit(SC_OP_INVALID, &sc->sc_flags))
|
||||
return -EAGAIN;
|
||||
|
||||
buf = vmalloc(size);
|
||||
|
|
|
@ -86,6 +86,7 @@ struct ath_interrupt_stats {
|
|||
u32 dtim;
|
||||
u32 bb_watchdog;
|
||||
u32 tsfoor;
|
||||
u32 mci;
|
||||
|
||||
/* Sync-cause stats */
|
||||
u32 sync_cause_all;
|
||||
|
|
|
@ -135,7 +135,7 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
|||
if (!dump_base_hdr) {
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "2GHz modal Header");
|
||||
len += ath9k_dump_4k_modal_eeprom(buf, len, size,
|
||||
len = ath9k_dump_4k_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
|||
if (!dump_base_hdr) {
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "2GHz modal Header");
|
||||
len += ar9287_dump_modal_eeprom(buf, len, size,
|
||||
len = ar9287_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -211,11 +211,11 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
|||
if (!dump_base_hdr) {
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "2GHz modal Header");
|
||||
len += ath9k_def_dump_modal_eeprom(buf, len, size,
|
||||
len = ath9k_def_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader[0]);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "5GHz modal Header");
|
||||
len += ath9k_def_dump_modal_eeprom(buf, len, size,
|
||||
len = ath9k_def_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader[1]);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -132,17 +132,18 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
|
|||
|
||||
if (time_after(jiffies, btcoex->bt_priority_time +
|
||||
msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
|
||||
sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
|
||||
clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
|
||||
clear_bit(BT_OP_SCAN, &btcoex->op_flags);
|
||||
/* Detect if colocated bt started scanning */
|
||||
if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
|
||||
ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
|
||||
"BT scan detected\n");
|
||||
sc->sc_flags |= (SC_OP_BT_SCAN |
|
||||
SC_OP_BT_PRIORITY_DETECTED);
|
||||
set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
|
||||
set_bit(BT_OP_SCAN, &btcoex->op_flags);
|
||||
} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
|
||||
ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
|
||||
"BT priority traffic detected\n");
|
||||
sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
|
||||
set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
|
||||
}
|
||||
|
||||
btcoex->bt_priority_cnt = 0;
|
||||
|
@ -190,13 +191,26 @@ static void ath_btcoex_period_timer(unsigned long data)
|
|||
struct ath_softc *sc = (struct ath_softc *) data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
struct ath_mci_profile *mci = &btcoex->mci;
|
||||
u32 timer_period;
|
||||
bool is_btscan;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
|
||||
ath_detect_bt_priority(sc);
|
||||
is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
|
||||
is_btscan = test_bit(BT_OP_SCAN, &btcoex->op_flags);
|
||||
|
||||
btcoex->bt_wait_time += btcoex->btcoex_period;
|
||||
if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {
|
||||
if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP, NULL) &&
|
||||
(mci->num_pan || mci->num_other_acl))
|
||||
ah->btcoex_hw.mci.stomp_ftp =
|
||||
(sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH);
|
||||
else
|
||||
ah->btcoex_hw.mci.stomp_ftp = false;
|
||||
btcoex->bt_wait_time = 0;
|
||||
sc->rx.num_pkts = 0;
|
||||
}
|
||||
|
||||
spin_lock_bh(&btcoex->btcoex_lock);
|
||||
|
||||
|
@ -219,8 +233,7 @@ static void ath_btcoex_period_timer(unsigned long data)
|
|||
|
||||
ath9k_ps_restore(sc);
|
||||
timer_period = btcoex->btcoex_period / 1000;
|
||||
mod_timer(&btcoex->period_timer, jiffies +
|
||||
msecs_to_jiffies(timer_period));
|
||||
mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -233,14 +246,14 @@ static void ath_btcoex_no_stomp_timer(void *arg)
|
|||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
|
||||
|
||||
ath_dbg(common, BTCOEX, "no stomp timer running\n");
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
spin_lock_bh(&btcoex->btcoex_lock);
|
||||
|
||||
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
|
||||
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
|
||||
test_bit(BT_OP_SCAN, &btcoex->op_flags))
|
||||
ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
|
||||
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
|
||||
ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
|
||||
|
@ -292,7 +305,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
|
|||
|
||||
btcoex->bt_priority_cnt = 0;
|
||||
btcoex->bt_priority_time = jiffies;
|
||||
sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
|
||||
btcoex->op_flags &= ~(BT_OP_PRIORITY_DETECTED | BT_OP_SCAN);
|
||||
|
||||
mod_timer(&btcoex->period_timer, jiffies);
|
||||
}
|
||||
|
@ -316,12 +329,13 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc)
|
|||
|
||||
u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
|
||||
{
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
struct ath_mci_profile *mci = &sc->btcoex.mci;
|
||||
u16 aggr_limit = 0;
|
||||
|
||||
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
|
||||
aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
|
||||
else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
|
||||
else if (test_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags))
|
||||
aggr_limit = min((max_4ms_framelen * 3) / 8,
|
||||
(u32)ATH_AMPDU_LIMIT_MAX);
|
||||
|
||||
|
|
|
@ -390,14 +390,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
|
|||
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
|
||||
}
|
||||
|
||||
static void ath9k_hw_aspm_init(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (common->bus_ops->aspm_init)
|
||||
common->bus_ops->aspm_init(common);
|
||||
}
|
||||
|
||||
/* This should work for all families including legacy */
|
||||
static bool ath9k_hw_chip_test(struct ath_hw *ah)
|
||||
{
|
||||
|
@ -693,9 +685,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (ah->is_pciexpress)
|
||||
ath9k_hw_aspm_init(ah);
|
||||
|
||||
r = ath9k_hw_init_macaddr(ah);
|
||||
if (r) {
|
||||
ath_err(common, "Failed to initialize MAC address\n");
|
||||
|
@ -1443,9 +1432,6 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
|
|||
break;
|
||||
}
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
|
||||
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1721,7 +1707,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
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))
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
ar9003_mci_2g5g_switch(ah, true);
|
||||
|
||||
if (AR_SREV_9271(ah))
|
||||
|
@ -1742,10 +1728,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
u64 tsf = 0;
|
||||
int i, r;
|
||||
bool start_mci_reset = false;
|
||||
bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
|
||||
bool save_fullsleep = ah->chip_fullsleep;
|
||||
|
||||
if (mci) {
|
||||
if (ath9k_hw_mci_is_enabled(ah)) {
|
||||
start_mci_reset = ar9003_mci_start_reset(ah, chan);
|
||||
if (start_mci_reset)
|
||||
return 0;
|
||||
|
@ -1774,7 +1759,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
return r;
|
||||
}
|
||||
|
||||
if (mci)
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
ar9003_mci_stop_bt(ah, save_fullsleep);
|
||||
|
||||
saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
|
||||
|
@ -1832,7 +1817,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (mci)
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
|
||||
|
||||
/*
|
||||
|
@ -1951,7 +1936,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
ath9k_hw_loadnf(ah, chan);
|
||||
ath9k_hw_start_nfcal(ah, true);
|
||||
|
||||
if (mci && ar9003_mci_end_reset(ah, chan, caldata))
|
||||
if (ath9k_hw_mci_is_enabled(ah) && ar9003_mci_end_reset(ah, chan, caldata))
|
||||
return -EIO;
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(ah);
|
||||
|
@ -1996,7 +1981,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
if (ath9k_hw_btcoex_is_enabled(ah))
|
||||
ath9k_hw_btcoex_enable(ah);
|
||||
|
||||
if (mci)
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
ar9003_mci_check_bt(ah);
|
||||
|
||||
if (AR_SREV_9300_20_OR_LATER(ah)) {
|
||||
|
@ -2019,39 +2004,35 @@ EXPORT_SYMBOL(ath9k_hw_reset);
|
|||
* Notify Power Mgt is disabled in self-generated frames.
|
||||
* If requested, force chip to sleep.
|
||||
*/
|
||||
static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
|
||||
static void ath9k_set_power_sleep(struct ath_hw *ah)
|
||||
{
|
||||
REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
|
||||
if (setChip) {
|
||||
if (AR_SREV_9462(ah)) {
|
||||
REG_WRITE(ah, AR_TIMER_MODE,
|
||||
REG_READ(ah, AR_TIMER_MODE) & 0xFFFFFF00);
|
||||
REG_WRITE(ah, AR_NDP2_TIMER_MODE, REG_READ(ah,
|
||||
AR_NDP2_TIMER_MODE) & 0xFFFFFF00);
|
||||
REG_WRITE(ah, AR_SLP32_INC,
|
||||
REG_READ(ah, AR_SLP32_INC) & 0xFFF00000);
|
||||
/* xxx Required for WLAN only case ? */
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the RTC force wake bit to allow the
|
||||
* mac to go to sleep.
|
||||
*/
|
||||
REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
|
||||
if (AR_SREV_9462(ah)) {
|
||||
REG_CLR_BIT(ah, AR_TIMER_MODE, 0xff);
|
||||
REG_CLR_BIT(ah, AR_NDP2_TIMER_MODE, 0xff);
|
||||
REG_CLR_BIT(ah, AR_SLP32_INC, 0xfffff);
|
||||
/* xxx Required for WLAN only case ? */
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (AR_SREV_9462(ah))
|
||||
udelay(100);
|
||||
/*
|
||||
* Clear the RTC force wake bit to allow the
|
||||
* mac to go to sleep.
|
||||
*/
|
||||
REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
|
||||
|
||||
if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
|
||||
REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
udelay(100);
|
||||
|
||||
/* Shutdown chip. Active low */
|
||||
if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
|
||||
REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
|
||||
udelay(2);
|
||||
}
|
||||
if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
|
||||
REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
|
||||
|
||||
/* Shutdown chip. Active low */
|
||||
if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
|
||||
REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
|
||||
udelay(2);
|
||||
}
|
||||
|
||||
/* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
|
||||
|
@ -2064,44 +2045,38 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
|
|||
* frames. If request, set power mode of chip to
|
||||
* auto/normal. Duration in units of 128us (1/8 TU).
|
||||
*/
|
||||
static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
|
||||
static void ath9k_set_power_network_sleep(struct ath_hw *ah)
|
||||
{
|
||||
u32 val;
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
|
||||
REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
|
||||
if (setChip) {
|
||||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
|
||||
if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
/* Set WakeOnInterrupt bit; clear ForceWake bit */
|
||||
REG_WRITE(ah, AR_RTC_FORCE_WAKE,
|
||||
AR_RTC_FORCE_WAKE_ON_INT);
|
||||
} else {
|
||||
if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
/* Set WakeOnInterrupt bit; clear ForceWake bit */
|
||||
REG_WRITE(ah, AR_RTC_FORCE_WAKE,
|
||||
AR_RTC_FORCE_WAKE_ON_INT);
|
||||
} else {
|
||||
|
||||
/* When chip goes into network sleep, it could be waken
|
||||
* up by MCI_INT interrupt caused by BT's HW messages
|
||||
* (LNA_xxx, CONT_xxx) which chould be in a very fast
|
||||
* rate (~100us). This will cause chip to leave and
|
||||
* re-enter network sleep mode frequently, which in
|
||||
* consequence will have WLAN MCI HW to generate lots of
|
||||
* SYS_WAKING and SYS_SLEEPING messages which will make
|
||||
* BT CPU to busy to process.
|
||||
*/
|
||||
if (AR_SREV_9462(ah)) {
|
||||
val = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) &
|
||||
~AR_MCI_INTERRUPT_RX_HW_MSG_MASK;
|
||||
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, val);
|
||||
}
|
||||
/*
|
||||
* Clear the RTC force wake bit to allow the
|
||||
* mac to go to sleep.
|
||||
*/
|
||||
REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
|
||||
AR_RTC_FORCE_WAKE_EN);
|
||||
/* When chip goes into network sleep, it could be waken
|
||||
* up by MCI_INT interrupt caused by BT's HW messages
|
||||
* (LNA_xxx, CONT_xxx) which chould be in a very fast
|
||||
* rate (~100us). This will cause chip to leave and
|
||||
* re-enter network sleep mode frequently, which in
|
||||
* consequence will have WLAN MCI HW to generate lots of
|
||||
* SYS_WAKING and SYS_SLEEPING messages which will make
|
||||
* BT CPU to busy to process.
|
||||
*/
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
REG_CLR_BIT(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
|
||||
AR_MCI_INTERRUPT_RX_HW_MSG_MASK);
|
||||
/*
|
||||
* Clear the RTC force wake bit to allow the
|
||||
* mac to go to sleep.
|
||||
*/
|
||||
REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
|
||||
|
||||
if (AR_SREV_9462(ah))
|
||||
udelay(30);
|
||||
}
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
udelay(30);
|
||||
}
|
||||
|
||||
/* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */
|
||||
|
@ -2109,7 +2084,7 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
|
|||
REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
|
||||
}
|
||||
|
||||
static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
|
||||
static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
|
||||
{
|
||||
u32 val;
|
||||
int i;
|
||||
|
@ -2120,37 +2095,35 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
|
|||
udelay(10);
|
||||
}
|
||||
|
||||
if (setChip) {
|
||||
if ((REG_READ(ah, AR_RTC_STATUS) &
|
||||
AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
|
||||
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
|
||||
return false;
|
||||
}
|
||||
if (!AR_SREV_9300_20_OR_LATER(ah))
|
||||
ath9k_hw_init_pll(ah, NULL);
|
||||
}
|
||||
if (AR_SREV_9100(ah))
|
||||
REG_SET_BIT(ah, AR_RTC_RESET,
|
||||
AR_RTC_RESET_EN);
|
||||
|
||||
REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
|
||||
AR_RTC_FORCE_WAKE_EN);
|
||||
udelay(50);
|
||||
|
||||
for (i = POWER_UP_TIME / 50; i > 0; i--) {
|
||||
val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
|
||||
if (val == AR_RTC_STATUS_ON)
|
||||
break;
|
||||
udelay(50);
|
||||
REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
|
||||
AR_RTC_FORCE_WAKE_EN);
|
||||
}
|
||||
if (i == 0) {
|
||||
ath_err(ath9k_hw_common(ah),
|
||||
"Failed to wakeup in %uus\n",
|
||||
POWER_UP_TIME / 20);
|
||||
if ((REG_READ(ah, AR_RTC_STATUS) &
|
||||
AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
|
||||
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
|
||||
return false;
|
||||
}
|
||||
if (!AR_SREV_9300_20_OR_LATER(ah))
|
||||
ath9k_hw_init_pll(ah, NULL);
|
||||
}
|
||||
if (AR_SREV_9100(ah))
|
||||
REG_SET_BIT(ah, AR_RTC_RESET,
|
||||
AR_RTC_RESET_EN);
|
||||
|
||||
REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
|
||||
AR_RTC_FORCE_WAKE_EN);
|
||||
udelay(50);
|
||||
|
||||
for (i = POWER_UP_TIME / 50; i > 0; i--) {
|
||||
val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
|
||||
if (val == AR_RTC_STATUS_ON)
|
||||
break;
|
||||
udelay(50);
|
||||
REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
|
||||
AR_RTC_FORCE_WAKE_EN);
|
||||
}
|
||||
if (i == 0) {
|
||||
ath_err(ath9k_hw_common(ah),
|
||||
"Failed to wakeup in %uus\n",
|
||||
POWER_UP_TIME / 20);
|
||||
return false;
|
||||
}
|
||||
|
||||
REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
|
||||
|
@ -2161,7 +2134,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
|
|||
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int status = true, setChip = true;
|
||||
int status = true;
|
||||
static const char *modes[] = {
|
||||
"AWAKE",
|
||||
"FULL-SLEEP",
|
||||
|
@ -2177,25 +2150,17 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
|
|||
|
||||
switch (mode) {
|
||||
case ATH9K_PM_AWAKE:
|
||||
status = ath9k_hw_set_power_awake(ah, setChip);
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
|
||||
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
|
||||
|
||||
status = ath9k_hw_set_power_awake(ah);
|
||||
break;
|
||||
case ATH9K_PM_FULL_SLEEP:
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
ar9003_mci_set_full_sleep(ah);
|
||||
|
||||
ath9k_set_power_sleep(ah, setChip);
|
||||
ath9k_set_power_sleep(ah);
|
||||
ah->chip_fullsleep = true;
|
||||
break;
|
||||
case ATH9K_PM_NETWORK_SLEEP:
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
|
||||
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
|
||||
|
||||
ath9k_set_power_network_sleep(ah, setChip);
|
||||
ath9k_set_power_network_sleep(ah);
|
||||
break;
|
||||
default:
|
||||
ath_err(common, "Unknown power mode %u\n", mode);
|
||||
|
@ -2765,6 +2730,9 @@ EXPORT_SYMBOL(ath9k_hw_setrxfilter);
|
|||
|
||||
bool ath9k_hw_phy_disable(struct ath_hw *ah)
|
||||
{
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
ar9003_mci_bt_gain_ctrl(ah);
|
||||
|
||||
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -824,7 +824,6 @@ struct ath_hw {
|
|||
struct ar5416IniArray ini_japan2484;
|
||||
struct ar5416IniArray iniModes_9271_ANI_reg;
|
||||
struct ar5416IniArray ini_radio_post_sys2ant;
|
||||
struct ar5416IniArray ini_BTCOEX_MAX_TXPWR;
|
||||
|
||||
struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT];
|
||||
struct ar5416IniArray iniBB[ATH_INI_NUM_SPLIT];
|
||||
|
@ -1037,6 +1036,11 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
|
|||
{
|
||||
return ah->btcoex_hw.enabled;
|
||||
}
|
||||
static inline bool ath9k_hw_mci_is_enabled(struct ath_hw *ah)
|
||||
{
|
||||
return ah->btcoex_hw.enabled && (ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
|
||||
|
||||
}
|
||||
void ath9k_hw_btcoex_enable(struct ath_hw *ah);
|
||||
static inline enum ath_btcoex_scheme
|
||||
ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
|
||||
|
@ -1048,6 +1052,10 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
static inline bool ath9k_hw_mci_is_enabled(struct ath_hw *ah)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline void ath9k_hw_btcoex_enable(struct ath_hw *ah)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -489,6 +489,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
|
|||
|
||||
setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
|
||||
|
||||
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
sc->config.txpowlimit = ATH_TXPOWER_MAX;
|
||||
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
||||
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
|
||||
|
@ -560,6 +561,12 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
|||
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
|
||||
(unsigned long)sc);
|
||||
|
||||
INIT_WORK(&sc->hw_reset_work, ath_reset_work);
|
||||
INIT_WORK(&sc->hw_check_work, ath_hw_check);
|
||||
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
|
||||
INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
|
||||
setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
|
||||
|
||||
/*
|
||||
* Cache line size is used to size and align various
|
||||
* structures used to communicate with the hardware.
|
||||
|
@ -590,6 +597,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
|||
ath9k_cmn_init_crypto(sc->sc_ah);
|
||||
ath9k_init_misc(sc);
|
||||
|
||||
if (common->bus_ops->aspm_init)
|
||||
common->bus_ops->aspm_init(common);
|
||||
|
||||
return 0;
|
||||
|
||||
err_btcoex:
|
||||
|
@ -782,11 +792,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
|
|||
ARRAY_SIZE(ath9k_tpt_blink));
|
||||
#endif
|
||||
|
||||
INIT_WORK(&sc->hw_reset_work, ath_reset_work);
|
||||
INIT_WORK(&sc->hw_check_work, ath_hw_check);
|
||||
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
|
||||
INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
|
||||
|
||||
/* Register with mac80211 */
|
||||
error = ieee80211_register_hw(hw);
|
||||
if (error)
|
||||
|
@ -805,9 +810,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
|
|||
goto error_world;
|
||||
}
|
||||
|
||||
setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
|
||||
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
|
||||
ath_init_leds(sc);
|
||||
ath_start_rfkill_poll(sc);
|
||||
|
||||
|
|
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ath9k.h"
|
||||
|
||||
/*
|
||||
* TX polling - checks if the TX engine is stuck somewhere
|
||||
* and issues a chip reset if so.
|
||||
*/
|
||||
void ath_tx_complete_poll_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
tx_complete_work.work);
|
||||
struct ath_txq *txq;
|
||||
int i;
|
||||
bool needreset = false;
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
sc->tx_complete_poll_work_seen++;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
|
||||
if (ATH_TXQ_SETUP(sc, i)) {
|
||||
txq = &sc->tx.txq[i];
|
||||
ath_txq_lock(sc, txq);
|
||||
if (txq->axq_depth) {
|
||||
if (txq->axq_tx_inprogress) {
|
||||
needreset = true;
|
||||
ath_txq_unlock(sc, txq);
|
||||
break;
|
||||
} else {
|
||||
txq->axq_tx_inprogress = true;
|
||||
}
|
||||
}
|
||||
ath_txq_unlock_complete(sc, txq);
|
||||
}
|
||||
|
||||
if (needreset) {
|
||||
ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
|
||||
"tx hung, resetting the chip\n");
|
||||
RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
|
||||
msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the BB/MAC is hung.
|
||||
*/
|
||||
void ath_hw_check(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
unsigned long flags;
|
||||
int busy;
|
||||
u8 is_alive, nbeacon = 1;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
is_alive = ath9k_hw_check_alive(sc->sc_ah);
|
||||
|
||||
if (is_alive && !AR_SREV_9300(sc->sc_ah))
|
||||
goto out;
|
||||
else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
|
||||
ath_dbg(common, RESET,
|
||||
"DCU stuck is detected. Schedule chip reset\n");
|
||||
RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
|
||||
goto sched_reset;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&common->cc_lock, flags);
|
||||
busy = ath_update_survey_stats(sc);
|
||||
spin_unlock_irqrestore(&common->cc_lock, flags);
|
||||
|
||||
ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
|
||||
busy, sc->hw_busy_count + 1);
|
||||
if (busy >= 99) {
|
||||
if (++sc->hw_busy_count >= 3) {
|
||||
RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
|
||||
goto sched_reset;
|
||||
}
|
||||
} else if (busy >= 0) {
|
||||
sc->hw_busy_count = 0;
|
||||
nbeacon = 3;
|
||||
}
|
||||
|
||||
ath_start_rx_poll(sc, nbeacon);
|
||||
goto out;
|
||||
|
||||
sched_reset:
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
out:
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* PLL-WAR for AR9485/AR9340
|
||||
*/
|
||||
static bool ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
|
||||
{
|
||||
static int count;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
if (pll_sqsum >= 0x40000) {
|
||||
count++;
|
||||
if (count == 3) {
|
||||
ath_dbg(common, RESET, "PLL WAR, resetting the chip\n");
|
||||
RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
count = 0;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ath_hw_pll_work(struct work_struct *work)
|
||||
{
|
||||
u32 pll_sqsum;
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
hw_pll_work.work);
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
|
||||
ath9k_ps_restore(sc);
|
||||
if (ath_hw_pll_rx_hang_check(sc, pll_sqsum))
|
||||
return;
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
|
||||
msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
|
||||
}
|
||||
|
||||
/*
|
||||
* RX Polling - monitors baseband hangs.
|
||||
*/
|
||||
void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
|
||||
{
|
||||
if (!AR_SREV_9300(sc->sc_ah))
|
||||
return;
|
||||
|
||||
if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
|
||||
return;
|
||||
|
||||
mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
|
||||
(nbeacon * sc->cur_beacon_conf.beacon_interval));
|
||||
}
|
||||
|
||||
void ath_rx_poll(unsigned long data)
|
||||
{
|
||||
struct ath_softc *sc = (struct ath_softc *)data;
|
||||
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
|
||||
}
|
||||
|
||||
/*
|
||||
* PA Pre-distortion.
|
||||
*/
|
||||
static void ath_paprd_activate(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath9k_hw_cal_data *caldata = ah->caldata;
|
||||
int chain;
|
||||
|
||||
if (!caldata || !caldata->paprd_done)
|
||||
return;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
ar9003_paprd_enable(ah, false);
|
||||
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
|
||||
if (!(ah->txchainmask & BIT(chain)))
|
||||
continue;
|
||||
|
||||
ar9003_paprd_populate_single_table(ah, caldata, chain);
|
||||
}
|
||||
|
||||
ar9003_paprd_enable(ah, true);
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_tx_control txctl;
|
||||
int time_left;
|
||||
|
||||
memset(&txctl, 0, sizeof(txctl));
|
||||
txctl.txq = sc->tx.txq_map[WME_AC_BE];
|
||||
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->band = hw->conf.channel->band;
|
||||
tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
tx_info->control.rates[0].idx = 0;
|
||||
tx_info->control.rates[0].count = 1;
|
||||
tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
|
||||
tx_info->control.rates[1].idx = -1;
|
||||
|
||||
init_completion(&sc->paprd_complete);
|
||||
txctl.paprd = BIT(chain);
|
||||
|
||||
if (ath_tx_start(hw, skb, &txctl) != 0) {
|
||||
ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return false;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&sc->paprd_complete,
|
||||
msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
|
||||
|
||||
if (!time_left)
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"Timeout waiting for paprd training on TX chain %d\n",
|
||||
chain);
|
||||
|
||||
return !!time_left;
|
||||
}
|
||||
|
||||
void ath_paprd_calibrate(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct ath9k_hw_cal_data *caldata = ah->caldata;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int ftype;
|
||||
int chain_ok = 0;
|
||||
int chain;
|
||||
int len = 1800;
|
||||
|
||||
if (!caldata)
|
||||
return;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
if (ar9003_paprd_init_table(ah) < 0)
|
||||
goto fail_paprd;
|
||||
|
||||
skb = alloc_skb(len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
goto fail_paprd;
|
||||
|
||||
skb_put(skb, len);
|
||||
memset(skb->data, 0, len);
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
|
||||
hdr->frame_control = cpu_to_le16(ftype);
|
||||
hdr->duration_id = cpu_to_le16(10);
|
||||
memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
|
||||
memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
|
||||
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
|
||||
|
||||
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
|
||||
if (!(ah->txchainmask & BIT(chain)))
|
||||
continue;
|
||||
|
||||
chain_ok = 0;
|
||||
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"Sending PAPRD frame for thermal measurement on chain %d\n",
|
||||
chain);
|
||||
if (!ath_paprd_send_frame(sc, skb, chain))
|
||||
goto fail_paprd;
|
||||
|
||||
ar9003_paprd_setup_gain_table(ah, chain);
|
||||
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"Sending PAPRD training frame on chain %d\n", chain);
|
||||
if (!ath_paprd_send_frame(sc, skb, chain))
|
||||
goto fail_paprd;
|
||||
|
||||
if (!ar9003_paprd_is_done(ah)) {
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"PAPRD not yet done on chain %d\n", chain);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ar9003_paprd_create_curve(ah, caldata, chain)) {
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"PAPRD create curve failed on chain %d\n",
|
||||
chain);
|
||||
break;
|
||||
}
|
||||
|
||||
chain_ok = 1;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
if (chain_ok) {
|
||||
caldata->paprd_done = true;
|
||||
ath_paprd_activate(sc);
|
||||
}
|
||||
|
||||
fail_paprd:
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* ANI performs periodic noise floor calibration
|
||||
* that is used to adjust and optimize the chip performance. This
|
||||
* takes environmental changes (location, temperature) into account.
|
||||
* When the task is complete, it reschedules itself depending on the
|
||||
* appropriate interval that was calculated.
|
||||
*/
|
||||
void ath_ani_calibrate(unsigned long data)
|
||||
{
|
||||
struct ath_softc *sc = (struct ath_softc *)data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
bool longcal = false;
|
||||
bool shortcal = false;
|
||||
bool aniflag = false;
|
||||
unsigned int timestamp = jiffies_to_msecs(jiffies);
|
||||
u32 cal_interval, short_cal_interval, long_cal_interval;
|
||||
unsigned long flags;
|
||||
|
||||
if (ah->caldata && ah->caldata->nfcal_interference)
|
||||
long_cal_interval = ATH_LONG_CALINTERVAL_INT;
|
||||
else
|
||||
long_cal_interval = ATH_LONG_CALINTERVAL;
|
||||
|
||||
short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
|
||||
ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
|
||||
|
||||
/* Only calibrate if awake */
|
||||
if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
|
||||
goto set_timer;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
/* Long calibration runs independently of short calibration. */
|
||||
if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
|
||||
longcal = true;
|
||||
common->ani.longcal_timer = timestamp;
|
||||
}
|
||||
|
||||
/* Short calibration applies only while caldone is false */
|
||||
if (!common->ani.caldone) {
|
||||
if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
|
||||
shortcal = true;
|
||||
common->ani.shortcal_timer = timestamp;
|
||||
common->ani.resetcal_timer = timestamp;
|
||||
}
|
||||
} else {
|
||||
if ((timestamp - common->ani.resetcal_timer) >=
|
||||
ATH_RESTART_CALINTERVAL) {
|
||||
common->ani.caldone = ath9k_hw_reset_calvalid(ah);
|
||||
if (common->ani.caldone)
|
||||
common->ani.resetcal_timer = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify whether we must check ANI */
|
||||
if (sc->sc_ah->config.enable_ani
|
||||
&& (timestamp - common->ani.checkani_timer) >=
|
||||
ah->config.ani_poll_interval) {
|
||||
aniflag = true;
|
||||
common->ani.checkani_timer = timestamp;
|
||||
}
|
||||
|
||||
/* Call ANI routine if necessary */
|
||||
if (aniflag) {
|
||||
spin_lock_irqsave(&common->cc_lock, flags);
|
||||
ath9k_hw_ani_monitor(ah, ah->curchan);
|
||||
ath_update_survey_stats(sc);
|
||||
spin_unlock_irqrestore(&common->cc_lock, flags);
|
||||
}
|
||||
|
||||
/* Perform calibration if necessary */
|
||||
if (longcal || shortcal) {
|
||||
common->ani.caldone =
|
||||
ath9k_hw_calibrate(ah, ah->curchan,
|
||||
ah->rxchainmask, longcal);
|
||||
}
|
||||
|
||||
ath_dbg(common, ANI,
|
||||
"Calibration @%lu finished: %s %s %s, caldone: %s\n",
|
||||
jiffies,
|
||||
longcal ? "long" : "", shortcal ? "short" : "",
|
||||
aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
set_timer:
|
||||
/*
|
||||
* Set timer interval based on previous results.
|
||||
* The interval must be the shortest necessary to satisfy ANI,
|
||||
* short calibration and long calibration.
|
||||
*/
|
||||
ath9k_debug_samp_bb_mac(sc);
|
||||
cal_interval = ATH_LONG_CALINTERVAL;
|
||||
if (sc->sc_ah->config.enable_ani)
|
||||
cal_interval = min(cal_interval,
|
||||
(u32)ah->config.ani_poll_interval);
|
||||
if (!common->ani.caldone)
|
||||
cal_interval = min(cal_interval, (u32)short_cal_interval);
|
||||
|
||||
mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
|
||||
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
|
||||
if (!ah->caldata->paprd_done)
|
||||
ieee80211_queue_work(sc->hw, &sc->paprd_work);
|
||||
else if (!ah->paprd_table_write_done)
|
||||
ath_paprd_activate(sc);
|
||||
}
|
||||
}
|
||||
|
||||
void ath_start_ani(struct ath_common *common)
|
||||
{
|
||||
struct ath_hw *ah = common->ah;
|
||||
unsigned long timestamp = jiffies_to_msecs(jiffies);
|
||||
struct ath_softc *sc = (struct ath_softc *) common->priv;
|
||||
|
||||
if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags))
|
||||
return;
|
||||
|
||||
if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
|
||||
return;
|
||||
|
||||
common->ani.longcal_timer = timestamp;
|
||||
common->ani.shortcal_timer = timestamp;
|
||||
common->ani.checkani_timer = timestamp;
|
||||
|
||||
mod_timer(&common->ani.timer,
|
||||
jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval));
|
||||
}
|
||||
|
||||
void ath_update_survey_nf(struct ath_softc *sc, int channel)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath9k_channel *chan = &ah->channels[channel];
|
||||
struct survey_info *survey = &sc->survey[channel];
|
||||
|
||||
if (chan->noisefloor) {
|
||||
survey->filled |= SURVEY_INFO_NOISE_DBM;
|
||||
survey->noise = ath9k_hw_getchan_noise(ah, chan);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the survey statistics and returns the busy time since last
|
||||
* update in %, if the measurement duration was long enough for the
|
||||
* result to be useful, -1 otherwise.
|
||||
*/
|
||||
int ath_update_survey_stats(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int pos = ah->curchan - &ah->channels[0];
|
||||
struct survey_info *survey = &sc->survey[pos];
|
||||
struct ath_cycle_counters *cc = &common->cc_survey;
|
||||
unsigned int div = common->clockrate * 1000;
|
||||
int ret = 0;
|
||||
|
||||
if (!ah->curchan)
|
||||
return -1;
|
||||
|
||||
if (ah->power_mode == ATH9K_PM_AWAKE)
|
||||
ath_hw_cycle_counters_update(common);
|
||||
|
||||
if (cc->cycles > 0) {
|
||||
survey->filled |= SURVEY_INFO_CHANNEL_TIME |
|
||||
SURVEY_INFO_CHANNEL_TIME_BUSY |
|
||||
SURVEY_INFO_CHANNEL_TIME_RX |
|
||||
SURVEY_INFO_CHANNEL_TIME_TX;
|
||||
survey->channel_time += cc->cycles / div;
|
||||
survey->channel_time_busy += cc->rx_busy / div;
|
||||
survey->channel_time_rx += cc->rx_frame / div;
|
||||
survey->channel_time_tx += cc->tx_frame / div;
|
||||
}
|
||||
|
||||
if (cc->cycles < div)
|
||||
return -1;
|
||||
|
||||
if (cc->cycles > 0)
|
||||
ret = cc->rx_busy * 100 / cc->cycles;
|
||||
|
||||
memset(cc, 0, sizeof(*cc));
|
||||
|
||||
ath_update_survey_nf(sc, pos);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -101,6 +101,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
|
|||
spin_lock(&common->cc_lock);
|
||||
ath_hw_cycle_counters_update(common);
|
||||
memset(&common->cc_survey, 0, sizeof(common->cc_survey));
|
||||
memset(&common->cc_ani, 0, sizeof(common->cc_ani));
|
||||
spin_unlock(&common->cc_lock);
|
||||
}
|
||||
|
||||
|
@ -143,84 +144,6 @@ void ath9k_ps_restore(struct ath_softc *sc)
|
|||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
}
|
||||
|
||||
void ath_start_ani(struct ath_common *common)
|
||||
{
|
||||
struct ath_hw *ah = common->ah;
|
||||
unsigned long timestamp = jiffies_to_msecs(jiffies);
|
||||
struct ath_softc *sc = (struct ath_softc *) common->priv;
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_ANI_RUN))
|
||||
return;
|
||||
|
||||
if (sc->sc_flags & SC_OP_OFFCHANNEL)
|
||||
return;
|
||||
|
||||
common->ani.longcal_timer = timestamp;
|
||||
common->ani.shortcal_timer = timestamp;
|
||||
common->ani.checkani_timer = timestamp;
|
||||
|
||||
mod_timer(&common->ani.timer,
|
||||
jiffies +
|
||||
msecs_to_jiffies((u32)ah->config.ani_poll_interval));
|
||||
}
|
||||
|
||||
static void ath_update_survey_nf(struct ath_softc *sc, int channel)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath9k_channel *chan = &ah->channels[channel];
|
||||
struct survey_info *survey = &sc->survey[channel];
|
||||
|
||||
if (chan->noisefloor) {
|
||||
survey->filled |= SURVEY_INFO_NOISE_DBM;
|
||||
survey->noise = ath9k_hw_getchan_noise(ah, chan);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the survey statistics and returns the busy time since last
|
||||
* update in %, if the measurement duration was long enough for the
|
||||
* result to be useful, -1 otherwise.
|
||||
*/
|
||||
static int ath_update_survey_stats(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int pos = ah->curchan - &ah->channels[0];
|
||||
struct survey_info *survey = &sc->survey[pos];
|
||||
struct ath_cycle_counters *cc = &common->cc_survey;
|
||||
unsigned int div = common->clockrate * 1000;
|
||||
int ret = 0;
|
||||
|
||||
if (!ah->curchan)
|
||||
return -1;
|
||||
|
||||
if (ah->power_mode == ATH9K_PM_AWAKE)
|
||||
ath_hw_cycle_counters_update(common);
|
||||
|
||||
if (cc->cycles > 0) {
|
||||
survey->filled |= SURVEY_INFO_CHANNEL_TIME |
|
||||
SURVEY_INFO_CHANNEL_TIME_BUSY |
|
||||
SURVEY_INFO_CHANNEL_TIME_RX |
|
||||
SURVEY_INFO_CHANNEL_TIME_TX;
|
||||
survey->channel_time += cc->cycles / div;
|
||||
survey->channel_time_busy += cc->rx_busy / div;
|
||||
survey->channel_time_rx += cc->rx_frame / div;
|
||||
survey->channel_time_tx += cc->tx_frame / div;
|
||||
}
|
||||
|
||||
if (cc->cycles < div)
|
||||
return -1;
|
||||
|
||||
if (cc->cycles > 0)
|
||||
ret = cc->rx_busy * 100 / cc->cycles;
|
||||
|
||||
memset(cc, 0, sizeof(*cc));
|
||||
|
||||
ath_update_survey_nf(sc, pos);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __ath_cancel_work(struct ath_softc *sc)
|
||||
{
|
||||
cancel_work_sync(&sc->paprd_work);
|
||||
|
@ -235,6 +158,22 @@ static void ath_cancel_work(struct ath_softc *sc)
|
|||
cancel_work_sync(&sc->hw_reset_work);
|
||||
}
|
||||
|
||||
static void ath_restart_work(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
|
||||
|
||||
if (AR_SREV_9485(sc->sc_ah) || AR_SREV_9340(sc->sc_ah))
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
|
||||
msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
|
||||
|
||||
ath_start_rx_poll(sc, 3);
|
||||
|
||||
if (!common->disable_ani)
|
||||
ath_start_ani(common);
|
||||
}
|
||||
|
||||
static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
@ -271,6 +210,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
|
|||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
unsigned long flags;
|
||||
|
||||
if (ath_startrecv(sc) != 0) {
|
||||
ath_err(common, "Unable to restart recv logic\n");
|
||||
|
@ -279,35 +219,29 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
|
|||
|
||||
ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||
sc->config.txpowlimit, &sc->curtxpow);
|
||||
|
||||
clear_bit(SC_OP_HW_RESET, &sc->sc_flags);
|
||||
ath9k_hw_set_interrupts(ah);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
|
||||
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) {
|
||||
if (sc->sc_flags & SC_OP_BEACONS)
|
||||
ath_set_beacon(sc);
|
||||
if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) {
|
||||
if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
|
||||
goto work;
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
|
||||
ath_start_rx_poll(sc, 3);
|
||||
if (!common->disable_ani)
|
||||
ath_start_ani(common);
|
||||
ath_set_beacon(sc);
|
||||
|
||||
if (ah->opmode == NL80211_IFTYPE_STATION &&
|
||||
test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
}
|
||||
work:
|
||||
ath_restart_work(sc);
|
||||
}
|
||||
|
||||
if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) {
|
||||
struct ath_hw_antcomb_conf div_ant_conf;
|
||||
u8 lna_conf;
|
||||
|
||||
ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
|
||||
|
||||
if (sc->ant_rx == 1)
|
||||
lna_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
lna_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.main_lna_conf = lna_conf;
|
||||
div_ant_conf.alt_lna_conf = lna_conf;
|
||||
|
||||
ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
|
||||
}
|
||||
if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3)
|
||||
ath_ant_comb_update(sc);
|
||||
|
||||
ieee80211_wake_queues(sc->hw);
|
||||
|
||||
|
@ -328,7 +262,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
|
|||
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) {
|
||||
if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
|
||||
fastcc = false;
|
||||
caldata = &sc->caldata;
|
||||
}
|
||||
|
@ -371,7 +305,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
|||
{
|
||||
int r;
|
||||
|
||||
if (sc->sc_flags & SC_OP_INVALID)
|
||||
if (test_bit(SC_OP_INVALID, &sc->sc_flags))
|
||||
return -EIO;
|
||||
|
||||
r = ath_reset_internal(sc, hchan, false);
|
||||
|
@ -379,258 +313,6 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
|||
return r;
|
||||
}
|
||||
|
||||
static void ath_paprd_activate(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath9k_hw_cal_data *caldata = ah->caldata;
|
||||
int chain;
|
||||
|
||||
if (!caldata || !caldata->paprd_done)
|
||||
return;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
ar9003_paprd_enable(ah, false);
|
||||
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
|
||||
if (!(ah->txchainmask & BIT(chain)))
|
||||
continue;
|
||||
|
||||
ar9003_paprd_populate_single_table(ah, caldata, chain);
|
||||
}
|
||||
|
||||
ar9003_paprd_enable(ah, true);
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_tx_control txctl;
|
||||
int time_left;
|
||||
|
||||
memset(&txctl, 0, sizeof(txctl));
|
||||
txctl.txq = sc->tx.txq_map[WME_AC_BE];
|
||||
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->band = hw->conf.channel->band;
|
||||
tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
tx_info->control.rates[0].idx = 0;
|
||||
tx_info->control.rates[0].count = 1;
|
||||
tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
|
||||
tx_info->control.rates[1].idx = -1;
|
||||
|
||||
init_completion(&sc->paprd_complete);
|
||||
txctl.paprd = BIT(chain);
|
||||
|
||||
if (ath_tx_start(hw, skb, &txctl) != 0) {
|
||||
ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return false;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&sc->paprd_complete,
|
||||
msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
|
||||
|
||||
if (!time_left)
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"Timeout waiting for paprd training on TX chain %d\n",
|
||||
chain);
|
||||
|
||||
return !!time_left;
|
||||
}
|
||||
|
||||
void ath_paprd_calibrate(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct ath9k_hw_cal_data *caldata = ah->caldata;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int ftype;
|
||||
int chain_ok = 0;
|
||||
int chain;
|
||||
int len = 1800;
|
||||
|
||||
if (!caldata)
|
||||
return;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
if (ar9003_paprd_init_table(ah) < 0)
|
||||
goto fail_paprd;
|
||||
|
||||
skb = alloc_skb(len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
goto fail_paprd;
|
||||
|
||||
skb_put(skb, len);
|
||||
memset(skb->data, 0, len);
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
|
||||
hdr->frame_control = cpu_to_le16(ftype);
|
||||
hdr->duration_id = cpu_to_le16(10);
|
||||
memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
|
||||
memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
|
||||
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
|
||||
|
||||
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
|
||||
if (!(ah->txchainmask & BIT(chain)))
|
||||
continue;
|
||||
|
||||
chain_ok = 0;
|
||||
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"Sending PAPRD frame for thermal measurement on chain %d\n",
|
||||
chain);
|
||||
if (!ath_paprd_send_frame(sc, skb, chain))
|
||||
goto fail_paprd;
|
||||
|
||||
ar9003_paprd_setup_gain_table(ah, chain);
|
||||
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"Sending PAPRD training frame on chain %d\n", chain);
|
||||
if (!ath_paprd_send_frame(sc, skb, chain))
|
||||
goto fail_paprd;
|
||||
|
||||
if (!ar9003_paprd_is_done(ah)) {
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"PAPRD not yet done on chain %d\n", chain);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ar9003_paprd_create_curve(ah, caldata, chain)) {
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"PAPRD create curve failed on chain %d\n",
|
||||
chain);
|
||||
break;
|
||||
}
|
||||
|
||||
chain_ok = 1;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
if (chain_ok) {
|
||||
caldata->paprd_done = true;
|
||||
ath_paprd_activate(sc);
|
||||
}
|
||||
|
||||
fail_paprd:
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine performs the periodic noise floor calibration function
|
||||
* that is used to adjust and optimize the chip performance. This
|
||||
* takes environmental changes (location, temperature) into account.
|
||||
* When the task is complete, it reschedules itself depending on the
|
||||
* appropriate interval that was calculated.
|
||||
*/
|
||||
void ath_ani_calibrate(unsigned long data)
|
||||
{
|
||||
struct ath_softc *sc = (struct ath_softc *)data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
bool longcal = false;
|
||||
bool shortcal = false;
|
||||
bool aniflag = false;
|
||||
unsigned int timestamp = jiffies_to_msecs(jiffies);
|
||||
u32 cal_interval, short_cal_interval, long_cal_interval;
|
||||
unsigned long flags;
|
||||
|
||||
if (ah->caldata && ah->caldata->nfcal_interference)
|
||||
long_cal_interval = ATH_LONG_CALINTERVAL_INT;
|
||||
else
|
||||
long_cal_interval = ATH_LONG_CALINTERVAL;
|
||||
|
||||
short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
|
||||
ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
|
||||
|
||||
/* Only calibrate if awake */
|
||||
if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
|
||||
goto set_timer;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
/* Long calibration runs independently of short calibration. */
|
||||
if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
|
||||
longcal = true;
|
||||
common->ani.longcal_timer = timestamp;
|
||||
}
|
||||
|
||||
/* Short calibration applies only while caldone is false */
|
||||
if (!common->ani.caldone) {
|
||||
if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
|
||||
shortcal = true;
|
||||
common->ani.shortcal_timer = timestamp;
|
||||
common->ani.resetcal_timer = timestamp;
|
||||
}
|
||||
} else {
|
||||
if ((timestamp - common->ani.resetcal_timer) >=
|
||||
ATH_RESTART_CALINTERVAL) {
|
||||
common->ani.caldone = ath9k_hw_reset_calvalid(ah);
|
||||
if (common->ani.caldone)
|
||||
common->ani.resetcal_timer = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify whether we must check ANI */
|
||||
if (sc->sc_ah->config.enable_ani
|
||||
&& (timestamp - common->ani.checkani_timer) >=
|
||||
ah->config.ani_poll_interval) {
|
||||
aniflag = true;
|
||||
common->ani.checkani_timer = timestamp;
|
||||
}
|
||||
|
||||
/* Call ANI routine if necessary */
|
||||
if (aniflag) {
|
||||
spin_lock_irqsave(&common->cc_lock, flags);
|
||||
ath9k_hw_ani_monitor(ah, ah->curchan);
|
||||
ath_update_survey_stats(sc);
|
||||
spin_unlock_irqrestore(&common->cc_lock, flags);
|
||||
}
|
||||
|
||||
/* Perform calibration if necessary */
|
||||
if (longcal || shortcal) {
|
||||
common->ani.caldone =
|
||||
ath9k_hw_calibrate(ah, ah->curchan,
|
||||
ah->rxchainmask, longcal);
|
||||
}
|
||||
|
||||
ath_dbg(common, ANI,
|
||||
"Calibration @%lu finished: %s %s %s, caldone: %s\n",
|
||||
jiffies,
|
||||
longcal ? "long" : "", shortcal ? "short" : "",
|
||||
aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
set_timer:
|
||||
/*
|
||||
* Set timer interval based on previous results.
|
||||
* The interval must be the shortest necessary to satisfy ANI,
|
||||
* short calibration and long calibration.
|
||||
*/
|
||||
ath9k_debug_samp_bb_mac(sc);
|
||||
cal_interval = ATH_LONG_CALINTERVAL;
|
||||
if (sc->sc_ah->config.enable_ani)
|
||||
cal_interval = min(cal_interval,
|
||||
(u32)ah->config.ani_poll_interval);
|
||||
if (!common->ani.caldone)
|
||||
cal_interval = min(cal_interval, (u32)short_cal_interval);
|
||||
|
||||
mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
|
||||
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
|
||||
if (!ah->caldata->paprd_done)
|
||||
ieee80211_queue_work(sc->hw, &sc->paprd_work);
|
||||
else if (!ah->paprd_table_write_done)
|
||||
ath_paprd_activate(sc);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
|
@ -668,13 +350,12 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
|
|||
ath_tx_node_cleanup(sc, an);
|
||||
}
|
||||
|
||||
|
||||
void ath9k_tasklet(unsigned long data)
|
||||
{
|
||||
struct ath_softc *sc = (struct ath_softc *)data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
unsigned long flags;
|
||||
u32 status = sc->intrstatus;
|
||||
u32 rxmask;
|
||||
|
||||
|
@ -693,10 +374,12 @@ void ath9k_tasklet(unsigned long data)
|
|||
|
||||
RESET_STAT_INC(sc, type);
|
||||
#endif
|
||||
set_bit(SC_OP_HW_RESET, &sc->sc_flags);
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
|
||||
/*
|
||||
* TSF sync does not look correct; remain awake to sync with
|
||||
|
@ -705,6 +388,7 @@ void ath9k_tasklet(unsigned long data)
|
|||
ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
|
||||
sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
|
||||
}
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
|
||||
rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
|
||||
|
@ -766,15 +450,17 @@ irqreturn_t ath_isr(int irq, void *dev)
|
|||
* touch anything. Note this can happen early
|
||||
* on if the IRQ is shared.
|
||||
*/
|
||||
if (sc->sc_flags & SC_OP_INVALID)
|
||||
if (test_bit(SC_OP_INVALID, &sc->sc_flags))
|
||||
return IRQ_NONE;
|
||||
|
||||
|
||||
/* shared irq, not for us */
|
||||
|
||||
if (!ath9k_hw_intrpend(ah))
|
||||
return IRQ_NONE;
|
||||
|
||||
if(test_bit(SC_OP_HW_RESET, &sc->sc_flags))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/*
|
||||
* Figure out the reason(s) for the interrupt. Note
|
||||
* that the hal returns a pseudo-ISR that may include
|
||||
|
@ -852,8 +538,10 @@ irqreturn_t ath_isr(int irq, void *dev)
|
|||
/* Clear RxAbort bit so that we can
|
||||
* receive frames */
|
||||
ath9k_setpower(sc, ATH9K_PM_AWAKE);
|
||||
spin_lock(&sc->sc_pm_lock);
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 0);
|
||||
sc->ps_flags |= PS_WAIT_FOR_BEACON;
|
||||
spin_unlock(&sc->sc_pm_lock);
|
||||
}
|
||||
|
||||
chip_reset:
|
||||
|
@ -902,87 +590,6 @@ void ath_reset_work(struct work_struct *work)
|
|||
ath_reset(sc, true);
|
||||
}
|
||||
|
||||
void ath_hw_check(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
unsigned long flags;
|
||||
int busy;
|
||||
u8 is_alive, nbeacon = 1;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
is_alive = ath9k_hw_check_alive(sc->sc_ah);
|
||||
|
||||
if (is_alive && !AR_SREV_9300(sc->sc_ah))
|
||||
goto out;
|
||||
else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
|
||||
ath_dbg(common, RESET,
|
||||
"DCU stuck is detected. Schedule chip reset\n");
|
||||
RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
|
||||
goto sched_reset;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&common->cc_lock, flags);
|
||||
busy = ath_update_survey_stats(sc);
|
||||
spin_unlock_irqrestore(&common->cc_lock, flags);
|
||||
|
||||
ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
|
||||
busy, sc->hw_busy_count + 1);
|
||||
if (busy >= 99) {
|
||||
if (++sc->hw_busy_count >= 3) {
|
||||
RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
|
||||
goto sched_reset;
|
||||
}
|
||||
} else if (busy >= 0) {
|
||||
sc->hw_busy_count = 0;
|
||||
nbeacon = 3;
|
||||
}
|
||||
|
||||
ath_start_rx_poll(sc, nbeacon);
|
||||
goto out;
|
||||
|
||||
sched_reset:
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
out:
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
|
||||
{
|
||||
static int count;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
if (pll_sqsum >= 0x40000) {
|
||||
count++;
|
||||
if (count == 3) {
|
||||
/* Rx is hung for more than 500ms. Reset it */
|
||||
ath_dbg(common, RESET, "Possible RX hang, resetting\n");
|
||||
RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
count = 0;
|
||||
}
|
||||
} else
|
||||
count = 0;
|
||||
}
|
||||
|
||||
void ath_hw_pll_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
hw_pll_work.work);
|
||||
u32 pll_sqsum;
|
||||
|
||||
if (AR_SREV_9485(sc->sc_ah)) {
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
ath_hw_pll_rx_hang_check(sc, pll_sqsum);
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* mac80211 callbacks */
|
||||
/**********************/
|
||||
|
@ -1045,10 +652,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
|||
if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
|
||||
ah->imask |= ATH9K_INT_CST;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
|
||||
ah->imask |= ATH9K_INT_MCI;
|
||||
ath_mci_enable(sc);
|
||||
|
||||
sc->sc_flags &= ~SC_OP_INVALID;
|
||||
clear_bit(SC_OP_INVALID, &sc->sc_flags);
|
||||
sc->sc_ah->is_monitoring = false;
|
||||
|
||||
if (!ath_complete_reset(sc, false)) {
|
||||
|
@ -1090,6 +696,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_tx_control txctl;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
unsigned long flags;
|
||||
|
||||
if (sc->ps_enabled) {
|
||||
/*
|
||||
|
@ -1112,6 +719,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
* completed and if needed, also for RX of buffered frames.
|
||||
*/
|
||||
ath9k_ps_wakeup(sc);
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 0);
|
||||
if (ieee80211_is_pspoll(hdr->frame_control)) {
|
||||
|
@ -1127,6 +735,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
* the ps_flags bit is cleared. We are just dropping
|
||||
* the ps_usecount here.
|
||||
*/
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
|
@ -1167,7 +776,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
|||
ath_cancel_work(sc);
|
||||
del_timer_sync(&sc->rx_poll_timer);
|
||||
|
||||
if (sc->sc_flags & SC_OP_INVALID) {
|
||||
if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
|
||||
ath_dbg(common, ANY, "Device not present\n");
|
||||
mutex_unlock(&sc->mutex);
|
||||
return;
|
||||
|
@ -1224,7 +833,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
|||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
sc->sc_flags |= SC_OP_INVALID;
|
||||
set_bit(SC_OP_INVALID, &sc->sc_flags);
|
||||
sc->ps_idle = prev_idle;
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
|
@ -1328,11 +937,11 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
|
|||
/* Set op-mode & TSF */
|
||||
if (iter_data.naps > 0) {
|
||||
ath9k_hw_set_tsfadjust(ah, 1);
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
ah->opmode = NL80211_IFTYPE_AP;
|
||||
} else {
|
||||
ath9k_hw_set_tsfadjust(ah, 0);
|
||||
sc->sc_flags &= ~SC_OP_TSF_RESET;
|
||||
clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
|
||||
if (iter_data.nmeshes)
|
||||
ah->opmode = NL80211_IFTYPE_MESH_POINT;
|
||||
|
@ -1363,12 +972,12 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
|
|||
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
||||
|
||||
if (!common->disable_ani) {
|
||||
sc->sc_flags |= SC_OP_ANI_RUN;
|
||||
set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
||||
ath_start_ani(common);
|
||||
}
|
||||
|
||||
} else {
|
||||
sc->sc_flags &= ~SC_OP_ANI_RUN;
|
||||
clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
||||
del_timer_sync(&common->ani.timer);
|
||||
}
|
||||
}
|
||||
|
@ -1389,25 +998,6 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
|
||||
{
|
||||
if (!AR_SREV_9300(sc->sc_ah))
|
||||
return;
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF))
|
||||
return;
|
||||
|
||||
mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
|
||||
(nbeacon * sc->cur_beacon_conf.beacon_interval));
|
||||
}
|
||||
|
||||
void ath_rx_poll(unsigned long data)
|
||||
{
|
||||
struct ath_softc *sc = (struct ath_softc *)data;
|
||||
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
|
||||
}
|
||||
|
||||
static int ath9k_add_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
|
@ -1627,11 +1217,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
|||
if (ah->curchan)
|
||||
old_pos = ah->curchan - &ah->channels[0];
|
||||
|
||||
if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
|
||||
sc->sc_flags |= SC_OP_OFFCHANNEL;
|
||||
else
|
||||
sc->sc_flags &= ~SC_OP_OFFCHANNEL;
|
||||
|
||||
ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n",
|
||||
curchan->center_freq, conf->channel_type);
|
||||
|
||||
|
@ -1911,16 +1496,16 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
|
||||
unsigned long flags;
|
||||
/*
|
||||
* Skip iteration if primary station vif's bss info
|
||||
* was not changed
|
||||
*/
|
||||
if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
|
||||
if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
|
||||
return;
|
||||
|
||||
if (bss_conf->assoc) {
|
||||
sc->sc_flags |= SC_OP_PRIM_STA_VIF;
|
||||
set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
|
||||
avp->primary_sta_vif = true;
|
||||
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
||||
common->curaid = bss_conf->aid;
|
||||
|
@ -1933,7 +1518,10 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|||
* on the receipt of the first Beacon frame (i.e.,
|
||||
* after time sync with the AP).
|
||||
*/
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
|
||||
/* Reset rssi stats */
|
||||
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
||||
|
@ -1941,7 +1529,7 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|||
ath_start_rx_poll(sc, 3);
|
||||
|
||||
if (!common->disable_ani) {
|
||||
sc->sc_flags |= SC_OP_ANI_RUN;
|
||||
set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
||||
ath_start_ani(common);
|
||||
}
|
||||
|
||||
|
@ -1961,7 +1549,8 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|||
if (avp->primary_sta_vif && !bss_conf->assoc) {
|
||||
ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n",
|
||||
common->curaid, common->curbssid);
|
||||
sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
|
||||
clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
|
||||
clear_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
avp->primary_sta_vif = false;
|
||||
memset(common->curbssid, 0, ETH_ALEN);
|
||||
common->curaid = 0;
|
||||
|
@ -1974,10 +1563,9 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|||
* None of station vifs are associated.
|
||||
* Clear bssid & aid
|
||||
*/
|
||||
if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
|
||||
if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
|
||||
ath9k_hw_write_associd(sc->sc_ah);
|
||||
/* Stop ANI */
|
||||
sc->sc_flags &= ~SC_OP_ANI_RUN;
|
||||
clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
||||
del_timer_sync(&common->ani.timer);
|
||||
del_timer_sync(&sc->rx_poll_timer);
|
||||
memset(&sc->caldata, 0, sizeof(sc->caldata));
|
||||
|
@ -2015,12 +1603,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
||||
|
||||
if (!common->disable_ani) {
|
||||
sc->sc_flags |= SC_OP_ANI_RUN;
|
||||
set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
||||
ath_start_ani(common);
|
||||
}
|
||||
|
||||
} else {
|
||||
sc->sc_flags &= ~SC_OP_ANI_RUN;
|
||||
clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
|
||||
del_timer_sync(&common->ani.timer);
|
||||
del_timer_sync(&sc->rx_poll_timer);
|
||||
}
|
||||
|
@ -2032,7 +1620,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
*/
|
||||
if ((changed & BSS_CHANGED_BEACON_INT) &&
|
||||
(vif->type == NL80211_IFTYPE_AP))
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
|
||||
/* Configure beaconing (AP, IBSS, MESH) */
|
||||
if (ath9k_uses_beacons(vif->type) &&
|
||||
|
@ -2224,7 +1812,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
|
|||
return;
|
||||
}
|
||||
|
||||
if (sc->sc_flags & SC_OP_INVALID) {
|
||||
if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
|
||||
ath_dbg(common, ANY, "Device not present\n");
|
||||
mutex_unlock(&sc->mutex);
|
||||
return;
|
||||
|
@ -2389,6 +1977,134 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
|
||||
/* Ethtool support for get-stats */
|
||||
|
||||
#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
|
||||
static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
|
||||
"tx_pkts_nic",
|
||||
"tx_bytes_nic",
|
||||
"rx_pkts_nic",
|
||||
"rx_bytes_nic",
|
||||
AMKSTR(d_tx_pkts),
|
||||
AMKSTR(d_tx_bytes),
|
||||
AMKSTR(d_tx_mpdus_queued),
|
||||
AMKSTR(d_tx_mpdus_completed),
|
||||
AMKSTR(d_tx_mpdu_xretries),
|
||||
AMKSTR(d_tx_aggregates),
|
||||
AMKSTR(d_tx_ampdus_queued_hw),
|
||||
AMKSTR(d_tx_ampdus_queued_sw),
|
||||
AMKSTR(d_tx_ampdus_completed),
|
||||
AMKSTR(d_tx_ampdu_retries),
|
||||
AMKSTR(d_tx_ampdu_xretries),
|
||||
AMKSTR(d_tx_fifo_underrun),
|
||||
AMKSTR(d_tx_op_exceeded),
|
||||
AMKSTR(d_tx_timer_expiry),
|
||||
AMKSTR(d_tx_desc_cfg_err),
|
||||
AMKSTR(d_tx_data_underrun),
|
||||
AMKSTR(d_tx_delim_underrun),
|
||||
|
||||
"d_rx_decrypt_crc_err",
|
||||
"d_rx_phy_err",
|
||||
"d_rx_mic_err",
|
||||
"d_rx_pre_delim_crc_err",
|
||||
"d_rx_post_delim_crc_err",
|
||||
"d_rx_decrypt_busy_err",
|
||||
|
||||
"d_rx_phyerr_radar",
|
||||
"d_rx_phyerr_ofdm_timing",
|
||||
"d_rx_phyerr_cck_timing",
|
||||
|
||||
};
|
||||
#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats)
|
||||
|
||||
static void ath9k_get_et_strings(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u32 sset, u8 *data)
|
||||
{
|
||||
if (sset == ETH_SS_STATS)
|
||||
memcpy(data, *ath9k_gstrings_stats,
|
||||
sizeof(ath9k_gstrings_stats));
|
||||
}
|
||||
|
||||
static int ath9k_get_et_sset_count(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, int sset)
|
||||
{
|
||||
if (sset == ETH_SS_STATS)
|
||||
return ATH9K_SSTATS_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum)
|
||||
#define AWDATA(elem) \
|
||||
do { \
|
||||
data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem; \
|
||||
data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem; \
|
||||
data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem; \
|
||||
data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem; \
|
||||
} while (0)
|
||||
|
||||
#define AWDATA_RX(elem) \
|
||||
do { \
|
||||
data[i++] = sc->debug.stats.rxstats.elem; \
|
||||
} while (0)
|
||||
|
||||
static void ath9k_get_et_stats(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
int i = 0;
|
||||
|
||||
data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_pkts_all +
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_pkts_all +
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_pkts_all +
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_pkts_all);
|
||||
data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_bytes_all +
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_bytes_all +
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_bytes_all +
|
||||
sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_bytes_all);
|
||||
AWDATA_RX(rx_pkts_all);
|
||||
AWDATA_RX(rx_bytes_all);
|
||||
|
||||
AWDATA(tx_pkts_all);
|
||||
AWDATA(tx_bytes_all);
|
||||
AWDATA(queued);
|
||||
AWDATA(completed);
|
||||
AWDATA(xretries);
|
||||
AWDATA(a_aggr);
|
||||
AWDATA(a_queued_hw);
|
||||
AWDATA(a_queued_sw);
|
||||
AWDATA(a_completed);
|
||||
AWDATA(a_retries);
|
||||
AWDATA(a_xretries);
|
||||
AWDATA(fifo_underrun);
|
||||
AWDATA(xtxop);
|
||||
AWDATA(timer_exp);
|
||||
AWDATA(desc_cfg_err);
|
||||
AWDATA(data_underrun);
|
||||
AWDATA(delim_underrun);
|
||||
|
||||
AWDATA_RX(decrypt_crc_err);
|
||||
AWDATA_RX(phy_err);
|
||||
AWDATA_RX(mic_err);
|
||||
AWDATA_RX(pre_delim_crc_err);
|
||||
AWDATA_RX(post_delim_crc_err);
|
||||
AWDATA_RX(decrypt_busy_err);
|
||||
|
||||
AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]);
|
||||
AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]);
|
||||
AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]);
|
||||
|
||||
WARN_ON(i != ATH9K_SSTATS_LEN);
|
||||
}
|
||||
|
||||
/* End of ethtool get-stats functions */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
struct ieee80211_ops ath9k_ops = {
|
||||
.tx = ath9k_tx,
|
||||
.start = ath9k_start,
|
||||
|
@ -2417,4 +2133,10 @@ struct ieee80211_ops ath9k_ops = {
|
|||
.get_stats = ath9k_get_stats,
|
||||
.set_antenna = ath9k_set_antenna,
|
||||
.get_antenna = ath9k_get_antenna,
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
.get_et_sset_count = ath9k_get_et_sset_count,
|
||||
.get_et_stats = ath9k_get_et_stats,
|
||||
.get_et_strings = ath9k_get_et_strings,
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -116,42 +116,58 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
|
|||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
struct ath_mci_profile *mci = &btcoex->mci;
|
||||
struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
|
||||
struct ath_mci_profile_info *info;
|
||||
u32 num_profile = NUM_PROF(mci);
|
||||
|
||||
if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING)
|
||||
goto skip_tuning;
|
||||
|
||||
if (num_profile == 1) {
|
||||
info = list_first_entry(&mci->info,
|
||||
struct ath_mci_profile_info,
|
||||
list);
|
||||
if (mci->num_sco && info->T == 12) {
|
||||
mci->aggr_limit = 8;
|
||||
if (mci->num_sco) {
|
||||
if (info->T == 12)
|
||||
mci->aggr_limit = 8;
|
||||
else if (info->T == 6) {
|
||||
mci->aggr_limit = 6;
|
||||
btcoex->duty_cycle = 30;
|
||||
}
|
||||
ath_dbg(common, MCI,
|
||||
"Single SCO, aggregation limit 2 ms\n");
|
||||
} else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) &&
|
||||
!info->master) {
|
||||
btcoex->btcoex_period = 60;
|
||||
"Single SCO, aggregation limit %d 1/4 ms\n",
|
||||
mci->aggr_limit);
|
||||
} else if (mci->num_pan || mci->num_other_acl) {
|
||||
/*
|
||||
* For single PAN/FTP profile, allocate 35% for BT
|
||||
* to improve WLAN throughput.
|
||||
*/
|
||||
btcoex->duty_cycle = 35;
|
||||
btcoex->btcoex_period = 53;
|
||||
ath_dbg(common, MCI,
|
||||
"Single slave PAN/FTP, bt period 60 ms\n");
|
||||
} else if ((info->type == MCI_GPM_COEX_PROFILE_HID) &&
|
||||
(info->T > 0 && info->T < 50) &&
|
||||
(info->A > 1 || info->W > 1)) {
|
||||
"Single PAN/FTP bt period %d ms dutycycle %d\n",
|
||||
btcoex->duty_cycle, btcoex->btcoex_period);
|
||||
} else if (mci->num_hid) {
|
||||
btcoex->duty_cycle = 30;
|
||||
mci->aggr_limit = 8;
|
||||
mci->aggr_limit = 6;
|
||||
ath_dbg(common, MCI,
|
||||
"Multiple attempt/timeout single HID "
|
||||
"aggregation limit 2 ms dutycycle 30%%\n");
|
||||
"aggregation limit 1.5 ms dutycycle 30%%\n");
|
||||
}
|
||||
} else if ((num_profile == 2) && (mci->num_hid == 2)) {
|
||||
btcoex->duty_cycle = 30;
|
||||
mci->aggr_limit = 8;
|
||||
ath_dbg(common, MCI,
|
||||
"Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
|
||||
} else if (num_profile > 3) {
|
||||
} else if (num_profile == 2) {
|
||||
if (mci->num_hid == 2)
|
||||
btcoex->duty_cycle = 30;
|
||||
mci->aggr_limit = 6;
|
||||
ath_dbg(common, MCI,
|
||||
"Three or more profiles aggregation limit 1.5 ms\n");
|
||||
"Two BT profiles aggr limit 1.5 ms dutycycle %d%%\n",
|
||||
btcoex->duty_cycle);
|
||||
} else if (num_profile >= 3) {
|
||||
mci->aggr_limit = 4;
|
||||
ath_dbg(common, MCI,
|
||||
"Three or more profiles aggregation limit 1 ms\n");
|
||||
}
|
||||
|
||||
skip_tuning:
|
||||
if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) {
|
||||
if (IS_CHAN_HT(sc->sc_ah->curchan))
|
||||
ath_mci_adjust_aggr_limit(btcoex);
|
||||
|
@ -538,3 +554,14 @@ void ath_mci_intr(struct ath_softc *sc)
|
|||
mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
|
||||
AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
|
||||
}
|
||||
|
||||
void ath_mci_enable(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
if (!common->btcoex_enabled)
|
||||
return;
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
|
||||
sc->sc_ah->imask |= ATH9K_INT_MCI;
|
||||
}
|
||||
|
|
|
@ -130,4 +130,13 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci);
|
|||
int ath_mci_setup(struct ath_softc *sc);
|
||||
void ath_mci_cleanup(struct ath_softc *sc);
|
||||
void ath_mci_intr(struct ath_softc *sc);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
|
||||
void ath_mci_enable(struct ath_softc *sc);
|
||||
#else
|
||||
static inline void ath_mci_enable(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
|
||||
|
||||
#endif /* MCI_H*/
|
||||
|
|
|
@ -115,6 +115,9 @@ static void ath_pci_aspm_init(struct ath_common *common)
|
|||
int pos;
|
||||
u8 aspm;
|
||||
|
||||
if (!ah->is_pciexpress)
|
||||
return;
|
||||
|
||||
pos = pci_pcie_cap(pdev);
|
||||
if (!pos)
|
||||
return;
|
||||
|
@ -138,6 +141,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
|
|||
aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
|
||||
pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm);
|
||||
|
||||
ath_info(common, "Disabling ASPM since BTCOEX is enabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -147,6 +151,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
|
|||
ah->aspm_enabled = true;
|
||||
/* Initialize PCIe PM and SERDES registers. */
|
||||
ath9k_hw_configpcipowersave(ah, false);
|
||||
ath_info(common, "ASPM enabled: 0x%x\n", aspm);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,7 +251,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
sc->mem = mem;
|
||||
|
||||
/* Will be cleared in ath9k_start() */
|
||||
sc->sc_flags |= SC_OP_INVALID;
|
||||
set_bit(SC_OP_INVALID, &sc->sc_flags);
|
||||
|
||||
ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
|
||||
if (ret) {
|
||||
|
|
|
@ -20,43 +20,6 @@
|
|||
|
||||
#define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb))
|
||||
|
||||
static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
|
||||
int mindelta, int main_rssi_avg,
|
||||
int alt_rssi_avg, int pkt_count)
|
||||
{
|
||||
return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
|
||||
(alt_rssi_avg > main_rssi_avg + maxdelta)) ||
|
||||
(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
|
||||
}
|
||||
|
||||
static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
|
||||
int curr_main_set, int curr_alt_set,
|
||||
int alt_rssi_avg, int main_rssi_avg)
|
||||
{
|
||||
bool result = false;
|
||||
switch (div_group) {
|
||||
case 0:
|
||||
if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
|
||||
result = true;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
|
||||
(curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
|
||||
(alt_rssi_avg >= (main_rssi_avg - 5))) ||
|
||||
((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
|
||||
(curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
|
||||
(alt_rssi_avg >= (main_rssi_avg - 2)))) &&
|
||||
(alt_rssi_avg >= 4))
|
||||
result = true;
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
|
||||
{
|
||||
return sc->ps_enabled &&
|
||||
|
@ -303,7 +266,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
|
|||
|
||||
ath_opmode_init(sc);
|
||||
|
||||
ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
|
||||
ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
|
||||
|
||||
spin_unlock_bh(&sc->rx.rxbuflock);
|
||||
}
|
||||
|
@ -322,8 +285,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
|
|||
int error = 0;
|
||||
|
||||
spin_lock_init(&sc->sc_pcu_lock);
|
||||
sc->sc_flags &= ~SC_OP_RXFLUSH;
|
||||
spin_lock_init(&sc->rx.rxbuflock);
|
||||
clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
|
||||
|
||||
common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
|
||||
sc->sc_ah->caps.rx_status_len;
|
||||
|
@ -500,7 +463,7 @@ int ath_startrecv(struct ath_softc *sc)
|
|||
|
||||
start_recv:
|
||||
ath_opmode_init(sc);
|
||||
ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
|
||||
ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
|
||||
|
||||
spin_unlock_bh(&sc->rx.rxbuflock);
|
||||
|
||||
|
@ -535,11 +498,11 @@ bool ath_stoprecv(struct ath_softc *sc)
|
|||
|
||||
void ath_flushrecv(struct ath_softc *sc)
|
||||
{
|
||||
sc->sc_flags |= SC_OP_RXFLUSH;
|
||||
set_bit(SC_OP_RXFLUSH, &sc->sc_flags);
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
|
||||
ath_rx_tasklet(sc, 1, true);
|
||||
ath_rx_tasklet(sc, 1, false);
|
||||
sc->sc_flags &= ~SC_OP_RXFLUSH;
|
||||
clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
|
||||
}
|
||||
|
||||
static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
|
||||
|
@ -624,13 +587,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
|
|||
|
||||
/* Process Beacon and CAB receive in PS state */
|
||||
if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
|
||||
&& mybeacon)
|
||||
&& mybeacon) {
|
||||
ath_rx_ps_beacon(sc, skb);
|
||||
else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
|
||||
(ieee80211_is_data(hdr->frame_control) ||
|
||||
ieee80211_is_action(hdr->frame_control)) &&
|
||||
is_multicast_ether_addr(hdr->addr1) &&
|
||||
!ieee80211_has_moredata(hdr->frame_control)) {
|
||||
} else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
|
||||
(ieee80211_is_data(hdr->frame_control) ||
|
||||
ieee80211_is_action(hdr->frame_control)) &&
|
||||
is_multicast_ether_addr(hdr->addr1) &&
|
||||
!ieee80211_has_moredata(hdr->frame_control)) {
|
||||
/*
|
||||
* No more broadcast/multicast frames to be received at this
|
||||
* point.
|
||||
|
@ -1067,709 +1030,6 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
|
|||
rxs->flag &= ~RX_FLAG_DECRYPTED;
|
||||
}
|
||||
|
||||
static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
|
||||
struct ath_hw_antcomb_conf ant_conf,
|
||||
int main_rssi_avg)
|
||||
{
|
||||
antcomb->quick_scan_cnt = 0;
|
||||
|
||||
if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
|
||||
antcomb->rssi_lna2 = main_rssi_avg;
|
||||
else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
|
||||
antcomb->rssi_lna1 = main_rssi_avg;
|
||||
|
||||
switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
|
||||
case 0x10: /* LNA2 A-B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
antcomb->first_quick_scan_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
|
||||
struct ath_hw_antcomb_conf *div_ant_conf,
|
||||
int main_rssi_avg, int alt_rssi_avg,
|
||||
int alt_ratio)
|
||||
{
|
||||
/* alt_good */
|
||||
switch (antcomb->quick_scan_cnt) {
|
||||
case 0:
|
||||
/* set alt to main, and alt to first conf */
|
||||
div_ant_conf->main_lna_conf = antcomb->main_conf;
|
||||
div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
|
||||
break;
|
||||
case 1:
|
||||
/* set alt to main, and alt to first conf */
|
||||
div_ant_conf->main_lna_conf = antcomb->main_conf;
|
||||
div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
|
||||
antcomb->rssi_first = main_rssi_avg;
|
||||
antcomb->rssi_second = alt_rssi_avg;
|
||||
|
||||
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
|
||||
/* main is LNA1 */
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->first_ratio = true;
|
||||
else
|
||||
antcomb->first_ratio = false;
|
||||
} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->first_ratio = true;
|
||||
else
|
||||
antcomb->first_ratio = false;
|
||||
} else {
|
||||
if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
|
||||
(alt_rssi_avg > main_rssi_avg +
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
|
||||
(alt_rssi_avg > main_rssi_avg)) &&
|
||||
(antcomb->total_pkt_count > 50))
|
||||
antcomb->first_ratio = true;
|
||||
else
|
||||
antcomb->first_ratio = false;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
antcomb->alt_good = false;
|
||||
antcomb->scan_not_start = false;
|
||||
antcomb->scan = false;
|
||||
antcomb->rssi_first = main_rssi_avg;
|
||||
antcomb->rssi_third = alt_rssi_avg;
|
||||
|
||||
if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
|
||||
antcomb->rssi_lna1 = alt_rssi_avg;
|
||||
else if (antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
antcomb->rssi_lna2 = alt_rssi_avg;
|
||||
else if (antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
|
||||
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
|
||||
antcomb->rssi_lna2 = main_rssi_avg;
|
||||
else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
|
||||
antcomb->rssi_lna1 = main_rssi_avg;
|
||||
}
|
||||
|
||||
if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
|
||||
ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
|
||||
div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||
|
||||
if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->second_ratio = true;
|
||||
else
|
||||
antcomb->second_ratio = false;
|
||||
} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
|
||||
if (ath_is_alt_ant_ratio_better(alt_ratio,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
antcomb->total_pkt_count))
|
||||
antcomb->second_ratio = true;
|
||||
else
|
||||
antcomb->second_ratio = false;
|
||||
} else {
|
||||
if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
|
||||
(alt_rssi_avg > main_rssi_avg +
|
||||
ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
|
||||
(alt_rssi_avg > main_rssi_avg)) &&
|
||||
(antcomb->total_pkt_count > 50))
|
||||
antcomb->second_ratio = true;
|
||||
else
|
||||
antcomb->second_ratio = false;
|
||||
}
|
||||
|
||||
/* set alt to the conf with maximun ratio */
|
||||
if (antcomb->first_ratio && antcomb->second_ratio) {
|
||||
if (antcomb->rssi_second > antcomb->rssi_third) {
|
||||
/* first alt*/
|
||||
if ((antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2*/
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->first_quick_scan_conf;
|
||||
} else if ((antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)) {
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
} else {
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->second_quick_scan_conf;
|
||||
}
|
||||
} else if (antcomb->first_ratio) {
|
||||
/* first alt */
|
||||
if ((antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->first_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->first_quick_scan_conf;
|
||||
} else if (antcomb->second_ratio) {
|
||||
/* second alt */
|
||||
if ((antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->second_quick_scan_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf =
|
||||
antcomb->second_quick_scan_conf;
|
||||
} else {
|
||||
/* main is largest */
|
||||
if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
|
||||
(antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
|
||||
/* Set alt LNA1 or LNA2 */
|
||||
if (div_ant_conf->main_lna_conf ==
|
||||
ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else
|
||||
div_ant_conf->alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
else
|
||||
/* Set alt to A+B or A-B */
|
||||
div_ant_conf->alt_lna_conf = antcomb->main_conf;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
|
||||
struct ath_ant_comb *antcomb, int alt_ratio)
|
||||
{
|
||||
if (ant_conf->div_group == 0) {
|
||||
/* Adjust the fast_div_bias based on main and alt lna conf */
|
||||
switch ((ant_conf->main_lna_conf << 4) |
|
||||
ant_conf->alt_lna_conf) {
|
||||
case 0x01: /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x3b;
|
||||
break;
|
||||
case 0x02: /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x3d;
|
||||
break;
|
||||
case 0x03: /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
case 0x10: /* LNA2 A-B */
|
||||
ant_conf->fast_div_bias = 0x7;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
ant_conf->fast_div_bias = 0x7;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
ant_conf->fast_div_bias = 0x6;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x0;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
ant_conf->fast_div_bias = 0x6;
|
||||
break;
|
||||
case 0x30: /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
break;
|
||||
case 0x31: /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x3b;
|
||||
break;
|
||||
case 0x32: /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x3d;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (ant_conf->div_group == 1) {
|
||||
/* Adjust the fast_div_bias based on main and alt_lna_conf */
|
||||
switch ((ant_conf->main_lna_conf << 4) |
|
||||
ant_conf->alt_lna_conf) {
|
||||
case 0x01: /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x02: /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x03: /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x10: /* LNA2 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x3f;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x30: /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x31: /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x32: /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (ant_conf->div_group == 2) {
|
||||
/* Adjust the fast_div_bias based on main and alt_lna_conf */
|
||||
switch ((ant_conf->main_lna_conf << 4) |
|
||||
ant_conf->alt_lna_conf) {
|
||||
case 0x01: /* A-B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x02: /* A-B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x03: /* A-B A+B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x10: /* LNA2 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x12: /* LNA2 LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x13: /* LNA2 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x20: /* LNA1 A-B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x21: /* LNA1 LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x23: /* LNA1 A+B */
|
||||
if (!(antcomb->scan) &&
|
||||
(alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
else
|
||||
ant_conf->fast_div_bias = 0x2;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x30: /* A+B A-B */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x31: /* A+B LNA2 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
case 0x32: /* A+B LNA1 */
|
||||
ant_conf->fast_div_bias = 0x1;
|
||||
ant_conf->main_gaintb = 0;
|
||||
ant_conf->alt_gaintb = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Antenna diversity and combining */
|
||||
static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
|
||||
{
|
||||
struct ath_hw_antcomb_conf div_ant_conf;
|
||||
struct ath_ant_comb *antcomb = &sc->ant_comb;
|
||||
int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
|
||||
int curr_main_set;
|
||||
int main_rssi = rs->rs_rssi_ctl0;
|
||||
int alt_rssi = rs->rs_rssi_ctl1;
|
||||
int rx_ant_conf, main_ant_conf;
|
||||
bool short_scan = false;
|
||||
|
||||
rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
|
||||
ATH_ANT_RX_MASK;
|
||||
main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
|
||||
ATH_ANT_RX_MASK;
|
||||
|
||||
/* Record packet only when both main_rssi and alt_rssi is positive */
|
||||
if (main_rssi > 0 && alt_rssi > 0) {
|
||||
antcomb->total_pkt_count++;
|
||||
antcomb->main_total_rssi += main_rssi;
|
||||
antcomb->alt_total_rssi += alt_rssi;
|
||||
if (main_ant_conf == rx_ant_conf)
|
||||
antcomb->main_recv_cnt++;
|
||||
else
|
||||
antcomb->alt_recv_cnt++;
|
||||
}
|
||||
|
||||
/* Short scan check */
|
||||
if (antcomb->scan && antcomb->alt_good) {
|
||||
if (time_after(jiffies, antcomb->scan_start_time +
|
||||
msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
|
||||
short_scan = true;
|
||||
else
|
||||
if (antcomb->total_pkt_count ==
|
||||
ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
|
||||
alt_ratio = ((antcomb->alt_recv_cnt * 100) /
|
||||
antcomb->total_pkt_count);
|
||||
if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
|
||||
short_scan = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
|
||||
rs->rs_moreaggr) && !short_scan)
|
||||
return;
|
||||
|
||||
if (antcomb->total_pkt_count) {
|
||||
alt_ratio = ((antcomb->alt_recv_cnt * 100) /
|
||||
antcomb->total_pkt_count);
|
||||
main_rssi_avg = (antcomb->main_total_rssi /
|
||||
antcomb->total_pkt_count);
|
||||
alt_rssi_avg = (antcomb->alt_total_rssi /
|
||||
antcomb->total_pkt_count);
|
||||
}
|
||||
|
||||
|
||||
ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
|
||||
curr_alt_set = div_ant_conf.alt_lna_conf;
|
||||
curr_main_set = div_ant_conf.main_lna_conf;
|
||||
|
||||
antcomb->count++;
|
||||
|
||||
if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
|
||||
if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
|
||||
ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
|
||||
main_rssi_avg);
|
||||
antcomb->alt_good = true;
|
||||
} else {
|
||||
antcomb->alt_good = false;
|
||||
}
|
||||
|
||||
antcomb->count = 0;
|
||||
antcomb->scan = true;
|
||||
antcomb->scan_not_start = true;
|
||||
}
|
||||
|
||||
if (!antcomb->scan) {
|
||||
if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
|
||||
alt_ratio, curr_main_set, curr_alt_set,
|
||||
alt_rssi_avg, main_rssi_avg)) {
|
||||
if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
|
||||
/* Switch main and alt LNA */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
} else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
}
|
||||
|
||||
goto div_comb_done;
|
||||
} else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
|
||||
(curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
|
||||
/* Set alt to another LNA */
|
||||
if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
|
||||
goto div_comb_done;
|
||||
}
|
||||
|
||||
if ((alt_rssi_avg < (main_rssi_avg +
|
||||
div_ant_conf.lna1_lna2_delta)))
|
||||
goto div_comb_done;
|
||||
}
|
||||
|
||||
if (!antcomb->scan_not_start) {
|
||||
switch (curr_alt_set) {
|
||||
case ATH_ANT_DIV_COMB_LNA2:
|
||||
antcomb->rssi_lna2 = alt_rssi_avg;
|
||||
antcomb->rssi_lna1 = main_rssi_avg;
|
||||
antcomb->scan = true;
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case ATH_ANT_DIV_COMB_LNA1:
|
||||
antcomb->rssi_lna1 = alt_rssi_avg;
|
||||
antcomb->rssi_lna2 = main_rssi_avg;
|
||||
antcomb->scan = true;
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
break;
|
||||
case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
|
||||
antcomb->rssi_add = alt_rssi_avg;
|
||||
antcomb->scan = true;
|
||||
/* set to A-B */
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
break;
|
||||
case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
|
||||
antcomb->rssi_sub = alt_rssi_avg;
|
||||
antcomb->scan = false;
|
||||
if (antcomb->rssi_lna2 >
|
||||
(antcomb->rssi_lna1 +
|
||||
ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
|
||||
/* use LNA2 as main LNA */
|
||||
if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
|
||||
(antcomb->rssi_add > antcomb->rssi_sub)) {
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
} else if (antcomb->rssi_sub >
|
||||
antcomb->rssi_lna1) {
|
||||
/* set to A-B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
} else {
|
||||
/* set to LNA1 */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
}
|
||||
} else {
|
||||
/* use LNA1 as main LNA */
|
||||
if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
|
||||
(antcomb->rssi_add > antcomb->rssi_sub)) {
|
||||
/* set to A+B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
|
||||
} else if (antcomb->rssi_sub >
|
||||
antcomb->rssi_lna1) {
|
||||
/* set to A-B */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
|
||||
} else {
|
||||
/* set to LNA2 */
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!antcomb->alt_good) {
|
||||
antcomb->scan_not_start = false;
|
||||
/* Set alt to another LNA */
|
||||
if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
} else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
|
||||
div_ant_conf.main_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA1;
|
||||
div_ant_conf.alt_lna_conf =
|
||||
ATH_ANT_DIV_COMB_LNA2;
|
||||
}
|
||||
goto div_comb_done;
|
||||
}
|
||||
}
|
||||
|
||||
ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
|
||||
main_rssi_avg, alt_rssi_avg,
|
||||
alt_ratio);
|
||||
|
||||
antcomb->quick_scan_cnt++;
|
||||
|
||||
div_comb_done:
|
||||
ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
|
||||
ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
|
||||
|
||||
antcomb->scan_start_time = jiffies;
|
||||
antcomb->total_pkt_count = 0;
|
||||
antcomb->main_total_rssi = 0;
|
||||
antcomb->alt_total_rssi = 0;
|
||||
antcomb->main_recv_cnt = 0;
|
||||
antcomb->alt_recv_cnt = 0;
|
||||
}
|
||||
|
||||
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
||||
{
|
||||
struct ath_buf *bf;
|
||||
|
@ -1803,7 +1063,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
|||
|
||||
do {
|
||||
/* If handling rx interrupt and flush is in progress => exit */
|
||||
if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
|
||||
if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
|
||||
break;
|
||||
|
||||
memset(&rs, 0, sizeof(rs));
|
||||
|
@ -1841,13 +1101,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
|||
else
|
||||
rs.is_mybeacon = false;
|
||||
|
||||
sc->rx.num_pkts++;
|
||||
ath_debug_stat_rx(sc, &rs);
|
||||
|
||||
/*
|
||||
* If we're asked to flush receive queue, directly
|
||||
* chain it back at the queue without processing it.
|
||||
*/
|
||||
if (sc->sc_flags & SC_OP_RXFLUSH) {
|
||||
if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) {
|
||||
RX_STAT_INC(rx_drop_rxflush);
|
||||
goto requeue_drop_frag;
|
||||
}
|
||||
|
@ -1968,7 +1229,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
|||
skb_trim(skb, skb->len - 8);
|
||||
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
|
||||
if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
|
||||
PS_WAIT_FOR_CAB |
|
||||
PS_WAIT_FOR_PSPOLL_DATA)) ||
|
||||
|
|
|
@ -2211,5 +2211,7 @@ enum {
|
|||
#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff
|
||||
#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0
|
||||
|
||||
#define AR_GLB_SWREG_DISCONT_MODE 0x2002c
|
||||
#define AR_GLB_SWREG_DISCONT_EN_BT_WLAN 0x3
|
||||
|
||||
#endif
|
||||
|
|
|
@ -105,19 +105,19 @@ static int ath_max_4ms_framelen[4][32] = {
|
|||
/* Aggregation logic */
|
||||
/*********************/
|
||||
|
||||
static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
|
||||
void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
|
||||
__acquires(&txq->axq_lock)
|
||||
{
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
}
|
||||
|
||||
static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
|
||||
void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
|
||||
__releases(&txq->axq_lock)
|
||||
{
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
}
|
||||
|
||||
static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
|
||||
void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
|
||||
__releases(&txq->axq_lock)
|
||||
{
|
||||
struct sk_buff_head q;
|
||||
|
@ -1536,7 +1536,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
|
|||
int i;
|
||||
u32 npend = 0;
|
||||
|
||||
if (sc->sc_flags & SC_OP_INVALID)
|
||||
if (test_bit(SC_OP_INVALID, &sc->sc_flags))
|
||||
return true;
|
||||
|
||||
ath9k_hw_abort_tx_dma(ah);
|
||||
|
@ -1994,6 +1994,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
|||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
|
||||
int q, padpos, padsize;
|
||||
unsigned long flags;
|
||||
|
||||
ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
|
||||
|
||||
|
@ -2012,6 +2013,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
|||
skb_pull(skb, padsize);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
|
||||
sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
|
||||
ath_dbg(common, PS,
|
||||
|
@ -2021,6 +2023,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
|||
PS_WAIT_FOR_PSPOLL_DATA |
|
||||
PS_WAIT_FOR_TX_ACK));
|
||||
}
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
|
||||
q = skb_get_queue_mapping(skb);
|
||||
if (txq == sc->tx.txq_map[q]) {
|
||||
|
@ -2231,46 +2234,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
ath_txq_unlock_complete(sc, txq);
|
||||
}
|
||||
|
||||
static void ath_tx_complete_poll_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
tx_complete_work.work);
|
||||
struct ath_txq *txq;
|
||||
int i;
|
||||
bool needreset = false;
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
sc->tx_complete_poll_work_seen++;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
|
||||
if (ATH_TXQ_SETUP(sc, i)) {
|
||||
txq = &sc->tx.txq[i];
|
||||
ath_txq_lock(sc, txq);
|
||||
if (txq->axq_depth) {
|
||||
if (txq->axq_tx_inprogress) {
|
||||
needreset = true;
|
||||
ath_txq_unlock(sc, txq);
|
||||
break;
|
||||
} else {
|
||||
txq->axq_tx_inprogress = true;
|
||||
}
|
||||
}
|
||||
ath_txq_unlock_complete(sc, txq);
|
||||
}
|
||||
|
||||
if (needreset) {
|
||||
ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
|
||||
"tx hung, resetting the chip\n");
|
||||
RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
}
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
|
||||
msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ath_tx_tasklet(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
|
|
@ -1508,7 +1508,7 @@ static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
|
|||
|
||||
static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl)
|
||||
{
|
||||
b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/"
|
||||
b43legacyerr(wl, "You must go to http://wireless.kernel.org/en/users/"
|
||||
"Drivers/b43#devicefirmware "
|
||||
"and download the correct firmware (version 3).\n");
|
||||
}
|
||||
|
|
|
@ -631,9 +631,8 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val)
|
|||
cc = sii->icbus->drv_cc.core;
|
||||
|
||||
/* mask and set */
|
||||
if (mask || val) {
|
||||
if (mask || val)
|
||||
bcma_maskset32(cc, regoff, ~mask, val);
|
||||
}
|
||||
|
||||
/* readback */
|
||||
w = bcma_read32(cc, regoff);
|
||||
|
|
|
@ -193,7 +193,7 @@ extern void ai_detach(struct si_pub *sih);
|
|||
extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val);
|
||||
extern void ai_clkctl_init(struct si_pub *sih);
|
||||
extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih);
|
||||
extern bool ai_clkctl_cc(struct si_pub *sih, uint mode);
|
||||
extern bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode);
|
||||
extern bool ai_deviceremoved(struct si_pub *sih);
|
||||
|
||||
extern void ai_pci_down(struct si_pub *sih);
|
||||
|
|
|
@ -14358,7 +14358,7 @@ void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs)
|
|||
|
||||
wlc_phy_write_txmacreg_nphy(pi, holdoff, delay);
|
||||
|
||||
if (pi && pi->sh && (pi->sh->_rifs_phy != rifs))
|
||||
if (pi->sh && (pi->sh->_rifs_phy != rifs))
|
||||
pi->sh->_rifs_phy = rifs;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
|
|||
/* Free the driver packet. Free the tag if present */
|
||||
void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
|
||||
{
|
||||
if (!skb)
|
||||
return;
|
||||
WARN_ON(skb->next);
|
||||
if (skb->destructor)
|
||||
/* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
|
||||
|
|
|
@ -2701,6 +2701,20 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
|
|||
memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6);
|
||||
}
|
||||
|
||||
static void ipw_read_eeprom(struct ipw_priv *priv)
|
||||
{
|
||||
int i;
|
||||
__le16 *eeprom = (__le16 *) priv->eeprom;
|
||||
|
||||
IPW_DEBUG_TRACE(">>\n");
|
||||
|
||||
/* read entire contents of eeprom into private buffer */
|
||||
for (i = 0; i < 128; i++)
|
||||
eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
|
||||
|
||||
IPW_DEBUG_TRACE("<<\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Either the device driver (i.e. the host) or the firmware can
|
||||
* load eeprom data into the designated region in SRAM. If neither
|
||||
|
@ -2712,14 +2726,9 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
|
|||
static void ipw_eeprom_init_sram(struct ipw_priv *priv)
|
||||
{
|
||||
int i;
|
||||
__le16 *eeprom = (__le16 *) priv->eeprom;
|
||||
|
||||
IPW_DEBUG_TRACE(">>\n");
|
||||
|
||||
/* read entire contents of eeprom into private buffer */
|
||||
for (i = 0; i < 128; i++)
|
||||
eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
|
||||
|
||||
/*
|
||||
If the data looks correct, then copy it to our private
|
||||
copy. Otherwise let the firmware know to perform the operation
|
||||
|
@ -3643,8 +3652,10 @@ static int ipw_load(struct ipw_priv *priv)
|
|||
/* ack fw init done interrupt */
|
||||
ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
|
||||
|
||||
/* read eeprom data and initialize the eeprom region of sram */
|
||||
/* read eeprom data */
|
||||
priv->eeprom_delay = 1;
|
||||
ipw_read_eeprom(priv);
|
||||
/* initialize the eeprom region of sram */
|
||||
ipw_eeprom_init_sram(priv);
|
||||
|
||||
/* enable interrupts */
|
||||
|
|
|
@ -5724,7 +5724,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
|
|||
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
hw->wiphy->flags |=
|
||||
WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS;
|
||||
WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
|
||||
WIPHY_FLAG_IBSS_RSN;
|
||||
|
||||
/*
|
||||
* For now, disable PS by default because it affects
|
||||
|
@ -5873,6 +5874,16 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/*
|
||||
* To support IBSS RSN, don't program group keys in IBSS, the
|
||||
* hardware will then not attempt to decrypt the frames.
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC &&
|
||||
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
|
||||
D_MAC80211("leave - ad-hoc group key\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
sta_id = il_sta_id_or_broadcast(il, sta);
|
||||
if (sta_id == IL_INVALID_STATION)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -6,6 +6,7 @@ config IWLWIFI
|
|||
select LEDS_CLASS
|
||||
select LEDS_TRIGGERS
|
||||
select MAC80211_LEDS
|
||||
select IWLDVM
|
||||
---help---
|
||||
Select to build the driver supporting the:
|
||||
|
||||
|
@ -41,6 +42,10 @@ config IWLWIFI
|
|||
say M here and read <file:Documentation/kbuild/modules.txt>. The
|
||||
module will be called iwlwifi.
|
||||
|
||||
config IWLDVM
|
||||
tristate "Intel Wireless WiFi"
|
||||
depends on IWLWIFI
|
||||
|
||||
menu "Debugging Options"
|
||||
depends on IWLWIFI
|
||||
|
||||
|
|
|
@ -1,27 +1,17 @@
|
|||
# WIFI
|
||||
obj-$(CONFIG_IWLWIFI) += iwlwifi.o
|
||||
iwlwifi-objs := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
|
||||
iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o iwl-debug.o
|
||||
iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
|
||||
iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
|
||||
|
||||
iwlwifi-objs += iwl-eeprom.o iwl-power.o
|
||||
iwlwifi-objs += iwl-scan.o iwl-led.o
|
||||
iwlwifi-objs += iwl-agn-rxon.o iwl-agn-devices.o
|
||||
iwlwifi-objs += iwl-5000.o
|
||||
iwlwifi-objs += iwl-6000.o
|
||||
iwlwifi-objs += iwl-1000.o
|
||||
iwlwifi-objs += iwl-2000.o
|
||||
iwlwifi-objs += iwl-pci.o
|
||||
iwlwifi-objs += iwl-drv.o
|
||||
iwlwifi-objs += iwl-notif-wait.o
|
||||
iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
|
||||
|
||||
|
||||
iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
|
||||
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
|
||||
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-testmode.o
|
||||
obj-$(CONFIG_IWLDVM) += dvm/
|
||||
|
||||
CFLAGS_iwl-devtrace.o := -I$(src)
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN__
|
||||
# common
|
||||
obj-$(CONFIG_IWLWIFI) += iwlwifi.o
|
||||
iwlwifi-objs += iwl-io.o
|
||||
iwlwifi-objs += iwl-drv.o
|
||||
iwlwifi-objs += iwl-debug.o
|
||||
iwlwifi-objs += iwl-notif-wait.o
|
||||
iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o
|
||||
iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
|
||||
iwlwifi-objs += pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o
|
||||
|
||||
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN__ -I$(src)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# DVM
|
||||
obj-$(CONFIG_IWLDVM) += iwldvm.o
|
||||
iwldvm-objs += main.o rs.o mac80211.o ucode.o tx.o
|
||||
iwldvm-objs += lib.o calib.o tt.o sta.o rx.o
|
||||
|
||||
iwldvm-objs += power.o
|
||||
iwldvm-objs += scan.o led.o
|
||||
iwldvm-objs += rxon.o devices.o
|
||||
|
||||
iwldvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
|
||||
iwldvm-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += testmode.o
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../
|
|
@ -63,9 +63,10 @@
|
|||
#ifndef __iwl_agn_h__
|
||||
#define __iwl_agn_h__
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-config.h"
|
||||
|
||||
#include "dev.h"
|
||||
|
||||
/* The first 11 queues (0-10) are used otherwise */
|
||||
#define IWLAGN_FIRST_AMPDU_QUEUE 11
|
||||
|
||||
|
@ -91,7 +92,6 @@ extern struct iwl_lib_ops iwl6030_lib;
|
|||
#define STATUS_CT_KILL 1
|
||||
#define STATUS_ALIVE 2
|
||||
#define STATUS_READY 3
|
||||
#define STATUS_GEO_CONFIGURED 4
|
||||
#define STATUS_EXIT_PENDING 5
|
||||
#define STATUS_STATISTICS 6
|
||||
#define STATUS_SCANNING 7
|
||||
|
@ -101,6 +101,7 @@ extern struct iwl_lib_ops iwl6030_lib;
|
|||
#define STATUS_CHANNEL_SWITCH_PENDING 11
|
||||
#define STATUS_SCAN_COMPLETE 12
|
||||
#define STATUS_POWER_PMI 13
|
||||
#define STATUS_SCAN_ROC_EXPIRED 14
|
||||
|
||||
struct iwl_ucode_capabilities;
|
||||
|
||||
|
@ -255,6 +256,10 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
|
|||
enum iwl_scan_type scan_type,
|
||||
enum ieee80211_band band);
|
||||
|
||||
void iwl_scan_roc_expired(struct iwl_priv *priv);
|
||||
void iwl_scan_offchannel_skb(struct iwl_priv *priv);
|
||||
void iwl_scan_offchannel_skb_status(struct iwl_priv *priv);
|
||||
|
||||
/* For faster active scanning, scan will move to the next channel if fewer than
|
||||
* PLCP_QUIET_THRESH packets are heard on this channel within
|
||||
* ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell
|
||||
|
@ -437,10 +442,8 @@ static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
|
|||
|
||||
static inline int iwl_is_ready(struct iwl_priv *priv)
|
||||
{
|
||||
/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
|
||||
* set but EXIT_PENDING is not */
|
||||
/* The adapter is 'ready' if READY EXIT_PENDING is not set */
|
||||
return test_bit(STATUS_READY, &priv->status) &&
|
||||
test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
|
||||
!test_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
}
|
||||
|
||||
|
@ -518,85 +521,4 @@ static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
|
|||
return s;
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
/* API method exported for mvm hybrid state */
|
||||
void iwl_setup_deferred_work(struct iwl_priv *priv);
|
||||
int iwl_send_wimax_coex(struct iwl_priv *priv);
|
||||
int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
|
||||
void iwl_option_config(struct iwl_priv *priv);
|
||||
void iwl_set_hw_params(struct iwl_priv *priv);
|
||||
void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags);
|
||||
int iwl_init_drv(struct iwl_priv *priv);
|
||||
void iwl_uninit_drv(struct iwl_priv *priv);
|
||||
void iwl_send_bt_config(struct iwl_priv *priv);
|
||||
void iwl_rf_kill_ct_config(struct iwl_priv *priv);
|
||||
int iwl_setup_interface(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
void iwl_teardown_interface(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif,
|
||||
bool mode_change);
|
||||
int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_bss_conf *bss_conf);
|
||||
void iwlagn_chain_noise_reset(struct iwl_priv *priv);
|
||||
int iwlagn_update_beacon(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif);
|
||||
void iwl_tt_handler(struct iwl_priv *priv);
|
||||
void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode);
|
||||
void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue);
|
||||
void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state);
|
||||
void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
|
||||
void iwl_nic_error(struct iwl_op_mode *op_mode);
|
||||
void iwl_cmd_queue_full(struct iwl_op_mode *op_mode);
|
||||
void iwl_nic_config(struct iwl_op_mode *op_mode);
|
||||
int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta, bool set);
|
||||
void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
|
||||
enum ieee80211_rssi_event rssi_event);
|
||||
int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw);
|
||||
int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw);
|
||||
void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop);
|
||||
void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue);
|
||||
void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
|
||||
struct ieee80211_channel_switch *ch_switch);
|
||||
int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
enum ieee80211_sta_state old_state,
|
||||
enum ieee80211_sta_state new_state);
|
||||
int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size);
|
||||
int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req);
|
||||
void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum sta_notify_cmd cmd,
|
||||
struct ieee80211_sta *sta);
|
||||
void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
||||
unsigned int changed_flags,
|
||||
unsigned int *total_flags,
|
||||
u64 multicast);
|
||||
int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params);
|
||||
void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_gtk_rekey_data *data);
|
||||
void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
struct ieee80211_sta *sta,
|
||||
u32 iv32, u16 *phase1key);
|
||||
int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key);
|
||||
void iwlagn_mac_stop(struct ieee80211_hw *hw);
|
||||
void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
|
||||
#endif /* __iwl_agn_h__ */
|
|
@ -63,10 +63,11 @@
|
|||
#include <linux/slab.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-agn-calib.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-agn.h"
|
||||
|
||||
#include "dev.h"
|
||||
#include "calib.h"
|
||||
#include "agn.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* INIT calibrations framework
|
||||
|
@ -832,14 +833,14 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
|
|||
* To be safe, simply mask out any chains that we know
|
||||
* are not on the device.
|
||||
*/
|
||||
active_chains &= priv->hw_params.valid_rx_ant;
|
||||
active_chains &= priv->eeprom_data->valid_rx_ant;
|
||||
|
||||
num_tx_chains = 0;
|
||||
for (i = 0; i < NUM_RX_CHAINS; i++) {
|
||||
/* loops on all the bits of
|
||||
* priv->hw_setting.valid_tx_ant */
|
||||
u8 ant_msk = (1 << i);
|
||||
if (!(priv->hw_params.valid_tx_ant & ant_msk))
|
||||
if (!(priv->eeprom_data->valid_tx_ant & ant_msk))
|
||||
continue;
|
||||
|
||||
num_tx_chains++;
|
||||
|
@ -853,7 +854,7 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
|
|||
* connect the first valid tx chain
|
||||
*/
|
||||
first_chain =
|
||||
find_first_chain(priv->hw_params.valid_tx_ant);
|
||||
find_first_chain(priv->eeprom_data->valid_tx_ant);
|
||||
data->disconn_array[first_chain] = 0;
|
||||
active_chains |= BIT(first_chain);
|
||||
IWL_DEBUG_CALIB(priv,
|
||||
|
@ -863,13 +864,13 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
|
|||
}
|
||||
}
|
||||
|
||||
if (active_chains != priv->hw_params.valid_rx_ant &&
|
||||
if (active_chains != priv->eeprom_data->valid_rx_ant &&
|
||||
active_chains != priv->chain_noise_data.active_chains)
|
||||
IWL_DEBUG_CALIB(priv,
|
||||
"Detected that not all antennas are connected! "
|
||||
"Connected: %#x, valid: %#x.\n",
|
||||
active_chains,
|
||||
priv->hw_params.valid_rx_ant);
|
||||
priv->eeprom_data->valid_rx_ant);
|
||||
|
||||
/* Save for use within RXON, TX, SCAN commands, etc. */
|
||||
data->active_chains = active_chains;
|
||||
|
@ -1054,7 +1055,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
|
|||
priv->cfg->bt_params->advanced_bt_coexist) {
|
||||
/* Disable disconnected antenna algorithm for advanced
|
||||
bt coex, assuming valid antennas are connected */
|
||||
data->active_chains = priv->hw_params.valid_rx_ant;
|
||||
data->active_chains = priv->eeprom_data->valid_rx_ant;
|
||||
for (i = 0; i < NUM_RX_CHAINS; i++)
|
||||
if (!(data->active_chains & (1<<i)))
|
||||
data->disconn_array[i] = 1;
|
||||
|
@ -1083,8 +1084,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
|
|||
IWL_DEBUG_CALIB(priv, "min_average_noise = %d, antenna %d\n",
|
||||
min_average_noise, min_average_noise_antenna_i);
|
||||
|
||||
iwlagn_gain_computation(priv, average_noise,
|
||||
find_first_chain(priv->hw_params.valid_rx_ant));
|
||||
iwlagn_gain_computation(
|
||||
priv, average_noise,
|
||||
find_first_chain(priv->eeprom_data->valid_rx_ant));
|
||||
|
||||
/* Some power changes may have been made during the calibration.
|
||||
* Update and commit the RXON
|
|
@ -62,8 +62,8 @@
|
|||
#ifndef __iwl_calib_h__
|
||||
#define __iwl_calib_h__
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-commands.h"
|
||||
#include "dev.h"
|
||||
#include "commands.h"
|
||||
|
||||
void iwl_chain_noise_calibration(struct iwl_priv *priv);
|
||||
void iwl_sensitivity_calibration(struct iwl_priv *priv);
|
|
@ -61,9 +61,9 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* Please use this file (iwl-commands.h) only for uCode API definitions.
|
||||
* Please use this file (commands.h) only for uCode API definitions.
|
||||
* Please use iwl-xxxx-hw.h for hardware-related definitions.
|
||||
* Please use iwl-dev.h for driver implementation definitions.
|
||||
* Please use dev.h for driver implementation definitions.
|
||||
*/
|
||||
|
||||
#ifndef __iwl_commands_h__
|
||||
|
@ -197,9 +197,6 @@ enum {
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/* iwl_cmd_header flags value */
|
||||
#define IWL_CMD_FAILED_MSK 0x40
|
||||
|
||||
/**
|
||||
* iwlagn rate_n_flags bit fields
|
||||
*
|
|
@ -30,16 +30,12 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-modparams.h"
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
|
||||
/* create and remove of files */
|
||||
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
|
||||
|
@ -307,13 +303,13 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
|
|||
const u8 *ptr;
|
||||
char *buf;
|
||||
u16 eeprom_ver;
|
||||
size_t eeprom_len = priv->cfg->base_params->eeprom_size;
|
||||
size_t eeprom_len = priv->eeprom_blob_size;
|
||||
buf_size = 4 * eeprom_len + 256;
|
||||
|
||||
if (eeprom_len % 16)
|
||||
return -ENODATA;
|
||||
|
||||
ptr = priv->eeprom;
|
||||
ptr = priv->eeprom_blob;
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -322,11 +318,9 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
|
||||
pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
|
||||
"version: 0x%x\n",
|
||||
(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
|
||||
? "OTP" : "EEPROM", eeprom_ver);
|
||||
eeprom_ver = priv->eeprom_data->eeprom_version;
|
||||
pos += scnprintf(buf + pos, buf_size - pos,
|
||||
"NVM version: 0x%x\n", eeprom_ver);
|
||||
for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
|
||||
pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
|
||||
hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
|
||||
|
@ -351,9 +345,6 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
|
|||
char *buf;
|
||||
ssize_t ret;
|
||||
|
||||
if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
|
||||
return -EAGAIN;
|
||||
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
@ -426,8 +417,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
|
|||
test_bit(STATUS_ALIVE, &priv->status));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
|
||||
test_bit(STATUS_READY, &priv->status));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
|
||||
test_bit(STATUS_GEO_CONFIGURED, &priv->status));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
|
||||
test_bit(STATUS_EXIT_PENDING, &priv->status));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
|
||||
|
@ -1341,17 +1330,17 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
|
|||
if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"tx power: (1/2 dB step)\n");
|
||||
if ((priv->hw_params.valid_tx_ant & ANT_A) &&
|
||||
if ((priv->eeprom_data->valid_tx_ant & ANT_A) &&
|
||||
tx->tx_power.ant_a)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_hex, "antenna A:",
|
||||
tx->tx_power.ant_a);
|
||||
if ((priv->hw_params.valid_tx_ant & ANT_B) &&
|
||||
if ((priv->eeprom_data->valid_tx_ant & ANT_B) &&
|
||||
tx->tx_power.ant_b)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_hex, "antenna B:",
|
||||
tx->tx_power.ant_b);
|
||||
if ((priv->hw_params.valid_tx_ant & ANT_C) &&
|
||||
if ((priv->eeprom_data->valid_tx_ant & ANT_C) &&
|
||||
tx->tx_power.ant_c)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_hex, "antenna C:",
|
|
@ -24,8 +24,8 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* Please use this file (iwl-dev.h) for driver implementation definitions.
|
||||
* Please use iwl-commands.h for uCode API definitions.
|
||||
* Please use this file (dev.h) for driver implementation definitions.
|
||||
* Please use commands.h for uCode API definitions.
|
||||
*/
|
||||
|
||||
#ifndef __iwl_dev_h__
|
||||
|
@ -39,17 +39,18 @@
|
|||
#include <linux/mutex.h>
|
||||
|
||||
#include "iwl-fw.h"
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-eeprom-parse.h"
|
||||
#include "iwl-csr.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-led.h"
|
||||
#include "iwl-power.h"
|
||||
#include "iwl-agn-rs.h"
|
||||
#include "iwl-agn-tt.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-op-mode.h"
|
||||
#include "iwl-notif-wait.h"
|
||||
#include "iwl-trans.h"
|
||||
|
||||
#include "led.h"
|
||||
#include "power.h"
|
||||
#include "rs.h"
|
||||
#include "tt.h"
|
||||
|
||||
/* CT-KILL constants */
|
||||
#define CT_KILL_THRESHOLD_LEGACY 110 /* in Celsius */
|
||||
|
@ -87,33 +88,6 @@
|
|||
|
||||
#define IWL_NUM_SCAN_RATES (2)
|
||||
|
||||
/*
|
||||
* One for each channel, holds all channel setup data
|
||||
* Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
|
||||
* with one another!
|
||||
*/
|
||||
struct iwl_channel_info {
|
||||
struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */
|
||||
struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for
|
||||
* HT40 channel */
|
||||
|
||||
u8 channel; /* channel number */
|
||||
u8 flags; /* flags copied from EEPROM */
|
||||
s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
|
||||
s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) limit */
|
||||
s8 min_power; /* always 0 */
|
||||
s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */
|
||||
|
||||
u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */
|
||||
u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */
|
||||
enum ieee80211_band band;
|
||||
|
||||
/* HT40 channel info */
|
||||
s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
|
||||
u8 ht40_flags; /* flags copied from EEPROM */
|
||||
u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
|
||||
};
|
||||
|
||||
/*
|
||||
* Minimum number of queues. MAX_NUM is defined in hw specific files.
|
||||
* Set the minimum to accommodate
|
||||
|
@ -153,29 +127,6 @@ union iwl_ht_rate_supp {
|
|||
};
|
||||
};
|
||||
|
||||
#define CFG_HT_RX_AMPDU_FACTOR_8K (0x0)
|
||||
#define CFG_HT_RX_AMPDU_FACTOR_16K (0x1)
|
||||
#define CFG_HT_RX_AMPDU_FACTOR_32K (0x2)
|
||||
#define CFG_HT_RX_AMPDU_FACTOR_64K (0x3)
|
||||
#define CFG_HT_RX_AMPDU_FACTOR_DEF CFG_HT_RX_AMPDU_FACTOR_64K
|
||||
#define CFG_HT_RX_AMPDU_FACTOR_MAX CFG_HT_RX_AMPDU_FACTOR_64K
|
||||
#define CFG_HT_RX_AMPDU_FACTOR_MIN CFG_HT_RX_AMPDU_FACTOR_8K
|
||||
|
||||
/*
|
||||
* Maximal MPDU density for TX aggregation
|
||||
* 4 - 2us density
|
||||
* 5 - 4us density
|
||||
* 6 - 8us density
|
||||
* 7 - 16us density
|
||||
*/
|
||||
#define CFG_HT_MPDU_DENSITY_2USEC (0x4)
|
||||
#define CFG_HT_MPDU_DENSITY_4USEC (0x5)
|
||||
#define CFG_HT_MPDU_DENSITY_8USEC (0x6)
|
||||
#define CFG_HT_MPDU_DENSITY_16USEC (0x7)
|
||||
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
|
||||
#define CFG_HT_MPDU_DENSITY_MAX CFG_HT_MPDU_DENSITY_16USEC
|
||||
#define CFG_HT_MPDU_DENSITY_MIN (0x1)
|
||||
|
||||
struct iwl_ht_config {
|
||||
bool single_chain_sufficient;
|
||||
enum ieee80211_smps_mode smps; /* current smps mode */
|
||||
|
@ -445,23 +396,6 @@ enum {
|
|||
MEASUREMENT_ACTIVE = (1 << 1),
|
||||
};
|
||||
|
||||
enum iwl_nvm_type {
|
||||
NVM_DEVICE_TYPE_EEPROM = 0,
|
||||
NVM_DEVICE_TYPE_OTP,
|
||||
};
|
||||
|
||||
/*
|
||||
* Two types of OTP memory access modes
|
||||
* IWL_OTP_ACCESS_ABSOLUTE - absolute address mode,
|
||||
* based on physical memory addressing
|
||||
* IWL_OTP_ACCESS_RELATIVE - relative address mode,
|
||||
* based on logical memory addressing
|
||||
*/
|
||||
enum iwl_access_mode {
|
||||
IWL_OTP_ACCESS_ABSOLUTE,
|
||||
IWL_OTP_ACCESS_RELATIVE,
|
||||
};
|
||||
|
||||
/* reply_tx_statistics (for _agn devices) */
|
||||
struct reply_tx_error_statistics {
|
||||
u32 pp_delay;
|
||||
|
@ -632,9 +566,6 @@ enum iwl_scan_type {
|
|||
*
|
||||
* @tx_chains_num: Number of TX chains
|
||||
* @rx_chains_num: Number of RX chains
|
||||
* @valid_tx_ant: usable antennas for TX
|
||||
* @valid_rx_ant: usable antennas for RX
|
||||
* @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX)
|
||||
* @sku: sku read from EEPROM
|
||||
* @ct_kill_threshold: temperature threshold - in hw dependent unit
|
||||
* @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
|
||||
|
@ -645,9 +576,6 @@ enum iwl_scan_type {
|
|||
struct iwl_hw_params {
|
||||
u8 tx_chains_num;
|
||||
u8 rx_chains_num;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
u8 ht40_channel;
|
||||
bool use_rts_for_aggregation;
|
||||
u16 sku;
|
||||
u32 ct_kill_threshold;
|
||||
|
@ -664,9 +592,6 @@ struct iwl_lib_ops {
|
|||
/* device specific configuration */
|
||||
void (*nic_config)(struct iwl_priv *priv);
|
||||
|
||||
/* eeprom operations (as defined in iwl-eeprom.h) */
|
||||
struct iwl_eeprom_ops eeprom_ops;
|
||||
|
||||
/* temperature */
|
||||
void (*temperature)(struct iwl_priv *priv);
|
||||
};
|
||||
|
@ -735,8 +660,6 @@ struct iwl_priv {
|
|||
|
||||
/* ieee device used by generic ieee processing code */
|
||||
struct ieee80211_hw *hw;
|
||||
struct ieee80211_channel *ieee_channels;
|
||||
struct ieee80211_rate *ieee_rates;
|
||||
|
||||
struct list_head calib_results;
|
||||
|
||||
|
@ -755,8 +678,6 @@ struct iwl_priv {
|
|||
|
||||
struct iwl_notif_wait_data notif_wait;
|
||||
|
||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||
|
||||
/* spectrum measurement report caching */
|
||||
struct iwl_spectrum_notification measure_report;
|
||||
u8 measurement_status;
|
||||
|
@ -787,11 +708,6 @@ struct iwl_priv {
|
|||
bool ucode_loaded;
|
||||
bool init_ucode_run; /* Don't run init uCode again */
|
||||
|
||||
/* we allocate array of iwl_channel_info for NIC's valid channels.
|
||||
* Access via channel # using indirect index array */
|
||||
struct iwl_channel_info *channel_info; /* channel info array */
|
||||
u8 channel_count; /* # of channels */
|
||||
|
||||
u8 plcp_delta_threshold;
|
||||
|
||||
/* thermal calibration */
|
||||
|
@ -846,6 +762,7 @@ struct iwl_priv {
|
|||
struct iwl_station_entry stations[IWLAGN_STATION_COUNT];
|
||||
unsigned long ucode_key_table;
|
||||
struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT];
|
||||
atomic_t num_aux_in_flight;
|
||||
|
||||
u8 mac80211_registered;
|
||||
|
||||
|
@ -950,10 +867,8 @@ struct iwl_priv {
|
|||
|
||||
struct delayed_work scan_check;
|
||||
|
||||
/* TX Power */
|
||||
/* TX Power settings */
|
||||
s8 tx_power_user_lmt;
|
||||
s8 tx_power_device_lmt;
|
||||
s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */
|
||||
s8 tx_power_next;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
|
@ -964,9 +879,10 @@ struct iwl_priv {
|
|||
void *wowlan_sram;
|
||||
#endif /* CONFIG_IWLWIFI_DEBUGFS */
|
||||
|
||||
/* eeprom -- this is in the card's little endian byte order */
|
||||
u8 *eeprom;
|
||||
enum iwl_nvm_type nvm_device_type;
|
||||
struct iwl_eeprom_data *eeprom_data;
|
||||
/* eeprom blob for debugfs/testmode */
|
||||
u8 *eeprom_blob;
|
||||
size_t eeprom_blob_size;
|
||||
|
||||
struct work_struct txpower_work;
|
||||
u32 calib_disabled;
|
||||
|
@ -1001,8 +917,6 @@ struct iwl_priv {
|
|||
enum iwl_ucode_type cur_ucode;
|
||||
}; /*iwl_priv */
|
||||
|
||||
extern struct kmem_cache *iwl_tx_cmd_pool;
|
||||
|
||||
static inline struct iwl_rxon_context *
|
||||
iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
|
||||
{
|
||||
|
@ -1036,36 +950,4 @@ static inline int iwl_is_any_associated(struct iwl_priv *priv)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
|
||||
{
|
||||
if (ch_info == NULL)
|
||||
return 0;
|
||||
return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
|
||||
{
|
||||
return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
|
||||
{
|
||||
return ch_info->band == IEEE80211_BAND_5GHZ;
|
||||
}
|
||||
|
||||
static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
|
||||
{
|
||||
return ch_info->band == IEEE80211_BAND_2GHZ;
|
||||
}
|
||||
|
||||
static inline int is_channel_passive(const struct iwl_channel_info *ch)
|
||||
{
|
||||
return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline int is_channel_ibss(const struct iwl_channel_info *ch)
|
||||
{
|
||||
return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
|
||||
}
|
||||
|
||||
#endif /* __iwl_dev_h__ */
|
|
@ -27,11 +27,14 @@
|
|||
/*
|
||||
* DVM device-specific data & functions
|
||||
*/
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-commands.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-eeprom-parse.h"
|
||||
|
||||
#include "agn.h"
|
||||
#include "dev.h"
|
||||
#include "commands.h"
|
||||
|
||||
|
||||
/*
|
||||
* 1000 series
|
||||
|
@ -58,11 +61,6 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
|
|||
/* NIC configuration for 1000 series */
|
||||
static void iwl1000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
/* set CSR_HW_CONFIG_REG for uCode use */
|
||||
iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
|
||||
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
|
||||
|
||||
/* Setting digital SVR for 1000 card to 1.32V */
|
||||
/* locking is acquired in iwl_set_bits_mask_prph() function */
|
||||
iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG,
|
||||
|
@ -170,16 +168,6 @@ static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
|
|||
|
||||
static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
if (priv->cfg->rx_with_siso_diversity)
|
||||
priv->hw_params.rx_chains_num = 1;
|
||||
else
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl1000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
|
@ -189,17 +177,6 @@ static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
|
|||
struct iwl_lib_ops iwl1000_lib = {
|
||||
.set_hw_params = iwl1000_hw_set_hw_params,
|
||||
.nic_config = iwl1000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
|
@ -219,8 +196,6 @@ static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
|
|||
/* NIC configuration for 2000 series */
|
||||
static void iwl2000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_rf_config(priv);
|
||||
|
||||
iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
|
||||
}
|
||||
|
@ -251,16 +226,6 @@ static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
|
|||
|
||||
static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
if (priv->cfg->rx_with_siso_diversity)
|
||||
priv->hw_params.rx_chains_num = 1;
|
||||
else
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl2000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
|
@ -270,36 +235,12 @@ static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
|
|||
struct iwl_lib_ops iwl2000_lib = {
|
||||
.set_hw_params = iwl2000_hw_set_hw_params,
|
||||
.nic_config = iwl2000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
struct iwl_lib_ops iwl2030_lib = {
|
||||
.set_hw_params = iwl2000_hw_set_hw_params,
|
||||
.nic_config = iwl2000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
|
@ -311,8 +252,6 @@ struct iwl_lib_ops iwl2030_lib = {
|
|||
/* NIC configuration for 5000 series */
|
||||
static void iwl5000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_rf_config(priv);
|
||||
|
||||
/* W/A : NIC is stuck in a reset state after Early PCIe power off
|
||||
* (PCIe power is lost before PERST# is asserted),
|
||||
* causing ME FW to lose ownership and not being able to obtain it back.
|
||||
|
@ -376,11 +315,9 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
|
|||
static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
|
||||
{
|
||||
u16 temperature, voltage;
|
||||
__le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv,
|
||||
EEPROM_KELVIN_TEMPERATURE);
|
||||
|
||||
temperature = le16_to_cpu(temp_calib[0]);
|
||||
voltage = le16_to_cpu(temp_calib[1]);
|
||||
temperature = le16_to_cpu(priv->eeprom_data->kelvin_temperature);
|
||||
voltage = le16_to_cpu(priv->eeprom_data->kelvin_voltage);
|
||||
|
||||
/* offset = temp - volt / coeff */
|
||||
return (s32)(temperature -
|
||||
|
@ -404,14 +341,6 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
|
|||
|
||||
static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl5000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
|
@ -420,14 +349,6 @@ static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
|
|||
|
||||
static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl5150_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
|
@ -455,7 +376,6 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
|
|||
*/
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
struct iwl5000_channel_switch_cmd cmd;
|
||||
const struct iwl_channel_info *ch_info;
|
||||
u32 switch_time_in_usec, ucode_switch_time;
|
||||
u16 ch;
|
||||
u32 tsf_low;
|
||||
|
@ -505,14 +425,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
|
|||
}
|
||||
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
|
||||
cmd.switch_time);
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, ch);
|
||||
if (ch_info)
|
||||
cmd.expect_beacon = is_channel_radar(ch_info);
|
||||
else {
|
||||
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
return -EFAULT;
|
||||
}
|
||||
cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
|
||||
|
||||
return iwl_dvm_send_cmd(priv, &hcmd);
|
||||
}
|
||||
|
@ -521,17 +434,6 @@ struct iwl_lib_ops iwl5000_lib = {
|
|||
.set_hw_params = iwl5000_hw_set_hw_params,
|
||||
.set_channel_switch = iwl5000_hw_channel_switch,
|
||||
.nic_config = iwl5000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
|
@ -539,17 +441,6 @@ struct iwl_lib_ops iwl5150_lib = {
|
|||
.set_hw_params = iwl5150_hw_set_hw_params,
|
||||
.set_channel_switch = iwl5000_hw_channel_switch,
|
||||
.nic_config = iwl5000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
},
|
||||
.temperature = iwl5150_temperature,
|
||||
};
|
||||
|
||||
|
@ -570,8 +461,6 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
|
|||
/* NIC configuration for 6000 series */
|
||||
static void iwl6000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_rf_config(priv);
|
||||
|
||||
switch (priv->cfg->device_family) {
|
||||
case IWL_DEVICE_FAMILY_6005:
|
||||
case IWL_DEVICE_FAMILY_6030:
|
||||
|
@ -584,13 +473,13 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
|
|||
break;
|
||||
case IWL_DEVICE_FAMILY_6050:
|
||||
/* Indicate calibration version to uCode. */
|
||||
if (iwl_eeprom_calib_version(priv) >= 6)
|
||||
if (priv->eeprom_data->calib_version >= 6)
|
||||
iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
|
||||
break;
|
||||
case IWL_DEVICE_FAMILY_6150:
|
||||
/* Indicate calibration version to uCode. */
|
||||
if (iwl_eeprom_calib_version(priv) >= 6)
|
||||
if (priv->eeprom_data->calib_version >= 6)
|
||||
iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
|
||||
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
|
||||
iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
|
||||
|
@ -627,17 +516,6 @@ static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
|
|||
|
||||
static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_tx_ant);
|
||||
if (priv->cfg->rx_with_siso_diversity)
|
||||
priv->hw_params.rx_chains_num = 1;
|
||||
else
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->hw_params.valid_rx_ant);
|
||||
|
||||
iwl6000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
|
@ -654,7 +532,6 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
|
|||
*/
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
struct iwl6000_channel_switch_cmd cmd;
|
||||
const struct iwl_channel_info *ch_info;
|
||||
u32 switch_time_in_usec, ucode_switch_time;
|
||||
u16 ch;
|
||||
u32 tsf_low;
|
||||
|
@ -704,14 +581,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
|
|||
}
|
||||
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
|
||||
cmd.switch_time);
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, ch);
|
||||
if (ch_info)
|
||||
cmd.expect_beacon = is_channel_radar(ch_info);
|
||||
else {
|
||||
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
return -EFAULT;
|
||||
}
|
||||
cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
|
||||
|
||||
return iwl_dvm_send_cmd(priv, &hcmd);
|
||||
}
|
||||
|
@ -720,18 +590,6 @@ struct iwl_lib_ops iwl6000_lib = {
|
|||
.set_hw_params = iwl6000_hw_set_hw_params,
|
||||
.set_channel_switch = iwl6000_hw_channel_switch,
|
||||
.nic_config = iwl6000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
||||
|
||||
|
@ -739,17 +597,5 @@ struct iwl_lib_ops iwl6030_lib = {
|
|||
.set_hw_params = iwl6000_hw_set_hw_params,
|
||||
.set_channel_switch = iwl6000_hw_channel_switch,
|
||||
.nic_config = iwl6000_nic_config,
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
},
|
||||
.temperature = iwlagn_temperature,
|
||||
};
|
|
@ -34,12 +34,11 @@
|
|||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-modparams.h"
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
|
||||
/* Throughput OFF time(ms) ON time (ms)
|
||||
* >300 25 25
|
|
@ -33,13 +33,14 @@
|
|||
#include <linux/sched.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-modparams.h"
|
||||
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
|
||||
int iwlagn_hw_valid_rtc_data_addr(u32 addr)
|
||||
{
|
||||
return (addr >= IWLAGN_RTC_DATA_LOWER_BOUND) &&
|
||||
|
@ -58,8 +59,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
|
|||
/* half dBm need to multiply */
|
||||
tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
|
||||
|
||||
if (priv->tx_power_lmt_in_half_dbm &&
|
||||
priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
|
||||
if (tx_power_cmd.global_lmt > priv->eeprom_data->max_tx_pwr_half_dbm) {
|
||||
/*
|
||||
* For the newer devices which using enhanced/extend tx power
|
||||
* table in EEPROM, the format is in half dBm. driver need to
|
||||
|
@ -71,7 +71,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
|
|||
* "tx_power_user_lmt" is higher than EEPROM value (in
|
||||
* half-dBm format), lower the tx power based on EEPROM
|
||||
*/
|
||||
tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
|
||||
tx_power_cmd.global_lmt =
|
||||
priv->eeprom_data->max_tx_pwr_half_dbm;
|
||||
}
|
||||
tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
|
||||
tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
|
||||
|
@ -617,6 +618,11 @@ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
|
|||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
int ave_rssi;
|
||||
|
||||
if (!ctx->vif || (ctx->vif->type != NL80211_IFTYPE_STATION)) {
|
||||
IWL_DEBUG_INFO(priv, "BSS ctx not active or not in sta mode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ave_rssi = ieee80211_ave_rssi(ctx->vif);
|
||||
if (!ave_rssi) {
|
||||
/* no rssi data, no changes to reduce tx power */
|
||||
|
@ -818,7 +824,7 @@ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
if (priv->chain_noise_data.active_chains)
|
||||
active_chains = priv->chain_noise_data.active_chains;
|
||||
else
|
||||
active_chains = priv->hw_params.valid_rx_ant;
|
||||
active_chains = priv->eeprom_data->valid_rx_ant;
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->advanced_bt_coexist &&
|
|
@ -38,19 +38,20 @@
|
|||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn-calib.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-op-mode.h"
|
||||
#include "iwl-modparams.h"
|
||||
|
||||
#include "dev.h"
|
||||
#include "calib.h"
|
||||
#include "agn.h"
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mac80211 entry point functions
|
||||
|
@ -154,6 +155,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
|
|||
IEEE80211_HW_SCAN_WHILE_IDLE;
|
||||
|
||||
hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
|
||||
hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
|
||||
|
||||
/*
|
||||
* Including the following line will crash some AP's. This
|
||||
|
@ -237,12 +239,12 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
|
|||
|
||||
hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
|
||||
|
||||
if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
|
||||
if (priv->eeprom_data->bands[IEEE80211_BAND_2GHZ].n_channels)
|
||||
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
|
||||
&priv->bands[IEEE80211_BAND_2GHZ];
|
||||
if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
|
||||
&priv->eeprom_data->bands[IEEE80211_BAND_2GHZ];
|
||||
if (priv->eeprom_data->bands[IEEE80211_BAND_5GHZ].n_channels)
|
||||
priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
|
||||
&priv->bands[IEEE80211_BAND_5GHZ];
|
||||
&priv->eeprom_data->bands[IEEE80211_BAND_5GHZ];
|
||||
|
||||
hw->wiphy->hw_version = priv->trans->hw_id;
|
||||
|
||||
|
@ -341,7 +343,7 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void iwlagn_mac_stop(struct ieee80211_hw *hw)
|
||||
static void iwlagn_mac_stop(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
|
@ -369,9 +371,9 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw)
|
|||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
}
|
||||
|
||||
void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_gtk_rekey_data *data)
|
||||
static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_gtk_rekey_data *data)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
|
@ -397,7 +399,8 @@ void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
|
|||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
|
||||
struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
|
@ -420,8 +423,6 @@ int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
if (ret)
|
||||
goto error;
|
||||
|
||||
device_set_wakeup_enable(priv->trans->dev, true);
|
||||
|
||||
iwl_trans_wowlan_suspend(priv->trans);
|
||||
|
||||
goto out;
|
||||
|
@ -488,8 +489,6 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
|
|||
|
||||
priv->wowlan = false;
|
||||
|
||||
device_set_wakeup_enable(priv->trans->dev, false);
|
||||
|
||||
iwlagn_prepare_restart(priv);
|
||||
|
||||
memset((void *)&ctx->active, 0, sizeof(ctx->active));
|
||||
|
@ -504,9 +503,15 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void iwlagn_mac_set_wakeup(struct ieee80211_hw *hw, bool enabled)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
device_set_wakeup_enable(priv->trans->dev, enabled);
|
||||
}
|
||||
#endif
|
||||
|
||||
void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
|
@ -517,21 +522,21 @@ void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
struct ieee80211_sta *sta,
|
||||
u32 iv32, u16 *phase1key)
|
||||
static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
struct ieee80211_sta *sta,
|
||||
u32 iv32, u16 *phase1key)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
|
||||
}
|
||||
|
||||
int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
|
||||
|
@ -631,11 +636,11 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
int ret = -EINVAL;
|
||||
|
@ -662,7 +667,7 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
|||
ret = iwl_sta_rx_agg_stop(priv, sta, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
if (!priv->trans->ops->tx_agg_setup)
|
||||
if (!priv->trans->ops->txq_enable)
|
||||
break;
|
||||
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
|
||||
break;
|
||||
|
@ -757,11 +762,11 @@ static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
enum ieee80211_sta_state old_state,
|
||||
enum ieee80211_sta_state new_state)
|
||||
static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
enum ieee80211_sta_state old_state,
|
||||
enum ieee80211_sta_state new_state)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
|
||||
|
@ -840,11 +845,10 @@ int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
|
|||
return ret;
|
||||
}
|
||||
|
||||
void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
|
||||
struct ieee80211_channel_switch *ch_switch)
|
||||
static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
|
||||
struct ieee80211_channel_switch *ch_switch)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
const struct iwl_channel_info *ch_info;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
struct ieee80211_channel *channel = ch_switch->channel;
|
||||
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
|
||||
|
@ -881,12 +885,6 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
|
|||
if (le16_to_cpu(ctx->active.channel) == ch)
|
||||
goto out;
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, channel->band, ch);
|
||||
if (!is_channel_valid(ch_info)) {
|
||||
IWL_DEBUG_MAC80211(priv, "invalid channel\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
priv->current_ht_config.smps = conf->smps_mode;
|
||||
|
||||
/* Configure HT40 channels */
|
||||
|
@ -935,10 +933,10 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
|
|||
ieee80211_chswitch_done(ctx->vif, is_success);
|
||||
}
|
||||
|
||||
void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
||||
unsigned int changed_flags,
|
||||
unsigned int *total_flags,
|
||||
u64 multicast)
|
||||
static void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
||||
unsigned int changed_flags,
|
||||
unsigned int *total_flags,
|
||||
u64 multicast)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
__le32 filter_or = 0, filter_nand = 0;
|
||||
|
@ -985,7 +983,7 @@ void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
|||
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
|
||||
}
|
||||
|
||||
void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
|
@ -1112,7 +1110,7 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
|
|||
return err;
|
||||
}
|
||||
|
||||
int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
|
||||
static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
|
@ -1129,8 +1127,8 @@ int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
|
||||
enum ieee80211_rssi_event rssi_event)
|
||||
static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
|
||||
enum ieee80211_rssi_event rssi_event)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
|
@ -1154,8 +1152,8 @@ void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
|
|||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
}
|
||||
|
||||
int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta, bool set)
|
||||
static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta, bool set)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
|
@ -1164,9 +1162,9 @@ int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
|
||||
|
@ -1208,7 +1206,7 @@ int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
|
||||
static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
|
@ -1224,7 +1222,8 @@ static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
return iwlagn_commit_rxon(priv, ctx);
|
||||
}
|
||||
|
||||
int iwl_setup_interface(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
||||
static int iwl_setup_interface(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
struct ieee80211_vif *vif = ctx->vif;
|
||||
int err, ac;
|
||||
|
@ -1344,9 +1343,9 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
|
|||
return err;
|
||||
}
|
||||
|
||||
void iwl_teardown_interface(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif,
|
||||
bool mode_change)
|
||||
static void iwl_teardown_interface(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif,
|
||||
bool mode_change)
|
||||
{
|
||||
struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
|
||||
|
||||
|
@ -1487,9 +1486,9 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
|
|||
return err;
|
||||
}
|
||||
|
||||
int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
int ret;
|
||||
|
@ -1544,10 +1543,10 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
|
|||
iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
|
||||
}
|
||||
|
||||
void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum sta_notify_cmd cmd,
|
||||
struct ieee80211_sta *sta)
|
||||
static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum sta_notify_cmd cmd,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
|
||||
|
@ -1584,6 +1583,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
|
|||
#ifdef CONFIG_PM_SLEEP
|
||||
.suspend = iwlagn_mac_suspend,
|
||||
.resume = iwlagn_mac_resume,
|
||||
.set_wakeup = iwlagn_mac_set_wakeup,
|
||||
#endif
|
||||
.add_interface = iwlagn_mac_add_interface,
|
||||
.remove_interface = iwlagn_mac_remove_interface,
|
|
@ -44,16 +44,18 @@
|
|||
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-eeprom-read.h"
|
||||
#include "iwl-eeprom-parse.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn-calib.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-op-mode.h"
|
||||
#include "iwl-drv.h"
|
||||
#include "iwl-modparams.h"
|
||||
|
||||
#include "dev.h"
|
||||
#include "calib.h"
|
||||
#include "agn.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* module boiler plate
|
||||
|
@ -78,7 +80,8 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
|||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("iwlagn");
|
||||
|
||||
static const struct iwl_op_mode_ops iwl_dvm_ops;
|
||||
|
||||
void iwl_update_chain_flags(struct iwl_priv *priv)
|
||||
{
|
||||
|
@ -180,7 +183,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
|
|||
rate = info->control.rates[0].idx;
|
||||
|
||||
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
|
||||
priv->hw_params.valid_tx_ant);
|
||||
priv->eeprom_data->valid_tx_ant);
|
||||
rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
|
||||
|
||||
/* In mac80211, rates for 5 GHz start at 0 */
|
||||
|
@ -578,7 +581,7 @@ static const u8 iwlagn_pan_ac_to_queue[] = {
|
|||
7, 6, 5, 4,
|
||||
};
|
||||
|
||||
void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
||||
static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -645,7 +648,7 @@ void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
|
|||
BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
|
||||
}
|
||||
|
||||
void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
||||
static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_ct_kill_config cmd;
|
||||
struct iwl_ct_kill_throttling_config adv_cmd;
|
||||
|
@ -726,7 +729,7 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
|
|||
}
|
||||
}
|
||||
|
||||
void iwl_send_bt_config(struct iwl_priv *priv)
|
||||
static void iwl_send_bt_config(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_bt_cmd bt_cmd = {
|
||||
.lead_time = BT_LEAD_TIME_DEF,
|
||||
|
@ -814,7 +817,7 @@ int iwl_alive_start(struct iwl_priv *priv)
|
|||
ieee80211_wake_queues(priv->hw);
|
||||
|
||||
/* Configure Tx antenna selection based on H/W config */
|
||||
iwlagn_send_tx_ant_config(priv, priv->hw_params.valid_tx_ant);
|
||||
iwlagn_send_tx_ant_config(priv, priv->eeprom_data->valid_tx_ant);
|
||||
|
||||
if (iwl_is_associated_ctx(ctx) && !priv->wowlan) {
|
||||
struct iwl_rxon_cmd *active_rxon =
|
||||
|
@ -932,11 +935,12 @@ void iwl_down(struct iwl_priv *priv)
|
|||
priv->ucode_loaded = false;
|
||||
iwl_trans_stop_device(priv->trans);
|
||||
|
||||
/* Set num_aux_in_flight must be done after the transport is stopped */
|
||||
atomic_set(&priv->num_aux_in_flight, 0);
|
||||
|
||||
/* Clear out all status bits but a few that are stable across reset */
|
||||
priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
|
||||
STATUS_RF_KILL_HW |
|
||||
test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
|
||||
STATUS_GEO_CONFIGURED |
|
||||
test_bit(STATUS_FW_ERROR, &priv->status) <<
|
||||
STATUS_FW_ERROR |
|
||||
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
|
||||
|
@ -1078,7 +1082,7 @@ static void iwlagn_disable_roc_work(struct work_struct *work)
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
void iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
{
|
||||
priv->workqueue = create_singlethread_workqueue(DRV_NAME);
|
||||
|
||||
|
@ -1123,224 +1127,14 @@ void iwl_cancel_deferred_work(struct iwl_priv *priv)
|
|||
del_timer_sync(&priv->ucode_trace);
|
||||
}
|
||||
|
||||
static void iwl_init_hw_rates(struct ieee80211_rate *rates)
|
||||
static int iwl_init_drv(struct iwl_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
|
||||
rates[i].bitrate = iwl_rates[i].ieee * 5;
|
||||
rates[i].hw_value = i; /* Rate scaling will work on indexes */
|
||||
rates[i].hw_value_short = i;
|
||||
rates[i].flags = 0;
|
||||
if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
|
||||
/*
|
||||
* If CCK != 1M then set short preamble rate flag.
|
||||
*/
|
||||
rates[i].flags |=
|
||||
(iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
|
||||
0 : IEEE80211_RATE_SHORT_PREAMBLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
|
||||
#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
|
||||
static void iwl_init_ht_hw_capab(const struct iwl_priv *priv,
|
||||
struct ieee80211_sta_ht_cap *ht_info,
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
u16 max_bit_rate = 0;
|
||||
u8 rx_chains_num = priv->hw_params.rx_chains_num;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
|
||||
ht_info->cap = 0;
|
||||
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
|
||||
|
||||
ht_info->ht_supported = true;
|
||||
|
||||
if (priv->cfg->ht_params &&
|
||||
priv->cfg->ht_params->ht_greenfield_support)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
||||
max_bit_rate = MAX_BIT_RATE_20_MHZ;
|
||||
if (priv->hw_params.ht40_channel & BIT(band)) {
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
|
||||
ht_info->mcs.rx_mask[4] = 0x01;
|
||||
max_bit_rate = MAX_BIT_RATE_40_MHZ;
|
||||
}
|
||||
|
||||
if (iwlwifi_mod_params.amsdu_size_8K)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
|
||||
|
||||
ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
|
||||
ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
|
||||
|
||||
ht_info->mcs.rx_mask[0] = 0xFF;
|
||||
if (rx_chains_num >= 2)
|
||||
ht_info->mcs.rx_mask[1] = 0xFF;
|
||||
if (rx_chains_num >= 3)
|
||||
ht_info->mcs.rx_mask[2] = 0xFF;
|
||||
|
||||
/* Highest supported Rx data rate */
|
||||
max_bit_rate *= rx_chains_num;
|
||||
WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
|
||||
ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
|
||||
|
||||
/* Tx MCS capabilities */
|
||||
ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
|
||||
if (tx_chains_num != rx_chains_num) {
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
|
||||
ht_info->mcs.tx_params |= ((tx_chains_num - 1) <<
|
||||
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
|
||||
*/
|
||||
static int iwl_init_geos(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_channel_info *ch;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *channels;
|
||||
struct ieee80211_channel *geo_ch;
|
||||
struct ieee80211_rate *rates;
|
||||
int i = 0;
|
||||
s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN;
|
||||
|
||||
if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
|
||||
priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
|
||||
IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n");
|
||||
set_bit(STATUS_GEO_CONFIGURED, &priv->status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
channels = kcalloc(priv->channel_count,
|
||||
sizeof(struct ieee80211_channel), GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate),
|
||||
GFP_KERNEL);
|
||||
if (!rates) {
|
||||
kfree(channels);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* 5.2GHz channels start after the 2.4GHz channels */
|
||||
sband = &priv->bands[IEEE80211_BAND_5GHZ];
|
||||
sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
|
||||
/* just OFDM */
|
||||
sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
|
||||
sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
|
||||
|
||||
if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
|
||||
iwl_init_ht_hw_capab(priv, &sband->ht_cap,
|
||||
IEEE80211_BAND_5GHZ);
|
||||
|
||||
sband = &priv->bands[IEEE80211_BAND_2GHZ];
|
||||
sband->channels = channels;
|
||||
/* OFDM & CCK */
|
||||
sband->bitrates = rates;
|
||||
sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
|
||||
|
||||
if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
|
||||
iwl_init_ht_hw_capab(priv, &sband->ht_cap,
|
||||
IEEE80211_BAND_2GHZ);
|
||||
|
||||
priv->ieee_channels = channels;
|
||||
priv->ieee_rates = rates;
|
||||
|
||||
for (i = 0; i < priv->channel_count; i++) {
|
||||
ch = &priv->channel_info[i];
|
||||
|
||||
/* FIXME: might be removed if scan is OK */
|
||||
if (!is_channel_valid(ch))
|
||||
continue;
|
||||
|
||||
sband = &priv->bands[ch->band];
|
||||
|
||||
geo_ch = &sband->channels[sband->n_channels++];
|
||||
|
||||
geo_ch->center_freq =
|
||||
ieee80211_channel_to_frequency(ch->channel, ch->band);
|
||||
geo_ch->max_power = ch->max_power_avg;
|
||||
geo_ch->max_antenna_gain = 0xff;
|
||||
geo_ch->hw_value = ch->channel;
|
||||
|
||||
if (is_channel_valid(ch)) {
|
||||
if (!(ch->flags & EEPROM_CHANNEL_IBSS))
|
||||
geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
|
||||
|
||||
if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
|
||||
geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
|
||||
|
||||
if (ch->flags & EEPROM_CHANNEL_RADAR)
|
||||
geo_ch->flags |= IEEE80211_CHAN_RADAR;
|
||||
|
||||
geo_ch->flags |= ch->ht40_extension_channel;
|
||||
|
||||
if (ch->max_power_avg > max_tx_power)
|
||||
max_tx_power = ch->max_power_avg;
|
||||
} else {
|
||||
geo_ch->flags |= IEEE80211_CHAN_DISABLED;
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n",
|
||||
ch->channel, geo_ch->center_freq,
|
||||
is_channel_a_band(ch) ? "5.2" : "2.4",
|
||||
geo_ch->flags & IEEE80211_CHAN_DISABLED ?
|
||||
"restricted" : "valid",
|
||||
geo_ch->flags);
|
||||
}
|
||||
|
||||
priv->tx_power_device_lmt = max_tx_power;
|
||||
priv->tx_power_user_lmt = max_tx_power;
|
||||
priv->tx_power_next = max_tx_power;
|
||||
|
||||
if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
|
||||
priv->hw_params.sku & EEPROM_SKU_CAP_BAND_52GHZ) {
|
||||
IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
|
||||
"Please send your %s to maintainer.\n",
|
||||
priv->trans->hw_id_str);
|
||||
priv->hw_params.sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
|
||||
}
|
||||
|
||||
if (iwlwifi_mod_params.disable_5ghz)
|
||||
priv->bands[IEEE80211_BAND_5GHZ].n_channels = 0;
|
||||
|
||||
IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
|
||||
priv->bands[IEEE80211_BAND_2GHZ].n_channels,
|
||||
priv->bands[IEEE80211_BAND_5GHZ].n_channels);
|
||||
|
||||
set_bit(STATUS_GEO_CONFIGURED, &priv->status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* iwl_free_geos - undo allocations in iwl_init_geos
|
||||
*/
|
||||
static void iwl_free_geos(struct iwl_priv *priv)
|
||||
{
|
||||
kfree(priv->ieee_channels);
|
||||
kfree(priv->ieee_rates);
|
||||
clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
|
||||
}
|
||||
|
||||
int iwl_init_drv(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
spin_lock_init(&priv->sta_lock);
|
||||
|
||||
mutex_init(&priv->mutex);
|
||||
|
||||
INIT_LIST_HEAD(&priv->calib_results);
|
||||
|
||||
priv->ieee_channels = NULL;
|
||||
priv->ieee_rates = NULL;
|
||||
priv->band = IEEE80211_BAND_2GHZ;
|
||||
|
||||
priv->plcp_delta_threshold =
|
||||
|
@ -1371,31 +1165,11 @@ int iwl_init_drv(struct iwl_priv *priv)
|
|||
priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
|
||||
}
|
||||
|
||||
ret = iwl_init_channel_map(priv);
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = iwl_init_geos(priv);
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "initializing geos failed: %d\n", ret);
|
||||
goto err_free_channel_map;
|
||||
}
|
||||
iwl_init_hw_rates(priv->ieee_rates);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_channel_map:
|
||||
iwl_free_channel_map(priv);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwl_uninit_drv(struct iwl_priv *priv)
|
||||
static void iwl_uninit_drv(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_free_geos(priv);
|
||||
iwl_free_channel_map(priv);
|
||||
kfree(priv->scan_cmd);
|
||||
kfree(priv->beacon_cmd);
|
||||
kfree(rcu_dereference_raw(priv->noa_data));
|
||||
|
@ -1405,7 +1179,7 @@ void iwl_uninit_drv(struct iwl_priv *priv)
|
|||
#endif
|
||||
}
|
||||
|
||||
void iwl_set_hw_params(struct iwl_priv *priv)
|
||||
static void iwl_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
if (priv->cfg->ht_params)
|
||||
priv->hw_params.use_rts_for_aggregation =
|
||||
|
@ -1421,7 +1195,7 @@ void iwl_set_hw_params(struct iwl_priv *priv)
|
|||
|
||||
|
||||
/* show what optional capabilities we have */
|
||||
void iwl_option_config(struct iwl_priv *priv)
|
||||
static void iwl_option_config(struct iwl_priv *priv)
|
||||
{
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG enabled\n");
|
||||
|
@ -1454,6 +1228,42 @@ void iwl_option_config(struct iwl_priv *priv)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
u16 radio_cfg;
|
||||
|
||||
priv->hw_params.sku = priv->eeprom_data->sku;
|
||||
|
||||
if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE &&
|
||||
!priv->cfg->ht_params) {
|
||||
IWL_ERR(priv, "Invalid 11n configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!priv->hw_params.sku) {
|
||||
IWL_ERR(priv, "Invalid device sku\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IWL_INFO(priv, "Device SKU: 0x%X\n", priv->hw_params.sku);
|
||||
|
||||
radio_cfg = priv->eeprom_data->radio_cfg;
|
||||
|
||||
priv->hw_params.tx_chains_num =
|
||||
num_of_ant(priv->eeprom_data->valid_tx_ant);
|
||||
if (priv->cfg->rx_with_siso_diversity)
|
||||
priv->hw_params.rx_chains_num = 1;
|
||||
else
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->eeprom_data->valid_rx_ant);
|
||||
|
||||
IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n",
|
||||
priv->eeprom_data->valid_tx_ant,
|
||||
priv->eeprom_data->valid_rx_ant);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
||||
const struct iwl_cfg *cfg,
|
||||
const struct iwl_fw *fw)
|
||||
|
@ -1539,7 +1349,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
|||
trans_cfg.queue_watchdog_timeout =
|
||||
priv->cfg->base_params->wd_timeout;
|
||||
else
|
||||
trans_cfg.queue_watchdog_timeout = IWL_WATCHHDOG_DISABLED;
|
||||
trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED;
|
||||
trans_cfg.command_names = iwl_dvm_cmd_strings;
|
||||
|
||||
ucode_flags = fw->ucode_capa.flags;
|
||||
|
@ -1599,25 +1409,33 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
|||
goto out_free_hw;
|
||||
|
||||
/* Read the EEPROM */
|
||||
if (iwl_eeprom_init(priv, priv->trans->hw_rev)) {
|
||||
if (iwl_read_eeprom(priv->trans, &priv->eeprom_blob,
|
||||
&priv->eeprom_blob_size)) {
|
||||
IWL_ERR(priv, "Unable to init EEPROM\n");
|
||||
goto out_free_hw;
|
||||
}
|
||||
|
||||
/* Reset chip to save power until we load uCode during "up". */
|
||||
iwl_trans_stop_hw(priv->trans, false);
|
||||
|
||||
if (iwl_eeprom_check_version(priv))
|
||||
priv->eeprom_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg,
|
||||
priv->eeprom_blob,
|
||||
priv->eeprom_blob_size);
|
||||
if (!priv->eeprom_data)
|
||||
goto out_free_eeprom_blob;
|
||||
|
||||
if (iwl_eeprom_check_version(priv->eeprom_data, priv->trans))
|
||||
goto out_free_eeprom;
|
||||
|
||||
if (iwl_eeprom_init_hw_params(priv))
|
||||
goto out_free_eeprom;
|
||||
|
||||
/* extract MAC Address */
|
||||
iwl_eeprom_get_mac(priv, priv->addresses[0].addr);
|
||||
memcpy(priv->addresses[0].addr, priv->eeprom_data->hw_addr, ETH_ALEN);
|
||||
IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr);
|
||||
priv->hw->wiphy->addresses = priv->addresses;
|
||||
priv->hw->wiphy->n_addresses = 1;
|
||||
num_mac = iwl_eeprom_query16(priv, EEPROM_NUM_MAC_ADDRESS);
|
||||
num_mac = priv->eeprom_data->n_hw_addrs;
|
||||
if (num_mac > 1) {
|
||||
memcpy(priv->addresses[1].addr, priv->addresses[0].addr,
|
||||
ETH_ALEN);
|
||||
|
@ -1711,8 +1529,10 @@ out_destroy_workqueue:
|
|||
destroy_workqueue(priv->workqueue);
|
||||
priv->workqueue = NULL;
|
||||
iwl_uninit_drv(priv);
|
||||
out_free_eeprom_blob:
|
||||
kfree(priv->eeprom_blob);
|
||||
out_free_eeprom:
|
||||
iwl_eeprom_free(priv);
|
||||
iwl_free_eeprom_data(priv->eeprom_data);
|
||||
out_free_hw:
|
||||
ieee80211_free_hw(priv->hw);
|
||||
out:
|
||||
|
@ -1720,7 +1540,7 @@ out:
|
|||
return op_mode;
|
||||
}
|
||||
|
||||
void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
|
||||
static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
|
@ -1737,7 +1557,8 @@ void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
|
|||
priv->ucode_loaded = false;
|
||||
iwl_trans_stop_device(priv->trans);
|
||||
|
||||
iwl_eeprom_free(priv);
|
||||
kfree(priv->eeprom_blob);
|
||||
iwl_free_eeprom_data(priv->eeprom_data);
|
||||
|
||||
/*netif_stop_queue(dev); */
|
||||
flush_workqueue(priv->workqueue);
|
||||
|
@ -2185,7 +2006,7 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
|
|||
}
|
||||
}
|
||||
|
||||
void iwl_nic_error(struct iwl_op_mode *op_mode)
|
||||
static void iwl_nic_error(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
|
@ -2198,7 +2019,7 @@ void iwl_nic_error(struct iwl_op_mode *op_mode)
|
|||
iwlagn_fw_error(priv, false);
|
||||
}
|
||||
|
||||
void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
|
||||
static void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
|
@ -2208,9 +2029,49 @@ void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
|
|||
}
|
||||
}
|
||||
|
||||
void iwl_nic_config(struct iwl_op_mode *op_mode)
|
||||
#define EEPROM_RF_CONFIG_TYPE_MAX 0x3
|
||||
|
||||
static void iwl_nic_config(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
u16 radio_cfg = priv->eeprom_data->radio_cfg;
|
||||
|
||||
/* SKU Control */
|
||||
iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
|
||||
CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP,
|
||||
(CSR_HW_REV_STEP(priv->trans->hw_rev) <<
|
||||
CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) |
|
||||
(CSR_HW_REV_DASH(priv->trans->hw_rev) <<
|
||||
CSR_HW_IF_CONFIG_REG_POS_MAC_DASH));
|
||||
|
||||
/* write radio config values to register */
|
||||
if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) {
|
||||
u32 reg_val =
|
||||
EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <<
|
||||
CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE |
|
||||
EEPROM_RF_CFG_STEP_MSK(radio_cfg) <<
|
||||
CSR_HW_IF_CONFIG_REG_POS_PHY_STEP |
|
||||
EEPROM_RF_CFG_DASH_MSK(radio_cfg) <<
|
||||
CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
|
||||
|
||||
iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
|
||||
CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
|
||||
CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, reg_val);
|
||||
|
||||
IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n",
|
||||
EEPROM_RF_CFG_TYPE_MSK(radio_cfg),
|
||||
EEPROM_RF_CFG_STEP_MSK(radio_cfg),
|
||||
EEPROM_RF_CFG_DASH_MSK(radio_cfg));
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
/* set CSR_HW_CONFIG_REG for uCode use */
|
||||
iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
|
||||
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
|
||||
|
||||
priv->lib->nic_config(priv);
|
||||
}
|
||||
|
@ -2223,7 +2084,7 @@ static void iwl_wimax_active(struct iwl_op_mode *op_mode)
|
|||
IWL_ERR(priv, "RF is used by WiMAX\n");
|
||||
}
|
||||
|
||||
void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
||||
static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
int mq = priv->queue_to_mac80211[queue];
|
||||
|
@ -2242,7 +2103,7 @@ void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
|||
ieee80211_stop_queue(priv->hw, mq);
|
||||
}
|
||||
|
||||
void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
||||
static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
int mq = priv->queue_to_mac80211[queue];
|
||||
|
@ -2282,16 +2143,17 @@ void iwlagn_lift_passive_no_rx(struct iwl_priv *priv)
|
|||
priv->passive_no_rx = false;
|
||||
}
|
||||
|
||||
void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
|
||||
static void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
|
||||
iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
|
||||
static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
|
||||
|
||||
|
@ -2303,7 +2165,7 @@ void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
|
|||
wiphy_rfkill_set_hw_state(priv->hw->wiphy, state);
|
||||
}
|
||||
|
||||
const struct iwl_op_mode_ops iwl_dvm_ops = {
|
||||
static const struct iwl_op_mode_ops iwl_dvm_ops = {
|
||||
.start = iwl_op_mode_dvm_start,
|
||||
.stop = iwl_op_mode_dvm_stop,
|
||||
.rx = iwl_rx_dispatch,
|
||||
|
@ -2322,9 +2184,6 @@ const struct iwl_op_mode_ops iwl_dvm_ops = {
|
|||
* driver and module entry point
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
struct kmem_cache *iwl_tx_cmd_pool;
|
||||
|
||||
static int __init iwl_init(void)
|
||||
{
|
||||
|
||||
|
@ -2332,36 +2191,25 @@ static int __init iwl_init(void)
|
|||
pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
|
||||
pr_info(DRV_COPYRIGHT "\n");
|
||||
|
||||
iwl_tx_cmd_pool = kmem_cache_create("iwl_dev_cmd",
|
||||
sizeof(struct iwl_device_cmd),
|
||||
sizeof(void *), 0, NULL);
|
||||
if (!iwl_tx_cmd_pool)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = iwlagn_rate_control_register();
|
||||
if (ret) {
|
||||
pr_err("Unable to register rate control algorithm: %d\n", ret);
|
||||
goto error_rc_register;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iwl_pci_register_driver();
|
||||
if (ret)
|
||||
goto error_pci_register;
|
||||
return ret;
|
||||
ret = iwl_opmode_register("iwldvm", &iwl_dvm_ops);
|
||||
if (ret) {
|
||||
pr_err("Unable to register op_mode: %d\n", ret);
|
||||
iwlagn_rate_control_unregister();
|
||||
}
|
||||
|
||||
error_pci_register:
|
||||
iwlagn_rate_control_unregister();
|
||||
error_rc_register:
|
||||
kmem_cache_destroy(iwl_tx_cmd_pool);
|
||||
return ret;
|
||||
}
|
||||
module_init(iwl_init);
|
||||
|
||||
static void __exit iwl_exit(void)
|
||||
{
|
||||
iwl_pci_unregister_driver();
|
||||
iwl_opmode_deregister("iwldvm");
|
||||
iwlagn_rate_control_unregister();
|
||||
kmem_cache_destroy(iwl_tx_cmd_pool);
|
||||
}
|
||||
|
||||
module_exit(iwl_exit);
|
||||
module_init(iwl_init);
|
|
@ -31,18 +31,15 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-commands.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-power.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-modparams.h"
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
#include "commands.h"
|
||||
#include "power.h"
|
||||
|
||||
/*
|
||||
* Setting power level allows the card to go to sleep when not busy.
|
|
@ -28,7 +28,7 @@
|
|||
#ifndef __iwl_power_setting_h__
|
||||
#define __iwl_power_setting_h__
|
||||
|
||||
#include "iwl-commands.h"
|
||||
#include "commands.h"
|
||||
|
||||
struct iwl_power_mgr {
|
||||
struct iwl_powertable_cmd sleep_cmd;
|
|
@ -35,10 +35,8 @@
|
|||
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-op-mode.h"
|
||||
#include "iwl-modparams.h"
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
|
||||
#define RS_NAME "iwl-agn-rs"
|
||||
|
||||
|
@ -819,7 +817,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
|
|||
|
||||
if (num_of_ant(tbl->ant_type) > 1)
|
||||
tbl->ant_type =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
|
||||
tbl->is_ht40 = 0;
|
||||
tbl->is_SGI = 0;
|
||||
|
@ -1447,7 +1445,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
|||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
int ret = 0;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
|
@ -1465,7 +1463,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
|||
case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
|
||||
/* avoid antenna B and MIMO */
|
||||
valid_tx_ant =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
|
||||
tbl->action != IWL_LEGACY_SWITCH_SISO)
|
||||
tbl->action = IWL_LEGACY_SWITCH_SISO;
|
||||
|
@ -1489,7 +1487,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
|||
else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
|
||||
tbl->action = IWL_LEGACY_SWITCH_SISO;
|
||||
valid_tx_ant =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
}
|
||||
|
||||
start_action = tbl->action;
|
||||
|
@ -1623,7 +1621,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
|||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
int ret;
|
||||
|
@ -1641,7 +1639,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
|||
case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
|
||||
/* avoid antenna B and MIMO */
|
||||
valid_tx_ant =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
|
||||
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
||||
break;
|
||||
|
@ -1659,7 +1657,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
|||
/* configure as 1x1 if bt full concurrency */
|
||||
if (priv->bt_full_concurrent) {
|
||||
valid_tx_ant =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
|
||||
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
||||
}
|
||||
|
@ -1795,7 +1793,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
|
|||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
int ret;
|
||||
|
@ -1965,7 +1963,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
|
|||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||
u8 start_action;
|
||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
|
||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||
int ret;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
|
@ -2699,7 +2697,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
|
|||
|
||||
i = lq_sta->last_txrate_idx;
|
||||
|
||||
valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
valid_tx_ant = priv->eeprom_data->valid_tx_ant;
|
||||
|
||||
if (!lq_sta->search_better_tbl)
|
||||
active_tbl = lq_sta->active_tbl;
|
||||
|
@ -2893,15 +2891,15 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
|
|||
|
||||
/* These values will be overridden later */
|
||||
lq_sta->lq.general_params.single_stream_ant_msk =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
lq_sta->lq.general_params.dual_stream_ant_msk =
|
||||
priv->hw_params.valid_tx_ant &
|
||||
~first_antenna(priv->hw_params.valid_tx_ant);
|
||||
priv->eeprom_data->valid_tx_ant &
|
||||
~first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
if (!lq_sta->lq.general_params.dual_stream_ant_msk) {
|
||||
lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
|
||||
} else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
|
||||
} else if (num_of_ant(priv->eeprom_data->valid_tx_ant) == 2) {
|
||||
lq_sta->lq.general_params.dual_stream_ant_msk =
|
||||
priv->hw_params.valid_tx_ant;
|
||||
priv->eeprom_data->valid_tx_ant;
|
||||
}
|
||||
|
||||
/* as default allow aggregation for all tids */
|
||||
|
@ -2947,7 +2945,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
|
|||
if (priv && priv->bt_full_concurrent) {
|
||||
/* 1x1 only */
|
||||
tbl_type.ant_type =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
}
|
||||
|
||||
/* How many times should we repeat the initial rate? */
|
||||
|
@ -2979,7 +2977,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
|
|||
if (priv->bt_full_concurrent)
|
||||
valid_tx_ant = ANT_A;
|
||||
else
|
||||
valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
valid_tx_ant = priv->eeprom_data->valid_tx_ant;
|
||||
}
|
||||
|
||||
/* Fill rest of rate table */
|
||||
|
@ -3013,7 +3011,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
|
|||
if (priv && priv->bt_full_concurrent) {
|
||||
/* 1x1 only */
|
||||
tbl_type.ant_type =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
}
|
||||
|
||||
/* Indicate to uCode which entries might be MIMO.
|
||||
|
@ -3100,7 +3098,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
|
|||
u8 ant_sel_tx;
|
||||
|
||||
priv = lq_sta->drv;
|
||||
valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||
valid_tx_ant = priv->eeprom_data->valid_tx_ant;
|
||||
if (lq_sta->dbg_fixed_rate) {
|
||||
ant_sel_tx =
|
||||
((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
|
||||
|
@ -3171,9 +3169,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
|||
desc += sprintf(buff+desc, "fixed rate 0x%X\n",
|
||||
lq_sta->dbg_fixed_rate);
|
||||
desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
|
||||
(priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
|
||||
(priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
|
||||
(priv->hw_params.valid_tx_ant & ANT_C) ? "ANT_C" : "");
|
||||
(priv->eeprom_data->valid_tx_ant & ANT_A) ? "ANT_A," : "",
|
||||
(priv->eeprom_data->valid_tx_ant & ANT_B) ? "ANT_B," : "",
|
||||
(priv->eeprom_data->valid_tx_ant & ANT_C) ? "ANT_C" : "");
|
||||
desc += sprintf(buff+desc, "lq type %s\n",
|
||||
(is_legacy(tbl->lq_type)) ? "legacy" : "HT");
|
||||
if (is_Ht(tbl->lq_type)) {
|
|
@ -29,9 +29,10 @@
|
|||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-commands.h"
|
||||
#include "iwl-config.h"
|
||||
|
||||
#include "commands.h"
|
||||
|
||||
struct iwl_rate_info {
|
||||
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
|
||||
u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
|
|
@ -32,12 +32,10 @@
|
|||
#include <linux/sched.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn-calib.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-modparams.h"
|
||||
#include "dev.h"
|
||||
#include "calib.h"
|
||||
#include "agn.h"
|
||||
|
||||
#define IWL_CMD_ENTRY(x) [x] = #x
|
||||
|
||||
|
@ -1012,6 +1010,8 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
|
|||
rx_status.flag |= RX_FLAG_40MHZ;
|
||||
if (rate_n_flags & RATE_MCS_SGI_MSK)
|
||||
rx_status.flag |= RX_FLAG_SHORT_GI;
|
||||
if (rate_n_flags & RATE_MCS_GF_MSK)
|
||||
rx_status.flag |= RX_FLAG_HT_GF;
|
||||
|
||||
iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,
|
||||
rxb, &rx_status);
|
|
@ -25,11 +25,11 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-agn-calib.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-modparams.h"
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
#include "calib.h"
|
||||
|
||||
/*
|
||||
* initialize rxon structure with default values from eeprom
|
||||
|
@ -37,8 +37,6 @@
|
|||
void iwl_connection_init_rx_config(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
const struct iwl_channel_info *ch_info;
|
||||
|
||||
memset(&ctx->staging, 0, sizeof(ctx->staging));
|
||||
|
||||
if (!ctx->vif) {
|
||||
|
@ -80,14 +78,8 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
|
|||
ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
|
||||
#endif
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, priv->band,
|
||||
le16_to_cpu(ctx->active.channel));
|
||||
|
||||
if (!ch_info)
|
||||
ch_info = &priv->channel_info[0];
|
||||
|
||||
ctx->staging.channel = cpu_to_le16(ch_info->channel);
|
||||
priv->band = ch_info->band;
|
||||
ctx->staging.channel = cpu_to_le16(priv->hw->conf.channel->hw_value);
|
||||
priv->band = priv->hw->conf.channel->band;
|
||||
|
||||
iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
|
||||
|
||||
|
@ -175,7 +167,8 @@ static int iwlagn_disconn_pan(struct iwl_priv *priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
||||
static void iwlagn_update_qos(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -202,8 +195,8 @@ void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
|
||||
}
|
||||
|
||||
int iwlagn_update_beacon(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif)
|
||||
static int iwlagn_update_beacon(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
|
@ -215,7 +208,7 @@ int iwlagn_update_beacon(struct iwl_priv *priv,
|
|||
}
|
||||
|
||||
static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
struct iwl_rxon_assoc_cmd rxon_assoc;
|
||||
|
@ -427,10 +420,10 @@ static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tx_power > priv->tx_power_device_lmt) {
|
||||
if (tx_power > DIV_ROUND_UP(priv->eeprom_data->max_tx_pwr_half_dbm, 2)) {
|
||||
IWL_WARN(priv,
|
||||
"Requested user TXPOWER %d above upper limit %d.\n",
|
||||
tx_power, priv->tx_power_device_lmt);
|
||||
tx_power, priv->eeprom_data->max_tx_pwr_half_dbm);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -863,8 +856,8 @@ static int iwl_check_rxon_cmd(struct iwl_priv *priv,
|
|||
* or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
|
||||
* a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
|
||||
*/
|
||||
int iwl_full_rxon_required(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
static int iwl_full_rxon_required(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
const struct iwl_rxon_cmd *staging = &ctx->staging;
|
||||
const struct iwl_rxon_cmd *active = &ctx->active;
|
||||
|
@ -1189,7 +1182,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
|
|||
struct iwl_rxon_context *ctx;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
struct ieee80211_channel *channel = conf->channel;
|
||||
const struct iwl_channel_info *ch_info;
|
||||
int ret = 0;
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "enter: changed %#x\n", changed);
|
||||
|
@ -1223,14 +1215,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
|
|||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
ch_info = iwl_get_channel_info(priv, channel->band,
|
||||
channel->hw_value);
|
||||
if (!is_channel_valid(ch_info)) {
|
||||
IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for_each_context(priv, ctx) {
|
||||
/* Configure HT40 channels */
|
||||
if (ctx->ht.enabled != conf_is_ht(conf))
|
||||
|
@ -1294,9 +1278,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_bss_conf *bss_conf)
|
||||
static void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_bss_conf *bss_conf)
|
||||
{
|
||||
struct ieee80211_vif *vif = ctx->vif;
|
||||
struct iwl_rxon_context *tmp;
|
||||
|
@ -1388,7 +1372,7 @@ void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
|||
ht_conf->single_chain_sufficient = !need_multiple;
|
||||
}
|
||||
|
||||
void iwlagn_chain_noise_reset(struct iwl_priv *priv)
|
||||
static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
|
||||
int ret;
|
|
@ -30,11 +30,8 @@
|
|||
#include <linux/etherdevice.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
|
||||
/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
|
||||
* sending probe req. This should be set long enough to hear probe responses
|
||||
|
@ -67,7 +64,6 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
|
|||
* to receive scan abort command or it does not perform
|
||||
* hardware scan currently */
|
||||
if (!test_bit(STATUS_READY, &priv->status) ||
|
||||
!test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
|
||||
!test_bit(STATUS_SCAN_HW, &priv->status) ||
|
||||
test_bit(STATUS_FW_ERROR, &priv->status))
|
||||
return -EIO;
|
||||
|
@ -101,11 +97,8 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
|
|||
ieee80211_scan_completed(priv->hw, aborted);
|
||||
}
|
||||
|
||||
if (priv->scan_type == IWL_SCAN_ROC) {
|
||||
ieee80211_remain_on_channel_expired(priv->hw);
|
||||
priv->hw_roc_channel = NULL;
|
||||
schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
|
||||
}
|
||||
if (priv->scan_type == IWL_SCAN_ROC)
|
||||
iwl_scan_roc_expired(priv);
|
||||
|
||||
priv->scan_type = IWL_SCAN_NORMAL;
|
||||
priv->scan_vif = NULL;
|
||||
|
@ -134,11 +127,8 @@ static void iwl_process_scan_complete(struct iwl_priv *priv)
|
|||
goto out_settings;
|
||||
}
|
||||
|
||||
if (priv->scan_type == IWL_SCAN_ROC) {
|
||||
ieee80211_remain_on_channel_expired(priv->hw);
|
||||
priv->hw_roc_channel = NULL;
|
||||
schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
|
||||
}
|
||||
if (priv->scan_type == IWL_SCAN_ROC)
|
||||
iwl_scan_roc_expired(priv);
|
||||
|
||||
if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
|
||||
int err;
|
||||
|
@ -453,27 +443,17 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
|
|||
|
||||
/* Return valid, unused, channel for a passive scan to reset the RF */
|
||||
static u8 iwl_get_single_channel_number(struct iwl_priv *priv,
|
||||
enum ieee80211_band band)
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
const struct iwl_channel_info *ch_info;
|
||||
int i;
|
||||
u8 channel = 0;
|
||||
u8 min, max;
|
||||
struct ieee80211_supported_band *sband = priv->hw->wiphy->bands[band];
|
||||
struct iwl_rxon_context *ctx;
|
||||
int i;
|
||||
|
||||
if (band == IEEE80211_BAND_5GHZ) {
|
||||
min = 14;
|
||||
max = priv->channel_count;
|
||||
} else {
|
||||
min = 0;
|
||||
max = 14;
|
||||
}
|
||||
|
||||
for (i = min; i < max; i++) {
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
bool busy = false;
|
||||
|
||||
for_each_context(priv, ctx) {
|
||||
busy = priv->channel_info[i].channel ==
|
||||
busy = sband->channels[i].hw_value ==
|
||||
le16_to_cpu(ctx->staging.channel);
|
||||
if (busy)
|
||||
break;
|
||||
|
@ -482,13 +462,11 @@ static u8 iwl_get_single_channel_number(struct iwl_priv *priv,
|
|||
if (busy)
|
||||
continue;
|
||||
|
||||
channel = priv->channel_info[i].channel;
|
||||
ch_info = iwl_get_channel_info(priv, band, channel);
|
||||
if (is_channel_valid(ch_info))
|
||||
break;
|
||||
if (!(sband->channels[i].flags & IEEE80211_CHAN_DISABLED))
|
||||
return sband->channels[i].hw_value;
|
||||
}
|
||||
|
||||
return channel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
|
||||
|
@ -540,7 +518,6 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
|
|||
{
|
||||
struct ieee80211_channel *chan;
|
||||
const struct ieee80211_supported_band *sband;
|
||||
const struct iwl_channel_info *ch_info;
|
||||
u16 passive_dwell = 0;
|
||||
u16 active_dwell = 0;
|
||||
int added, i;
|
||||
|
@ -565,16 +542,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
|
|||
channel = chan->hw_value;
|
||||
scan_ch->channel = cpu_to_le16(channel);
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, band, channel);
|
||||
if (!is_channel_valid(ch_info)) {
|
||||
IWL_DEBUG_SCAN(priv,
|
||||
"Channel %d is INVALID for this band.\n",
|
||||
channel);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_active || is_channel_passive(ch_info) ||
|
||||
(chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
|
||||
if (!is_active || (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
|
||||
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
|
||||
else
|
||||
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
|
||||
|
@ -678,12 +646,12 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
u16 rx_chain = 0;
|
||||
enum ieee80211_band band;
|
||||
u8 n_probes = 0;
|
||||
u8 rx_ant = priv->hw_params.valid_rx_ant;
|
||||
u8 rx_ant = priv->eeprom_data->valid_rx_ant;
|
||||
u8 rate;
|
||||
bool is_active = false;
|
||||
int chan_mod;
|
||||
u8 active_chains;
|
||||
u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
|
||||
u8 scan_tx_antennas = priv->eeprom_data->valid_tx_ant;
|
||||
int ret;
|
||||
int scan_cmd_size = sizeof(struct iwl_scan_cmd) +
|
||||
MAX_SCAN_CHANNEL * sizeof(struct iwl_scan_channel) +
|
||||
|
@ -893,7 +861,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
|
||||
/* MIMO is not used here, but value is required */
|
||||
rx_chain |=
|
||||
priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
|
||||
priv->eeprom_data->valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
|
||||
rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
|
||||
rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
|
||||
rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
|
||||
|
@ -994,8 +962,10 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
set_bit(STATUS_SCAN_HW, &priv->status);
|
||||
|
||||
ret = iwlagn_set_pan_params(priv);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iwl_dvm_send_cmd(priv, &cmd);
|
||||
if (ret) {
|
||||
|
@ -1008,7 +978,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
|||
|
||||
void iwl_init_scan_params(struct iwl_priv *priv)
|
||||
{
|
||||
u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
|
||||
u8 ant_idx = fls(priv->eeprom_data->valid_tx_ant) - 1;
|
||||
if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
|
||||
priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
|
||||
if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
|
||||
|
@ -1158,3 +1128,40 @@ void iwl_cancel_scan_deferred_work(struct iwl_priv *priv)
|
|||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_scan_roc_expired(struct iwl_priv *priv)
|
||||
{
|
||||
/*
|
||||
* The status bit should be set here, to prevent a race
|
||||
* where the atomic_read returns 1, but before the execution continues
|
||||
* iwl_scan_offchannel_skb_status() checks if the status bit is set
|
||||
*/
|
||||
set_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status);
|
||||
|
||||
if (atomic_read(&priv->num_aux_in_flight) == 0) {
|
||||
ieee80211_remain_on_channel_expired(priv->hw);
|
||||
priv->hw_roc_channel = NULL;
|
||||
schedule_delayed_work(&priv->hw_roc_disable_work,
|
||||
10 * HZ);
|
||||
|
||||
clear_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status);
|
||||
} else {
|
||||
IWL_DEBUG_SCAN(priv, "ROC done with %d frames in aux\n",
|
||||
atomic_read(&priv->num_aux_in_flight));
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_scan_offchannel_skb(struct iwl_priv *priv)
|
||||
{
|
||||
WARN_ON(!priv->hw_roc_start_notified);
|
||||
atomic_inc(&priv->num_aux_in_flight);
|
||||
}
|
||||
|
||||
void iwl_scan_offchannel_skb_status(struct iwl_priv *priv)
|
||||
{
|
||||
if (atomic_dec_return(&priv->num_aux_in_flight) == 0 &&
|
||||
test_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "0 aux frames. Calling ROC expired\n");
|
||||
iwl_scan_roc_expired(priv);
|
||||
}
|
||||
}
|
|
@ -28,10 +28,9 @@
|
|||
*****************************************************************************/
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
|
||||
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
|
@ -171,26 +170,6 @@ int iwl_send_add_sta(struct iwl_priv *priv,
|
|||
return cmd.handler_status;
|
||||
}
|
||||
|
||||
static bool iwl_is_channel_extension(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
u16 channel, u8 extension_chan_offset)
|
||||
{
|
||||
const struct iwl_channel_info *ch_info;
|
||||
|
||||
ch_info = iwl_get_channel_info(priv, band, channel);
|
||||
if (!is_channel_valid(ch_info))
|
||||
return false;
|
||||
|
||||
if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
|
||||
return !(ch_info->ht40_extension_channel &
|
||||
IEEE80211_CHAN_NO_HT40PLUS);
|
||||
else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
|
||||
return !(ch_info->ht40_extension_channel &
|
||||
IEEE80211_CHAN_NO_HT40MINUS);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_sta_ht_cap *ht_cap)
|
||||
|
@ -198,21 +177,25 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
|
|||
if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
|
||||
* the bit will not set if it is pure 40MHz case
|
||||
*/
|
||||
if (ht_cap && !ht_cap->ht_supported)
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (priv->disable_ht40)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return iwl_is_channel_extension(priv, priv->band,
|
||||
le16_to_cpu(ctx->staging.channel),
|
||||
ctx->ht.extension_chan_offset);
|
||||
/*
|
||||
* Remainder of this function checks ht_cap, but if it's
|
||||
* NULL then we can do HT40 (special case for RXON)
|
||||
*/
|
||||
if (!ht_cap)
|
||||
return true;
|
||||
|
||||
if (!ht_cap->ht_supported)
|
||||
return false;
|
||||
|
||||
if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
|
||||
|
@ -236,6 +219,7 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
|
|||
mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
|
||||
sta->addr,
|
||||
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
|
||||
"static" :
|
||||
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
|
||||
|
@ -649,23 +633,23 @@ static void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
|||
if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
|
||||
rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
|
||||
rate_flags |= first_antenna(priv->eeprom_data->valid_tx_ant) <<
|
||||
RATE_MCS_ANT_POS;
|
||||
rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
|
||||
|
||||
link_cmd->general_params.single_stream_ant_msk =
|
||||
first_antenna(priv->hw_params.valid_tx_ant);
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
|
||||
link_cmd->general_params.dual_stream_ant_msk =
|
||||
priv->hw_params.valid_tx_ant &
|
||||
~first_antenna(priv->hw_params.valid_tx_ant);
|
||||
priv->eeprom_data->valid_tx_ant &
|
||||
~first_antenna(priv->eeprom_data->valid_tx_ant);
|
||||
if (!link_cmd->general_params.dual_stream_ant_msk) {
|
||||
link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
|
||||
} else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
|
||||
} else if (num_of_ant(priv->eeprom_data->valid_tx_ant) == 2) {
|
||||
link_cmd->general_params.dual_stream_ant_msk =
|
||||
priv->hw_params.valid_tx_ant;
|
||||
priv->eeprom_data->valid_tx_ant;
|
||||
}
|
||||
|
||||
link_cmd->agg_params.agg_dis_start_th =
|
|
@ -69,15 +69,14 @@
|
|||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-testmode.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-fh.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
#include "testmode.h"
|
||||
|
||||
|
||||
/* Periphery registers absolute lower bound. This is used in order to
|
||||
|
@ -89,7 +88,7 @@
|
|||
/* The TLVs used in the gnl message policy between the kernel module and
|
||||
* user space application. iwl_testmode_gnl_msg_policy is to be carried
|
||||
* through the NL80211_CMD_TESTMODE channel regulated by nl80211.
|
||||
* See iwl-testmode.h
|
||||
* See testmode.h
|
||||
*/
|
||||
static
|
||||
struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
|
||||
|
@ -129,7 +128,7 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
|
|||
};
|
||||
|
||||
/*
|
||||
* See the struct iwl_rx_packet in iwl-commands.h for the format of the
|
||||
* See the struct iwl_rx_packet in commands.h for the format of the
|
||||
* received events from the device
|
||||
*/
|
||||
static inline int get_event_length(struct iwl_rx_cmd_buffer *rxb)
|
||||
|
@ -535,9 +534,9 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
|
|||
break;
|
||||
|
||||
case IWL_TM_CMD_APP2DEV_GET_EEPROM:
|
||||
if (priv->eeprom) {
|
||||
if (priv->eeprom_blob) {
|
||||
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
|
||||
priv->cfg->base_params->eeprom_size + 20);
|
||||
priv->eeprom_blob_size + 20);
|
||||
if (!skb) {
|
||||
IWL_ERR(priv, "Memory allocation fail\n");
|
||||
return -ENOMEM;
|
||||
|
@ -545,15 +544,15 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
|
|||
if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
|
||||
IWL_TM_CMD_DEV2APP_EEPROM_RSP) ||
|
||||
nla_put(skb, IWL_TM_ATTR_EEPROM,
|
||||
priv->cfg->base_params->eeprom_size,
|
||||
priv->eeprom))
|
||||
priv->eeprom_blob_size,
|
||||
priv->eeprom_blob))
|
||||
goto nla_put_failure;
|
||||
status = cfg80211_testmode_reply(skb);
|
||||
if (status < 0)
|
||||
IWL_ERR(priv, "Error sending msg : %d\n",
|
||||
status);
|
||||
} else
|
||||
return -EFAULT;
|
||||
return -ENODATA;
|
||||
break;
|
||||
|
||||
case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
|
|
@ -31,17 +31,14 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-commands.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-agn-tt.h"
|
||||
#include "iwl-modparams.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "agn.h"
|
||||
#include "dev.h"
|
||||
#include "commands.h"
|
||||
#include "tt.h"
|
||||
|
||||
/* default Thermal Throttling transaction table
|
||||
* Current state | Throttling Down | Throttling Up
|
|
@ -28,7 +28,7 @@
|
|||
#ifndef __iwl_tt_setting_h__
|
||||
#define __iwl_tt_setting_h__
|
||||
|
||||
#include "iwl-commands.h"
|
||||
#include "commands.h"
|
||||
|
||||
#define IWL_ABSOLUTE_ZERO 0
|
||||
#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
|
|
@ -32,12 +32,11 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ieee80211.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
|
||||
static const u8 tid_to_ac[] = {
|
||||
IEEE80211_AC_BE,
|
||||
|
@ -187,7 +186,8 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
|
|||
rate_idx = info->control.rates[0].idx;
|
||||
if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
|
||||
(rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
|
||||
rate_idx = rate_lowest_index(&priv->bands[info->band],
|
||||
rate_idx = rate_lowest_index(
|
||||
&priv->eeprom_data->bands[info->band],
|
||||
info->control.sta);
|
||||
/* For 5 GHZ band, remap mac80211 rate indices into driver indices */
|
||||
if (info->band == IEEE80211_BAND_5GHZ)
|
||||
|
@ -207,10 +207,11 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
|
|||
priv->bt_full_concurrent) {
|
||||
/* operated as 1x1 in full concurrency mode */
|
||||
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
|
||||
first_antenna(priv->hw_params.valid_tx_ant));
|
||||
first_antenna(priv->eeprom_data->valid_tx_ant));
|
||||
} else
|
||||
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
|
||||
priv->hw_params.valid_tx_ant);
|
||||
priv->mgmt_tx_ant = iwl_toggle_tx_ant(
|
||||
priv, priv->mgmt_tx_ant,
|
||||
priv->eeprom_data->valid_tx_ant);
|
||||
rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
|
||||
|
||||
/* Set the rate in the TX cmd */
|
||||
|
@ -296,7 +297,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct iwl_station_priv *sta_priv = NULL;
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
struct iwl_device_cmd *dev_cmd = NULL;
|
||||
struct iwl_device_cmd *dev_cmd;
|
||||
struct iwl_tx_cmd *tx_cmd;
|
||||
__le16 fc;
|
||||
u8 hdr_len;
|
||||
|
@ -378,7 +379,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
if (info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||
is_agg = true;
|
||||
|
||||
dev_cmd = kmem_cache_alloc(iwl_tx_cmd_pool, GFP_ATOMIC);
|
||||
dev_cmd = iwl_trans_alloc_tx_cmd(priv->trans);
|
||||
|
||||
if (unlikely(!dev_cmd))
|
||||
goto drop_unlock_priv;
|
||||
|
@ -486,11 +487,14 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
if (sta_priv && sta_priv->client && !is_agg)
|
||||
atomic_inc(&sta_priv->pending_frames);
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
|
||||
iwl_scan_offchannel_skb(priv);
|
||||
|
||||
return 0;
|
||||
|
||||
drop_unlock_sta:
|
||||
if (dev_cmd)
|
||||
kmem_cache_free(iwl_tx_cmd_pool, dev_cmd);
|
||||
iwl_trans_free_tx_cmd(priv->trans, dev_cmd);
|
||||
spin_unlock(&priv->sta_lock);
|
||||
drop_unlock_priv:
|
||||
return -1;
|
||||
|
@ -597,7 +601,7 @@ turn_off:
|
|||
* time, or we hadn't time to drain the AC queues.
|
||||
*/
|
||||
if (agg_state == IWL_AGG_ON)
|
||||
iwl_trans_tx_agg_disable(priv->trans, txq_id);
|
||||
iwl_trans_txq_disable(priv->trans, txq_id);
|
||||
else
|
||||
IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
|
||||
agg_state);
|
||||
|
@ -686,9 +690,8 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
|
|||
|
||||
fifo = ctx->ac_to_fifo[tid_to_ac[tid]];
|
||||
|
||||
iwl_trans_tx_agg_setup(priv->trans, q, fifo,
|
||||
sta_priv->sta_id, tid,
|
||||
buf_size, ssn);
|
||||
iwl_trans_txq_enable(priv->trans, q, fifo, sta_priv->sta_id, tid,
|
||||
buf_size, ssn);
|
||||
|
||||
/*
|
||||
* If the limit is 0, then it wasn't initialised yet,
|
||||
|
@ -753,8 +756,8 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid)
|
|||
IWL_DEBUG_TX_QUEUES(priv,
|
||||
"Can continue DELBA flow ssn = next_recl ="
|
||||
" %d", tid_data->next_reclaimed);
|
||||
iwl_trans_tx_agg_disable(priv->trans,
|
||||
tid_data->agg.txq_id);
|
||||
iwl_trans_txq_disable(priv->trans,
|
||||
tid_data->agg.txq_id);
|
||||
iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id);
|
||||
tid_data->agg.state = IWL_AGG_OFF;
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
|
||||
|
@ -1136,6 +1139,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
|||
struct sk_buff *skb;
|
||||
struct iwl_rxon_context *ctx;
|
||||
bool is_agg = (txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
|
||||
bool is_offchannel_skb;
|
||||
|
||||
tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
|
||||
IWLAGN_TX_RES_TID_POS;
|
||||
|
@ -1149,6 +1153,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
|||
|
||||
__skb_queue_head_init(&skbs);
|
||||
|
||||
is_offchannel_skb = false;
|
||||
|
||||
if (tx_resp->frame_count == 1) {
|
||||
u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
|
||||
next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
|
||||
|
@ -1189,8 +1195,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
|||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
ctx = info->driver_data[0];
|
||||
kmem_cache_free(iwl_tx_cmd_pool,
|
||||
(info->driver_data[1]));
|
||||
iwl_trans_free_tx_cmd(priv->trans,
|
||||
info->driver_data[1]);
|
||||
|
||||
memset(&info->status, 0, sizeof(info->status));
|
||||
|
||||
|
@ -1225,10 +1231,19 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
|||
if (!is_agg)
|
||||
iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
|
||||
|
||||
is_offchannel_skb =
|
||||
(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN);
|
||||
freed++;
|
||||
}
|
||||
|
||||
WARN_ON(!is_agg && freed != 1);
|
||||
|
||||
/*
|
||||
* An offchannel frame can be send only on the AUX queue, where
|
||||
* there is no aggregation (and reordering) so it only is single
|
||||
* skb is expected to be processed.
|
||||
*/
|
||||
WARN_ON(is_offchannel_skb && freed != 1);
|
||||
}
|
||||
|
||||
iwl_check_abort_status(priv, tx_resp->frame_count, status);
|
||||
|
@ -1239,6 +1254,9 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
|||
ieee80211_tx_status(priv->hw, skb);
|
||||
}
|
||||
|
||||
if (is_offchannel_skb)
|
||||
iwl_scan_offchannel_skb_status(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1341,7 +1359,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
|
|||
WARN_ON_ONCE(1);
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
|
||||
iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
|
||||
|
||||
if (freed == 1) {
|
||||
/* this is the first skb we deliver in this batch */
|
|
@ -30,15 +30,16 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-agn-calib.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-fh.h"
|
||||
#include "iwl-op-mode.h"
|
||||
|
||||
#include "dev.h"
|
||||
#include "agn.h"
|
||||
#include "calib.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* uCode download functions
|
||||
|
@ -60,8 +61,7 @@ iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type)
|
|||
static int iwl_set_Xtal_calib(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_calib_xtal_freq_cmd cmd;
|
||||
__le16 *xtal_calib =
|
||||
(__le16 *)iwl_eeprom_query_addr(priv, EEPROM_XTAL);
|
||||
__le16 *xtal_calib = priv->eeprom_data->xtal_calib;
|
||||
|
||||
iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD);
|
||||
cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
|
||||
|
@ -72,12 +72,10 @@ static int iwl_set_Xtal_calib(struct iwl_priv *priv)
|
|||
static int iwl_set_temperature_offset_calib(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_calib_temperature_offset_cmd cmd;
|
||||
__le16 *offset_calib =
|
||||
(__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
|
||||
memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(*offset_calib));
|
||||
cmd.radio_sensor_offset = priv->eeprom_data->raw_temperature;
|
||||
if (!(cmd.radio_sensor_offset))
|
||||
cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
|
||||
|
||||
|
@ -89,27 +87,17 @@ static int iwl_set_temperature_offset_calib(struct iwl_priv *priv)
|
|||
static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_calib_temperature_offset_v2_cmd cmd;
|
||||
__le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv,
|
||||
EEPROM_KELVIN_TEMPERATURE);
|
||||
__le16 *offset_calib_low =
|
||||
(__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE);
|
||||
struct iwl_eeprom_calib_hdr *hdr;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
|
||||
hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
|
||||
EEPROM_CALIB_ALL);
|
||||
memcpy(&cmd.radio_sensor_offset_high, offset_calib_high,
|
||||
sizeof(*offset_calib_high));
|
||||
memcpy(&cmd.radio_sensor_offset_low, offset_calib_low,
|
||||
sizeof(*offset_calib_low));
|
||||
if (!(cmd.radio_sensor_offset_low)) {
|
||||
cmd.radio_sensor_offset_high = priv->eeprom_data->kelvin_temperature;
|
||||
cmd.radio_sensor_offset_low = priv->eeprom_data->raw_temperature;
|
||||
if (!cmd.radio_sensor_offset_low) {
|
||||
IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n");
|
||||
cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET;
|
||||
cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET;
|
||||
}
|
||||
memcpy(&cmd.burntVoltageRef, &hdr->voltage,
|
||||
sizeof(hdr->voltage));
|
||||
cmd.burntVoltageRef = priv->eeprom_data->calib_voltage;
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n",
|
||||
le16_to_cpu(cmd.radio_sensor_offset_high));
|
||||
|
@ -177,7 +165,7 @@ int iwl_init_alive_start(struct iwl_priv *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int iwl_send_wimax_coex(struct iwl_priv *priv)
|
||||
static int iwl_send_wimax_coex(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_wimax_coex_cmd coex_cmd;
|
||||
|
|
@ -113,7 +113,7 @@ enum iwl_led_mode {
|
|||
#define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE 0
|
||||
|
||||
/* TX queue watchdog timeouts in mSecs */
|
||||
#define IWL_WATCHHDOG_DISABLED 0
|
||||
#define IWL_WATCHDOG_DISABLED 0
|
||||
#define IWL_DEF_WD_TIMEOUT 2000
|
||||
#define IWL_LONG_WD_TIMEOUT 10000
|
||||
#define IWL_MAX_WD_TIMEOUT 120000
|
||||
|
@ -143,7 +143,7 @@ enum iwl_led_mode {
|
|||
* @chain_noise_scale: default chain noise scale used for gain computation
|
||||
* @wd_timeout: TX queues watchdog timeout
|
||||
* @max_event_log_size: size of event log buffer size for ucode event logging
|
||||
* @shadow_reg_enable: HW shadhow register bit
|
||||
* @shadow_reg_enable: HW shadow register support
|
||||
* @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
|
||||
* @no_idle_support: do not support idle mode
|
||||
*/
|
||||
|
@ -182,13 +182,34 @@ struct iwl_bt_params {
|
|||
bool bt_sco_disable;
|
||||
bool bt_session_2;
|
||||
};
|
||||
|
||||
/*
|
||||
* @use_rts_for_aggregation: use rts/cts protection for HT traffic
|
||||
* @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
|
||||
*/
|
||||
struct iwl_ht_params {
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
const bool ht_greenfield_support; /* if used set to true */
|
||||
bool use_rts_for_aggregation;
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
u8 ht40_bands;
|
||||
};
|
||||
|
||||
/*
|
||||
* information on how to parse the EEPROM
|
||||
*/
|
||||
#define EEPROM_REG_BAND_1_CHANNELS 0x08
|
||||
#define EEPROM_REG_BAND_2_CHANNELS 0x26
|
||||
#define EEPROM_REG_BAND_3_CHANNELS 0x42
|
||||
#define EEPROM_REG_BAND_4_CHANNELS 0x5C
|
||||
#define EEPROM_REG_BAND_5_CHANNELS 0x74
|
||||
#define EEPROM_REG_BAND_24_HT40_CHANNELS 0x82
|
||||
#define EEPROM_REG_BAND_52_HT40_CHANNELS 0x92
|
||||
#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS 0x80
|
||||
#define EEPROM_REGULATORY_BAND_NO_HT40 0
|
||||
|
||||
struct iwl_eeprom_params {
|
||||
const u8 regulatory_bands[7];
|
||||
bool enhanced_txpower;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -243,6 +264,7 @@ struct iwl_cfg {
|
|||
/* params likely to change within a device family */
|
||||
const struct iwl_ht_params *ht_params;
|
||||
const struct iwl_bt_params *bt_params;
|
||||
const struct iwl_eeprom_params *eeprom_params;
|
||||
const bool need_temp_offset_calib; /* if used set to true */
|
||||
const bool no_xtal_calib;
|
||||
enum iwl_led_mode led_mode;
|
||||
|
|
|
@ -97,13 +97,10 @@
|
|||
/*
|
||||
* Hardware revision info
|
||||
* Bit fields:
|
||||
* 31-8: Reserved
|
||||
* 7-4: Type of device: see CSR_HW_REV_TYPE_xxx definitions
|
||||
* 31-16: Reserved
|
||||
* 15-4: Type of device: see CSR_HW_REV_TYPE_xxx definitions
|
||||
* 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D
|
||||
* 1-0: "Dash" (-) value, as in A-1, etc.
|
||||
*
|
||||
* NOTE: Revision step affects calculation of CCK txpower for 4965.
|
||||
* NOTE: See also CSR_HW_REV_WA_REG (work-around for bug in 4965).
|
||||
*/
|
||||
#define CSR_HW_REV (CSR_BASE+0x028)
|
||||
|
||||
|
@ -155,9 +152,21 @@
|
|||
#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)
|
||||
|
||||
/* Bits for CSR_HW_IF_CONFIG_REG */
|
||||
#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100)
|
||||
#define CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH (0x00000003)
|
||||
#define CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP (0x0000000C)
|
||||
#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x000000C0)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200)
|
||||
#define CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE (0x00000C00)
|
||||
#define CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH (0x00003000)
|
||||
#define CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP (0x0000C000)
|
||||
|
||||
#define CSR_HW_IF_CONFIG_REG_POS_MAC_DASH (0)
|
||||
#define CSR_HW_IF_CONFIG_REG_POS_MAC_STEP (2)
|
||||
#define CSR_HW_IF_CONFIG_REG_POS_BOARD_VER (6)
|
||||
#define CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE (10)
|
||||
#define CSR_HW_IF_CONFIG_REG_POS_PHY_DASH (12)
|
||||
#define CSR_HW_IF_CONFIG_REG_POS_PHY_STEP (14)
|
||||
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
|
||||
|
@ -270,7 +279,10 @@
|
|||
|
||||
|
||||
/* HW REV */
|
||||
#define CSR_HW_REV_TYPE_MSK (0x00001F0)
|
||||
#define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0)
|
||||
#define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2)
|
||||
|
||||
#define CSR_HW_REV_TYPE_MSK (0x000FFF0)
|
||||
#define CSR_HW_REV_TYPE_5300 (0x0000020)
|
||||
#define CSR_HW_REV_TYPE_5350 (0x0000030)
|
||||
#define CSR_HW_REV_TYPE_5100 (0x0000050)
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/export.h>
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-devtrace.h"
|
||||
|
||||
|
@ -81,8 +82,11 @@ void __iwl_ ##fn(struct device *dev, const char *fmt, ...) \
|
|||
}
|
||||
|
||||
__iwl_fn(warn)
|
||||
EXPORT_SYMBOL_GPL(__iwl_warn);
|
||||
__iwl_fn(info)
|
||||
EXPORT_SYMBOL_GPL(__iwl_info);
|
||||
__iwl_fn(crit)
|
||||
EXPORT_SYMBOL_GPL(__iwl_crit);
|
||||
|
||||
void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
|
||||
const char *fmt, ...)
|
||||
|
@ -103,6 +107,7 @@ void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
|
|||
trace_iwlwifi_err(&vaf);
|
||||
va_end(args);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__iwl_err);
|
||||
|
||||
#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
|
||||
void __iwl_dbg(struct device *dev,
|
||||
|
@ -125,4 +130,5 @@ void __iwl_dbg(struct device *dev,
|
|||
trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf);
|
||||
va_end(args);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__iwl_dbg);
|
||||
#endif
|
||||
|
|
|
@ -38,13 +38,14 @@ static inline bool iwl_have_debug_level(u32 level)
|
|||
}
|
||||
|
||||
void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace,
|
||||
const char *fmt, ...);
|
||||
void __iwl_warn(struct device *dev, const char *fmt, ...);
|
||||
void __iwl_info(struct device *dev, const char *fmt, ...);
|
||||
void __iwl_crit(struct device *dev, const char *fmt, ...);
|
||||
const char *fmt, ...) __printf(4, 5);
|
||||
void __iwl_warn(struct device *dev, const char *fmt, ...) __printf(2, 3);
|
||||
void __iwl_info(struct device *dev, const char *fmt, ...) __printf(2, 3);
|
||||
void __iwl_crit(struct device *dev, const char *fmt, ...) __printf(2, 3);
|
||||
|
||||
/* No matter what is m (priv, bus, trans), this will work */
|
||||
#define IWL_ERR(m, f, a...) __iwl_err((m)->dev, false, false, f, ## a)
|
||||
#define IWL_ERR_DEV(d, f, a...) __iwl_err((d), false, false, f, ## a)
|
||||
#define IWL_WARN(m, f, a...) __iwl_warn((m)->dev, f, ## a)
|
||||
#define IWL_INFO(m, f, a...) __iwl_info((m)->dev, f, ## a)
|
||||
#define IWL_CRIT(m, f, a...) __iwl_crit((m)->dev, f, ## a)
|
||||
|
@ -52,9 +53,9 @@ void __iwl_crit(struct device *dev, const char *fmt, ...);
|
|||
#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
|
||||
void __iwl_dbg(struct device *dev,
|
||||
u32 level, bool limit, const char *function,
|
||||
const char *fmt, ...);
|
||||
const char *fmt, ...) __printf(5, 6);
|
||||
#else
|
||||
static inline void
|
||||
__printf(5, 6) static inline void
|
||||
__iwl_dbg(struct device *dev,
|
||||
u32 level, bool limit, const char *function,
|
||||
const char *fmt, ...)
|
||||
|
@ -69,6 +70,8 @@ do { \
|
|||
|
||||
#define IWL_DEBUG(m, level, fmt, args...) \
|
||||
__iwl_dbg((m)->dev, level, false, __func__, fmt, ##args)
|
||||
#define IWL_DEBUG_DEV(dev, level, fmt, args...) \
|
||||
__iwl_dbg((dev), level, false, __func__, fmt, ##args)
|
||||
#define IWL_DEBUG_LIMIT(m, level, fmt, args...) \
|
||||
__iwl_dbg((m)->dev, level, true, __func__, fmt, ##args)
|
||||
|
||||
|
@ -153,7 +156,7 @@ do { \
|
|||
#define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a)
|
||||
#define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
|
||||
#define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
|
||||
#define IWL_DEBUG_EEPROM(p, f, a...) IWL_DEBUG(p, IWL_DL_EEPROM, f, ## a)
|
||||
#define IWL_DEBUG_EEPROM(d, f, a...) IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a)
|
||||
#define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
|
||||
#define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a)
|
||||
#define IWL_DEBUG_RF_KILL(p, f, a...) IWL_DEBUG(p, IWL_DL_RF_KILL, f, ## a)
|
||||
|
|
|
@ -42,4 +42,9 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
|
|||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_info);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_warn);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_crit);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_err);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dbg);
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define __IWLWIFI_DEVICE_TRACE
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
|
||||
#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
|
||||
|
|
|
@ -77,8 +77,33 @@
|
|||
/* private includes */
|
||||
#include "iwl-fw-file.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* module boiler plate
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* module name, copyright, version, etc.
|
||||
*/
|
||||
#define DRV_DESCRIPTION "Intel(R) Wireless WiFi driver for Linux"
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
#define VD "d"
|
||||
#else
|
||||
#define VD
|
||||
#endif
|
||||
|
||||
#define DRV_VERSION IWLWIFI_VERSION VD
|
||||
|
||||
MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/**
|
||||
* struct iwl_drv - drv common data
|
||||
* @list: list of drv structures using this opmode
|
||||
* @fw: the iwl_fw structure
|
||||
* @op_mode: the running op_mode
|
||||
* @trans: transport layer
|
||||
|
@ -89,6 +114,7 @@
|
|||
* @request_firmware_complete: the firmware has been obtained from user space
|
||||
*/
|
||||
struct iwl_drv {
|
||||
struct list_head list;
|
||||
struct iwl_fw fw;
|
||||
|
||||
struct iwl_op_mode *op_mode;
|
||||
|
@ -102,7 +128,17 @@ struct iwl_drv {
|
|||
struct completion request_firmware_complete;
|
||||
};
|
||||
|
||||
#define DVM_OP_MODE 0
|
||||
#define MVM_OP_MODE 1
|
||||
|
||||
static struct iwlwifi_opmode_table {
|
||||
const char *name; /* name: iwldvm, iwlmvm, etc */
|
||||
const struct iwl_op_mode_ops *ops; /* pointer to op_mode ops */
|
||||
struct list_head drv; /* list of devices using this op_mode */
|
||||
} iwlwifi_opmode_table[] = { /* ops set when driver is initialized */
|
||||
{ .name = "iwldvm", .ops = NULL },
|
||||
{ .name = "iwlmvm", .ops = NULL },
|
||||
};
|
||||
|
||||
/*
|
||||
* struct fw_sec: Just for the image parsing proccess.
|
||||
|
@ -721,7 +757,6 @@ static int validate_sec_sizes(struct iwl_drv *drv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* iwl_ucode_callback - callback when firmware was loaded
|
||||
*
|
||||
|
@ -733,6 +768,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
|||
struct iwl_drv *drv = context;
|
||||
struct iwl_fw *fw = &drv->fw;
|
||||
struct iwl_ucode_header *ucode;
|
||||
struct iwlwifi_opmode_table *op;
|
||||
int err;
|
||||
struct iwl_firmware_pieces pieces;
|
||||
const unsigned int api_max = drv->cfg->ucode_api_max;
|
||||
|
@ -862,10 +898,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
|||
/* We have our copies now, allow OS release its copies */
|
||||
release_firmware(ucode_raw);
|
||||
|
||||
drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw);
|
||||
op = &iwlwifi_opmode_table[DVM_OP_MODE];
|
||||
|
||||
if (!drv->op_mode)
|
||||
goto out_unbind;
|
||||
/* add this device to the list of devices using this op_mode */
|
||||
list_add_tail(&drv->list, &op->drv);
|
||||
|
||||
if (op->ops) {
|
||||
const struct iwl_op_mode_ops *ops = op->ops;
|
||||
drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw);
|
||||
|
||||
if (!drv->op_mode)
|
||||
goto out_unbind;
|
||||
} else {
|
||||
request_module_nowait("%s", op->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Complete the firmware request last so that
|
||||
|
@ -943,6 +989,67 @@ struct iwl_mod_params iwlwifi_mod_params = {
|
|||
.auto_agg = true,
|
||||
/* the rest are 0 by default */
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(iwlwifi_mod_params);
|
||||
|
||||
int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
|
||||
{
|
||||
int i;
|
||||
struct iwl_drv *drv;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
|
||||
if (strcmp(iwlwifi_opmode_table[i].name, name))
|
||||
continue;
|
||||
iwlwifi_opmode_table[i].ops = ops;
|
||||
list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list)
|
||||
drv->op_mode = ops->start(drv->trans, drv->cfg,
|
||||
&drv->fw);
|
||||
return 0;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_opmode_register);
|
||||
|
||||
void iwl_opmode_deregister(const char *name)
|
||||
{
|
||||
int i;
|
||||
struct iwl_drv *drv;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
|
||||
if (strcmp(iwlwifi_opmode_table[i].name, name))
|
||||
continue;
|
||||
iwlwifi_opmode_table[i].ops = NULL;
|
||||
|
||||
/* call the stop routine for all devices */
|
||||
list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) {
|
||||
if (drv->op_mode) {
|
||||
iwl_op_mode_stop(drv->op_mode);
|
||||
drv->op_mode = NULL;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_opmode_deregister);
|
||||
|
||||
static int __init iwl_drv_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++)
|
||||
INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv);
|
||||
|
||||
pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
|
||||
pr_info(DRV_COPYRIGHT "\n");
|
||||
|
||||
return iwl_pci_register_driver();
|
||||
}
|
||||
module_init(iwl_drv_init);
|
||||
|
||||
static void __exit iwl_drv_exit(void)
|
||||
{
|
||||
iwl_pci_unregister_driver();
|
||||
}
|
||||
module_exit(iwl_drv_exit);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
module_param_named(debug, iwlwifi_mod_params.debug_level, uint,
|
||||
|
|
|
@ -0,0 +1,900 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called LICENSE.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include "iwl-modparams.h"
|
||||
#include "iwl-eeprom-parse.h"
|
||||
|
||||
/* EEPROM offset definitions */
|
||||
|
||||
/* indirect access definitions */
|
||||
#define ADDRESS_MSK 0x0000FFFF
|
||||
#define INDIRECT_TYPE_MSK 0x000F0000
|
||||
#define INDIRECT_HOST 0x00010000
|
||||
#define INDIRECT_GENERAL 0x00020000
|
||||
#define INDIRECT_REGULATORY 0x00030000
|
||||
#define INDIRECT_CALIBRATION 0x00040000
|
||||
#define INDIRECT_PROCESS_ADJST 0x00050000
|
||||
#define INDIRECT_OTHERS 0x00060000
|
||||
#define INDIRECT_TXP_LIMIT 0x00070000
|
||||
#define INDIRECT_TXP_LIMIT_SIZE 0x00080000
|
||||
#define INDIRECT_ADDRESS 0x00100000
|
||||
|
||||
/* corresponding link offsets in EEPROM */
|
||||
#define EEPROM_LINK_HOST (2*0x64)
|
||||
#define EEPROM_LINK_GENERAL (2*0x65)
|
||||
#define EEPROM_LINK_REGULATORY (2*0x66)
|
||||
#define EEPROM_LINK_CALIBRATION (2*0x67)
|
||||
#define EEPROM_LINK_PROCESS_ADJST (2*0x68)
|
||||
#define EEPROM_LINK_OTHERS (2*0x69)
|
||||
#define EEPROM_LINK_TXP_LIMIT (2*0x6a)
|
||||
#define EEPROM_LINK_TXP_LIMIT_SIZE (2*0x6b)
|
||||
|
||||
/* General */
|
||||
#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */
|
||||
#define EEPROM_SUBSYSTEM_ID (2*0x0A) /* 2 bytes */
|
||||
#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */
|
||||
#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */
|
||||
#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
|
||||
#define EEPROM_VERSION (2*0x44) /* 2 bytes */
|
||||
#define EEPROM_SKU_CAP (2*0x45) /* 2 bytes */
|
||||
#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
|
||||
#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */
|
||||
#define EEPROM_NUM_MAC_ADDRESS (2*0x4C) /* 2 bytes */
|
||||
|
||||
/* calibration */
|
||||
struct iwl_eeprom_calib_hdr {
|
||||
u8 version;
|
||||
u8 pa_type;
|
||||
__le16 voltage;
|
||||
} __packed;
|
||||
|
||||
#define EEPROM_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
|
||||
#define EEPROM_XTAL ((2*0x128) | EEPROM_CALIB_ALL)
|
||||
|
||||
/* temperature */
|
||||
#define EEPROM_KELVIN_TEMPERATURE ((2*0x12A) | EEPROM_CALIB_ALL)
|
||||
#define EEPROM_RAW_TEMPERATURE ((2*0x12B) | EEPROM_CALIB_ALL)
|
||||
|
||||
/*
|
||||
* EEPROM bands
|
||||
* These are the channel numbers from each band in the order
|
||||
* that they are stored in the EEPROM band information. Note
|
||||
* that EEPROM bands aren't the same as mac80211 bands, and
|
||||
* there are even special "ht40 bands" in the EEPROM.
|
||||
*/
|
||||
static const u8 iwl_eeprom_band_1[14] = { /* 2.4 GHz */
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
};
|
||||
|
||||
static const u8 iwl_eeprom_band_2[] = { /* 4915-5080MHz */
|
||||
183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
|
||||
};
|
||||
|
||||
static const u8 iwl_eeprom_band_3[] = { /* 5170-5320MHz */
|
||||
34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
|
||||
};
|
||||
|
||||
static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */
|
||||
100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
|
||||
};
|
||||
|
||||
static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */
|
||||
145, 149, 153, 157, 161, 165
|
||||
};
|
||||
|
||||
static const u8 iwl_eeprom_band_6[] = { /* 2.4 ht40 channel */
|
||||
1, 2, 3, 4, 5, 6, 7
|
||||
};
|
||||
|
||||
static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */
|
||||
36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
|
||||
};
|
||||
|
||||
#define IWL_NUM_CHANNELS (ARRAY_SIZE(iwl_eeprom_band_1) + \
|
||||
ARRAY_SIZE(iwl_eeprom_band_2) + \
|
||||
ARRAY_SIZE(iwl_eeprom_band_3) + \
|
||||
ARRAY_SIZE(iwl_eeprom_band_4) + \
|
||||
ARRAY_SIZE(iwl_eeprom_band_5))
|
||||
|
||||
/* rate data (static) */
|
||||
static struct ieee80211_rate iwl_cfg80211_rates[] = {
|
||||
{ .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
|
||||
{ .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
|
||||
.flags = IEEE80211_RATE_SHORT_PREAMBLE, },
|
||||
{ .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
|
||||
.flags = IEEE80211_RATE_SHORT_PREAMBLE, },
|
||||
{ .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
|
||||
.flags = IEEE80211_RATE_SHORT_PREAMBLE, },
|
||||
{ .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
|
||||
{ .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
|
||||
{ .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
|
||||
{ .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
|
||||
{ .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
|
||||
{ .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
|
||||
{ .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
|
||||
{ .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
|
||||
};
|
||||
#define RATES_24_OFFS 0
|
||||
#define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates)
|
||||
#define RATES_52_OFFS 4
|
||||
#define N_RATES_52 (N_RATES_24 - RATES_52_OFFS)
|
||||
|
||||
/* EEPROM reading functions */
|
||||
|
||||
static u16 iwl_eeprom_query16(const u8 *eeprom, size_t eeprom_size, int offset)
|
||||
{
|
||||
if (WARN_ON(offset + sizeof(u16) > eeprom_size))
|
||||
return 0;
|
||||
return le16_to_cpup((__le16 *)(eeprom + offset));
|
||||
}
|
||||
|
||||
static u32 eeprom_indirect_address(const u8 *eeprom, size_t eeprom_size,
|
||||
u32 address)
|
||||
{
|
||||
u16 offset = 0;
|
||||
|
||||
if ((address & INDIRECT_ADDRESS) == 0)
|
||||
return address;
|
||||
|
||||
switch (address & INDIRECT_TYPE_MSK) {
|
||||
case INDIRECT_HOST:
|
||||
offset = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_LINK_HOST);
|
||||
break;
|
||||
case INDIRECT_GENERAL:
|
||||
offset = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_LINK_GENERAL);
|
||||
break;
|
||||
case INDIRECT_REGULATORY:
|
||||
offset = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_LINK_REGULATORY);
|
||||
break;
|
||||
case INDIRECT_TXP_LIMIT:
|
||||
offset = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_LINK_TXP_LIMIT);
|
||||
break;
|
||||
case INDIRECT_TXP_LIMIT_SIZE:
|
||||
offset = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_LINK_TXP_LIMIT_SIZE);
|
||||
break;
|
||||
case INDIRECT_CALIBRATION:
|
||||
offset = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_LINK_CALIBRATION);
|
||||
break;
|
||||
case INDIRECT_PROCESS_ADJST:
|
||||
offset = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_LINK_PROCESS_ADJST);
|
||||
break;
|
||||
case INDIRECT_OTHERS:
|
||||
offset = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_LINK_OTHERS);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* translate the offset from words to byte */
|
||||
return (address & ADDRESS_MSK) + (offset << 1);
|
||||
}
|
||||
|
||||
static const u8 *iwl_eeprom_query_addr(const u8 *eeprom, size_t eeprom_size,
|
||||
u32 offset)
|
||||
{
|
||||
u32 address = eeprom_indirect_address(eeprom, eeprom_size, offset);
|
||||
|
||||
if (WARN_ON(address >= eeprom_size))
|
||||
return NULL;
|
||||
|
||||
return &eeprom[address];
|
||||
}
|
||||
|
||||
static int iwl_eeprom_read_calib(const u8 *eeprom, size_t eeprom_size,
|
||||
struct iwl_eeprom_data *data)
|
||||
{
|
||||
struct iwl_eeprom_calib_hdr *hdr;
|
||||
|
||||
hdr = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size,
|
||||
EEPROM_CALIB_ALL);
|
||||
if (!hdr)
|
||||
return -ENODATA;
|
||||
data->calib_version = hdr->version;
|
||||
data->calib_voltage = hdr->voltage;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* enum iwl_eeprom_channel_flags - channel flags in EEPROM
|
||||
* @EEPROM_CHANNEL_VALID: channel is usable for this SKU/geo
|
||||
* @EEPROM_CHANNEL_IBSS: usable as an IBSS channel
|
||||
* @EEPROM_CHANNEL_ACTIVE: active scanning allowed
|
||||
* @EEPROM_CHANNEL_RADAR: radar detection required
|
||||
* @EEPROM_CHANNEL_WIDE: 20 MHz channel okay (?)
|
||||
* @EEPROM_CHANNEL_DFS: dynamic freq selection candidate
|
||||
*/
|
||||
enum iwl_eeprom_channel_flags {
|
||||
EEPROM_CHANNEL_VALID = BIT(0),
|
||||
EEPROM_CHANNEL_IBSS = BIT(1),
|
||||
EEPROM_CHANNEL_ACTIVE = BIT(3),
|
||||
EEPROM_CHANNEL_RADAR = BIT(4),
|
||||
EEPROM_CHANNEL_WIDE = BIT(5),
|
||||
EEPROM_CHANNEL_DFS = BIT(7),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_eeprom_channel - EEPROM channel data
|
||||
* @flags: %EEPROM_CHANNEL_* flags
|
||||
* @max_power_avg: max power (in dBm) on this channel, at most 31 dBm
|
||||
*/
|
||||
struct iwl_eeprom_channel {
|
||||
u8 flags;
|
||||
s8 max_power_avg;
|
||||
} __packed;
|
||||
|
||||
|
||||
enum iwl_eeprom_enhanced_txpwr_flags {
|
||||
IWL_EEPROM_ENH_TXP_FL_VALID = BIT(0),
|
||||
IWL_EEPROM_ENH_TXP_FL_BAND_52G = BIT(1),
|
||||
IWL_EEPROM_ENH_TXP_FL_OFDM = BIT(2),
|
||||
IWL_EEPROM_ENH_TXP_FL_40MHZ = BIT(3),
|
||||
IWL_EEPROM_ENH_TXP_FL_HT_AP = BIT(4),
|
||||
IWL_EEPROM_ENH_TXP_FL_RES1 = BIT(5),
|
||||
IWL_EEPROM_ENH_TXP_FL_RES2 = BIT(6),
|
||||
IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE = BIT(7),
|
||||
};
|
||||
|
||||
/**
|
||||
* iwl_eeprom_enhanced_txpwr structure
|
||||
* @flags: entry flags
|
||||
* @channel: channel number
|
||||
* @chain_a_max_pwr: chain a max power in 1/2 dBm
|
||||
* @chain_b_max_pwr: chain b max power in 1/2 dBm
|
||||
* @chain_c_max_pwr: chain c max power in 1/2 dBm
|
||||
* @delta_20_in_40: 20-in-40 deltas (hi/lo)
|
||||
* @mimo2_max_pwr: mimo2 max power in 1/2 dBm
|
||||
* @mimo3_max_pwr: mimo3 max power in 1/2 dBm
|
||||
*
|
||||
* This structure presents the enhanced regulatory tx power limit layout
|
||||
* in an EEPROM image.
|
||||
*/
|
||||
struct iwl_eeprom_enhanced_txpwr {
|
||||
u8 flags;
|
||||
u8 channel;
|
||||
s8 chain_a_max;
|
||||
s8 chain_b_max;
|
||||
s8 chain_c_max;
|
||||
u8 delta_20_in_40;
|
||||
s8 mimo2_max;
|
||||
s8 mimo3_max;
|
||||
} __packed;
|
||||
|
||||
static s8 iwl_get_max_txpwr_half_dbm(const struct iwl_eeprom_data *data,
|
||||
struct iwl_eeprom_enhanced_txpwr *txp)
|
||||
{
|
||||
s8 result = 0; /* (.5 dBm) */
|
||||
|
||||
/* Take the highest tx power from any valid chains */
|
||||
if (data->valid_tx_ant & ANT_A && txp->chain_a_max > result)
|
||||
result = txp->chain_a_max;
|
||||
|
||||
if (data->valid_tx_ant & ANT_B && txp->chain_b_max > result)
|
||||
result = txp->chain_b_max;
|
||||
|
||||
if (data->valid_tx_ant & ANT_C && txp->chain_c_max > result)
|
||||
result = txp->chain_c_max;
|
||||
|
||||
if ((data->valid_tx_ant == ANT_AB ||
|
||||
data->valid_tx_ant == ANT_BC ||
|
||||
data->valid_tx_ant == ANT_AC) && txp->mimo2_max > result)
|
||||
result = txp->mimo2_max;
|
||||
|
||||
if (data->valid_tx_ant == ANT_ABC && txp->mimo3_max > result)
|
||||
result = txp->mimo3_max;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
|
||||
#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
|
||||
#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
|
||||
|
||||
#define TXP_CHECK_AND_PRINT(x) \
|
||||
((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) ? # x " " : "")
|
||||
|
||||
static void
|
||||
iwl_eeprom_enh_txp_read_element(struct iwl_eeprom_data *data,
|
||||
struct iwl_eeprom_enhanced_txpwr *txp,
|
||||
int n_channels, s8 max_txpower_avg)
|
||||
{
|
||||
int ch_idx;
|
||||
enum ieee80211_band band;
|
||||
|
||||
band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
|
||||
IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
|
||||
|
||||
for (ch_idx = 0; ch_idx < n_channels; ch_idx++) {
|
||||
struct ieee80211_channel *chan = &data->channels[ch_idx];
|
||||
|
||||
/* update matching channel or from common data only */
|
||||
if (txp->channel != 0 && chan->hw_value != txp->channel)
|
||||
continue;
|
||||
|
||||
/* update matching band only */
|
||||
if (band != chan->band)
|
||||
continue;
|
||||
|
||||
if (chan->max_power < max_txpower_avg &&
|
||||
!(txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ))
|
||||
chan->max_power = max_txpower_avg;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_eeprom_enhanced_txpower(struct device *dev,
|
||||
struct iwl_eeprom_data *data,
|
||||
const u8 *eeprom, size_t eeprom_size,
|
||||
int n_channels)
|
||||
{
|
||||
struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
|
||||
int idx, entries;
|
||||
__le16 *txp_len;
|
||||
s8 max_txp_avg_halfdbm;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
|
||||
|
||||
/* the length is in 16-bit words, but we want entries */
|
||||
txp_len = (__le16 *)iwl_eeprom_query_addr(eeprom, eeprom_size,
|
||||
EEPROM_TXP_SZ_OFFS);
|
||||
entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
|
||||
|
||||
txp_array = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size,
|
||||
EEPROM_TXP_OFFS);
|
||||
|
||||
for (idx = 0; idx < entries; idx++) {
|
||||
txp = &txp_array[idx];
|
||||
/* skip invalid entries */
|
||||
if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
|
||||
continue;
|
||||
|
||||
IWL_DEBUG_EEPROM(dev, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
|
||||
(txp->channel && (txp->flags &
|
||||
IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
|
||||
"Common " : (txp->channel) ?
|
||||
"Channel" : "Common",
|
||||
(txp->channel),
|
||||
TXP_CHECK_AND_PRINT(VALID),
|
||||
TXP_CHECK_AND_PRINT(BAND_52G),
|
||||
TXP_CHECK_AND_PRINT(OFDM),
|
||||
TXP_CHECK_AND_PRINT(40MHZ),
|
||||
TXP_CHECK_AND_PRINT(HT_AP),
|
||||
TXP_CHECK_AND_PRINT(RES1),
|
||||
TXP_CHECK_AND_PRINT(RES2),
|
||||
TXP_CHECK_AND_PRINT(COMMON_TYPE),
|
||||
txp->flags);
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"\t\t chain_A: 0x%02x chain_B: 0X%02x chain_C: 0X%02x\n",
|
||||
txp->chain_a_max, txp->chain_b_max,
|
||||
txp->chain_c_max);
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"\t\t MIMO2: 0x%02x MIMO3: 0x%02x High 20_on_40: 0x%02x Low 20_on_40: 0x%02x\n",
|
||||
txp->mimo2_max, txp->mimo3_max,
|
||||
((txp->delta_20_in_40 & 0xf0) >> 4),
|
||||
(txp->delta_20_in_40 & 0x0f));
|
||||
|
||||
max_txp_avg_halfdbm = iwl_get_max_txpwr_half_dbm(data, txp);
|
||||
|
||||
iwl_eeprom_enh_txp_read_element(data, txp, n_channels,
|
||||
DIV_ROUND_UP(max_txp_avg_halfdbm, 2));
|
||||
|
||||
if (max_txp_avg_halfdbm > data->max_tx_pwr_half_dbm)
|
||||
data->max_tx_pwr_half_dbm = max_txp_avg_halfdbm;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_init_band_reference(const struct iwl_cfg *cfg,
|
||||
const u8 *eeprom, size_t eeprom_size,
|
||||
int eeprom_band, int *eeprom_ch_count,
|
||||
const struct iwl_eeprom_channel **ch_info,
|
||||
const u8 **eeprom_ch_array)
|
||||
{
|
||||
u32 offset = cfg->eeprom_params->regulatory_bands[eeprom_band - 1];
|
||||
|
||||
offset |= INDIRECT_ADDRESS | INDIRECT_REGULATORY;
|
||||
|
||||
*ch_info = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size, offset);
|
||||
|
||||
switch (eeprom_band) {
|
||||
case 1: /* 2.4GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
|
||||
*eeprom_ch_array = iwl_eeprom_band_1;
|
||||
break;
|
||||
case 2: /* 4.9GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
|
||||
*eeprom_ch_array = iwl_eeprom_band_2;
|
||||
break;
|
||||
case 3: /* 5.2GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
|
||||
*eeprom_ch_array = iwl_eeprom_band_3;
|
||||
break;
|
||||
case 4: /* 5.5GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
|
||||
*eeprom_ch_array = iwl_eeprom_band_4;
|
||||
break;
|
||||
case 5: /* 5.7GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
|
||||
*eeprom_ch_array = iwl_eeprom_band_5;
|
||||
break;
|
||||
case 6: /* 2.4GHz ht40 channels */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
|
||||
*eeprom_ch_array = iwl_eeprom_band_6;
|
||||
break;
|
||||
case 7: /* 5 GHz ht40 channels */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
|
||||
*eeprom_ch_array = iwl_eeprom_band_7;
|
||||
break;
|
||||
default:
|
||||
*eeprom_ch_count = 0;
|
||||
*eeprom_ch_array = NULL;
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_AND_PRINT(x) \
|
||||
((eeprom_ch->flags & EEPROM_CHANNEL_##x) ? # x " " : "")
|
||||
|
||||
static void iwl_mod_ht40_chan_info(struct device *dev,
|
||||
struct iwl_eeprom_data *data, int n_channels,
|
||||
enum ieee80211_band band, u16 channel,
|
||||
const struct iwl_eeprom_channel *eeprom_ch,
|
||||
u8 clear_ht40_extension_channel)
|
||||
{
|
||||
struct ieee80211_channel *chan = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
if (data->channels[i].band != band)
|
||||
continue;
|
||||
if (data->channels[i].hw_value != channel)
|
||||
continue;
|
||||
chan = &data->channels[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!chan)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
|
||||
channel,
|
||||
band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4",
|
||||
CHECK_AND_PRINT(IBSS),
|
||||
CHECK_AND_PRINT(ACTIVE),
|
||||
CHECK_AND_PRINT(RADAR),
|
||||
CHECK_AND_PRINT(WIDE),
|
||||
CHECK_AND_PRINT(DFS),
|
||||
eeprom_ch->flags,
|
||||
eeprom_ch->max_power_avg,
|
||||
((eeprom_ch->flags & EEPROM_CHANNEL_IBSS) &&
|
||||
!(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? ""
|
||||
: "not ");
|
||||
|
||||
if (eeprom_ch->flags & EEPROM_CHANNEL_VALID)
|
||||
chan->flags &= ~clear_ht40_extension_channel;
|
||||
}
|
||||
|
||||
#define CHECK_AND_PRINT_I(x) \
|
||||
((eeprom_ch_info[ch_idx].flags & EEPROM_CHANNEL_##x) ? # x " " : "")
|
||||
|
||||
static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
||||
struct iwl_eeprom_data *data,
|
||||
const u8 *eeprom, size_t eeprom_size)
|
||||
{
|
||||
int band, ch_idx;
|
||||
const struct iwl_eeprom_channel *eeprom_ch_info;
|
||||
const u8 *eeprom_ch_array;
|
||||
int eeprom_ch_count;
|
||||
int n_channels = 0;
|
||||
|
||||
/*
|
||||
* Loop through the 5 EEPROM bands and add them to the parse list
|
||||
*/
|
||||
for (band = 1; band <= 5; band++) {
|
||||
struct ieee80211_channel *channel;
|
||||
|
||||
iwl_init_band_reference(cfg, eeprom, eeprom_size, band,
|
||||
&eeprom_ch_count, &eeprom_ch_info,
|
||||
&eeprom_ch_array);
|
||||
|
||||
/* Loop through each band adding each of the channels */
|
||||
for (ch_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) {
|
||||
const struct iwl_eeprom_channel *eeprom_ch;
|
||||
|
||||
eeprom_ch = &eeprom_ch_info[ch_idx];
|
||||
|
||||
if (!(eeprom_ch->flags & EEPROM_CHANNEL_VALID)) {
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"Ch. %d Flags %x [%sGHz] - No traffic\n",
|
||||
eeprom_ch_array[ch_idx],
|
||||
eeprom_ch_info[ch_idx].flags,
|
||||
(band != 1) ? "5.2" : "2.4");
|
||||
continue;
|
||||
}
|
||||
|
||||
channel = &data->channels[n_channels];
|
||||
n_channels++;
|
||||
|
||||
channel->hw_value = eeprom_ch_array[ch_idx];
|
||||
channel->band = (band == 1) ? IEEE80211_BAND_2GHZ
|
||||
: IEEE80211_BAND_5GHZ;
|
||||
channel->center_freq =
|
||||
ieee80211_channel_to_frequency(
|
||||
channel->hw_value, channel->band);
|
||||
|
||||
/* set no-HT40, will enable as appropriate later */
|
||||
channel->flags = IEEE80211_CHAN_NO_HT40;
|
||||
|
||||
if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS))
|
||||
channel->flags |= IEEE80211_CHAN_NO_IBSS;
|
||||
|
||||
if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE))
|
||||
channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
|
||||
|
||||
if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR)
|
||||
channel->flags |= IEEE80211_CHAN_RADAR;
|
||||
|
||||
/* Initialize regulatory-based run-time data */
|
||||
channel->max_power =
|
||||
eeprom_ch_info[ch_idx].max_power_avg;
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
|
||||
channel->hw_value,
|
||||
(band != 1) ? "5.2" : "2.4",
|
||||
CHECK_AND_PRINT_I(VALID),
|
||||
CHECK_AND_PRINT_I(IBSS),
|
||||
CHECK_AND_PRINT_I(ACTIVE),
|
||||
CHECK_AND_PRINT_I(RADAR),
|
||||
CHECK_AND_PRINT_I(WIDE),
|
||||
CHECK_AND_PRINT_I(DFS),
|
||||
eeprom_ch_info[ch_idx].flags,
|
||||
eeprom_ch_info[ch_idx].max_power_avg,
|
||||
((eeprom_ch_info[ch_idx].flags &
|
||||
EEPROM_CHANNEL_IBSS) &&
|
||||
!(eeprom_ch_info[ch_idx].flags &
|
||||
EEPROM_CHANNEL_RADAR))
|
||||
? "" : "not ");
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->eeprom_params->enhanced_txpower) {
|
||||
/*
|
||||
* for newer device (6000 series and up)
|
||||
* EEPROM contain enhanced tx power information
|
||||
* driver need to process addition information
|
||||
* to determine the max channel tx power limits
|
||||
*/
|
||||
iwl_eeprom_enhanced_txpower(dev, data, eeprom, eeprom_size,
|
||||
n_channels);
|
||||
} else {
|
||||
/* All others use data from channel map */
|
||||
int i;
|
||||
|
||||
data->max_tx_pwr_half_dbm = -128;
|
||||
|
||||
for (i = 0; i < n_channels; i++)
|
||||
data->max_tx_pwr_half_dbm =
|
||||
max_t(s8, data->max_tx_pwr_half_dbm,
|
||||
data->channels[i].max_power * 2);
|
||||
}
|
||||
|
||||
/* Check if we do have HT40 channels */
|
||||
if (cfg->eeprom_params->regulatory_bands[5] ==
|
||||
EEPROM_REGULATORY_BAND_NO_HT40 &&
|
||||
cfg->eeprom_params->regulatory_bands[6] ==
|
||||
EEPROM_REGULATORY_BAND_NO_HT40)
|
||||
return n_channels;
|
||||
|
||||
/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
|
||||
for (band = 6; band <= 7; band++) {
|
||||
enum ieee80211_band ieeeband;
|
||||
|
||||
iwl_init_band_reference(cfg, eeprom, eeprom_size, band,
|
||||
&eeprom_ch_count, &eeprom_ch_info,
|
||||
&eeprom_ch_array);
|
||||
|
||||
/* EEPROM band 6 is 2.4, band 7 is 5 GHz */
|
||||
ieeeband = (band == 6) ? IEEE80211_BAND_2GHZ
|
||||
: IEEE80211_BAND_5GHZ;
|
||||
|
||||
/* Loop through each band adding each of the channels */
|
||||
for (ch_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) {
|
||||
/* Set up driver's info for lower half */
|
||||
iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband,
|
||||
eeprom_ch_array[ch_idx],
|
||||
&eeprom_ch_info[ch_idx],
|
||||
IEEE80211_CHAN_NO_HT40PLUS);
|
||||
|
||||
/* Set up driver's info for upper half */
|
||||
iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband,
|
||||
eeprom_ch_array[ch_idx] + 4,
|
||||
&eeprom_ch_info[ch_idx],
|
||||
IEEE80211_CHAN_NO_HT40MINUS);
|
||||
}
|
||||
}
|
||||
|
||||
return n_channels;
|
||||
}
|
||||
|
||||
static int iwl_init_sband_channels(struct iwl_eeprom_data *data,
|
||||
struct ieee80211_supported_band *sband,
|
||||
int n_channels, enum ieee80211_band band)
|
||||
{
|
||||
struct ieee80211_channel *chan = &data->channels[0];
|
||||
int n = 0, idx = 0;
|
||||
|
||||
while (chan->band != band && idx < n_channels)
|
||||
chan = &data->channels[++idx];
|
||||
|
||||
sband->channels = &data->channels[idx];
|
||||
|
||||
while (chan->band == band && idx < n_channels) {
|
||||
chan = &data->channels[++idx];
|
||||
n++;
|
||||
}
|
||||
|
||||
sband->n_channels = n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
|
||||
#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
|
||||
|
||||
static void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
|
||||
struct iwl_eeprom_data *data,
|
||||
struct ieee80211_sta_ht_cap *ht_info,
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
int max_bit_rate = 0;
|
||||
u8 rx_chains;
|
||||
u8 tx_chains;
|
||||
|
||||
tx_chains = hweight8(data->valid_tx_ant);
|
||||
if (cfg->rx_with_siso_diversity)
|
||||
rx_chains = 1;
|
||||
else
|
||||
rx_chains = hweight8(data->valid_rx_ant);
|
||||
|
||||
if (!(data->sku & EEPROM_SKU_CAP_11N_ENABLE) || !cfg->ht_params) {
|
||||
ht_info->ht_supported = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ht_info->ht_supported = true;
|
||||
ht_info->cap = 0;
|
||||
|
||||
if (iwlwifi_mod_params.amsdu_size_8K)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
|
||||
|
||||
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
||||
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
|
||||
|
||||
ht_info->mcs.rx_mask[0] = 0xFF;
|
||||
if (rx_chains >= 2)
|
||||
ht_info->mcs.rx_mask[1] = 0xFF;
|
||||
if (rx_chains >= 3)
|
||||
ht_info->mcs.rx_mask[2] = 0xFF;
|
||||
|
||||
if (cfg->ht_params->ht_greenfield_support)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
||||
|
||||
max_bit_rate = MAX_BIT_RATE_20_MHZ;
|
||||
|
||||
if (cfg->ht_params->ht40_bands & BIT(band)) {
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
|
||||
ht_info->mcs.rx_mask[4] = 0x01;
|
||||
max_bit_rate = MAX_BIT_RATE_40_MHZ;
|
||||
}
|
||||
|
||||
/* Highest supported Rx data rate */
|
||||
max_bit_rate *= rx_chains;
|
||||
WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
|
||||
ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
|
||||
|
||||
/* Tx MCS capabilities */
|
||||
ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
|
||||
if (tx_chains != rx_chains) {
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
|
||||
ht_info->mcs.tx_params |= ((tx_chains - 1) <<
|
||||
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
|
||||
struct iwl_eeprom_data *data,
|
||||
const u8 *eeprom, size_t eeprom_size)
|
||||
{
|
||||
int n_channels = iwl_init_channel_map(dev, cfg, data,
|
||||
eeprom, eeprom_size);
|
||||
int n_used = 0;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sband = &data->bands[IEEE80211_BAND_2GHZ];
|
||||
sband->band = IEEE80211_BAND_2GHZ;
|
||||
sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
|
||||
sband->n_bitrates = N_RATES_24;
|
||||
n_used += iwl_init_sband_channels(data, sband, n_channels,
|
||||
IEEE80211_BAND_2GHZ);
|
||||
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ);
|
||||
|
||||
sband = &data->bands[IEEE80211_BAND_5GHZ];
|
||||
sband->band = IEEE80211_BAND_5GHZ;
|
||||
sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
|
||||
sband->n_bitrates = N_RATES_52;
|
||||
n_used += iwl_init_sband_channels(data, sband, n_channels,
|
||||
IEEE80211_BAND_5GHZ);
|
||||
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
|
||||
|
||||
if (n_channels != n_used)
|
||||
IWL_ERR_DEV(dev, "EEPROM: used only %d of %d channels\n",
|
||||
n_used, n_channels);
|
||||
}
|
||||
|
||||
/* EEPROM data functions */
|
||||
|
||||
struct iwl_eeprom_data *
|
||||
iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
const u8 *eeprom, size_t eeprom_size)
|
||||
{
|
||||
struct iwl_eeprom_data *data;
|
||||
const void *tmp;
|
||||
|
||||
if (WARN_ON(!cfg || !cfg->eeprom_params))
|
||||
return NULL;
|
||||
|
||||
data = kzalloc(sizeof(*data) +
|
||||
sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
/* get MAC address(es) */
|
||||
tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, EEPROM_MAC_ADDRESS);
|
||||
if (!tmp)
|
||||
goto err_free;
|
||||
memcpy(data->hw_addr, tmp, ETH_ALEN);
|
||||
data->n_hw_addrs = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_NUM_MAC_ADDRESS);
|
||||
|
||||
if (iwl_eeprom_read_calib(eeprom, eeprom_size, data))
|
||||
goto err_free;
|
||||
|
||||
tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, EEPROM_XTAL);
|
||||
if (!tmp)
|
||||
goto err_free;
|
||||
memcpy(data->xtal_calib, tmp, sizeof(data->xtal_calib));
|
||||
|
||||
tmp = iwl_eeprom_query_addr(eeprom, eeprom_size,
|
||||
EEPROM_RAW_TEMPERATURE);
|
||||
if (!tmp)
|
||||
goto err_free;
|
||||
data->raw_temperature = *(__le16 *)tmp;
|
||||
|
||||
tmp = iwl_eeprom_query_addr(eeprom, eeprom_size,
|
||||
EEPROM_KELVIN_TEMPERATURE);
|
||||
if (!tmp)
|
||||
goto err_free;
|
||||
data->kelvin_temperature = *(__le16 *)tmp;
|
||||
data->kelvin_voltage = *((__le16 *)tmp + 1);
|
||||
|
||||
data->radio_cfg = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_RADIO_CONFIG);
|
||||
data->sku = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_SKU_CAP);
|
||||
data->eeprom_version = iwl_eeprom_query16(eeprom, eeprom_size,
|
||||
EEPROM_VERSION);
|
||||
|
||||
data->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(data->radio_cfg);
|
||||
data->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(data->radio_cfg);
|
||||
|
||||
/* check overrides (some devices have wrong EEPROM) */
|
||||
if (cfg->valid_tx_ant)
|
||||
data->valid_tx_ant = cfg->valid_tx_ant;
|
||||
if (cfg->valid_rx_ant)
|
||||
data->valid_rx_ant = cfg->valid_rx_ant;
|
||||
|
||||
if (!data->valid_tx_ant || !data->valid_rx_ant) {
|
||||
IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
|
||||
data->valid_tx_ant, data->valid_rx_ant);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
iwl_init_sbands(dev, cfg, data, eeprom, eeprom_size);
|
||||
|
||||
return data;
|
||||
err_free:
|
||||
kfree(data);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_parse_eeprom_data);
|
||||
|
||||
/* helper functions */
|
||||
int iwl_eeprom_check_version(struct iwl_eeprom_data *data,
|
||||
struct iwl_trans *trans)
|
||||
{
|
||||
if (data->eeprom_version >= trans->cfg->eeprom_ver ||
|
||||
data->calib_version >= trans->cfg->eeprom_calib_ver) {
|
||||
IWL_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n",
|
||||
data->eeprom_version, data->calib_version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
IWL_ERR(trans,
|
||||
"Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
|
||||
data->eeprom_version, trans->cfg->eeprom_ver,
|
||||
data->calib_version, trans->cfg->eeprom_calib_ver);
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_eeprom_check_version);
|
|
@ -0,0 +1,138 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called LICENSE.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
#ifndef __iwl_eeprom_parse_h__
|
||||
#define __iwl_eeprom_parse_h__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include "iwl-trans.h"
|
||||
|
||||
/* SKU Capabilities (actual values from EEPROM definition) */
|
||||
#define EEPROM_SKU_CAP_BAND_24GHZ (1 << 4)
|
||||
#define EEPROM_SKU_CAP_BAND_52GHZ (1 << 5)
|
||||
#define EEPROM_SKU_CAP_11N_ENABLE (1 << 6)
|
||||
#define EEPROM_SKU_CAP_AMT_ENABLE (1 << 7)
|
||||
#define EEPROM_SKU_CAP_IPAN_ENABLE (1 << 8)
|
||||
|
||||
/* radio config bits (actual values from EEPROM definition) */
|
||||
#define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */
|
||||
#define EEPROM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
|
||||
#define EEPROM_RF_CFG_DASH_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
|
||||
#define EEPROM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
|
||||
#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
|
||||
#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
|
||||
|
||||
struct iwl_eeprom_data {
|
||||
int n_hw_addrs;
|
||||
u8 hw_addr[ETH_ALEN];
|
||||
|
||||
u16 radio_config;
|
||||
|
||||
u8 calib_version;
|
||||
__le16 calib_voltage;
|
||||
|
||||
__le16 raw_temperature;
|
||||
__le16 kelvin_temperature;
|
||||
__le16 kelvin_voltage;
|
||||
__le16 xtal_calib[2];
|
||||
|
||||
u16 sku;
|
||||
u16 radio_cfg;
|
||||
u16 eeprom_version;
|
||||
s8 max_tx_pwr_half_dbm;
|
||||
|
||||
u8 valid_tx_ant, valid_rx_ant;
|
||||
|
||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||
struct ieee80211_channel channels[];
|
||||
};
|
||||
|
||||
/**
|
||||
* iwl_parse_eeprom_data - parse EEPROM data and return values
|
||||
*
|
||||
* @dev: device pointer we're parsing for, for debug only
|
||||
* @cfg: device configuration for parsing and overrides
|
||||
* @eeprom: the EEPROM data
|
||||
* @eeprom_size: length of the EEPROM data
|
||||
*
|
||||
* This function parses all EEPROM values we need and then
|
||||
* returns a (newly allocated) struct containing all the
|
||||
* relevant values for driver use. The struct must be freed
|
||||
* later with iwl_free_eeprom_data().
|
||||
*/
|
||||
struct iwl_eeprom_data *
|
||||
iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
const u8 *eeprom, size_t eeprom_size);
|
||||
|
||||
/**
|
||||
* iwl_free_eeprom_data - free EEPROM data
|
||||
* @data: the data to free
|
||||
*/
|
||||
static inline void iwl_free_eeprom_data(struct iwl_eeprom_data *data)
|
||||
{
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
int iwl_eeprom_check_version(struct iwl_eeprom_data *data,
|
||||
struct iwl_trans *trans);
|
||||
|
||||
#endif /* __iwl_eeprom_parse_h__ */
|
|
@ -0,0 +1,463 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called LICENSE.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-eeprom-read.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-csr.h"
|
||||
|
||||
/*
|
||||
* EEPROM access time values:
|
||||
*
|
||||
* Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG.
|
||||
* Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
|
||||
* When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
|
||||
* Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
|
||||
*/
|
||||
#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */
|
||||
|
||||
#define IWL_EEPROM_SEM_TIMEOUT 10 /* microseconds */
|
||||
#define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
|
||||
|
||||
|
||||
/*
|
||||
* The device's EEPROM semaphore prevents conflicts between driver and uCode
|
||||
* when accessing the EEPROM; each access is a series of pulses to/from the
|
||||
* EEPROM chip, not a single event, so even reads could conflict if they
|
||||
* weren't arbitrated by the semaphore.
|
||||
*/
|
||||
|
||||
#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */
|
||||
#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
|
||||
|
||||
static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans)
|
||||
{
|
||||
u16 count;
|
||||
int ret;
|
||||
|
||||
for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
|
||||
/* Request semaphore */
|
||||
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
|
||||
|
||||
/* See if we got it */
|
||||
ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
|
||||
EEPROM_SEM_TIMEOUT);
|
||||
if (ret >= 0) {
|
||||
IWL_DEBUG_EEPROM(trans->dev,
|
||||
"Acquired semaphore after %d tries.\n",
|
||||
count+1);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_eeprom_release_semaphore(struct iwl_trans *trans)
|
||||
{
|
||||
iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
|
||||
}
|
||||
|
||||
static int iwl_eeprom_verify_signature(struct iwl_trans *trans, bool nvm_is_otp)
|
||||
{
|
||||
u32 gp = iwl_read32(trans, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
|
||||
|
||||
IWL_DEBUG_EEPROM(trans->dev, "EEPROM signature=0x%08x\n", gp);
|
||||
|
||||
switch (gp) {
|
||||
case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
|
||||
if (!nvm_is_otp) {
|
||||
IWL_ERR(trans, "EEPROM with bad signature: 0x%08x\n",
|
||||
gp);
|
||||
return -ENOENT;
|
||||
}
|
||||
return 0;
|
||||
case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
|
||||
case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
|
||||
if (nvm_is_otp) {
|
||||
IWL_ERR(trans, "OTP with bad signature: 0x%08x\n", gp);
|
||||
return -ENOENT;
|
||||
}
|
||||
return 0;
|
||||
case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP:
|
||||
default:
|
||||
IWL_ERR(trans,
|
||||
"bad EEPROM/OTP signature, type=%s, EEPROM_GP=0x%08x\n",
|
||||
nvm_is_otp ? "OTP" : "EEPROM", gp);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OTP related functions
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static void iwl_set_otp_access_absolute(struct iwl_trans *trans)
|
||||
{
|
||||
iwl_read32(trans, CSR_OTP_GP_REG);
|
||||
|
||||
iwl_clear_bit(trans, CSR_OTP_GP_REG,
|
||||
CSR_OTP_GP_REG_OTP_ACCESS_MODE);
|
||||
}
|
||||
|
||||
static int iwl_nvm_is_otp(struct iwl_trans *trans)
|
||||
{
|
||||
u32 otpgp;
|
||||
|
||||
/* OTP only valid for CP/PP and after */
|
||||
switch (trans->hw_rev & CSR_HW_REV_TYPE_MSK) {
|
||||
case CSR_HW_REV_TYPE_NONE:
|
||||
IWL_ERR(trans, "Unknown hardware type\n");
|
||||
return -EIO;
|
||||
case CSR_HW_REV_TYPE_5300:
|
||||
case CSR_HW_REV_TYPE_5350:
|
||||
case CSR_HW_REV_TYPE_5100:
|
||||
case CSR_HW_REV_TYPE_5150:
|
||||
return 0;
|
||||
default:
|
||||
otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
|
||||
if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int iwl_init_otp_access(struct iwl_trans *trans)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Enable 40MHz radio clock */
|
||||
iwl_write32(trans, CSR_GP_CNTRL,
|
||||
iwl_read32(trans, CSR_GP_CNTRL) |
|
||||
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
|
||||
|
||||
/* wait for clock to be ready */
|
||||
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
||||
25000);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(trans, "Time out access OTP\n");
|
||||
} else {
|
||||
iwl_set_bits_prph(trans, APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_VAL_RESET_REQ);
|
||||
udelay(5);
|
||||
iwl_clear_bits_prph(trans, APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_VAL_RESET_REQ);
|
||||
|
||||
/*
|
||||
* CSR auto clock gate disable bit -
|
||||
* this is only applicable for HW with OTP shadow RAM
|
||||
*/
|
||||
if (trans->cfg->base_params->shadow_ram_support)
|
||||
iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
|
||||
CSR_RESET_LINK_PWR_MGMT_DISABLED);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr,
|
||||
__le16 *eeprom_data)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 r;
|
||||
u32 otpgp;
|
||||
|
||||
iwl_write32(trans, CSR_EEPROM_REG,
|
||||
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
|
||||
ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
|
||||
CSR_EEPROM_REG_READ_VALID_MSK,
|
||||
CSR_EEPROM_REG_READ_VALID_MSK,
|
||||
IWL_EEPROM_ACCESS_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(trans, "Time out reading OTP[%d]\n", addr);
|
||||
return ret;
|
||||
}
|
||||
r = iwl_read32(trans, CSR_EEPROM_REG);
|
||||
/* check for ECC errors: */
|
||||
otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
|
||||
if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
|
||||
/* stop in this case */
|
||||
/* set the uncorrectable OTP ECC bit for acknowledgement */
|
||||
iwl_set_bit(trans, CSR_OTP_GP_REG,
|
||||
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
|
||||
IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
|
||||
/* continue in this case */
|
||||
/* set the correctable OTP ECC bit for acknowledgement */
|
||||
iwl_set_bit(trans, CSR_OTP_GP_REG,
|
||||
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
|
||||
IWL_ERR(trans, "Correctable OTP ECC error, continue read\n");
|
||||
}
|
||||
*eeprom_data = cpu_to_le16(r >> 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* iwl_is_otp_empty: check for empty OTP
|
||||
*/
|
||||
static bool iwl_is_otp_empty(struct iwl_trans *trans)
|
||||
{
|
||||
u16 next_link_addr = 0;
|
||||
__le16 link_value;
|
||||
bool is_empty = false;
|
||||
|
||||
/* locate the beginning of OTP link list */
|
||||
if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) {
|
||||
if (!link_value) {
|
||||
IWL_ERR(trans, "OTP is empty\n");
|
||||
is_empty = true;
|
||||
}
|
||||
} else {
|
||||
IWL_ERR(trans, "Unable to read first block of OTP list.\n");
|
||||
is_empty = true;
|
||||
}
|
||||
|
||||
return is_empty;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* iwl_find_otp_image: find EEPROM image in OTP
|
||||
* finding the OTP block that contains the EEPROM image.
|
||||
* the last valid block on the link list (the block _before_ the last block)
|
||||
* is the block we should read and used to configure the device.
|
||||
* If all the available OTP blocks are full, the last block will be the block
|
||||
* we should read and used to configure the device.
|
||||
* only perform this operation if shadow RAM is disabled
|
||||
*/
|
||||
static int iwl_find_otp_image(struct iwl_trans *trans,
|
||||
u16 *validblockaddr)
|
||||
{
|
||||
u16 next_link_addr = 0, valid_addr;
|
||||
__le16 link_value = 0;
|
||||
int usedblocks = 0;
|
||||
|
||||
/* set addressing mode to absolute to traverse the link list */
|
||||
iwl_set_otp_access_absolute(trans);
|
||||
|
||||
/* checking for empty OTP or error */
|
||||
if (iwl_is_otp_empty(trans))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* start traverse link list
|
||||
* until reach the max number of OTP blocks
|
||||
* different devices have different number of OTP blocks
|
||||
*/
|
||||
do {
|
||||
/* save current valid block address
|
||||
* check for more block on the link list
|
||||
*/
|
||||
valid_addr = next_link_addr;
|
||||
next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
|
||||
IWL_DEBUG_EEPROM(trans->dev, "OTP blocks %d addr 0x%x\n",
|
||||
usedblocks, next_link_addr);
|
||||
if (iwl_read_otp_word(trans, next_link_addr, &link_value))
|
||||
return -EINVAL;
|
||||
if (!link_value) {
|
||||
/*
|
||||
* reach the end of link list, return success and
|
||||
* set address point to the starting address
|
||||
* of the image
|
||||
*/
|
||||
*validblockaddr = valid_addr;
|
||||
/* skip first 2 bytes (link list pointer) */
|
||||
*validblockaddr += 2;
|
||||
return 0;
|
||||
}
|
||||
/* more in the link list, continue */
|
||||
usedblocks++;
|
||||
} while (usedblocks <= trans->cfg->base_params->max_ll_items);
|
||||
|
||||
/* OTP has no valid blocks */
|
||||
IWL_DEBUG_EEPROM(trans->dev, "OTP has no valid blocks\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_read_eeprom - read EEPROM contents
|
||||
*
|
||||
* Load the EEPROM contents from adapter and return it
|
||||
* and its size.
|
||||
*
|
||||
* NOTE: This routine uses the non-debug IO access functions.
|
||||
*/
|
||||
int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size)
|
||||
{
|
||||
__le16 *e;
|
||||
u32 gp = iwl_read32(trans, CSR_EEPROM_GP);
|
||||
int sz;
|
||||
int ret;
|
||||
u16 addr;
|
||||
u16 validblockaddr = 0;
|
||||
u16 cache_addr = 0;
|
||||
int nvm_is_otp;
|
||||
|
||||
if (!eeprom || !eeprom_size)
|
||||
return -EINVAL;
|
||||
|
||||
nvm_is_otp = iwl_nvm_is_otp(trans);
|
||||
if (nvm_is_otp < 0)
|
||||
return nvm_is_otp;
|
||||
|
||||
sz = trans->cfg->base_params->eeprom_size;
|
||||
IWL_DEBUG_EEPROM(trans->dev, "NVM size = %d\n", sz);
|
||||
|
||||
e = kmalloc(sz, GFP_KERNEL);
|
||||
if (!e)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = iwl_eeprom_verify_signature(trans, nvm_is_otp);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
/* Make sure driver (instead of uCode) is allowed to read EEPROM */
|
||||
ret = iwl_eeprom_acquire_semaphore(trans);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (nvm_is_otp) {
|
||||
ret = iwl_init_otp_access(trans);
|
||||
if (ret) {
|
||||
IWL_ERR(trans, "Failed to initialize OTP access.\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
iwl_write32(trans, CSR_EEPROM_GP,
|
||||
iwl_read32(trans, CSR_EEPROM_GP) &
|
||||
~CSR_EEPROM_GP_IF_OWNER_MSK);
|
||||
|
||||
iwl_set_bit(trans, CSR_OTP_GP_REG,
|
||||
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
|
||||
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
|
||||
/* traversing the linked list if no shadow ram supported */
|
||||
if (!trans->cfg->base_params->shadow_ram_support) {
|
||||
ret = iwl_find_otp_image(trans, &validblockaddr);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
}
|
||||
for (addr = validblockaddr; addr < validblockaddr + sz;
|
||||
addr += sizeof(u16)) {
|
||||
__le16 eeprom_data;
|
||||
|
||||
ret = iwl_read_otp_word(trans, addr, &eeprom_data);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
e[cache_addr / 2] = eeprom_data;
|
||||
cache_addr += sizeof(u16);
|
||||
}
|
||||
} else {
|
||||
/* eeprom is an array of 16bit values */
|
||||
for (addr = 0; addr < sz; addr += sizeof(u16)) {
|
||||
u32 r;
|
||||
|
||||
iwl_write32(trans, CSR_EEPROM_REG,
|
||||
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
|
||||
|
||||
ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
|
||||
CSR_EEPROM_REG_READ_VALID_MSK,
|
||||
CSR_EEPROM_REG_READ_VALID_MSK,
|
||||
IWL_EEPROM_ACCESS_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(trans,
|
||||
"Time out reading EEPROM[%d]\n", addr);
|
||||
goto err_unlock;
|
||||
}
|
||||
r = iwl_read32(trans, CSR_EEPROM_REG);
|
||||
e[addr / 2] = cpu_to_le16(r >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_EEPROM(trans->dev, "NVM Type: %s\n",
|
||||
nvm_is_otp ? "OTP" : "EEPROM");
|
||||
|
||||
iwl_eeprom_release_semaphore(trans);
|
||||
|
||||
*eeprom_size = sz;
|
||||
*eeprom = (u8 *)e;
|
||||
return 0;
|
||||
|
||||
err_unlock:
|
||||
iwl_eeprom_release_semaphore(trans);
|
||||
err_free:
|
||||
kfree(e);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_read_eeprom);
|
|
@ -0,0 +1,70 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called LICENSE.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __iwl_eeprom_h__
|
||||
#define __iwl_eeprom_h__
|
||||
|
||||
#include "iwl-trans.h"
|
||||
|
||||
int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size);
|
||||
|
||||
#endif /* __iwl_eeprom_h__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,269 +0,0 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called LICENSE.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __iwl_eeprom_h__
|
||||
#define __iwl_eeprom_h__
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
struct iwl_priv;
|
||||
|
||||
/*
|
||||
* EEPROM access time values:
|
||||
*
|
||||
* Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG.
|
||||
* Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
|
||||
* When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
|
||||
* Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
|
||||
*/
|
||||
#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */
|
||||
|
||||
#define IWL_EEPROM_SEM_TIMEOUT 10 /* microseconds */
|
||||
#define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
|
||||
|
||||
|
||||
/*
|
||||
* Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags.
|
||||
*
|
||||
* IBSS and/or AP operation is allowed *only* on those channels with
|
||||
* (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because
|
||||
* RADAR detection is not supported by the 4965 driver, but is a
|
||||
* requirement for establishing a new network for legal operation on channels
|
||||
* requiring RADAR detection or restricting ACTIVE scanning.
|
||||
*
|
||||
* NOTE: "WIDE" flag does not indicate anything about "HT40" 40 MHz channels.
|
||||
* It only indicates that 20 MHz channel use is supported; HT40 channel
|
||||
* usage is indicated by a separate set of regulatory flags for each
|
||||
* HT40 channel pair.
|
||||
*
|
||||
* NOTE: Using a channel inappropriately will result in a uCode error!
|
||||
*/
|
||||
#define IWL_NUM_TX_CALIB_GROUPS 5
|
||||
enum {
|
||||
EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */
|
||||
EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */
|
||||
/* Bit 2 Reserved */
|
||||
EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */
|
||||
EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */
|
||||
EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */
|
||||
/* Bit 6 Reserved (was Narrow Channel) */
|
||||
EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */
|
||||
};
|
||||
|
||||
/* SKU Capabilities */
|
||||
#define EEPROM_SKU_CAP_BAND_24GHZ (1 << 4)
|
||||
#define EEPROM_SKU_CAP_BAND_52GHZ (1 << 5)
|
||||
#define EEPROM_SKU_CAP_11N_ENABLE (1 << 6)
|
||||
#define EEPROM_SKU_CAP_AMT_ENABLE (1 << 7)
|
||||
#define EEPROM_SKU_CAP_IPAN_ENABLE (1 << 8)
|
||||
|
||||
/* *regulatory* channel data format in eeprom, one for each channel.
|
||||
* There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */
|
||||
struct iwl_eeprom_channel {
|
||||
u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */
|
||||
s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
|
||||
} __packed;
|
||||
|
||||
enum iwl_eeprom_enhanced_txpwr_flags {
|
||||
IWL_EEPROM_ENH_TXP_FL_VALID = BIT(0),
|
||||
IWL_EEPROM_ENH_TXP_FL_BAND_52G = BIT(1),
|
||||
IWL_EEPROM_ENH_TXP_FL_OFDM = BIT(2),
|
||||
IWL_EEPROM_ENH_TXP_FL_40MHZ = BIT(3),
|
||||
IWL_EEPROM_ENH_TXP_FL_HT_AP = BIT(4),
|
||||
IWL_EEPROM_ENH_TXP_FL_RES1 = BIT(5),
|
||||
IWL_EEPROM_ENH_TXP_FL_RES2 = BIT(6),
|
||||
IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE = BIT(7),
|
||||
};
|
||||
|
||||
/**
|
||||
* iwl_eeprom_enhanced_txpwr structure
|
||||
* This structure presents the enhanced regulatory tx power limit layout
|
||||
* in eeprom image
|
||||
* Enhanced regulatory tx power portion of eeprom image can be broken down
|
||||
* into individual structures; each one is 8 bytes in size and contain the
|
||||
* following information
|
||||
* @flags: entry flags
|
||||
* @channel: channel number
|
||||
* @chain_a_max_pwr: chain a max power in 1/2 dBm
|
||||
* @chain_b_max_pwr: chain b max power in 1/2 dBm
|
||||
* @chain_c_max_pwr: chain c max power in 1/2 dBm
|
||||
* @delta_20_in_40: 20-in-40 deltas (hi/lo)
|
||||
* @mimo2_max_pwr: mimo2 max power in 1/2 dBm
|
||||
* @mimo3_max_pwr: mimo3 max power in 1/2 dBm
|
||||
*
|
||||
*/
|
||||
struct iwl_eeprom_enhanced_txpwr {
|
||||
u8 flags;
|
||||
u8 channel;
|
||||
s8 chain_a_max;
|
||||
s8 chain_b_max;
|
||||
s8 chain_c_max;
|
||||
u8 delta_20_in_40;
|
||||
s8 mimo2_max;
|
||||
s8 mimo3_max;
|
||||
} __packed;
|
||||
|
||||
/* calibration */
|
||||
struct iwl_eeprom_calib_hdr {
|
||||
u8 version;
|
||||
u8 pa_type;
|
||||
__le16 voltage;
|
||||
} __packed;
|
||||
|
||||
#define EEPROM_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
|
||||
#define EEPROM_XTAL ((2*0x128) | EEPROM_CALIB_ALL)
|
||||
|
||||
/* temperature */
|
||||
#define EEPROM_KELVIN_TEMPERATURE ((2*0x12A) | EEPROM_CALIB_ALL)
|
||||
#define EEPROM_RAW_TEMPERATURE ((2*0x12B) | EEPROM_CALIB_ALL)
|
||||
|
||||
|
||||
/* agn links */
|
||||
#define EEPROM_LINK_HOST (2*0x64)
|
||||
#define EEPROM_LINK_GENERAL (2*0x65)
|
||||
#define EEPROM_LINK_REGULATORY (2*0x66)
|
||||
#define EEPROM_LINK_CALIBRATION (2*0x67)
|
||||
#define EEPROM_LINK_PROCESS_ADJST (2*0x68)
|
||||
#define EEPROM_LINK_OTHERS (2*0x69)
|
||||
#define EEPROM_LINK_TXP_LIMIT (2*0x6a)
|
||||
#define EEPROM_LINK_TXP_LIMIT_SIZE (2*0x6b)
|
||||
|
||||
/* agn regulatory - indirect access */
|
||||
#define EEPROM_REG_BAND_1_CHANNELS ((0x08)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 28 bytes */
|
||||
#define EEPROM_REG_BAND_2_CHANNELS ((0x26)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 26 bytes */
|
||||
#define EEPROM_REG_BAND_3_CHANNELS ((0x42)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
|
||||
#define EEPROM_REG_BAND_4_CHANNELS ((0x5C)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
|
||||
#define EEPROM_REG_BAND_5_CHANNELS ((0x74)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */
|
||||
#define EEPROM_REG_BAND_24_HT40_CHANNELS ((0x82)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */
|
||||
#define EEPROM_REG_BAND_52_HT40_CHANNELS ((0x92)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
|
||||
|
||||
/* 6000 regulatory - indirect access */
|
||||
#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS ((0x80)\
|
||||
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */
|
||||
/* 2.4 GHz */
|
||||
extern const u8 iwl_eeprom_band_1[14];
|
||||
|
||||
#define ADDRESS_MSK 0x0000FFFF
|
||||
#define INDIRECT_TYPE_MSK 0x000F0000
|
||||
#define INDIRECT_HOST 0x00010000
|
||||
#define INDIRECT_GENERAL 0x00020000
|
||||
#define INDIRECT_REGULATORY 0x00030000
|
||||
#define INDIRECT_CALIBRATION 0x00040000
|
||||
#define INDIRECT_PROCESS_ADJST 0x00050000
|
||||
#define INDIRECT_OTHERS 0x00060000
|
||||
#define INDIRECT_TXP_LIMIT 0x00070000
|
||||
#define INDIRECT_TXP_LIMIT_SIZE 0x00080000
|
||||
#define INDIRECT_ADDRESS 0x00100000
|
||||
|
||||
/* General */
|
||||
#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */
|
||||
#define EEPROM_SUBSYSTEM_ID (2*0x0A) /* 2 bytes */
|
||||
#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */
|
||||
#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */
|
||||
#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
|
||||
#define EEPROM_VERSION (2*0x44) /* 2 bytes */
|
||||
#define EEPROM_SKU_CAP (2*0x45) /* 2 bytes */
|
||||
#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
|
||||
#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */
|
||||
#define EEPROM_NUM_MAC_ADDRESS (2*0x4C) /* 2 bytes */
|
||||
|
||||
/* The following masks are to be applied on EEPROM_RADIO_CONFIG */
|
||||
#define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */
|
||||
#define EEPROM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
|
||||
#define EEPROM_RF_CFG_DASH_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
|
||||
#define EEPROM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
|
||||
#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
|
||||
#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
|
||||
|
||||
#define EEPROM_RF_CONFIG_TYPE_MAX 0x3
|
||||
|
||||
#define EEPROM_REGULATORY_BAND_NO_HT40 (0)
|
||||
|
||||
struct iwl_eeprom_ops {
|
||||
const u32 regulatory_bands[7];
|
||||
bool enhanced_txpower;
|
||||
};
|
||||
|
||||
|
||||
int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev);
|
||||
void iwl_eeprom_free(struct iwl_priv *priv);
|
||||
int iwl_eeprom_check_version(struct iwl_priv *priv);
|
||||
int iwl_eeprom_init_hw_params(struct iwl_priv *priv);
|
||||
u16 iwl_eeprom_calib_version(struct iwl_priv *priv);
|
||||
const u8 *iwl_eeprom_query_addr(struct iwl_priv *priv, size_t offset);
|
||||
u16 iwl_eeprom_query16(struct iwl_priv *priv, size_t offset);
|
||||
void iwl_eeprom_get_mac(struct iwl_priv *priv, u8 *mac);
|
||||
int iwl_init_channel_map(struct iwl_priv *priv);
|
||||
void iwl_free_channel_map(struct iwl_priv *priv);
|
||||
const struct iwl_channel_info *iwl_get_channel_info(
|
||||
const struct iwl_priv *priv,
|
||||
enum ieee80211_band band, u16 channel);
|
||||
void iwl_rf_config(struct iwl_priv *priv);
|
||||
|
||||
#endif /* __iwl_eeprom_h__ */
|
|
@ -27,6 +27,7 @@
|
|||
*****************************************************************************/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "iwl-io.h"
|
||||
#include"iwl-csr.h"
|
||||
|
@ -52,6 +53,7 @@ void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
|
|||
__iwl_set_bit(trans, reg, mask);
|
||||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_set_bit);
|
||||
|
||||
void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
|
||||
{
|
||||
|
@ -61,6 +63,25 @@ void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
|
|||
__iwl_clear_bit(trans, reg, mask);
|
||||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_clear_bit);
|
||||
|
||||
void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 v;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
WARN_ON_ONCE(value & ~mask);
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&trans->reg_lock, flags);
|
||||
v = iwl_read32(trans, reg);
|
||||
v &= ~mask;
|
||||
v |= value;
|
||||
iwl_write32(trans, reg, v);
|
||||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_set_bits_mask);
|
||||
|
||||
int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
|
||||
u32 bits, u32 mask, int timeout)
|
||||
|
@ -76,6 +97,7 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
|
|||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_poll_bit);
|
||||
|
||||
int iwl_grab_nic_access_silent(struct iwl_trans *trans)
|
||||
{
|
||||
|
@ -117,6 +139,7 @@ int iwl_grab_nic_access_silent(struct iwl_trans *trans)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent);
|
||||
|
||||
bool iwl_grab_nic_access(struct iwl_trans *trans)
|
||||
{
|
||||
|
@ -130,6 +153,7 @@ bool iwl_grab_nic_access(struct iwl_trans *trans)
|
|||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_grab_nic_access);
|
||||
|
||||
void iwl_release_nic_access(struct iwl_trans *trans)
|
||||
{
|
||||
|
@ -144,6 +168,7 @@ void iwl_release_nic_access(struct iwl_trans *trans)
|
|||
*/
|
||||
mmiowb();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_release_nic_access);
|
||||
|
||||
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
|
||||
{
|
||||
|
@ -158,6 +183,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
|
|||
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_read_direct32);
|
||||
|
||||
void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
|
||||
{
|
||||
|
@ -170,6 +196,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
|
|||
}
|
||||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_write_direct32);
|
||||
|
||||
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
|
||||
int timeout)
|
||||
|
@ -185,6 +212,7 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
|
|||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_poll_direct_bit);
|
||||
|
||||
static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 reg)
|
||||
{
|
||||
|
@ -211,6 +239,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 reg)
|
|||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_read_prph);
|
||||
|
||||
void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
|
||||
{
|
||||
|
@ -223,6 +252,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
|
|||
}
|
||||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_write_prph);
|
||||
|
||||
void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
|
||||
{
|
||||
|
@ -236,6 +266,7 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
|
|||
}
|
||||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
|
||||
|
||||
void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
|
||||
u32 bits, u32 mask)
|
||||
|
@ -250,6 +281,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
|
|||
}
|
||||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
|
||||
|
||||
void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
|
||||
{
|
||||
|
@ -264,6 +296,7 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
|
|||
}
|
||||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
|
||||
|
||||
void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
|
||||
void *buf, int words)
|
||||
|
@ -281,6 +314,7 @@ void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
|
|||
}
|
||||
spin_unlock_irqrestore(&trans->reg_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_words);
|
||||
|
||||
u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
|
||||
{
|
||||
|
@ -290,6 +324,7 @@ u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
|
|||
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
|
||||
|
||||
int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
|
||||
void *buf, int words)
|
||||
|
@ -310,8 +345,10 @@ int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
|
|||
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_words);
|
||||
|
||||
int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val)
|
||||
{
|
||||
return _iwl_write_targ_mem_words(trans, addr, &val, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_write_targ_mem);
|
||||
|
|
|
@ -54,6 +54,8 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
|
|||
void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
|
||||
void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
|
||||
|
||||
void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value);
|
||||
|
||||
int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
|
||||
u32 bits, u32 mask, int timeout);
|
||||
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
#include <linux/sched.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "iwl-notif-wait.h"
|
||||
|
||||
|
@ -71,6 +72,7 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
|
|||
INIT_LIST_HEAD(¬if_wait->notif_waits);
|
||||
init_waitqueue_head(¬if_wait->notif_waitq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_notification_wait_init);
|
||||
|
||||
void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
|
||||
struct iwl_rx_packet *pkt)
|
||||
|
@ -115,6 +117,7 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
|
|||
if (triggered)
|
||||
wake_up_all(¬if_wait->notif_waitq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_notification_wait_notify);
|
||||
|
||||
void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
|
||||
{
|
||||
|
@ -128,7 +131,7 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
|
|||
|
||||
wake_up_all(¬if_wait->notif_waitq);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(iwl_abort_notification_waits);
|
||||
|
||||
void
|
||||
iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
|
||||
|
@ -152,6 +155,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
|
|||
list_add(&wait_entry->list, ¬if_wait->notif_waits);
|
||||
spin_unlock_bh(¬if_wait->notif_wait_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_init_notification_wait);
|
||||
|
||||
int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
|
@ -175,6 +179,7 @@ int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
|
|||
return -ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_wait_notification);
|
||||
|
||||
void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
|
||||
struct iwl_notification_wait *wait_entry)
|
||||
|
@ -183,3 +188,4 @@ void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
|
|||
list_del(&wait_entry->list);
|
||||
spin_unlock_bh(¬if_wait->notif_wait_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_remove_notification);
|
||||
|
|
|
@ -145,6 +145,9 @@ struct iwl_op_mode_ops {
|
|||
void (*wimax_active)(struct iwl_op_mode *op_mode);
|
||||
};
|
||||
|
||||
int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops);
|
||||
void iwl_opmode_deregister(const char *name);
|
||||
|
||||
/**
|
||||
* struct iwl_op_mode - operational mode
|
||||
*
|
||||
|
@ -218,9 +221,4 @@ static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
|
|||
op_mode->ops->wimax_active(op_mode);
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* Op mode layers implementations
|
||||
******************************************************/
|
||||
extern const struct iwl_op_mode_ops iwl_dvm_ops;
|
||||
|
||||
#endif /* __iwl_op_mode_h__ */
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
#define SCD_QUEUE_STTS_REG_POS_ACTIVE (3)
|
||||
#define SCD_QUEUE_STTS_REG_POS_WSL (4)
|
||||
#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
|
||||
#define SCD_QUEUE_STTS_REG_MSK (0x00FF0000)
|
||||
#define SCD_QUEUE_STTS_REG_MSK (0x017F0000)
|
||||
|
||||
#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8)
|
||||
#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00)
|
||||
|
|
|
@ -154,6 +154,9 @@ struct iwl_cmd_header {
|
|||
__le16 sequence;
|
||||
} __packed;
|
||||
|
||||
/* iwl_cmd_header flags value */
|
||||
#define IWL_CMD_FAILED_MSK 0x40
|
||||
|
||||
|
||||
#define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */
|
||||
#define FH_RSCSR_FRAME_INVALID 0x55550000
|
||||
|
@ -280,6 +283,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
|
|||
|
||||
#define MAX_NO_RECLAIM_CMDS 6
|
||||
|
||||
#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
|
||||
|
||||
/*
|
||||
* Maximum number of HW queues the transport layer
|
||||
* currently supports
|
||||
|
@ -350,10 +355,10 @@ struct iwl_trans;
|
|||
* Must be atomic
|
||||
* @reclaim: free packet until ssn. Returns a list of freed packets.
|
||||
* Must be atomic
|
||||
* @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is
|
||||
* @txq_enable: setup a tx queue for AMPDU - will be called once the HW is
|
||||
* ready and a successful ADDBA response has been received.
|
||||
* May sleep
|
||||
* @tx_agg_disable: de-configure a Tx queue to send AMPDUs
|
||||
* @txq_disable: de-configure a Tx queue to send AMPDUs
|
||||
* Must be atomic
|
||||
* @wait_tx_queue_empty: wait until all tx queues are empty
|
||||
* May sleep
|
||||
|
@ -386,9 +391,9 @@ struct iwl_trans_ops {
|
|||
void (*reclaim)(struct iwl_trans *trans, int queue, int ssn,
|
||||
struct sk_buff_head *skbs);
|
||||
|
||||
void (*tx_agg_setup)(struct iwl_trans *trans, int queue, int fifo,
|
||||
int sta_id, int tid, int frame_limit, u16 ssn);
|
||||
void (*tx_agg_disable)(struct iwl_trans *trans, int queue);
|
||||
void (*txq_enable)(struct iwl_trans *trans, int queue, int fifo,
|
||||
int sta_id, int tid, int frame_limit, u16 ssn);
|
||||
void (*txq_disable)(struct iwl_trans *trans, int queue);
|
||||
|
||||
int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
|
||||
int (*wait_tx_queue_empty)(struct iwl_trans *trans);
|
||||
|
@ -428,6 +433,11 @@ enum iwl_trans_state {
|
|||
* @hw_id_str: a string with info about HW ID. Set during transport allocation.
|
||||
* @pm_support: set to true in start_hw if link pm is supported
|
||||
* @wait_command_queue: the wait_queue for SYNC host commands
|
||||
* @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
|
||||
* The user should use iwl_trans_{alloc,free}_tx_cmd.
|
||||
* @dev_cmd_headroom: room needed for the transport's private use before the
|
||||
* device_cmd for Tx - for internal use only
|
||||
* The user should use iwl_trans_{alloc,free}_tx_cmd.
|
||||
*/
|
||||
struct iwl_trans {
|
||||
const struct iwl_trans_ops *ops;
|
||||
|
@ -445,6 +455,10 @@ struct iwl_trans {
|
|||
|
||||
wait_queue_head_t wait_command_queue;
|
||||
|
||||
/* The following fields are internal only */
|
||||
struct kmem_cache *dev_cmd_pool;
|
||||
size_t dev_cmd_headroom;
|
||||
|
||||
/* pointer to trans specific struct */
|
||||
/*Ensure that this pointer will always be aligned to sizeof pointer */
|
||||
char trans_specific[0] __aligned(sizeof(void *));
|
||||
|
@ -520,6 +534,26 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
|
|||
return trans->ops->send_cmd(trans, cmd);
|
||||
}
|
||||
|
||||
static inline struct iwl_device_cmd *
|
||||
iwl_trans_alloc_tx_cmd(struct iwl_trans *trans)
|
||||
{
|
||||
u8 *dev_cmd_ptr = kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC);
|
||||
|
||||
if (unlikely(dev_cmd_ptr == NULL))
|
||||
return NULL;
|
||||
|
||||
return (struct iwl_device_cmd *)
|
||||
(dev_cmd_ptr + trans->dev_cmd_headroom);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
|
||||
struct iwl_device_cmd *dev_cmd)
|
||||
{
|
||||
u8 *dev_cmd_ptr = (u8 *)dev_cmd - trans->dev_cmd_headroom;
|
||||
|
||||
kmem_cache_free(trans->dev_cmd_pool, dev_cmd_ptr);
|
||||
}
|
||||
|
||||
static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
||||
struct iwl_device_cmd *dev_cmd, int queue)
|
||||
{
|
||||
|
@ -538,24 +572,24 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
|
|||
trans->ops->reclaim(trans, queue, ssn, skbs);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_tx_agg_disable(struct iwl_trans *trans, int queue)
|
||||
static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
|
||||
{
|
||||
WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
|
||||
"%s bad state = %d", __func__, trans->state);
|
||||
|
||||
trans->ops->tx_agg_disable(trans, queue);
|
||||
trans->ops->txq_disable(trans, queue);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, int queue,
|
||||
int fifo, int sta_id, int tid,
|
||||
int frame_limit, u16 ssn)
|
||||
static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
|
||||
int fifo, int sta_id, int tid,
|
||||
int frame_limit, u16 ssn)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
|
||||
"%s bad state = %d", __func__, trans->state);
|
||||
|
||||
trans->ops->tx_agg_setup(trans, queue, fifo, sta_id, tid,
|
||||
trans->ops->txq_enable(trans, queue, fifo, sta_id, tid,
|
||||
frame_limit, ssn);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/stringify.h>
|
||||
#include "iwl-config.h"
|
||||
#include "iwl-cfg.h"
|
||||
#include "iwl-csr.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "cfg.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL1000_UCODE_API_MAX 5
|
||||
|
@ -64,13 +64,26 @@ static const struct iwl_base_params iwl1000_base_params = {
|
|||
.support_ct_kill_exit = true,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
.wd_timeout = IWL_WATCHHDOG_DISABLED,
|
||||
.wd_timeout = IWL_WATCHDOG_DISABLED,
|
||||
.max_event_log_size = 128,
|
||||
};
|
||||
|
||||
static const struct iwl_ht_params iwl1000_ht_params = {
|
||||
.ht_greenfield_support = true,
|
||||
.use_rts_for_aggregation = true, /* use rts/cts protection */
|
||||
.ht40_bands = BIT(IEEE80211_BAND_2GHZ),
|
||||
};
|
||||
|
||||
static const struct iwl_eeprom_params iwl1000_eeprom_params = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
}
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_1000 \
|
||||
|
@ -84,6 +97,7 @@ static const struct iwl_ht_params iwl1000_ht_params = {
|
|||
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl1000_base_params, \
|
||||
.eeprom_params = &iwl1000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK
|
||||
|
||||
const struct iwl_cfg iwl1000_bgn_cfg = {
|
||||
|
@ -108,6 +122,7 @@ const struct iwl_cfg iwl1000_bg_cfg = {
|
|||
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl1000_base_params, \
|
||||
.eeprom_params = &iwl1000_eeprom_params, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.rx_with_siso_diversity = true
|
||||
|
|
@ -27,9 +27,9 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/stringify.h>
|
||||
#include "iwl-config.h"
|
||||
#include "iwl-cfg.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-commands.h" /* needed for BT for now */
|
||||
#include "cfg.h"
|
||||
#include "dvm/commands.h" /* needed for BT for now */
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL2030_UCODE_API_MAX 6
|
||||
|
@ -104,6 +104,7 @@ static const struct iwl_base_params iwl2030_base_params = {
|
|||
static const struct iwl_ht_params iwl2000_ht_params = {
|
||||
.ht_greenfield_support = true,
|
||||
.use_rts_for_aggregation = true, /* use rts/cts protection */
|
||||
.ht40_bands = BIT(IEEE80211_BAND_2GHZ),
|
||||
};
|
||||
|
||||
static const struct iwl_bt_params iwl2030_bt_params = {
|
||||
|
@ -116,6 +117,19 @@ static const struct iwl_bt_params iwl2030_bt_params = {
|
|||
.bt_session_2 = true,
|
||||
};
|
||||
|
||||
static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REGULATORY_BAND_NO_HT40,
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_2000 \
|
||||
.fw_name_pre = IWL2000_FW_PRE, \
|
||||
.ucode_api_max = IWL2000_UCODE_API_MAX, \
|
||||
|
@ -127,6 +141,7 @@ static const struct iwl_bt_params iwl2030_bt_params = {
|
|||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl2000_base_params, \
|
||||
.eeprom_params = &iwl20x0_eeprom_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.temp_offset_v2 = true, \
|
||||
.led_mode = IWL_LED_RF_STATE
|
||||
|
@ -155,6 +170,7 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = {
|
|||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl2030_base_params, \
|
||||
.bt_params = &iwl2030_bt_params, \
|
||||
.eeprom_params = &iwl20x0_eeprom_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.temp_offset_v2 = true, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
|
@ -177,6 +193,7 @@ const struct iwl_cfg iwl2030_2bgn_cfg = {
|
|||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl2000_base_params, \
|
||||
.eeprom_params = &iwl20x0_eeprom_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.temp_offset_v2 = true, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
|
@ -207,6 +224,7 @@ const struct iwl_cfg iwl105_bgn_d_cfg = {
|
|||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl2030_base_params, \
|
||||
.bt_params = &iwl2030_bt_params, \
|
||||
.eeprom_params = &iwl20x0_eeprom_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.temp_offset_v2 = true, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
|
@ -27,9 +27,9 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/stringify.h>
|
||||
#include "iwl-config.h"
|
||||
#include "iwl-cfg.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-csr.h"
|
||||
#include "cfg.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL5000_UCODE_API_MAX 5
|
||||
|
@ -62,13 +62,26 @@ static const struct iwl_base_params iwl5000_base_params = {
|
|||
.led_compensation = 51,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
.wd_timeout = IWL_WATCHHDOG_DISABLED,
|
||||
.wd_timeout = IWL_WATCHDOG_DISABLED,
|
||||
.max_event_log_size = 512,
|
||||
.no_idle_support = true,
|
||||
};
|
||||
|
||||
static const struct iwl_ht_params iwl5000_ht_params = {
|
||||
.ht_greenfield_support = true,
|
||||
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
|
||||
};
|
||||
|
||||
static const struct iwl_eeprom_params iwl5000_eeprom_params = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_5000 \
|
||||
|
@ -82,6 +95,7 @@ static const struct iwl_ht_params iwl5000_ht_params = {
|
|||
.eeprom_ver = EEPROM_5000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl5000_base_params, \
|
||||
.eeprom_params = &iwl5000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK
|
||||
|
||||
const struct iwl_cfg iwl5300_agn_cfg = {
|
||||
|
@ -128,6 +142,7 @@ const struct iwl_cfg iwl5350_agn_cfg = {
|
|||
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
|
||||
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
|
||||
.base_params = &iwl5000_base_params,
|
||||
.eeprom_params = &iwl5000_eeprom_params,
|
||||
.ht_params = &iwl5000_ht_params,
|
||||
.led_mode = IWL_LED_BLINK,
|
||||
.internal_wimax_coex = true,
|
||||
|
@ -144,6 +159,7 @@ const struct iwl_cfg iwl5350_agn_cfg = {
|
|||
.eeprom_ver = EEPROM_5050_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \
|
||||
.base_params = &iwl5000_base_params, \
|
||||
.eeprom_params = &iwl5000_eeprom_params, \
|
||||
.no_xtal_calib = true, \
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
.internal_wimax_coex = true
|
|
@ -27,9 +27,9 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/stringify.h>
|
||||
#include "iwl-config.h"
|
||||
#include "iwl-cfg.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-commands.h" /* needed for BT for now */
|
||||
#include "cfg.h"
|
||||
#include "dvm/commands.h" /* needed for BT for now */
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL6000_UCODE_API_MAX 6
|
||||
|
@ -124,6 +124,7 @@ static const struct iwl_base_params iwl6000_g2_base_params = {
|
|||
static const struct iwl_ht_params iwl6000_ht_params = {
|
||||
.ht_greenfield_support = true,
|
||||
.use_rts_for_aggregation = true, /* use rts/cts protection */
|
||||
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
|
||||
};
|
||||
|
||||
static const struct iwl_bt_params iwl6000_bt_params = {
|
||||
|
@ -135,6 +136,19 @@ static const struct iwl_bt_params iwl6000_bt_params = {
|
|||
.bt_sco_disable = true,
|
||||
};
|
||||
|
||||
static const struct iwl_eeprom_params iwl6000_eeprom_params = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.enhanced_txpower = true,
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_6005 \
|
||||
.fw_name_pre = IWL6005_FW_PRE, \
|
||||
.ucode_api_max = IWL6000G2_UCODE_API_MAX, \
|
||||
|
@ -146,6 +160,7 @@ static const struct iwl_bt_params iwl6000_bt_params = {
|
|||
.eeprom_ver = EEPROM_6005_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.led_mode = IWL_LED_RF_STATE
|
||||
|
||||
|
@ -201,6 +216,7 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
|
|||
.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
.bt_params = &iwl6000_bt_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.adv_pm = true \
|
||||
|
@ -273,6 +289,7 @@ const struct iwl_cfg iwl130_bg_cfg = {
|
|||
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6000_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK
|
||||
|
||||
const struct iwl_cfg iwl6000i_2agn_cfg = {
|
||||
|
@ -303,6 +320,7 @@ const struct iwl_cfg iwl6000i_2bg_cfg = {
|
|||
.eeprom_ver = EEPROM_6050_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6050_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
.internal_wimax_coex = true
|
||||
|
||||
|
@ -327,6 +345,7 @@ const struct iwl_cfg iwl6050_2abg_cfg = {
|
|||
.eeprom_ver = EEPROM_6150_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6050_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
.internal_wimax_coex = true
|
||||
|
||||
|
@ -353,6 +372,7 @@ const struct iwl_cfg iwl6000_3agn_cfg = {
|
|||
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
|
||||
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
|
||||
.base_params = &iwl6000_base_params,
|
||||
.eeprom_params = &iwl6000_eeprom_params,
|
||||
.ht_params = &iwl6000_ht_params,
|
||||
.led_mode = IWL_LED_BLINK,
|
||||
};
|
|
@ -68,10 +68,11 @@
|
|||
#include <linux/pci-aspm.h>
|
||||
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-cfg.h"
|
||||
#include "iwl-drv.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-trans-pcie-int.h"
|
||||
|
||||
#include "cfg.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
|
||||
.vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
|
|
@ -313,7 +313,7 @@ void iwl_bg_rx_replenish(struct work_struct *data);
|
|||
void iwl_irq_tasklet(struct iwl_trans *trans);
|
||||
void iwlagn_rx_replenish(struct iwl_trans *trans);
|
||||
void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
|
||||
struct iwl_rx_queue *q);
|
||||
struct iwl_rx_queue *q);
|
||||
|
||||
/*****************************************************
|
||||
* ICT
|
||||
|
@ -328,7 +328,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data);
|
|||
* TX / HCMD
|
||||
******************************************************/
|
||||
void iwl_txq_update_write_ptr(struct iwl_trans *trans,
|
||||
struct iwl_tx_queue *txq);
|
||||
struct iwl_tx_queue *txq);
|
||||
int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
|
||||
struct iwl_tx_queue *txq,
|
||||
dma_addr_t addr, u16 len, u8 reset);
|
||||
|
@ -337,17 +337,20 @@ int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
|
|||
void iwl_tx_cmd_complete(struct iwl_trans *trans,
|
||||
struct iwl_rx_cmd_buffer *rxb, int handler_status);
|
||||
void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
|
||||
struct iwl_tx_queue *txq,
|
||||
u16 byte_cnt);
|
||||
void iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int queue);
|
||||
struct iwl_tx_queue *txq,
|
||||
u16 byte_cnt);
|
||||
void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue);
|
||||
void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index);
|
||||
void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
|
||||
struct iwl_tx_queue *txq,
|
||||
int tx_fifo_id, bool active);
|
||||
void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int queue, int fifo,
|
||||
int sta_id, int tid, int frame_limit, u16 ssn);
|
||||
void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
|
||||
enum dma_data_direction dma_dir);
|
||||
void __iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id,
|
||||
int fifo, int sta_id, int tid,
|
||||
int frame_limit, u16 ssn);
|
||||
void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
|
||||
int sta_id, int tid, int frame_limit, u16 ssn);
|
||||
void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
|
||||
enum dma_data_direction dma_dir);
|
||||
int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
|
||||
struct sk_buff_head *skbs);
|
||||
int iwl_queue_space(const struct iwl_queue *q);
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-trans-pcie-int.h"
|
||||
#include "internal.h"
|
||||
#include "iwl-op-mode.h"
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_IDI
|
||||
|
@ -130,7 +130,7 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
|
|||
* iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
|
||||
*/
|
||||
void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
|
||||
struct iwl_rx_queue *q)
|
||||
struct iwl_rx_queue *q)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
@ -201,9 +201,7 @@ static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr)
|
|||
*/
|
||||
static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
|
||||
struct list_head *element;
|
||||
struct iwl_rx_mem_buffer *rxb;
|
||||
|
@ -253,9 +251,7 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
|
|||
*/
|
||||
static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
|
||||
struct list_head *element;
|
||||
struct iwl_rx_mem_buffer *rxb;
|
||||
|
@ -278,8 +274,7 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
|
|||
gfp_mask |= __GFP_COMP;
|
||||
|
||||
/* Alloc a new receive buffer */
|
||||
page = alloc_pages(gfp_mask,
|
||||
trans_pcie->rx_page_order);
|
||||
page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
|
||||
if (!page) {
|
||||
if (net_ratelimit())
|
||||
IWL_DEBUG_INFO(trans, "alloc_pages failed, "
|
||||
|
@ -315,9 +310,10 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
|
|||
BUG_ON(rxb->page);
|
||||
rxb->page = page;
|
||||
/* Get physical address of the RB */
|
||||
rxb->page_dma = dma_map_page(trans->dev, page, 0,
|
||||
PAGE_SIZE << trans_pcie->rx_page_order,
|
||||
DMA_FROM_DEVICE);
|
||||
rxb->page_dma =
|
||||
dma_map_page(trans->dev, page, 0,
|
||||
PAGE_SIZE << trans_pcie->rx_page_order,
|
||||
DMA_FROM_DEVICE);
|
||||
/* dma address must be no more than 36 bits */
|
||||
BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
|
||||
/* and also 256 byte aligned! */
|
||||
|
@ -465,8 +461,8 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
|
|||
if (rxb->page != NULL) {
|
||||
rxb->page_dma =
|
||||
dma_map_page(trans->dev, rxb->page, 0,
|
||||
PAGE_SIZE << trans_pcie->rx_page_order,
|
||||
DMA_FROM_DEVICE);
|
||||
PAGE_SIZE << trans_pcie->rx_page_order,
|
||||
DMA_FROM_DEVICE);
|
||||
list_add_tail(&rxb->list, &rxq->rx_free);
|
||||
rxq->free_count++;
|
||||
} else
|
||||
|
@ -497,7 +493,7 @@ static void iwl_rx_handle(struct iwl_trans *trans)
|
|||
|
||||
/* Rx interrupt, but nothing sent from uCode */
|
||||
if (i == r)
|
||||
IWL_DEBUG_RX(trans, "r = %d, i = %d\n", r, i);
|
||||
IWL_DEBUG_RX(trans, "HW = SW = %d\n", r);
|
||||
|
||||
/* calculate total frames need to be restock after handling RX */
|
||||
total_empty = r - rxq->write_actual;
|
||||
|
@ -513,8 +509,8 @@ static void iwl_rx_handle(struct iwl_trans *trans)
|
|||
rxb = rxq->queue[i];
|
||||
rxq->queue[i] = NULL;
|
||||
|
||||
IWL_DEBUG_RX(trans, "rxbuf: r = %d, i = %d (%p)\n", rxb);
|
||||
|
||||
IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d (%p)\n",
|
||||
r, i, rxb);
|
||||
iwl_rx_handle_rxbuf(trans, rxb);
|
||||
|
||||
i = (i + 1) & RX_QUEUE_MASK;
|
||||
|
@ -546,12 +542,12 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
|
|||
/* W/A for WiFi/WiMAX coex and WiMAX own the RF */
|
||||
if (trans->cfg->internal_wimax_coex &&
|
||||
(!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
|
||||
APMS_CLK_VAL_MRB_FUNC_MODE) ||
|
||||
APMS_CLK_VAL_MRB_FUNC_MODE) ||
|
||||
(iwl_read_prph(trans, APMG_PS_CTRL_REG) &
|
||||
APMG_PS_CTRL_VAL_RESET_REQ))) {
|
||||
struct iwl_trans_pcie *trans_pcie;
|
||||
APMG_PS_CTRL_VAL_RESET_REQ))) {
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
|
||||
iwl_op_mode_wimax_active(trans->op_mode);
|
||||
wake_up(&trans->wait_command_queue);
|
||||
|
@ -567,6 +563,8 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
|
|||
/* tasklet for iwlagn interrupt */
|
||||
void iwl_irq_tasklet(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
|
||||
u32 inta = 0;
|
||||
u32 handled = 0;
|
||||
unsigned long flags;
|
||||
|
@ -575,10 +573,6 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
|
|||
u32 inta_mask;
|
||||
#endif
|
||||
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
|
||||
|
||||
|
||||
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
|
||||
|
||||
/* Ack/clear/reset pending uCode interrupts.
|
||||
|
@ -593,7 +587,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
|
|||
* interrupt coalescing can still be achieved.
|
||||
*/
|
||||
iwl_write32(trans, CSR_INT,
|
||||
trans_pcie->inta | ~trans_pcie->inta_mask);
|
||||
trans_pcie->inta | ~trans_pcie->inta_mask);
|
||||
|
||||
inta = trans_pcie->inta;
|
||||
|
||||
|
@ -602,7 +596,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
|
|||
/* just for debug */
|
||||
inta_mask = iwl_read32(trans, CSR_INT_MASK);
|
||||
IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n",
|
||||
inta, inta_mask);
|
||||
inta, inta_mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -651,7 +645,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
|
|||
|
||||
hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
|
||||
hw_rfkill ? "disable radio" : "enable radio");
|
||||
hw_rfkill ? "disable radio" : "enable radio");
|
||||
|
||||
isr_stats->rfkill++;
|
||||
|
||||
|
@ -693,7 +687,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
|
|||
* Rx "responses" (frame-received notification), and other
|
||||
* notifications from uCode come through here*/
|
||||
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
|
||||
CSR_INT_BIT_RX_PERIODIC)) {
|
||||
CSR_INT_BIT_RX_PERIODIC)) {
|
||||
IWL_DEBUG_ISR(trans, "Rx interrupt\n");
|
||||
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
|
||||
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
|
||||
|
@ -733,7 +727,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
|
|||
*/
|
||||
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
|
||||
iwl_write8(trans, CSR_INT_PERIODIC_REG,
|
||||
CSR_INT_PERIODIC_ENA);
|
||||
CSR_INT_PERIODIC_ENA);
|
||||
|
||||
isr_stats->rx++;
|
||||
}
|
||||
|
@ -782,8 +776,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
|
|||
/* Free dram table */
|
||||
void iwl_free_isr_ict(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
if (trans_pcie->ict_tbl) {
|
||||
dma_free_coherent(trans->dev, ICT_SIZE,
|
||||
|
@ -802,8 +795,7 @@ void iwl_free_isr_ict(struct iwl_trans *trans)
|
|||
*/
|
||||
int iwl_alloc_isr_ict(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
trans_pcie->ict_tbl =
|
||||
dma_alloc_coherent(trans->dev, ICT_SIZE,
|
||||
|
@ -837,10 +829,9 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans)
|
|||
*/
|
||||
void iwl_reset_ict(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
if (!trans_pcie->ict_tbl)
|
||||
return;
|
||||
|
@ -868,9 +859,7 @@ void iwl_reset_ict(struct iwl_trans *trans)
|
|||
/* Device is going down disable ict interrupt usage */
|
||||
void iwl_disable_ict(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
|
||||
|
@ -934,7 +923,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
|
|||
if (likely(inta))
|
||||
tasklet_schedule(&trans_pcie->irq_tasklet);
|
||||
else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
|
||||
!trans_pcie->inta)
|
||||
!trans_pcie->inta)
|
||||
iwl_enable_interrupts(trans);
|
||||
|
||||
unplugged:
|
||||
|
@ -945,7 +934,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
|
|||
/* re-enable interrupts here since we don't have anything to service. */
|
||||
/* only Re-enable if disabled by irq and no schedules tasklet. */
|
||||
if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
|
||||
!trans_pcie->inta)
|
||||
!trans_pcie->inta)
|
||||
iwl_enable_interrupts(trans);
|
||||
|
||||
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
|
||||
|
@ -1036,7 +1025,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
|
|||
|
||||
inta = (0xff & val) | ((0xff00 & val) << 16);
|
||||
IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
|
||||
inta, inta_mask, val);
|
||||
inta, inta_mask, val);
|
||||
|
||||
inta &= trans_pcie->inta_mask;
|
||||
trans_pcie->inta |= inta;
|
|
@ -70,15 +70,12 @@
|
|||
|
||||
#include "iwl-drv.h"
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-trans-pcie-int.h"
|
||||
#include "iwl-csr.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "internal.h"
|
||||
/* FIXME: need to abstract out TX command (once we know what it looks like) */
|
||||
#include "iwl-commands.h"
|
||||
|
||||
#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
|
||||
#include "dvm/commands.h"
|
||||
|
||||
#define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie) \
|
||||
(((1<<trans->cfg->base_params->num_of_queues) - 1) &\
|
||||
|
@ -86,8 +83,7 @@
|
|||
|
||||
static int iwl_trans_rx_alloc(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
|
||||
struct device *dev = trans->dev;
|
||||
|
||||
|
@ -114,7 +110,7 @@ static int iwl_trans_rx_alloc(struct iwl_trans *trans)
|
|||
|
||||
err_rb_stts:
|
||||
dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
|
||||
rxq->bd, rxq->bd_dma);
|
||||
rxq->bd, rxq->bd_dma);
|
||||
memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
|
||||
rxq->bd = NULL;
|
||||
err_bd:
|
||||
|
@ -123,8 +119,7 @@ err_bd:
|
|||
|
||||
static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
|
||||
int i;
|
||||
|
||||
|
@ -134,8 +129,8 @@ static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
|
|||
* to an SKB, so we need to unmap and free potential storage */
|
||||
if (rxq->pool[i].page != NULL) {
|
||||
dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
|
||||
PAGE_SIZE << trans_pcie->rx_page_order,
|
||||
DMA_FROM_DEVICE);
|
||||
PAGE_SIZE << trans_pcie->rx_page_order,
|
||||
DMA_FROM_DEVICE);
|
||||
__free_pages(rxq->pool[i].page,
|
||||
trans_pcie->rx_page_order);
|
||||
rxq->pool[i].page = NULL;
|
||||
|
@ -193,8 +188,7 @@ static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
|
|||
|
||||
static int iwl_rx_init(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
|
||||
|
||||
int i, err;
|
||||
|
@ -236,10 +230,8 @@ static int iwl_rx_init(struct iwl_trans *trans)
|
|||
|
||||
static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
/*if rxq->bd is NULL, it means that nothing has been allocated,
|
||||
|
@ -274,11 +266,11 @@ static int iwl_trans_rx_stop(struct iwl_trans *trans)
|
|||
/* stop Rx DMA */
|
||||
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
|
||||
return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
|
||||
FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
|
||||
FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
|
||||
}
|
||||
|
||||
static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
|
||||
struct iwl_dma_ptr *ptr, size_t size)
|
||||
static int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
|
||||
struct iwl_dma_ptr *ptr, size_t size)
|
||||
{
|
||||
if (WARN_ON(ptr->addr))
|
||||
return -EINVAL;
|
||||
|
@ -291,8 +283,8 @@ static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans,
|
||||
struct iwl_dma_ptr *ptr)
|
||||
static void iwlagn_free_dma_ptr(struct iwl_trans *trans,
|
||||
struct iwl_dma_ptr *ptr)
|
||||
{
|
||||
if (unlikely(!ptr->addr))
|
||||
return;
|
||||
|
@ -329,12 +321,12 @@ static void iwl_trans_pcie_queue_stuck_timer(unsigned long data)
|
|||
}
|
||||
|
||||
static int iwl_trans_txq_alloc(struct iwl_trans *trans,
|
||||
struct iwl_tx_queue *txq, int slots_num,
|
||||
u32 txq_id)
|
||||
struct iwl_tx_queue *txq, int slots_num,
|
||||
u32 txq_id)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
|
||||
int i;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
if (WARN_ON(txq->entries || txq->tfds))
|
||||
return -EINVAL;
|
||||
|
@ -435,7 +427,7 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
|
|||
|
||||
spin_lock_bh(&txq->lock);
|
||||
while (q->write_ptr != q->read_ptr) {
|
||||
iwlagn_txq_free_tfd(trans, txq, dma_dir);
|
||||
iwl_txq_free_tfd(trans, txq, dma_dir);
|
||||
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
|
||||
}
|
||||
spin_unlock_bh(&txq->lock);
|
||||
|
@ -455,6 +447,7 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
|
|||
struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
|
||||
struct device *dev = trans->dev;
|
||||
int i;
|
||||
|
||||
if (WARN_ON(!txq))
|
||||
return;
|
||||
|
||||
|
@ -574,11 +567,11 @@ error:
|
|||
}
|
||||
static int iwl_tx_init(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int ret;
|
||||
int txq_id, slots_num;
|
||||
unsigned long flags;
|
||||
bool alloc = false;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
if (!trans_pcie->txq) {
|
||||
ret = iwl_trans_tx_alloc(trans);
|
||||
|
@ -643,10 +636,9 @@ static void iwl_set_pwr_vmain(struct iwl_trans *trans)
|
|||
|
||||
static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int pos;
|
||||
u16 pci_lnk_ctl;
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
struct pci_dev *pci_dev = trans_pcie->pci_dev;
|
||||
|
||||
|
@ -700,14 +692,14 @@ static int iwl_apm_init(struct iwl_trans *trans)
|
|||
|
||||
/* Disable L0S exit timer (platform NMI Work/Around) */
|
||||
iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
|
||||
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
|
||||
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
|
||||
|
||||
/*
|
||||
* Disable L0s without affecting L1;
|
||||
* don't wait for ICH L0s (ICH bug W/A)
|
||||
*/
|
||||
iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
|
||||
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
|
||||
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
|
||||
|
||||
/* Set FH wait threshold to maximum (HW error during stress W/A) */
|
||||
iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
|
||||
|
@ -717,7 +709,7 @@ static int iwl_apm_init(struct iwl_trans *trans)
|
|||
* wake device's PCI Express link L1a -> L0s
|
||||
*/
|
||||
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
|
||||
CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
|
||||
|
||||
iwl_apm_config(trans);
|
||||
|
||||
|
@ -738,8 +730,8 @@ static int iwl_apm_init(struct iwl_trans *trans)
|
|||
* and accesses to uCode SRAM.
|
||||
*/
|
||||
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
|
||||
if (ret < 0) {
|
||||
IWL_DEBUG_INFO(trans, "Failed to init the card\n");
|
||||
goto out;
|
||||
|
@ -773,8 +765,8 @@ static int iwl_apm_stop_master(struct iwl_trans *trans)
|
|||
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
|
||||
|
||||
ret = iwl_poll_bit(trans, CSR_RESET,
|
||||
CSR_RESET_REG_FLAG_MASTER_DISABLED,
|
||||
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
|
||||
CSR_RESET_REG_FLAG_MASTER_DISABLED,
|
||||
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
|
||||
if (ret)
|
||||
IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
|
||||
|
||||
|
@ -816,8 +808,7 @@ static int iwl_nic_init(struct iwl_trans *trans)
|
|||
iwl_apm_init(trans);
|
||||
|
||||
/* Set interrupt coalescing calibration timer to default (512 usecs) */
|
||||
iwl_write8(trans, CSR_INT_COALESCING,
|
||||
IWL_HOST_INT_CALIB_TIMEOUT_DEF);
|
||||
iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
|
||||
|
||||
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
|
||||
|
||||
|
@ -836,8 +827,8 @@ static int iwl_nic_init(struct iwl_trans *trans)
|
|||
|
||||
if (trans->cfg->base_params->shadow_reg_enable) {
|
||||
/* enable shadow regs in HW */
|
||||
iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL,
|
||||
0x800FFFFF);
|
||||
iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF);
|
||||
IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -851,13 +842,13 @@ static int iwl_set_hw_ready(struct iwl_trans *trans)
|
|||
int ret;
|
||||
|
||||
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
|
||||
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
|
||||
|
||||
/* See if we got it */
|
||||
ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
|
||||
HW_READY_TIMEOUT);
|
||||
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
|
||||
HW_READY_TIMEOUT);
|
||||
|
||||
IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : "");
|
||||
return ret;
|
||||
|
@ -877,11 +868,11 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
|
|||
|
||||
/* If HW is not ready, prepare the conditions to check again */
|
||||
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_PREPARE);
|
||||
CSR_HW_IF_CONFIG_REG_PREPARE);
|
||||
|
||||
ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
|
||||
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
|
||||
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -908,32 +899,33 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
|
|||
trans_pcie->ucode_write_complete = false;
|
||||
|
||||
iwl_write_direct32(trans,
|
||||
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
|
||||
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
|
||||
|
||||
iwl_write_direct32(trans,
|
||||
FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
|
||||
FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL),
|
||||
dst_addr);
|
||||
|
||||
iwl_write_direct32(trans,
|
||||
FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
|
||||
phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
|
||||
|
||||
iwl_write_direct32(trans,
|
||||
FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
|
||||
(iwl_get_dma_hi_addr(phy_addr)
|
||||
<< FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
|
||||
FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
|
||||
(iwl_get_dma_hi_addr(phy_addr)
|
||||
<< FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
|
||||
|
||||
iwl_write_direct32(trans,
|
||||
FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
|
||||
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
|
||||
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
|
||||
FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
|
||||
FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
|
||||
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
|
||||
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
|
||||
FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
|
||||
|
||||
iwl_write_direct32(trans,
|
||||
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
|
||||
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
|
||||
|
||||
IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
|
||||
section_num);
|
||||
|
@ -1038,6 +1030,10 @@ static void iwl_tx_start(struct iwl_trans *trans)
|
|||
|
||||
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
|
||||
|
||||
/* make sure all queue are not stopped/used */
|
||||
memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
|
||||
memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
|
||||
|
||||
trans_pcie->scd_base_addr =
|
||||
iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
|
||||
a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
|
||||
|
@ -1058,64 +1054,33 @@ static void iwl_tx_start(struct iwl_trans *trans)
|
|||
iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
|
||||
trans_pcie->scd_bc_tbls.dma >> 10);
|
||||
|
||||
for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
|
||||
int fifo = trans_pcie->setup_q_to_fifo[i];
|
||||
|
||||
__iwl_trans_pcie_txq_enable(trans, i, fifo, IWL_INVALID_STATION,
|
||||
IWL_TID_NON_QOS,
|
||||
SCD_FRAME_LIMIT, 0);
|
||||
}
|
||||
|
||||
/* Activate all Tx DMA/FIFO channels */
|
||||
iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
|
||||
|
||||
/* Enable DMA channel */
|
||||
for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
|
||||
iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
|
||||
|
||||
/* Update FH chicken bits */
|
||||
reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG);
|
||||
iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG,
|
||||
reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
|
||||
|
||||
iwl_write_prph(trans, SCD_QUEUECHAIN_SEL,
|
||||
SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie));
|
||||
iwl_write_prph(trans, SCD_AGGR_SEL, 0);
|
||||
|
||||
/* initiate the queues */
|
||||
for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
|
||||
iwl_write_prph(trans, SCD_QUEUE_RDPTR(i), 0);
|
||||
iwl_write_direct32(trans, HBUS_TARG_WRPTR, 0 | (i << 8));
|
||||
iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
|
||||
SCD_CONTEXT_QUEUE_OFFSET(i), 0);
|
||||
iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
|
||||
SCD_CONTEXT_QUEUE_OFFSET(i) +
|
||||
sizeof(u32),
|
||||
((SCD_WIN_SIZE <<
|
||||
SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
|
||||
SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
|
||||
((SCD_FRAME_LIMIT <<
|
||||
SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
|
||||
SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
|
||||
}
|
||||
|
||||
iwl_write_prph(trans, SCD_INTERRUPT_MASK,
|
||||
IWL_MASK(0, trans->cfg->base_params->num_of_queues));
|
||||
|
||||
/* Activate all Tx DMA/FIFO channels */
|
||||
iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
|
||||
|
||||
iwl_trans_set_wr_ptrs(trans, trans_pcie->cmd_queue, 0);
|
||||
|
||||
/* make sure all queue are not stopped/used */
|
||||
memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
|
||||
memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
|
||||
|
||||
for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
|
||||
int fifo = trans_pcie->setup_q_to_fifo[i];
|
||||
|
||||
set_bit(i, trans_pcie->queue_used);
|
||||
|
||||
iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i],
|
||||
fifo, true);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
|
||||
|
||||
/* Enable L1-Active */
|
||||
iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
|
||||
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
|
||||
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
|
||||
}
|
||||
|
||||
static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
|
||||
|
@ -1129,9 +1094,9 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
|
|||
*/
|
||||
static int iwl_trans_tx_stop(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int ch, txq_id, ret;
|
||||
unsigned long flags;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
/* Turn off all Tx DMA fifos */
|
||||
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
|
||||
|
@ -1143,13 +1108,13 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans)
|
|||
iwl_write_direct32(trans,
|
||||
FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
|
||||
ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
|
||||
FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
|
||||
1000);
|
||||
FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000);
|
||||
if (ret < 0)
|
||||
IWL_ERR(trans, "Failing on timeout while stopping"
|
||||
" DMA channel %d [0x%08x]", ch,
|
||||
iwl_read_direct32(trans,
|
||||
FH_TSSR_TX_STATUS_REG));
|
||||
IWL_ERR(trans,
|
||||
"Failing on timeout while stopping DMA channel %d [0x%08x]",
|
||||
ch,
|
||||
iwl_read_direct32(trans,
|
||||
FH_TSSR_TX_STATUS_REG));
|
||||
}
|
||||
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
|
||||
|
||||
|
@ -1168,8 +1133,8 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans)
|
|||
|
||||
static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
unsigned long flags;
|
||||
|
||||
/* tell the device to stop sending interrupts */
|
||||
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
|
||||
|
@ -1199,7 +1164,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
|
|||
|
||||
/* Make sure (redundant) we've released our request to stay awake */
|
||||
iwl_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
|
||||
/* Stop the device, and put it in low power state */
|
||||
iwl_apm_stop(trans);
|
||||
|
@ -1273,8 +1238,9 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
txq->entries[q->write_ptr].cmd = dev_cmd;
|
||||
|
||||
dev_cmd->hdr.cmd = REPLY_TX;
|
||||
dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
|
||||
INDEX_TO_SEQ(q->write_ptr)));
|
||||
dev_cmd->hdr.sequence =
|
||||
cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
|
||||
INDEX_TO_SEQ(q->write_ptr)));
|
||||
|
||||
/* Set up first empty entry in queue's array of Tx/cmd buffers */
|
||||
out_meta = &txq->entries[q->write_ptr].meta;
|
||||
|
@ -1339,7 +1305,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
|
||||
/* take back ownership of DMA buffer to enable update */
|
||||
dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen,
|
||||
DMA_BIDIRECTIONAL);
|
||||
DMA_BIDIRECTIONAL);
|
||||
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
|
||||
tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
|
||||
|
||||
|
@ -1351,7 +1317,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
|
||||
|
||||
dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
|
||||
DMA_BIDIRECTIONAL);
|
||||
DMA_BIDIRECTIONAL);
|
||||
|
||||
trace_iwlwifi_dev_tx(trans->dev,
|
||||
&txq->tfds[txq->q.write_ptr],
|
||||
|
@ -1390,8 +1356,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
|
||||
static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int err;
|
||||
bool hw_rfkill;
|
||||
|
||||
|
@ -1404,7 +1369,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
|
|||
iwl_alloc_isr_ict(trans);
|
||||
|
||||
err = request_irq(trans_pcie->irq, iwl_isr_ict, IRQF_SHARED,
|
||||
DRV_NAME, trans);
|
||||
DRV_NAME, trans);
|
||||
if (err) {
|
||||
IWL_ERR(trans, "Error allocating IRQ %d\n",
|
||||
trans_pcie->irq);
|
||||
|
@ -1442,9 +1407,9 @@ error:
|
|||
static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
|
||||
bool op_mode_leaving)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
bool hw_rfkill;
|
||||
unsigned long flags;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
iwl_apm_stop(trans);
|
||||
|
||||
|
@ -1548,8 +1513,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
|
|||
|
||||
void iwl_trans_pcie_free(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
iwl_trans_pcie_tx_free(trans);
|
||||
#ifndef CONFIG_IWLWIFI_IDI
|
||||
|
@ -1564,6 +1528,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
|
|||
iounmap(trans_pcie->hw_base);
|
||||
pci_release_regions(trans_pcie->pci_dev);
|
||||
pci_disable_device(trans_pcie->pci_dev);
|
||||
kmem_cache_destroy(trans->dev_cmd_pool);
|
||||
|
||||
kfree(trans);
|
||||
}
|
||||
|
@ -1811,8 +1776,8 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \
|
|||
};
|
||||
|
||||
static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
@ -1848,11 +1813,11 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
|
|||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
|
||||
char buf[256];
|
||||
int pos = 0;
|
||||
|
@ -1876,11 +1841,10 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
|
|||
|
||||
static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos) {
|
||||
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
|
||||
|
||||
int pos = 0;
|
||||
|
@ -1938,8 +1902,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
|
|||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
struct iwl_trans_pcie *trans_pcie =
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
|
||||
|
||||
char buf[8];
|
||||
|
@ -1959,8 +1922,8 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
|
|||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_csr_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
char buf[8];
|
||||
|
@ -1980,8 +1943,8 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file,
|
|||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
char *buf;
|
||||
|
@ -2024,7 +1987,7 @@ DEBUGFS_WRITE_FILE_OPS(fw_restart);
|
|||
*
|
||||
*/
|
||||
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
|
||||
struct dentry *dir)
|
||||
struct dentry *dir)
|
||||
{
|
||||
DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
|
||||
|
@ -2036,9 +1999,10 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
|
|||
}
|
||||
#else
|
||||
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
|
||||
struct dentry *dir)
|
||||
{ return 0; }
|
||||
|
||||
struct dentry *dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /*CONFIG_IWLWIFI_DEBUGFS */
|
||||
|
||||
static const struct iwl_trans_ops trans_ops_pcie = {
|
||||
|
@ -2055,8 +2019,8 @@ static const struct iwl_trans_ops trans_ops_pcie = {
|
|||
.tx = iwl_trans_pcie_tx,
|
||||
.reclaim = iwl_trans_pcie_reclaim,
|
||||
|
||||
.tx_agg_disable = iwl_trans_pcie_tx_agg_disable,
|
||||
.tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
|
||||
.txq_disable = iwl_trans_pcie_txq_disable,
|
||||
.txq_enable = iwl_trans_pcie_txq_enable,
|
||||
|
||||
.dbgfs_register = iwl_trans_pcie_dbgfs_register,
|
||||
|
||||
|
@ -2079,11 +2043,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
|||
{
|
||||
struct iwl_trans_pcie *trans_pcie;
|
||||
struct iwl_trans *trans;
|
||||
char cmd_pool_name[100];
|
||||
u16 pci_cmd;
|
||||
int err;
|
||||
|
||||
trans = kzalloc(sizeof(struct iwl_trans) +
|
||||
sizeof(struct iwl_trans_pcie), GFP_KERNEL);
|
||||
sizeof(struct iwl_trans_pcie), GFP_KERNEL);
|
||||
|
||||
if (WARN_ON(!trans))
|
||||
return NULL;
|
||||
|
@ -2099,7 +2064,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
|||
/* W/A - seems to solve weird behavior. We need to remove this if we
|
||||
* don't want to stay in L1 all the time. This wastes a lot of power */
|
||||
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
|
||||
PCIE_LINK_STATE_CLKPM);
|
||||
PCIE_LINK_STATE_CLKPM);
|
||||
|
||||
if (pci_enable_device(pdev)) {
|
||||
err = -ENODEV;
|
||||
|
@ -2115,7 +2080,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
|||
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
if (!err)
|
||||
err = pci_set_consistent_dma_mask(pdev,
|
||||
DMA_BIT_MASK(32));
|
||||
DMA_BIT_MASK(32));
|
||||
/* both attempts failed: */
|
||||
if (err) {
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
|
@ -2138,13 +2103,13 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"pci_resource_len = 0x%08llx\n",
|
||||
(unsigned long long) pci_resource_len(pdev, 0));
|
||||
"pci_resource_len = 0x%08llx\n",
|
||||
(unsigned long long) pci_resource_len(pdev, 0));
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"pci_resource_base = %p\n", trans_pcie->hw_base);
|
||||
"pci_resource_base = %p\n", trans_pcie->hw_base);
|
||||
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"HW Revision ID = 0x%X\n", pdev->revision);
|
||||
"HW Revision ID = 0x%X\n", pdev->revision);
|
||||
|
||||
/* We disable the RETRY_TIMEOUT register (0x41) to keep
|
||||
* PCI Tx retries from interfering with C3 CPU state */
|
||||
|
@ -2153,7 +2118,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
|||
err = pci_enable_msi(pdev);
|
||||
if (err)
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"pci_enable_msi failed(0X%x)", err);
|
||||
"pci_enable_msi failed(0X%x)", err);
|
||||
|
||||
trans->dev = &pdev->dev;
|
||||
trans_pcie->irq = pdev->irq;
|
||||
|
@ -2175,8 +2140,25 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
|||
init_waitqueue_head(&trans->wait_command_queue);
|
||||
spin_lock_init(&trans->reg_lock);
|
||||
|
||||
snprintf(cmd_pool_name, sizeof(cmd_pool_name), "iwl_cmd_pool:%s",
|
||||
dev_name(trans->dev));
|
||||
|
||||
trans->dev_cmd_headroom = 0;
|
||||
trans->dev_cmd_pool =
|
||||
kmem_cache_create(cmd_pool_name,
|
||||
sizeof(struct iwl_device_cmd)
|
||||
+ trans->dev_cmd_headroom,
|
||||
sizeof(void *),
|
||||
SLAB_HWCACHE_ALIGN,
|
||||
NULL);
|
||||
|
||||
if (!trans->dev_cmd_pool)
|
||||
goto out_pci_disable_msi;
|
||||
|
||||
return trans;
|
||||
|
||||
out_pci_disable_msi:
|
||||
pci_disable_msi(pdev);
|
||||
out_pci_release_regions:
|
||||
pci_release_regions(pdev);
|
||||
out_pci_disable_device:
|
||||
|
@ -2185,4 +2167,3 @@ out_no_pci:
|
|||
kfree(trans);
|
||||
return NULL;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue