forked from Minki/linux
Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next
This commit is contained in:
commit
627ae3ddd6
30
MAINTAINERS
30
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/
|
||||
|
||||
@ -1800,6 +1800,9 @@ F: include/linux/cfag12864b.h
|
||||
CFG80211 and NL80211
|
||||
M: Johannes Berg <johannes@sipsolutions.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://wireless.kernel.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
|
||||
S: Maintained
|
||||
F: include/linux/nl80211.h
|
||||
F: include/net/cfg80211.h
|
||||
@ -4339,8 +4342,9 @@ F: arch/m68k/hp300/
|
||||
MAC80211
|
||||
M: Johannes Berg <johannes@sipsolutions.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://linuxwireless.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
|
||||
W: http://wireless.kernel.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
|
||||
S: Maintained
|
||||
F: Documentation/networking/mac80211-injection.txt
|
||||
F: include/net/mac80211.h
|
||||
@ -4350,8 +4354,9 @@ 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
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
|
||||
W: http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
|
||||
S: Maintained
|
||||
F: net/mac80211/rc80211_pid*
|
||||
|
||||
@ -5027,7 +5032,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/
|
||||
@ -5695,6 +5700,9 @@ F: include/linux/remoteproc.h
|
||||
RFKILL
|
||||
M: Johannes Berg <johannes@sipsolutions.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://wireless.kernel.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
|
||||
S: Maintained
|
||||
F: Documentation/rfkill.txt
|
||||
F: net/rfkill/
|
||||
@ -5729,7 +5737,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 +5747,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 +5756,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/
|
||||
|
@ -139,7 +139,9 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
|
||||
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
|
||||
break;
|
||||
case 0x4331:
|
||||
/* BCM4331 workaround is SPROM-related, we put it in sprom.c */
|
||||
case 43431:
|
||||
/* Ext PA lines must be enabled for tx on BCM4331 */
|
||||
bcma_chipco_bcm4331_ext_pa_lines_ctl(cc, true);
|
||||
break;
|
||||
case 43224:
|
||||
if (bus->chipinfo.rev == 0) {
|
||||
|
@ -232,17 +232,19 @@ void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc)
|
||||
int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
|
||||
bool enable)
|
||||
{
|
||||
struct pci_dev *pdev = pc->core->bus->host_pci;
|
||||
struct pci_dev *pdev;
|
||||
u32 coremask, tmp;
|
||||
int err = 0;
|
||||
|
||||
if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
|
||||
if (!pc || core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
|
||||
/* This bcma device is not on a PCI host-bus. So the IRQs are
|
||||
* not routed through the PCI core.
|
||||
* So we must not enable routing through the PCI core. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
pdev = pc->core->bus->host_pci;
|
||||
|
||||
err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -579,13 +579,13 @@ int bcma_sprom_get(struct bcma_bus *bus)
|
||||
if (!sprom)
|
||||
return -ENOMEM;
|
||||
|
||||
if (bus->chipinfo.id == 0x4331)
|
||||
if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431)
|
||||
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
|
||||
|
||||
pr_debug("SPROM offset 0x%x\n", offset);
|
||||
bcma_sprom_read(bus, offset, sprom);
|
||||
|
||||
if (bus->chipinfo.id == 0x4331)
|
||||
if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431)
|
||||
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
|
||||
|
||||
err = bcma_sprom_valid(sprom);
|
||||
|
@ -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) {
|
||||
|
776
drivers/net/wireless/ath/ath9k/antenna.c
Normal file
776
drivers/net/wireless/ath/ath9k/antenna.c
Normal file
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
502
drivers/net/wireless/ath/ath9k/link.c
Normal file
502
drivers/net/wireless/ath/ath9k/link.c
Normal file
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -877,6 +877,10 @@ struct b43_wl {
|
||||
* from the mac80211 subsystem. */
|
||||
u16 mac80211_initially_registered_queues;
|
||||
|
||||
/* Set this if we call ieee80211_register_hw() and check if we call
|
||||
* ieee80211_unregister_hw(). */
|
||||
bool hw_registred;
|
||||
|
||||
/* We can only have one operating interface (802.11 core)
|
||||
* at a time. General information about this interface follows.
|
||||
*/
|
||||
|
@ -2437,6 +2437,7 @@ start_ieee80211:
|
||||
err = ieee80211_register_hw(wl->hw);
|
||||
if (err)
|
||||
goto err_one_core_detach;
|
||||
wl->hw_registred = true;
|
||||
b43_leds_register(wl->current_dev);
|
||||
goto out;
|
||||
|
||||
@ -5299,6 +5300,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
|
||||
|
||||
hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1;
|
||||
wl->mac80211_initially_registered_queues = hw->queues;
|
||||
wl->hw_registred = false;
|
||||
hw->max_rates = 2;
|
||||
SET_IEEE80211_DEV(hw, dev->dev);
|
||||
if (is_valid_ether_addr(sprom->et1mac))
|
||||
@ -5370,12 +5372,15 @@ static void b43_bcma_remove(struct bcma_device *core)
|
||||
* as the ieee80211 unreg will destroy the workqueue. */
|
||||
cancel_work_sync(&wldev->restart_work);
|
||||
|
||||
/* Restore the queues count before unregistering, because firmware detect
|
||||
* might have modified it. Restoring is important, so the networking
|
||||
* stack can properly free resources. */
|
||||
wl->hw->queues = wl->mac80211_initially_registered_queues;
|
||||
b43_leds_stop(wldev);
|
||||
ieee80211_unregister_hw(wl->hw);
|
||||
B43_WARN_ON(!wl);
|
||||
if (wl->current_dev == wldev && wl->hw_registred) {
|
||||
/* Restore the queues count before unregistering, because firmware detect
|
||||
* might have modified it. Restoring is important, so the networking
|
||||
* stack can properly free resources. */
|
||||
wl->hw->queues = wl->mac80211_initially_registered_queues;
|
||||
b43_leds_stop(wldev);
|
||||
ieee80211_unregister_hw(wl->hw);
|
||||
}
|
||||
|
||||
b43_one_core_detach(wldev->dev);
|
||||
|
||||
@ -5446,7 +5451,7 @@ static void b43_ssb_remove(struct ssb_device *sdev)
|
||||
cancel_work_sync(&wldev->restart_work);
|
||||
|
||||
B43_WARN_ON(!wl);
|
||||
if (wl->current_dev == wldev) {
|
||||
if (wl->current_dev == wldev && wl->hw_registred) {
|
||||
/* Restore the queues count before unregistering, because firmware detect
|
||||
* might have modified it. Restoring is important, so the networking
|
||||
* stack can properly free resources. */
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -89,9 +89,9 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
|
||||
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
|
||||
|
||||
/* redirect, configure ane enable io for interrupt signal */
|
||||
/* redirect, configure and enable io for interrupt signal */
|
||||
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
|
||||
if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH)
|
||||
if (sdiodev->irq_flags & IRQF_TRIGGER_HIGH)
|
||||
data |= SDIO_SEPINT_ACT_HI;
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -1903,14 +1903,6 @@ static void ipw2100_down(struct ipw2100_priv *priv)
|
||||
netif_stop_queue(priv->net_dev);
|
||||
}
|
||||
|
||||
/* Called by register_netdev() */
|
||||
static int ipw2100_net_init(struct net_device *dev)
|
||||
{
|
||||
struct ipw2100_priv *priv = libipw_priv(dev);
|
||||
|
||||
return ipw2100_up(priv, 1);
|
||||
}
|
||||
|
||||
static int ipw2100_wdev_init(struct net_device *dev)
|
||||
{
|
||||
struct ipw2100_priv *priv = libipw_priv(dev);
|
||||
@ -6087,7 +6079,6 @@ static const struct net_device_ops ipw2100_netdev_ops = {
|
||||
.ndo_stop = ipw2100_close,
|
||||
.ndo_start_xmit = libipw_xmit,
|
||||
.ndo_change_mtu = libipw_change_mtu,
|
||||
.ndo_init = ipw2100_net_init,
|
||||
.ndo_tx_timeout = ipw2100_tx_timeout,
|
||||
.ndo_set_mac_address = ipw2100_set_address,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
@ -6329,6 +6320,10 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": Detected Intel PRO/Wireless 2100 Network Connection\n");
|
||||
|
||||
err = ipw2100_up(priv, 1);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
err = ipw2100_wdev_init(dev);
|
||||
if (err)
|
||||
goto fail;
|
||||
@ -6338,12 +6333,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
|
||||
* network device we would call ipw2100_up. This introduced a race
|
||||
* condition with newer hotplug configurations (network was coming
|
||||
* up and making calls before the device was initialized).
|
||||
*
|
||||
* If we called ipw2100_up before we registered the device, then the
|
||||
* device name wasn't registered. So, we instead use the net_dev->init
|
||||
* member to call a function that then just turns and calls ipw2100_up.
|
||||
* net_dev->init is called after name allocation but before the
|
||||
* notifier chain is called */
|
||||
*/
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
|
@ -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;
|
||||
|
@ -201,6 +201,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
|
||||
WIPHY_FLAG_DISABLE_BEACON_HINTS |
|
||||
WIPHY_FLAG_IBSS_RSN;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
|
||||
priv->trans->ops->wowlan_suspend &&
|
||||
device_can_wakeup(priv->trans->dev)) {
|
||||
@ -219,6 +220,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
|
||||
hw->wiphy->wowlan.pattern_max_len =
|
||||
IWLAGN_WOWLAN_MAX_PATTERN_LEN;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (iwlwifi_mod_params.power_save)
|
||||
hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
@ -251,6 +253,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
|
||||
ret = ieee80211_register_hw(priv->hw);
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
|
||||
iwl_leds_exit(priv);
|
||||
return ret;
|
||||
}
|
||||
priv->mac80211_registered = 1;
|
||||
|
@ -1251,7 +1251,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
|
||||
key_flags |= STA_KEY_MULTICAST_MSK;
|
||||
|
||||
sta_cmd.key.key_flags = key_flags;
|
||||
sta_cmd.key.key_offset = WEP_INVALID_OFFSET;
|
||||
sta_cmd.key.key_offset = keyconf->hw_key_idx;
|
||||
sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
|
||||
|
||||
|
@ -899,7 +899,6 @@ 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);
|
||||
complete(&drv->request_firmware_complete);
|
||||
|
||||
mutex_lock(&iwlwifi_opmode_table_mtx);
|
||||
op = &iwlwifi_opmode_table[DVM_OP_MODE];
|
||||
@ -910,11 +909,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
||||
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);
|
||||
}
|
||||
mutex_unlock(&iwlwifi_opmode_table_mtx);
|
||||
|
||||
/*
|
||||
* Complete the firmware request last so that
|
||||
* a driver unbind (stop) doesn't run while we
|
||||
* are doing the start() above.
|
||||
*/
|
||||
complete(&drv->request_firmware_complete);
|
||||
return;
|
||||
|
||||
try_again:
|
||||
|
@ -224,6 +224,7 @@
|
||||
#define SCD_TXFACT (SCD_BASE + 0x10)
|
||||
#define SCD_ACTIVE (SCD_BASE + 0x14)
|
||||
#define SCD_QUEUECHAIN_SEL (SCD_BASE + 0xe8)
|
||||
#define SCD_CHAINEXT_EN (SCD_BASE + 0x244)
|
||||
#define SCD_AGGR_SEL (SCD_BASE + 0x248)
|
||||
#define SCD_INTERRUPT_MASK (SCD_BASE + 0x108)
|
||||
|
||||
|
@ -35,17 +35,20 @@
|
||||
#define IWL6000_UCODE_API_MAX 6
|
||||
#define IWL6050_UCODE_API_MAX 5
|
||||
#define IWL6000G2_UCODE_API_MAX 6
|
||||
#define IWL6035_UCODE_API_MAX 6
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL6000_UCODE_API_OK 4
|
||||
#define IWL6000G2_UCODE_API_OK 5
|
||||
#define IWL6050_UCODE_API_OK 5
|
||||
#define IWL6000G2B_UCODE_API_OK 6
|
||||
#define IWL6035_UCODE_API_OK 6
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL6000_UCODE_API_MIN 4
|
||||
#define IWL6050_UCODE_API_MIN 4
|
||||
#define IWL6000G2_UCODE_API_MIN 4
|
||||
#define IWL6000G2_UCODE_API_MIN 5
|
||||
#define IWL6035_UCODE_API_MIN 6
|
||||
|
||||
/* EEPROM versions */
|
||||
#define EEPROM_6000_TX_POWER_VERSION (4)
|
||||
@ -243,9 +246,25 @@ const struct iwl_cfg iwl6030_2bg_cfg = {
|
||||
IWL_DEVICE_6030,
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_6035 \
|
||||
.fw_name_pre = IWL6030_FW_PRE, \
|
||||
.ucode_api_max = IWL6035_UCODE_API_MAX, \
|
||||
.ucode_api_ok = IWL6035_UCODE_API_OK, \
|
||||
.ucode_api_min = IWL6035_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_6030, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.eeprom_ver = EEPROM_6030_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
.bt_params = &iwl6000_bt_params, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.adv_pm = true
|
||||
|
||||
const struct iwl_cfg iwl6035_2agn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
|
||||
IWL_DEVICE_6030,
|
||||
IWL_DEVICE_6035,
|
||||
.ht_params = &iwl6000_ht_params,
|
||||
};
|
||||
|
||||
|
@ -1083,6 +1083,11 @@ static void iwl_tx_start(struct iwl_trans *trans)
|
||||
iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
|
||||
trans_pcie->scd_bc_tbls.dma >> 10);
|
||||
|
||||
/* The chain extension of the SCD doesn't work well. This feature is
|
||||
* enabled by default by the HW, so we need to disable it manually.
|
||||
*/
|
||||
iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
|
||||
|
||||
for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
|
||||
int fifo = trans_pcie->setup_q_to_fifo[i];
|
||||
|
||||
|
@ -435,24 +435,40 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
|
||||
* Set Channel
|
||||
*/
|
||||
|
||||
static int lbs_cfg_set_channel(struct wiphy *wiphy,
|
||||
struct net_device *netdev,
|
||||
struct ieee80211_channel *channel,
|
||||
enum nl80211_channel_type channel_type)
|
||||
static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
int ret = -ENOTSUPP;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
|
||||
netdev_name(netdev), channel->center_freq, channel_type);
|
||||
lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
|
||||
channel->center_freq, channel_type);
|
||||
|
||||
if (channel_type != NL80211_CHAN_NO_HT)
|
||||
goto out;
|
||||
|
||||
if (netdev == priv->mesh_dev)
|
||||
ret = lbs_mesh_set_channel(priv, channel->hw_value);
|
||||
else
|
||||
ret = lbs_set_channel(priv, channel->hw_value);
|
||||
ret = lbs_set_channel(priv, channel->hw_value);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
|
||||
struct net_device *netdev,
|
||||
struct ieee80211_channel *channel)
|
||||
{
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
int ret = -ENOTSUPP;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
|
||||
netdev_name(netdev), channel->center_freq);
|
||||
|
||||
if (netdev != priv->mesh_dev)
|
||||
goto out;
|
||||
|
||||
ret = lbs_mesh_set_channel(priv, channel->hw_value);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
@ -2029,7 +2045,8 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
|
||||
*/
|
||||
|
||||
static struct cfg80211_ops lbs_cfg80211_ops = {
|
||||
.set_channel = lbs_cfg_set_channel,
|
||||
.set_monitor_channel = lbs_cfg_set_monitor_channel,
|
||||
.libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
|
||||
.scan = lbs_cfg_scan,
|
||||
.connect = lbs_cfg_connect,
|
||||
.disconnect = lbs_cfg_disconnect,
|
||||
|
@ -58,6 +58,7 @@ struct lbs_private {
|
||||
uint16_t mesh_tlv;
|
||||
u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
|
||||
u8 mesh_ssid_len;
|
||||
u8 mesh_channel;
|
||||
#endif
|
||||
|
||||
/* Debugfs */
|
||||
|
@ -131,16 +131,13 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
|
||||
|
||||
int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
|
||||
{
|
||||
priv->mesh_channel = channel;
|
||||
return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
|
||||
}
|
||||
|
||||
static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
|
||||
{
|
||||
struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
|
||||
if (mesh_wdev->channel)
|
||||
return mesh_wdev->channel->hw_value;
|
||||
else
|
||||
return 1;
|
||||
return priv->mesh_channel ?: 1;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -1555,6 +1555,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2);
|
||||
}
|
||||
txi->flags |= IEEE80211_TX_STAT_ACK;
|
||||
}
|
||||
ieee80211_tx_status_irqsafe(data2->hw, skb);
|
||||
return 0;
|
||||
@ -1721,6 +1722,24 @@ static void hwsim_exit_netlink(void)
|
||||
"unregister family %i\n", ret);
|
||||
}
|
||||
|
||||
static const struct ieee80211_iface_limit hwsim_if_limits[] = {
|
||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
|
||||
{ .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) },
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination hwsim_if_comb = {
|
||||
.limits = hwsim_if_limits,
|
||||
.n_limits = ARRAY_SIZE(hwsim_if_limits),
|
||||
.max_interfaces = 2048,
|
||||
.num_different_channels = 1,
|
||||
};
|
||||
|
||||
static int __init init_mac80211_hwsim(void)
|
||||
{
|
||||
int i, err = 0;
|
||||
@ -1782,6 +1801,9 @@ static int __init init_mac80211_hwsim(void)
|
||||
hw->wiphy->n_addresses = 2;
|
||||
hw->wiphy->addresses = data->addresses;
|
||||
|
||||
hw->wiphy->iface_combinations = &hwsim_if_comb;
|
||||
hw->wiphy->n_iface_combinations = 1;
|
||||
|
||||
if (fake_hw_scan) {
|
||||
hw->wiphy->max_scan_ssids = 255;
|
||||
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
|
||||
|
@ -57,6 +57,68 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void scan_delay_timer_fn(unsigned long data)
|
||||
{
|
||||
struct mwifiex_private *priv = (struct mwifiex_private *)data;
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
struct cmd_ctrl_node *cmd_node, *tmp_node;
|
||||
unsigned long flags;
|
||||
|
||||
if (!mwifiex_wmm_lists_empty(adapter)) {
|
||||
if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
|
||||
/*
|
||||
* Abort scan operation by cancelling all pending scan
|
||||
* command
|
||||
*/
|
||||
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
|
||||
list_for_each_entry_safe(cmd_node, tmp_node,
|
||||
&adapter->scan_pending_q,
|
||||
list) {
|
||||
list_del(&cmd_node->list);
|
||||
cmd_node->wait_q_enabled = false;
|
||||
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
|
||||
}
|
||||
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
|
||||
flags);
|
||||
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
|
||||
adapter->scan_processing = false;
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock,
|
||||
flags);
|
||||
|
||||
if (priv->user_scan_cfg) {
|
||||
dev_dbg(priv->adapter->dev,
|
||||
"info: %s: scan aborted\n", __func__);
|
||||
cfg80211_scan_done(priv->scan_request, 1);
|
||||
priv->scan_request = NULL;
|
||||
kfree(priv->user_scan_cfg);
|
||||
priv->user_scan_cfg = NULL;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Tx data queue is still not empty, delay scan
|
||||
* operation further by 20msec.
|
||||
*/
|
||||
mod_timer(&priv->scan_delay_timer, jiffies +
|
||||
msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
|
||||
adapter->scan_delay_cnt++;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Tx data queue is empty. Get scan command from scan_pending_q
|
||||
* and put to cmd_pending_q to resume scan operation
|
||||
*/
|
||||
adapter->scan_delay_cnt = 0;
|
||||
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
|
||||
cmd_node = list_first_entry(&adapter->scan_pending_q,
|
||||
struct cmd_ctrl_node, list);
|
||||
list_del(&cmd_node->list);
|
||||
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
|
||||
|
||||
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initializes the private structure and sets default
|
||||
* values to the members.
|
||||
@ -136,6 +198,9 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
|
||||
|
||||
priv->scan_block = false;
|
||||
|
||||
setup_timer(&priv->scan_delay_timer, scan_delay_timer_fn,
|
||||
(unsigned long)priv);
|
||||
|
||||
return mwifiex_add_bss_prio_tbl(priv);
|
||||
}
|
||||
|
||||
|
@ -244,8 +244,8 @@ process_start:
|
||||
}
|
||||
}
|
||||
|
||||
if (!adapter->scan_processing && !adapter->data_sent &&
|
||||
!mwifiex_wmm_lists_empty(adapter)) {
|
||||
if ((!adapter->scan_processing || adapter->scan_delay_cnt) &&
|
||||
!adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) {
|
||||
mwifiex_wmm_process_tx(adapter);
|
||||
if (adapter->hs_activated) {
|
||||
adapter->is_hs_configured = false;
|
||||
|
@ -79,14 +79,17 @@ enum {
|
||||
|
||||
#define SCAN_BEACON_ENTRY_PAD 6
|
||||
|
||||
#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200
|
||||
#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 200
|
||||
#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 110
|
||||
#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 110
|
||||
#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 30
|
||||
#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 30
|
||||
|
||||
#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
|
||||
|
||||
#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
|
||||
|
||||
#define MWIFIEX_MAX_SCAN_DELAY_CNT 50
|
||||
#define MWIFIEX_SCAN_DELAY_MSEC 20
|
||||
|
||||
#define RSN_GTK_OUI_OFFSET 2
|
||||
|
||||
#define MWIFIEX_OUI_NOT_PRESENT 0
|
||||
@ -482,6 +485,7 @@ struct mwifiex_private {
|
||||
u16 proberesp_idx;
|
||||
u16 assocresp_idx;
|
||||
u16 rsn_idx;
|
||||
struct timer_list scan_delay_timer;
|
||||
};
|
||||
|
||||
enum mwifiex_ba_status {
|
||||
@ -686,6 +690,7 @@ struct mwifiex_adapter {
|
||||
struct completion fw_load;
|
||||
u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
|
||||
u16 max_mgmt_ie_index;
|
||||
u8 scan_delay_cnt;
|
||||
};
|
||||
|
||||
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
|
||||
|
@ -28,7 +28,10 @@
|
||||
/* The maximum number of channels the firmware can scan per command */
|
||||
#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14
|
||||
|
||||
#define MWIFIEX_CHANNELS_PER_SCAN_CMD 4
|
||||
#define MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD 4
|
||||
#define MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD 15
|
||||
#define MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD 27
|
||||
#define MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD 35
|
||||
|
||||
/* Memory needed to store a max sized Channel List TLV for a firmware scan */
|
||||
#define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \
|
||||
@ -471,7 +474,7 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
|
||||
* This routine is used for any scan that is not provided with a
|
||||
* specific channel list to scan.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
|
||||
const struct mwifiex_user_scan_cfg
|
||||
*user_scan_in,
|
||||
@ -528,6 +531,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
|
||||
}
|
||||
|
||||
}
|
||||
return chan_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -727,6 +731,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
|
||||
u32 num_probes;
|
||||
u32 ssid_len;
|
||||
u32 chan_idx;
|
||||
u32 chan_num;
|
||||
u32 scan_type;
|
||||
u16 scan_dur;
|
||||
u8 channel;
|
||||
@ -850,7 +855,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
|
||||
if (*filtered_scan)
|
||||
*max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
|
||||
else
|
||||
*max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD;
|
||||
*max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD;
|
||||
|
||||
/* If the input config or adapter has the number of Probes set,
|
||||
add tlv */
|
||||
@ -962,13 +967,28 @@ mwifiex_config_scan(struct mwifiex_private *priv,
|
||||
dev_dbg(adapter->dev,
|
||||
"info: Scan: Scanning current channel only\n");
|
||||
}
|
||||
|
||||
chan_num = chan_idx;
|
||||
} else {
|
||||
dev_dbg(adapter->dev,
|
||||
"info: Scan: Creating full region channel list\n");
|
||||
mwifiex_scan_create_channel_list(priv, user_scan_in,
|
||||
scan_chan_list,
|
||||
*filtered_scan);
|
||||
chan_num = mwifiex_scan_create_channel_list(priv, user_scan_in,
|
||||
scan_chan_list,
|
||||
*filtered_scan);
|
||||
}
|
||||
|
||||
/*
|
||||
* In associated state we will reduce the number of channels scanned per
|
||||
* scan command to avoid any traffic delay/loss. This number is decided
|
||||
* based on total number of channels to be scanned due to constraints
|
||||
* of command buffers.
|
||||
*/
|
||||
if (priv->media_connected) {
|
||||
if (chan_num < MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD)
|
||||
*max_chan_per_scan = 1;
|
||||
else if (chan_num < MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD)
|
||||
*max_chan_per_scan = 2;
|
||||
else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD)
|
||||
*max_chan_per_scan = 3;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1772,14 +1792,23 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
|
||||
priv->user_scan_cfg = NULL;
|
||||
}
|
||||
} else {
|
||||
/* Get scan command from scan_pending_q and put to
|
||||
cmd_pending_q */
|
||||
cmd_node = list_first_entry(&adapter->scan_pending_q,
|
||||
struct cmd_ctrl_node, list);
|
||||
list_del(&cmd_node->list);
|
||||
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
|
||||
|
||||
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
|
||||
if (!mwifiex_wmm_lists_empty(adapter)) {
|
||||
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
|
||||
flags);
|
||||
adapter->scan_delay_cnt = 1;
|
||||
mod_timer(&priv->scan_delay_timer, jiffies +
|
||||
msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
|
||||
} else {
|
||||
/* Get scan command from scan_pending_q and put to
|
||||
cmd_pending_q */
|
||||
cmd_node = list_first_entry(&adapter->scan_pending_q,
|
||||
struct cmd_ctrl_node, list);
|
||||
list_del(&cmd_node->list);
|
||||
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
|
||||
flags);
|
||||
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
@ -160,10 +160,9 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int orinoco_set_channel(struct wiphy *wiphy,
|
||||
struct net_device *netdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
static int orinoco_set_monitor_channel(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct orinoco_private *priv = wiphy_priv(wiphy);
|
||||
int err = 0;
|
||||
@ -286,7 +285,7 @@ static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
||||
|
||||
const struct cfg80211_ops orinoco_cfg_ops = {
|
||||
.change_virtual_intf = orinoco_change_vif,
|
||||
.set_channel = orinoco_set_channel,
|
||||
.set_monitor_channel = orinoco_set_monitor_channel,
|
||||
.scan = orinoco_scan,
|
||||
.set_wiphy_params = orinoco_set_wiphy_params,
|
||||
};
|
||||
|
@ -72,6 +72,7 @@
|
||||
#define RF5370 0x5370
|
||||
#define RF5372 0x5372
|
||||
#define RF5390 0x5390
|
||||
#define RF5392 0x5392
|
||||
|
||||
/*
|
||||
* Chipset revisions.
|
||||
@ -1945,6 +1946,11 @@ struct mac_iveiv_entry {
|
||||
*/
|
||||
#define RFCSR49_TX FIELD8(0x3f)
|
||||
|
||||
/*
|
||||
* RFCSR 50:
|
||||
*/
|
||||
#define RFCSR50_TX FIELD8(0x3f)
|
||||
|
||||
/*
|
||||
* RF registers
|
||||
*/
|
||||
|
@ -1958,7 +1958,22 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
|
||||
rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
|
||||
rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
|
||||
|
||||
if (rt2x00_rt(rt2x00dev, RT5392)) {
|
||||
rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
|
||||
if (info->default_power1 > RT5390_POWER_BOUND)
|
||||
rt2x00_set_field8(&rfcsr, RFCSR50_TX,
|
||||
RT5390_POWER_BOUND);
|
||||
else
|
||||
rt2x00_set_field8(&rfcsr, RFCSR50_TX,
|
||||
info->default_power2);
|
||||
rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
|
||||
}
|
||||
|
||||
rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
|
||||
if (rt2x00_rt(rt2x00dev, RT5392)) {
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
|
||||
}
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
|
||||
@ -2064,6 +2079,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
|
||||
case RF5370:
|
||||
case RF5372:
|
||||
case RF5390:
|
||||
case RF5392:
|
||||
rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
|
||||
break;
|
||||
default:
|
||||
@ -2554,6 +2570,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
|
||||
case RF5370:
|
||||
case RF5372:
|
||||
case RF5390:
|
||||
case RF5392:
|
||||
rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
|
||||
rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
|
||||
@ -4269,6 +4286,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
|
||||
case RF5370:
|
||||
case RF5372:
|
||||
case RF5390:
|
||||
case RF5392:
|
||||
break;
|
||||
default:
|
||||
ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n",
|
||||
@ -4583,7 +4601,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
||||
rt2x00_rf(rt2x00dev, RF5360) ||
|
||||
rt2x00_rf(rt2x00dev, RF5370) ||
|
||||
rt2x00_rf(rt2x00dev, RF5372) ||
|
||||
rt2x00_rf(rt2x00dev, RF5390)) {
|
||||
rt2x00_rf(rt2x00dev, RF5390) ||
|
||||
rt2x00_rf(rt2x00dev, RF5392)) {
|
||||
spec->num_channels = 14;
|
||||
spec->channels = rf_vals_3x;
|
||||
} else if (rt2x00_rf(rt2x00dev, RF3052)) {
|
||||
@ -4670,6 +4689,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
||||
case RF5370:
|
||||
case RF5372:
|
||||
case RF5390:
|
||||
case RF5392:
|
||||
__set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags);
|
||||
break;
|
||||
}
|
||||
|
@ -396,8 +396,7 @@ struct rt2x00_intf {
|
||||
* for hardware which doesn't support hardware
|
||||
* sequence counting.
|
||||
*/
|
||||
spinlock_t seqlock;
|
||||
u16 seqno;
|
||||
atomic_t seqno;
|
||||
};
|
||||
|
||||
static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
|
||||
|
@ -1161,6 +1161,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
BIT(NL80211_IFTYPE_WDS);
|
||||
|
||||
rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
|
||||
|
||||
/*
|
||||
* Initialize work.
|
||||
*/
|
||||
|
@ -277,7 +277,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
|
||||
else
|
||||
rt2x00dev->intf_sta_count++;
|
||||
|
||||
spin_lock_init(&intf->seqlock);
|
||||
mutex_init(&intf->beacon_skb_mutex);
|
||||
intf->beacon = entry;
|
||||
|
||||
@ -507,9 +506,19 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
|
||||
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
|
||||
return 0;
|
||||
else if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
|
||||
|
||||
if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
|
||||
return -EOPNOTSUPP;
|
||||
else if (key->keylen > 32)
|
||||
|
||||
/*
|
||||
* 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))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (key->keylen > 32)
|
||||
return -ENOSPC;
|
||||
|
||||
memset(&crypto, 0, sizeof(crypto));
|
||||
|
@ -207,6 +207,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
|
||||
u16 seqno;
|
||||
|
||||
if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
|
||||
return;
|
||||
@ -238,15 +239,13 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
|
||||
* sequence counting per-frame, since those will override the
|
||||
* sequence counter given by mac80211.
|
||||
*/
|
||||
spin_lock(&intf->seqlock);
|
||||
|
||||
if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
|
||||
intf->seqno += 0x10;
|
||||
seqno = atomic_add_return(0x10, &intf->seqno);
|
||||
else
|
||||
seqno = atomic_read(&intf->seqno);
|
||||
|
||||
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
|
||||
hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
|
||||
|
||||
spin_unlock(&intf->seqlock);
|
||||
|
||||
hdr->seq_ctrl |= cpu_to_le16(seqno);
|
||||
}
|
||||
|
||||
static void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev,
|
||||
|
@ -117,7 +117,7 @@ static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
|
||||
radio_on = true;
|
||||
} else if (radio_on) {
|
||||
radio_on = false;
|
||||
cancel_delayed_work_sync(&priv->led_on);
|
||||
cancel_delayed_work(&priv->led_on);
|
||||
ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
|
||||
}
|
||||
} else if (radio_on) {
|
||||
|
@ -8,6 +8,7 @@ menuconfig WL_TI
|
||||
if WL_TI
|
||||
source "drivers/net/wireless/ti/wl1251/Kconfig"
|
||||
source "drivers/net/wireless/ti/wl12xx/Kconfig"
|
||||
source "drivers/net/wireless/ti/wl18xx/Kconfig"
|
||||
|
||||
# keep last for automatic dependencies
|
||||
source "drivers/net/wireless/ti/wlcore/Kconfig"
|
||||
|
@ -2,3 +2,4 @@ obj-$(CONFIG_WLCORE) += wlcore/
|
||||
obj-$(CONFIG_WL12XX) += wl12xx/
|
||||
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wlcore/
|
||||
obj-$(CONFIG_WL1251) += wl1251/
|
||||
obj-$(CONFIG_WL18XX) += wl18xx/
|
||||
|
@ -1,3 +1,3 @@
|
||||
wl12xx-objs = main.o cmd.o acx.o
|
||||
wl12xx-objs = main.o cmd.o acx.o debugfs.o
|
||||
|
||||
obj-$(CONFIG_WL12XX) += wl12xx.o
|
||||
|
@ -24,6 +24,21 @@
|
||||
#define __WL12XX_ACX_H__
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
#include "../wlcore/acx.h"
|
||||
|
||||
#define WL12XX_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_INIT_COMPLETE | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_CMD_COMPLETE | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
|
||||
#define WL12XX_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
|
||||
struct wl1271_acx_host_config_bitmap {
|
||||
struct acx_header header;
|
||||
@ -31,6 +46,228 @@ struct wl1271_acx_host_config_bitmap {
|
||||
__le32 host_cfg_bitmap;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_tx_statistics {
|
||||
__le32 internal_desc_overflow;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_rx_statistics {
|
||||
__le32 out_of_mem;
|
||||
__le32 hdr_overflow;
|
||||
__le32 hw_stuck;
|
||||
__le32 dropped;
|
||||
__le32 fcs_err;
|
||||
__le32 xfr_hint_trig;
|
||||
__le32 path_reset;
|
||||
__le32 reset_counter;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_dma_statistics {
|
||||
__le32 rx_requested;
|
||||
__le32 rx_errors;
|
||||
__le32 tx_requested;
|
||||
__le32 tx_errors;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_isr_statistics {
|
||||
/* host command complete */
|
||||
__le32 cmd_cmplt;
|
||||
|
||||
/* fiqisr() */
|
||||
__le32 fiqs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_HEADER) */
|
||||
__le32 rx_headers;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
|
||||
__le32 rx_completes;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
|
||||
__le32 rx_mem_overflow;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
|
||||
__le32 rx_rdys;
|
||||
|
||||
/* irqisr() */
|
||||
__le32 irqs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_TX_PROC) */
|
||||
__le32 tx_procs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
|
||||
__le32 decrypt_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DMA0) */
|
||||
__le32 dma0_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DMA1) */
|
||||
__le32 dma1_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
|
||||
__le32 tx_exch_complete;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_COMMAND) */
|
||||
__le32 commands;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_PROC) */
|
||||
__le32 rx_procs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_PM_802) */
|
||||
__le32 hw_pm_mode_changes;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
|
||||
__le32 host_acknowledges;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_PM_PCI) */
|
||||
__le32 pci_pm;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
|
||||
__le32 wakeups;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
|
||||
__le32 low_rssi;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_wep_statistics {
|
||||
/* WEP address keys configured */
|
||||
__le32 addr_key_count;
|
||||
|
||||
/* default keys configured */
|
||||
__le32 default_key_count;
|
||||
|
||||
__le32 reserved;
|
||||
|
||||
/* number of times that WEP key not found on lookup */
|
||||
__le32 key_not_found;
|
||||
|
||||
/* number of times that WEP key decryption failed */
|
||||
__le32 decrypt_fail;
|
||||
|
||||
/* WEP packets decrypted */
|
||||
__le32 packets;
|
||||
|
||||
/* WEP decrypt interrupts */
|
||||
__le32 interrupt;
|
||||
} __packed;
|
||||
|
||||
#define ACX_MISSED_BEACONS_SPREAD 10
|
||||
|
||||
struct wl12xx_acx_pwr_statistics {
|
||||
/* the amount of enters into power save mode (both PD & ELP) */
|
||||
__le32 ps_enter;
|
||||
|
||||
/* the amount of enters into ELP mode */
|
||||
__le32 elp_enter;
|
||||
|
||||
/* the amount of missing beacon interrupts to the host */
|
||||
__le32 missing_bcns;
|
||||
|
||||
/* the amount of wake on host-access times */
|
||||
__le32 wake_on_host;
|
||||
|
||||
/* the amount of wake on timer-expire */
|
||||
__le32 wake_on_timer_exp;
|
||||
|
||||
/* the number of packets that were transmitted with PS bit set */
|
||||
__le32 tx_with_ps;
|
||||
|
||||
/* the number of packets that were transmitted with PS bit clear */
|
||||
__le32 tx_without_ps;
|
||||
|
||||
/* the number of received beacons */
|
||||
__le32 rcvd_beacons;
|
||||
|
||||
/* the number of entering into PowerOn (power save off) */
|
||||
__le32 power_save_off;
|
||||
|
||||
/* the number of entries into power save mode */
|
||||
__le16 enable_ps;
|
||||
|
||||
/*
|
||||
* the number of exits from power save, not including failed PS
|
||||
* transitions
|
||||
*/
|
||||
__le16 disable_ps;
|
||||
|
||||
/*
|
||||
* the number of times the TSF counter was adjusted because
|
||||
* of drift
|
||||
*/
|
||||
__le32 fix_tsf_ps;
|
||||
|
||||
/* Gives statistics about the spread continuous missed beacons.
|
||||
* The 16 LSB are dedicated for the PS mode.
|
||||
* The 16 MSB are dedicated for the PS mode.
|
||||
* cont_miss_bcns_spread[0] - single missed beacon.
|
||||
* cont_miss_bcns_spread[1] - two continuous missed beacons.
|
||||
* cont_miss_bcns_spread[2] - three continuous missed beacons.
|
||||
* ...
|
||||
* cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
|
||||
*/
|
||||
__le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
|
||||
|
||||
/* the number of beacons in awake mode */
|
||||
__le32 rcvd_awake_beacons;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_mic_statistics {
|
||||
__le32 rx_pkts;
|
||||
__le32 calc_failure;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_aes_statistics {
|
||||
__le32 encrypt_fail;
|
||||
__le32 decrypt_fail;
|
||||
__le32 encrypt_packets;
|
||||
__le32 decrypt_packets;
|
||||
__le32 encrypt_interrupt;
|
||||
__le32 decrypt_interrupt;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_event_statistics {
|
||||
__le32 heart_beat;
|
||||
__le32 calibration;
|
||||
__le32 rx_mismatch;
|
||||
__le32 rx_mem_empty;
|
||||
__le32 rx_pool;
|
||||
__le32 oom_late;
|
||||
__le32 phy_transmit_error;
|
||||
__le32 tx_stuck;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_ps_statistics {
|
||||
__le32 pspoll_timeouts;
|
||||
__le32 upsd_timeouts;
|
||||
__le32 upsd_max_sptime;
|
||||
__le32 upsd_max_apturn;
|
||||
__le32 pspoll_max_apturn;
|
||||
__le32 pspoll_utilization;
|
||||
__le32 upsd_utilization;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_rxpipe_statistics {
|
||||
__le32 rx_prep_beacon_drop;
|
||||
__le32 descr_host_int_trig_rx_data;
|
||||
__le32 beacon_buffer_thres_host_int_trig_rx_data;
|
||||
__le32 missed_beacon_host_int_trig_rx_data;
|
||||
__le32 tx_xfr_host_int_trig_rx_data;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_acx_statistics {
|
||||
struct acx_header header;
|
||||
|
||||
struct wl12xx_acx_tx_statistics tx;
|
||||
struct wl12xx_acx_rx_statistics rx;
|
||||
struct wl12xx_acx_dma_statistics dma;
|
||||
struct wl12xx_acx_isr_statistics isr;
|
||||
struct wl12xx_acx_wep_statistics wep;
|
||||
struct wl12xx_acx_pwr_statistics pwr;
|
||||
struct wl12xx_acx_aes_statistics aes;
|
||||
struct wl12xx_acx_mic_statistics mic;
|
||||
struct wl12xx_acx_event_statistics event;
|
||||
struct wl12xx_acx_ps_statistics ps;
|
||||
struct wl12xx_acx_rxpipe_statistics rxpipe;
|
||||
} __packed;
|
||||
|
||||
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
|
||||
|
||||
#endif /* __WL12XX_ACX_H__ */
|
||||
|
@ -65,6 +65,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
|
||||
struct wl1271_general_parms_cmd *gen_parms;
|
||||
struct wl1271_ini_general_params *gp =
|
||||
&((struct wl1271_nvs_file *)wl->nvs)->general_params;
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
bool answer = false;
|
||||
int ret;
|
||||
|
||||
@ -88,7 +89,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
|
||||
answer = true;
|
||||
|
||||
/* Override the REF CLK from the NVS with the one from platform data */
|
||||
gen_parms->general_params.ref_clock = wl->ref_clock;
|
||||
gen_parms->general_params.ref_clock = priv->ref_clock;
|
||||
|
||||
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
|
||||
if (ret < 0) {
|
||||
@ -118,6 +119,7 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
|
||||
struct wl128x_general_parms_cmd *gen_parms;
|
||||
struct wl128x_ini_general_params *gp =
|
||||
&((struct wl128x_nvs_file *)wl->nvs)->general_params;
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
bool answer = false;
|
||||
int ret;
|
||||
|
||||
@ -141,8 +143,8 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
|
||||
answer = true;
|
||||
|
||||
/* Replace REF and TCXO CLKs with the ones from platform data */
|
||||
gen_parms->general_params.ref_clock = wl->ref_clock;
|
||||
gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
|
||||
gen_parms->general_params.ref_clock = priv->ref_clock;
|
||||
gen_parms->general_params.tcxo_ref_clock = priv->tcxo_clock;
|
||||
|
||||
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
|
||||
if (ret < 0) {
|
||||
|
243
drivers/net/wireless/ti/wl12xx/debugfs.c
Normal file
243
drivers/net/wireless/ti/wl12xx/debugfs.c
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* This file is part of wl12xx
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Copyright (C) 2011-2012 Texas Instruments
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/debugfs.h"
|
||||
#include "../wlcore/wlcore.h"
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "acx.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
#define WL12XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
|
||||
DEBUGFS_FWSTATS_FILE(a, b, c, wl12xx_acx_statistics)
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, dropped, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, commands, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u");
|
||||
/* skipping wep.reserved */
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, packets, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u");
|
||||
/* skipping cont_miss_bcns_spread for now */
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, calibration, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, oom_late, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u");
|
||||
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data,
|
||||
"%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u");
|
||||
WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u");
|
||||
|
||||
int wl12xx_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dentry *entry, *stats, *moddir;
|
||||
|
||||
moddir = debugfs_create_dir(KBUILD_MODNAME, rootdir);
|
||||
if (!moddir || IS_ERR(moddir)) {
|
||||
entry = moddir;
|
||||
goto err;
|
||||
}
|
||||
|
||||
stats = debugfs_create_dir("fw_stats", moddir);
|
||||
if (!stats || IS_ERR(stats)) {
|
||||
entry = stats;
|
||||
goto err;
|
||||
}
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
|
||||
DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
|
||||
DEBUGFS_FWSTATS_ADD(rx, dropped);
|
||||
DEBUGFS_FWSTATS_ADD(rx, fcs_err);
|
||||
DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
|
||||
DEBUGFS_FWSTATS_ADD(rx, path_reset);
|
||||
DEBUGFS_FWSTATS_ADD(rx, reset_counter);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(dma, rx_requested);
|
||||
DEBUGFS_FWSTATS_ADD(dma, rx_errors);
|
||||
DEBUGFS_FWSTATS_ADD(dma, tx_requested);
|
||||
DEBUGFS_FWSTATS_ADD(dma, tx_errors);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
|
||||
DEBUGFS_FWSTATS_ADD(isr, fiqs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_headers);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
|
||||
DEBUGFS_FWSTATS_ADD(isr, irqs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, tx_procs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, dma0_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, dma1_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
|
||||
DEBUGFS_FWSTATS_ADD(isr, commands);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_procs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
|
||||
DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
|
||||
DEBUGFS_FWSTATS_ADD(isr, pci_pm);
|
||||
DEBUGFS_FWSTATS_ADD(isr, wakeups);
|
||||
DEBUGFS_FWSTATS_ADD(isr, low_rssi);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
|
||||
DEBUGFS_FWSTATS_ADD(wep, default_key_count);
|
||||
/* skipping wep.reserved */
|
||||
DEBUGFS_FWSTATS_ADD(wep, key_not_found);
|
||||
DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(wep, packets);
|
||||
DEBUGFS_FWSTATS_ADD(wep, interrupt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
|
||||
/* skipping cont_miss_bcns_spread for now */
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
|
||||
DEBUGFS_FWSTATS_ADD(mic, calc_failure);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(event, heart_beat);
|
||||
DEBUGFS_FWSTATS_ADD(event, calibration);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_pool);
|
||||
DEBUGFS_FWSTATS_ADD(event, oom_late);
|
||||
DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
|
||||
DEBUGFS_FWSTATS_ADD(event, tx_stuck);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (IS_ERR(entry))
|
||||
ret = PTR_ERR(entry);
|
||||
else
|
||||
ret = -ENOMEM;
|
||||
|
||||
return ret;
|
||||
}
|
28
drivers/net/wireless/ti/wl12xx/debugfs.h
Normal file
28
drivers/net/wireless/ti/wl12xx/debugfs.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of wl12xx
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL12XX_DEBUGFS_H__
|
||||
#define __WL12XX_DEBUGFS_H__
|
||||
|
||||
int wl12xx_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir);
|
||||
|
||||
#endif /* __WL12XX_DEBUGFS_H__ */
|
@ -39,6 +39,10 @@
|
||||
#include "reg.h"
|
||||
#include "cmd.h"
|
||||
#include "acx.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
static char *fref_param;
|
||||
static char *tcxo_param;
|
||||
|
||||
static struct wlcore_conf wl12xx_conf = {
|
||||
.sg = {
|
||||
@ -212,7 +216,7 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
|
||||
.suspend_listen_interval = 3,
|
||||
.bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
|
||||
.bcn_filt_ie_count = 2,
|
||||
.bcn_filt_ie_count = 3,
|
||||
.bcn_filt_ie = {
|
||||
[0] = {
|
||||
.ie = WLAN_EID_CHANNEL_SWITCH,
|
||||
@ -222,9 +226,13 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
.ie = WLAN_EID_HT_OPERATION,
|
||||
.rule = CONF_BCN_RULE_PASS_ON_CHANGE,
|
||||
},
|
||||
[2] = {
|
||||
.ie = WLAN_EID_ERP_INFO,
|
||||
.rule = CONF_BCN_RULE_PASS_ON_CHANGE,
|
||||
},
|
||||
},
|
||||
.synch_fail_thold = 10,
|
||||
.bss_lose_timeout = 100,
|
||||
.synch_fail_thold = 12,
|
||||
.bss_lose_timeout = 400,
|
||||
.beacon_rx_timeout = 10000,
|
||||
.broadcast_timeout = 20000,
|
||||
.rx_broadcast_in_ps = 1,
|
||||
@ -234,7 +242,7 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
.psm_entry_retries = 8,
|
||||
.psm_exit_retries = 16,
|
||||
.psm_entry_nullfunc_retries = 3,
|
||||
.dynamic_ps_timeout = 40,
|
||||
.dynamic_ps_timeout = 200,
|
||||
.forced_ps = false,
|
||||
.keep_alive_interval = 55000,
|
||||
.max_listen_interval = 20,
|
||||
@ -245,7 +253,7 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
},
|
||||
.pm_config = {
|
||||
.host_clk_settling_time = 5000,
|
||||
.host_fast_wakeup_support = false
|
||||
.host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
|
||||
},
|
||||
.roam_trigger = {
|
||||
.trigger_pacing = 1,
|
||||
@ -305,8 +313,8 @@ static struct wlcore_conf wl12xx_conf = {
|
||||
.swallow_period = 5,
|
||||
.n_divider_fref_set_1 = 0xff, /* default */
|
||||
.n_divider_fref_set_2 = 12,
|
||||
.m_divider_fref_set_1 = 148,
|
||||
.m_divider_fref_set_2 = 0xffff, /* default */
|
||||
.m_divider_fref_set_1 = 0xffff,
|
||||
.m_divider_fref_set_2 = 148, /* default */
|
||||
.coex_pll_stabilization_time = 0xffffffff, /* default */
|
||||
.ldo_stabilization_time = 0xffff, /* default */
|
||||
.fm_disturbed_band_margin = 0xff, /* default */
|
||||
@ -593,7 +601,7 @@ static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
|
||||
{
|
||||
if (wl->chip.id != CHIP_ID_1283_PG20) {
|
||||
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
|
||||
struct wl1271_rx_mem_pool_addr rx_mem_addr;
|
||||
struct wl127x_rx_mem_pool_addr rx_mem_addr;
|
||||
|
||||
/*
|
||||
* Choose the block we want to read
|
||||
@ -621,10 +629,8 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
|
||||
wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
|
||||
wl->chip.id);
|
||||
|
||||
/* clear the alignment quirk, since we don't support it */
|
||||
wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
|
||||
|
||||
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS;
|
||||
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
|
||||
WLCORE_QUIRK_TKIP_HEADER_SPACE;
|
||||
wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
|
||||
wl->mr_fw_name = WL127X_FW_NAME_MULTI;
|
||||
memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
|
||||
@ -639,10 +645,8 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
|
||||
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
|
||||
wl->chip.id);
|
||||
|
||||
/* clear the alignment quirk, since we don't support it */
|
||||
wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
|
||||
|
||||
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS;
|
||||
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
|
||||
WLCORE_QUIRK_TKIP_HEADER_SPACE;
|
||||
wl->plt_fw_name = WL127X_PLT_FW_NAME;
|
||||
wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
|
||||
wl->mr_fw_name = WL127X_FW_NAME_MULTI;
|
||||
@ -660,6 +664,11 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
|
||||
wl->plt_fw_name = WL128X_PLT_FW_NAME;
|
||||
wl->sr_fw_name = WL128X_FW_NAME_SINGLE;
|
||||
wl->mr_fw_name = WL128X_FW_NAME_MULTI;
|
||||
|
||||
/* wl128x requires TX blocksize alignment */
|
||||
wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
|
||||
WLCORE_QUIRK_TKIP_HEADER_SPACE;
|
||||
|
||||
break;
|
||||
case CHIP_ID_1283_PG10:
|
||||
default:
|
||||
@ -773,6 +782,7 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
|
||||
u16 spare_reg;
|
||||
u16 pll_config;
|
||||
u8 input_freq;
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
|
||||
/* Mask bits [3:1] in the sys_clk_cfg register */
|
||||
spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG);
|
||||
@ -782,8 +792,8 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
|
||||
wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
|
||||
|
||||
/* Handle special cases of the TCXO clock */
|
||||
if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
|
||||
wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
|
||||
if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
|
||||
priv->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
|
||||
return wl128x_manually_configure_mcs_pll(wl);
|
||||
|
||||
/* Set the input frequency according to the selected clock source */
|
||||
@ -808,11 +818,12 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
|
||||
*/
|
||||
static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
|
||||
{
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
u16 sys_clk_cfg;
|
||||
|
||||
/* For XTAL-only modes, FREF will be used after switching from TCXO */
|
||||
if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
|
||||
wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
|
||||
if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
|
||||
priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
|
||||
if (!wl128x_switch_tcxo_to_fref(wl))
|
||||
return -EINVAL;
|
||||
goto fref_clk;
|
||||
@ -826,8 +837,8 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
|
||||
goto fref_clk;
|
||||
|
||||
/* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */
|
||||
if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
|
||||
wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
|
||||
if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
|
||||
priv->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
|
||||
if (!wl128x_switch_tcxo_to_fref(wl))
|
||||
return -EINVAL;
|
||||
goto fref_clk;
|
||||
@ -836,14 +847,14 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
|
||||
/* TCXO clock is selected */
|
||||
if (!wl128x_is_tcxo_valid(wl))
|
||||
return -EINVAL;
|
||||
*selected_clock = wl->tcxo_clock;
|
||||
*selected_clock = priv->tcxo_clock;
|
||||
goto config_mcs_pll;
|
||||
|
||||
fref_clk:
|
||||
/* FREF clock is selected */
|
||||
if (!wl128x_is_fref_valid(wl))
|
||||
return -EINVAL;
|
||||
*selected_clock = wl->ref_clock;
|
||||
*selected_clock = priv->ref_clock;
|
||||
|
||||
config_mcs_pll:
|
||||
return wl128x_configure_mcs_pll(wl, *selected_clock);
|
||||
@ -851,25 +862,27 @@ config_mcs_pll:
|
||||
|
||||
static int wl127x_boot_clk(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
u32 pause;
|
||||
u32 clk;
|
||||
|
||||
if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
|
||||
wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION;
|
||||
|
||||
if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
|
||||
wl->ref_clock == CONF_REF_CLK_38_4_E ||
|
||||
wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
|
||||
if (priv->ref_clock == CONF_REF_CLK_19_2_E ||
|
||||
priv->ref_clock == CONF_REF_CLK_38_4_E ||
|
||||
priv->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
|
||||
/* ref clk: 19.2/38.4/38.4-XTAL */
|
||||
clk = 0x3;
|
||||
else if (wl->ref_clock == CONF_REF_CLK_26_E ||
|
||||
wl->ref_clock == CONF_REF_CLK_52_E)
|
||||
else if (priv->ref_clock == CONF_REF_CLK_26_E ||
|
||||
priv->ref_clock == CONF_REF_CLK_26_M_XTAL ||
|
||||
priv->ref_clock == CONF_REF_CLK_52_E)
|
||||
/* ref clk: 26/52 */
|
||||
clk = 0x5;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (wl->ref_clock != CONF_REF_CLK_19_2_E) {
|
||||
if (priv->ref_clock != CONF_REF_CLK_19_2_E) {
|
||||
u16 val;
|
||||
/* Set clock type (open drain) */
|
||||
val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE);
|
||||
@ -939,6 +952,7 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
|
||||
|
||||
static int wl12xx_pre_boot(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
int ret = 0;
|
||||
u32 clk;
|
||||
int selected_clock = -1;
|
||||
@ -970,7 +984,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
|
||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
||||
clk |= ((selected_clock & 0x3) << 1) << 4;
|
||||
else
|
||||
clk |= (wl->ref_clock << 1) << 4;
|
||||
clk |= (priv->ref_clock << 1) << 4;
|
||||
|
||||
wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk);
|
||||
|
||||
@ -989,7 +1003,7 @@ out:
|
||||
|
||||
static void wl12xx_pre_upload(struct wl1271 *wl)
|
||||
{
|
||||
u32 tmp;
|
||||
u32 tmp, polarity;
|
||||
|
||||
/* write firmware's last address (ie. it's length) to
|
||||
* ACX_EEPROMLESS_IND_REG */
|
||||
@ -1009,23 +1023,23 @@ static void wl12xx_pre_upload(struct wl1271 *wl)
|
||||
|
||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
||||
wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
|
||||
}
|
||||
|
||||
static void wl12xx_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
u32 polarity;
|
||||
|
||||
/* polarity must be set before the firmware is loaded */
|
||||
polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY);
|
||||
|
||||
/* We use HIGH polarity, so unset the LOW bit */
|
||||
polarity &= ~POLARITY_LOW;
|
||||
wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity);
|
||||
|
||||
wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR);
|
||||
}
|
||||
|
||||
static void wl12xx_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL12XX_ACX_ALL_EVENTS_VECTOR);
|
||||
|
||||
wlcore_enable_interrupts(wl);
|
||||
wlcore_write_reg(wl, REG_INTERRUPT_MASK,
|
||||
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
|
||||
WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
|
||||
|
||||
wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
|
||||
}
|
||||
@ -1149,7 +1163,8 @@ static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
|
||||
|
||||
static void wl12xx_tx_delayed_compl(struct wl1271 *wl)
|
||||
{
|
||||
if (wl->fw_status->tx_results_counter == (wl->tx_results_count & 0xff))
|
||||
if (wl->fw_status_1->tx_results_counter ==
|
||||
(wl->tx_results_count & 0xff))
|
||||
return;
|
||||
|
||||
wl1271_tx_complete(wl);
|
||||
@ -1288,10 +1303,90 @@ static void wl12xx_get_mac(struct wl1271 *wl)
|
||||
wl12xx_get_fuse_mac(wl);
|
||||
}
|
||||
|
||||
static void wl12xx_set_tx_desc_csum(struct wl1271 *wl,
|
||||
struct wl1271_tx_hw_descr *desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
desc->wl12xx_reserved = 0;
|
||||
}
|
||||
|
||||
static int wl12xx_plt_init(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl->ops->boot(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl->ops->hw_init(wl);
|
||||
if (ret < 0)
|
||||
goto out_irq_disable;
|
||||
|
||||
ret = wl1271_acx_init_mem_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_irq_disable;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Enable data path */
|
||||
ret = wl1271_cmd_data_path(wl, 1);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure for CAM power saving (ie. always active) */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* configure PM */
|
||||
ret = wl1271_acx_pm_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
goto out;
|
||||
|
||||
out_free_memmap:
|
||||
kfree(wl->target_mem_map);
|
||||
wl->target_mem_map = NULL;
|
||||
|
||||
out_irq_disable:
|
||||
mutex_unlock(&wl->mutex);
|
||||
/* Unlocking the mutex in the middle of handling is
|
||||
inherently unsafe. In this case we deem it safe to do,
|
||||
because we need to let any possibly pending IRQ out of
|
||||
the system (and while we are WL1271_STATE_OFF the IRQ
|
||||
work function will not do anything.) Also, any other
|
||||
possible concurrent operations will fail due to the
|
||||
current state, hence the wl1271 struct should be safe. */
|
||||
wlcore_disable_interrupts(wl);
|
||||
mutex_lock(&wl->mutex);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl12xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
|
||||
{
|
||||
if (is_gem)
|
||||
return WL12XX_TX_HW_BLOCK_GEM_SPARE;
|
||||
|
||||
return WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
|
||||
}
|
||||
|
||||
static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
return wlcore_set_key(wl, cmd, vif, sta, key_conf);
|
||||
}
|
||||
|
||||
static struct wlcore_ops wl12xx_ops = {
|
||||
.identify_chip = wl12xx_identify_chip,
|
||||
.identify_fw = wl12xx_identify_fw,
|
||||
.boot = wl12xx_boot,
|
||||
.plt_init = wl12xx_plt_init,
|
||||
.trigger_cmd = wl12xx_trigger_cmd,
|
||||
.ack_event = wl12xx_ack_event,
|
||||
.calc_tx_blocks = wl12xx_calc_tx_blocks,
|
||||
@ -1306,6 +1401,13 @@ static struct wlcore_ops wl12xx_ops = {
|
||||
.sta_get_ap_rate_mask = wl12xx_sta_get_ap_rate_mask,
|
||||
.get_pg_ver = wl12xx_get_pg_ver,
|
||||
.get_mac = wl12xx_get_mac,
|
||||
.set_tx_desc_csum = wl12xx_set_tx_desc_csum,
|
||||
.set_rx_csum = NULL,
|
||||
.ap_get_mimo_wide_rate_mask = NULL,
|
||||
.debugfs_init = wl12xx_debugfs_add_files,
|
||||
.get_spare_blocks = wl12xx_get_spare_blocks,
|
||||
.set_key = wl12xx_set_key,
|
||||
.pre_pkt_send = NULL,
|
||||
};
|
||||
|
||||
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
|
||||
@ -1323,6 +1425,7 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
|
||||
|
||||
static int __devinit wl12xx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct wl1271 *wl;
|
||||
struct ieee80211_hw *hw;
|
||||
struct wl12xx_priv *priv;
|
||||
@ -1334,19 +1437,65 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
wl = hw->priv;
|
||||
priv = wl->priv;
|
||||
wl->ops = &wl12xx_ops;
|
||||
wl->ptable = wl12xx_ptable;
|
||||
wl->rtable = wl12xx_rtable;
|
||||
wl->num_tx_desc = 16;
|
||||
wl->normal_tx_spare = WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
|
||||
wl->gem_tx_spare = WL12XX_TX_HW_BLOCK_GEM_SPARE;
|
||||
wl->num_rx_desc = 8;
|
||||
wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
|
||||
wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
|
||||
wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
|
||||
wl->fw_status_priv_len = 0;
|
||||
memcpy(&wl->ht_cap, &wl12xx_ht_cap, sizeof(wl12xx_ht_cap));
|
||||
wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
|
||||
memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], &wl12xx_ht_cap,
|
||||
sizeof(wl12xx_ht_cap));
|
||||
memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], &wl12xx_ht_cap,
|
||||
sizeof(wl12xx_ht_cap));
|
||||
wl12xx_conf_init(wl);
|
||||
|
||||
if (!fref_param) {
|
||||
priv->ref_clock = pdata->board_ref_clock;
|
||||
} else {
|
||||
if (!strcmp(fref_param, "19.2"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_19;
|
||||
else if (!strcmp(fref_param, "26"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_26;
|
||||
else if (!strcmp(fref_param, "26x"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_26_XTAL;
|
||||
else if (!strcmp(fref_param, "38.4"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_38;
|
||||
else if (!strcmp(fref_param, "38.4x"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_38_XTAL;
|
||||
else if (!strcmp(fref_param, "52"))
|
||||
priv->ref_clock = WL12XX_REFCLOCK_52;
|
||||
else
|
||||
wl1271_error("Invalid fref parameter %s", fref_param);
|
||||
}
|
||||
|
||||
if (!tcxo_param) {
|
||||
priv->tcxo_clock = pdata->board_tcxo_clock;
|
||||
} else {
|
||||
if (!strcmp(tcxo_param, "19.2"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2;
|
||||
else if (!strcmp(tcxo_param, "26"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_26;
|
||||
else if (!strcmp(tcxo_param, "38.4"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_38_4;
|
||||
else if (!strcmp(tcxo_param, "52"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_52;
|
||||
else if (!strcmp(tcxo_param, "16.368"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_16_368;
|
||||
else if (!strcmp(tcxo_param, "32.736"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_32_736;
|
||||
else if (!strcmp(tcxo_param, "16.8"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_16_8;
|
||||
else if (!strcmp(tcxo_param, "33.6"))
|
||||
priv->tcxo_clock = WL12XX_TCXOCLOCK_33_6;
|
||||
else
|
||||
wl1271_error("Invalid tcxo parameter %s", tcxo_param);
|
||||
}
|
||||
|
||||
return wlcore_probe(wl, pdev);
|
||||
}
|
||||
|
||||
@ -1378,6 +1527,13 @@ static void __exit wl12xx_exit(void)
|
||||
}
|
||||
module_exit(wl12xx_exit);
|
||||
|
||||
module_param_named(fref, fref_param, charp, 0);
|
||||
MODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52");
|
||||
|
||||
module_param_named(tcxo, tcxo_param, charp, 0);
|
||||
MODULE_PARM_DESC(tcxo,
|
||||
"TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6");
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
||||
MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
|
||||
|
@ -24,8 +24,16 @@
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
struct wl127x_rx_mem_pool_addr {
|
||||
u32 addr;
|
||||
u32 addr_extra;
|
||||
};
|
||||
|
||||
struct wl12xx_priv {
|
||||
struct wl12xx_priv_conf conf;
|
||||
|
||||
int ref_clock;
|
||||
int tcxo_clock;
|
||||
};
|
||||
|
||||
#endif /* __WL12XX_PRIV_H__ */
|
||||
|
7
drivers/net/wireless/ti/wl18xx/Kconfig
Normal file
7
drivers/net/wireless/ti/wl18xx/Kconfig
Normal file
@ -0,0 +1,7 @@
|
||||
config WL18XX
|
||||
tristate "TI wl18xx support"
|
||||
depends on MAC80211
|
||||
select WLCORE
|
||||
---help---
|
||||
This module adds support for wireless adapters based on TI
|
||||
WiLink 8 chipsets.
|
3
drivers/net/wireless/ti/wl18xx/Makefile
Normal file
3
drivers/net/wireless/ti/wl18xx/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
wl18xx-objs = main.o acx.o tx.o io.o debugfs.o
|
||||
|
||||
obj-$(CONFIG_WL18XX) += wl18xx.o
|
111
drivers/net/wireless/ti/wl18xx/acx.c
Normal file
111
drivers/net/wireless/ti/wl18xx/acx.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/cmd.h"
|
||||
#include "../wlcore/debug.h"
|
||||
#include "../wlcore/acx.h"
|
||||
|
||||
#include "acx.h"
|
||||
|
||||
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
|
||||
u32 sdio_blk_size, u32 extra_mem_blks,
|
||||
u32 len_field_size)
|
||||
{
|
||||
struct wl18xx_acx_host_config_bitmap *bitmap_conf;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx cfg bitmap %d blk %d spare %d field %d",
|
||||
host_cfg_bitmap, sdio_blk_size, extra_mem_blks,
|
||||
len_field_size);
|
||||
|
||||
bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
|
||||
if (!bitmap_conf) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
|
||||
bitmap_conf->host_sdio_block_size = cpu_to_le32(sdio_blk_size);
|
||||
bitmap_conf->extra_mem_blocks = cpu_to_le32(extra_mem_blks);
|
||||
bitmap_conf->length_field_size = cpu_to_le32(len_field_size);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
|
||||
bitmap_conf, sizeof(*bitmap_conf));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(bitmap_conf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
|
||||
{
|
||||
struct wl18xx_acx_checksum_state *acx;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx checksum state");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("failed to set Tx checksum state: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl18xx_acx_clear_statistics(struct wl1271 *wl)
|
||||
{
|
||||
struct wl18xx_acx_clear_statistics *acx;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx clear statistics");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_CLEAR_STATISTICS, acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("failed to clear firmware statistics: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
291
drivers/net/wireless/ti/wl18xx/acx.h
Normal file
291
drivers/net/wireless/ti/wl18xx/acx.h
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_ACX_H__
|
||||
#define __WL18XX_ACX_H__
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
#include "../wlcore/acx.h"
|
||||
|
||||
enum {
|
||||
ACX_CLEAR_STATISTICS = 0x0047,
|
||||
};
|
||||
|
||||
/* numbers of bits the length field takes (add 1 for the actual number) */
|
||||
#define WL18XX_HOST_IF_LEN_SIZE_FIELD 15
|
||||
|
||||
#define WL18XX_ACX_EVENTS_VECTOR_PG1 (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_INIT_COMPLETE | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_CMD_COMPLETE | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
|
||||
#define WL18XX_ACX_EVENTS_VECTOR_PG2 (WL18XX_ACX_EVENTS_VECTOR_PG1 | \
|
||||
WL1271_ACX_SW_INTR_WATCHDOG)
|
||||
|
||||
#define WL18XX_INTR_MASK_PG1 (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
|
||||
#define WL18XX_INTR_MASK_PG2 (WL18XX_INTR_MASK_PG1 | \
|
||||
WL1271_ACX_SW_INTR_WATCHDOG)
|
||||
|
||||
struct wl18xx_acx_host_config_bitmap {
|
||||
struct acx_header header;
|
||||
|
||||
__le32 host_cfg_bitmap;
|
||||
|
||||
__le32 host_sdio_block_size;
|
||||
|
||||
/* extra mem blocks per frame in TX. */
|
||||
__le32 extra_mem_blocks;
|
||||
|
||||
/*
|
||||
* number of bits of the length field in the first TX word
|
||||
* (up to 15 - for using the entire 16 bits).
|
||||
*/
|
||||
__le32 length_field_size;
|
||||
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
CHECKSUM_OFFLOAD_DISABLED = 0,
|
||||
CHECKSUM_OFFLOAD_ENABLED = 1,
|
||||
CHECKSUM_OFFLOAD_FAKE_RX = 2,
|
||||
CHECKSUM_OFFLOAD_INVALID = 0xFF
|
||||
};
|
||||
|
||||
struct wl18xx_acx_checksum_state {
|
||||
struct acx_header header;
|
||||
|
||||
/* enum acx_checksum_state */
|
||||
u8 checksum_state;
|
||||
u8 pad[3];
|
||||
} __packed;
|
||||
|
||||
|
||||
struct wl18xx_acx_error_stats {
|
||||
u32 error_frame;
|
||||
u32 error_null_Frame_tx_start;
|
||||
u32 error_numll_frame_cts_start;
|
||||
u32 error_bar_retry;
|
||||
u32 error_frame_cts_nul_flid;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_debug_stats {
|
||||
u32 debug1;
|
||||
u32 debug2;
|
||||
u32 debug3;
|
||||
u32 debug4;
|
||||
u32 debug5;
|
||||
u32 debug6;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_ring_stats {
|
||||
u32 prepared_descs;
|
||||
u32 tx_cmplt;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_tx_stats {
|
||||
u32 tx_prepared_descs;
|
||||
u32 tx_cmplt;
|
||||
u32 tx_template_prepared;
|
||||
u32 tx_data_prepared;
|
||||
u32 tx_template_programmed;
|
||||
u32 tx_data_programmed;
|
||||
u32 tx_burst_programmed;
|
||||
u32 tx_starts;
|
||||
u32 tx_imm_resp;
|
||||
u32 tx_start_templates;
|
||||
u32 tx_start_int_templates;
|
||||
u32 tx_start_fw_gen;
|
||||
u32 tx_start_data;
|
||||
u32 tx_start_null_frame;
|
||||
u32 tx_exch;
|
||||
u32 tx_retry_template;
|
||||
u32 tx_retry_data;
|
||||
u32 tx_exch_pending;
|
||||
u32 tx_exch_expiry;
|
||||
u32 tx_done_template;
|
||||
u32 tx_done_data;
|
||||
u32 tx_done_int_template;
|
||||
u32 tx_frame_checksum;
|
||||
u32 tx_checksum_result;
|
||||
u32 frag_called;
|
||||
u32 frag_mpdu_alloc_failed;
|
||||
u32 frag_init_called;
|
||||
u32 frag_in_process_called;
|
||||
u32 frag_tkip_called;
|
||||
u32 frag_key_not_found;
|
||||
u32 frag_need_fragmentation;
|
||||
u32 frag_bad_mblk_num;
|
||||
u32 frag_failed;
|
||||
u32 frag_cache_hit;
|
||||
u32 frag_cache_miss;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_rx_stats {
|
||||
u32 rx_beacon_early_term;
|
||||
u32 rx_out_of_mpdu_nodes;
|
||||
u32 rx_hdr_overflow;
|
||||
u32 rx_dropped_frame;
|
||||
u32 rx_done_stage;
|
||||
u32 rx_done;
|
||||
u32 rx_defrag;
|
||||
u32 rx_defrag_end;
|
||||
u32 rx_cmplt;
|
||||
u32 rx_pre_complt;
|
||||
u32 rx_cmplt_task;
|
||||
u32 rx_phy_hdr;
|
||||
u32 rx_timeout;
|
||||
u32 rx_timeout_wa;
|
||||
u32 rx_wa_density_dropped_frame;
|
||||
u32 rx_wa_ba_not_expected;
|
||||
u32 rx_frame_checksum;
|
||||
u32 rx_checksum_result;
|
||||
u32 defrag_called;
|
||||
u32 defrag_init_called;
|
||||
u32 defrag_in_process_called;
|
||||
u32 defrag_tkip_called;
|
||||
u32 defrag_need_defrag;
|
||||
u32 defrag_decrypt_failed;
|
||||
u32 decrypt_key_not_found;
|
||||
u32 defrag_need_decrypt;
|
||||
u32 rx_tkip_replays;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_isr_stats {
|
||||
u32 irqs;
|
||||
} __packed;
|
||||
|
||||
#define PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD 10
|
||||
|
||||
struct wl18xx_acx_pwr_stats {
|
||||
u32 missing_bcns_cnt;
|
||||
u32 rcvd_bcns_cnt;
|
||||
u32 connection_out_of_sync;
|
||||
u32 cont_miss_bcns_spread[PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD];
|
||||
u32 rcvd_awake_bcns_cnt;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_event_stats {
|
||||
u32 calibration;
|
||||
u32 rx_mismatch;
|
||||
u32 rx_mem_empty;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_ps_poll_stats {
|
||||
u32 ps_poll_timeouts;
|
||||
u32 upsd_timeouts;
|
||||
u32 upsd_max_ap_turn;
|
||||
u32 ps_poll_max_ap_turn;
|
||||
u32 ps_poll_utilization;
|
||||
u32 upsd_utilization;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_rx_filter_stats {
|
||||
u32 beacon_filter;
|
||||
u32 arp_filter;
|
||||
u32 mc_filter;
|
||||
u32 dup_filter;
|
||||
u32 data_filter;
|
||||
u32 ibss_filter;
|
||||
u32 protection_filter;
|
||||
u32 accum_arp_pend_requests;
|
||||
u32 max_arp_queue_dep;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_rx_rate_stats {
|
||||
u32 rx_frames_per_rates[50];
|
||||
} __packed;
|
||||
|
||||
#define AGGR_STATS_TX_AGG 16
|
||||
#define AGGR_STATS_TX_RATE 16
|
||||
#define AGGR_STATS_RX_SIZE_LEN 16
|
||||
|
||||
struct wl18xx_acx_aggr_stats {
|
||||
u32 tx_agg_vs_rate[AGGR_STATS_TX_AGG * AGGR_STATS_TX_RATE];
|
||||
u32 rx_size[AGGR_STATS_RX_SIZE_LEN];
|
||||
} __packed;
|
||||
|
||||
#define PIPE_STATS_HW_FIFO 11
|
||||
|
||||
struct wl18xx_acx_pipeline_stats {
|
||||
u32 hs_tx_stat_fifo_int;
|
||||
u32 hs_rx_stat_fifo_int;
|
||||
u32 tcp_tx_stat_fifo_int;
|
||||
u32 tcp_rx_stat_fifo_int;
|
||||
u32 enc_tx_stat_fifo_int;
|
||||
u32 enc_rx_stat_fifo_int;
|
||||
u32 rx_complete_stat_fifo_int;
|
||||
u32 pre_proc_swi;
|
||||
u32 post_proc_swi;
|
||||
u32 sec_frag_swi;
|
||||
u32 pre_to_defrag_swi;
|
||||
u32 defrag_to_csum_swi;
|
||||
u32 csum_to_rx_xfer_swi;
|
||||
u32 dec_packet_in;
|
||||
u32 dec_packet_in_fifo_full;
|
||||
u32 dec_packet_out;
|
||||
u32 cs_rx_packet_in;
|
||||
u32 cs_rx_packet_out;
|
||||
u16 pipeline_fifo_full[PIPE_STATS_HW_FIFO];
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_mem_stats {
|
||||
u32 rx_free_mem_blks;
|
||||
u32 tx_free_mem_blks;
|
||||
u32 fwlog_free_mem_blks;
|
||||
u32 fw_gen_free_mem_blks;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_statistics {
|
||||
struct acx_header header;
|
||||
|
||||
struct wl18xx_acx_error_stats error;
|
||||
struct wl18xx_acx_debug_stats debug;
|
||||
struct wl18xx_acx_tx_stats tx;
|
||||
struct wl18xx_acx_rx_stats rx;
|
||||
struct wl18xx_acx_isr_stats isr;
|
||||
struct wl18xx_acx_pwr_stats pwr;
|
||||
struct wl18xx_acx_ps_poll_stats ps_poll;
|
||||
struct wl18xx_acx_rx_filter_stats rx_filter;
|
||||
struct wl18xx_acx_rx_rate_stats rx_rate;
|
||||
struct wl18xx_acx_aggr_stats aggr_size;
|
||||
struct wl18xx_acx_pipeline_stats pipeline;
|
||||
struct wl18xx_acx_mem_stats mem;
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_acx_clear_statistics {
|
||||
struct acx_header header;
|
||||
};
|
||||
|
||||
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
|
||||
u32 sdio_blk_size, u32 extra_mem_blks,
|
||||
u32 len_field_size);
|
||||
int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
|
||||
int wl18xx_acx_clear_statistics(struct wl1271 *wl);
|
||||
|
||||
#endif /* __WL18XX_ACX_H__ */
|
92
drivers/net/wireless/ti/wl18xx/conf.h
Normal file
92
drivers/net/wireless/ti/wl18xx/conf.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_CONF_H__
|
||||
#define __WL18XX_CONF_H__
|
||||
|
||||
#define WL18XX_CONF_MAGIC 0x10e100ca
|
||||
#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0002)
|
||||
#define WL18XX_CONF_MASK 0x0000ffff
|
||||
#define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \
|
||||
sizeof(struct wl18xx_priv_conf))
|
||||
|
||||
#define NUM_OF_CHANNELS_11_ABG 150
|
||||
#define NUM_OF_CHANNELS_11_P 7
|
||||
#define WL18XX_NUM_OF_SUB_BANDS 9
|
||||
#define SRF_TABLE_LEN 16
|
||||
#define PIN_MUXING_SIZE 2
|
||||
|
||||
struct wl18xx_mac_and_phy_params {
|
||||
u8 phy_standalone;
|
||||
u8 rdl;
|
||||
u8 enable_clpc;
|
||||
u8 enable_tx_low_pwr_on_siso_rdl;
|
||||
u8 auto_detect;
|
||||
u8 dedicated_fem;
|
||||
|
||||
u8 low_band_component;
|
||||
|
||||
/* Bit 0: One Hot, Bit 1: Control Enable, Bit 2: 1.8V, Bit 3: 3V */
|
||||
u8 low_band_component_type;
|
||||
|
||||
u8 high_band_component;
|
||||
|
||||
/* Bit 0: One Hot, Bit 1: Control Enable, Bit 2: 1.8V, Bit 3: 3V */
|
||||
u8 high_band_component_type;
|
||||
u8 number_of_assembled_ant2_4;
|
||||
u8 number_of_assembled_ant5;
|
||||
u8 pin_muxing_platform_options[PIN_MUXING_SIZE];
|
||||
u8 external_pa_dc2dc;
|
||||
u8 tcxo_ldo_voltage;
|
||||
u8 xtal_itrim_val;
|
||||
u8 srf_state;
|
||||
u8 srf1[SRF_TABLE_LEN];
|
||||
u8 srf2[SRF_TABLE_LEN];
|
||||
u8 srf3[SRF_TABLE_LEN];
|
||||
u8 io_configuration;
|
||||
u8 sdio_configuration;
|
||||
u8 settings;
|
||||
u8 rx_profile;
|
||||
u8 per_chan_pwr_limit_arr_11abg[NUM_OF_CHANNELS_11_ABG];
|
||||
u8 pwr_limit_reference_11_abg;
|
||||
u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P];
|
||||
u8 pwr_limit_reference_11p;
|
||||
u8 per_sub_band_tx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
|
||||
u8 per_sub_band_rx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
|
||||
u8 primary_clock_setting_time;
|
||||
u8 clock_valid_on_wake_up;
|
||||
u8 secondary_clock_setting_time;
|
||||
u8 board_type;
|
||||
/* enable point saturation */
|
||||
u8 psat;
|
||||
/* low/medium/high Tx power in dBm */
|
||||
s8 low_power_val;
|
||||
s8 med_power_val;
|
||||
s8 high_power_val;
|
||||
u8 padding[1];
|
||||
} __packed;
|
||||
|
||||
struct wl18xx_priv_conf {
|
||||
/* this structure is copied wholesale to FW */
|
||||
struct wl18xx_mac_and_phy_params phy;
|
||||
} __packed;
|
||||
|
||||
#endif /* __WL18XX_CONF_H__ */
|
403
drivers/net/wireless/ti/wl18xx/debugfs.c
Normal file
403
drivers/net/wireless/ti/wl18xx/debugfs.c
Normal file
@ -0,0 +1,403 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Copyright (C) 2011-2012 Texas Instruments
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/debugfs.h"
|
||||
#include "../wlcore/wlcore.h"
|
||||
|
||||
#include "wl18xx.h"
|
||||
#include "acx.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
#define WL18XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
|
||||
DEBUGFS_FWSTATS_FILE(a, b, c, wl18xx_acx_statistics)
|
||||
#define WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c) \
|
||||
DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c, wl18xx_acx_statistics)
|
||||
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug1, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug2, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug3, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug4, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug5, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug6, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_null_Frame_tx_start, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_numll_frame_cts_start, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_bar_retry, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_cts_nul_flid, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_prepared_descs, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cmplt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_prepared, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_prepared, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_programmed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_programmed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_burst_programmed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_starts, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_imm_resp, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_templates, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_int_templates, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_fw_gen, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_data, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_null_frame, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_template, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_data, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_pending, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_expiry, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_template, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_data, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_int_template, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_frame_checksum, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_checksum_result, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_mpdu_alloc_failed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_init_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_in_process_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_tkip_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_key_not_found, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_need_fragmentation, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_bad_mblk_num, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_failed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_cache_hit, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_cache_miss, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_beacon_early_term, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_out_of_mpdu_nodes, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_hdr_overflow, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_dropped_frame, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_done, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_defrag, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_defrag_end, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_pre_complt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt_task, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_phy_hdr, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout_wa, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_density_dropped_frame, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_ba_not_expected, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_frame_checksum, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_checksum_result, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_init_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_in_process_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_tkip_called, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_defrag, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_decrypt_failed, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, decrypt_key_not_found, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_decrypt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_tkip_replays, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pwr, missing_bcns_cnt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_bcns_cnt, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pwr, connection_out_of_sync, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pwr, cont_miss_bcns_spread,
|
||||
PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD);
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_bcns_cnt, "%u");
|
||||
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_timeouts, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_timeouts, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_max_ap_turn, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_max_ap_turn, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_utilization, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_utilization, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, beacon_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, arp_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, mc_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, dup_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, data_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, ibss_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, protection_filter, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, accum_arp_pend_requests, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, max_arp_queue_dep, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(rx_rate, rx_frames_per_rates, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_vs_rate,
|
||||
AGGR_STATS_TX_AGG*AGGR_STATS_TX_RATE);
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, rx_size,
|
||||
AGGR_STATS_RX_SIZE_LEN);
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, hs_tx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_tx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_rx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_tx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_rx_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, rx_complete_stat_fifo_int, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_proc_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, post_proc_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, sec_frag_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_to_defrag_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, defrag_to_csum_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, csum_to_rx_xfer_swi, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in_fifo_full, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_out, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_in, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_out, "%u");
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pipeline, pipeline_fifo_full,
|
||||
PIPE_STATS_HW_FIFO);
|
||||
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(mem, rx_free_mem_blks, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(mem, tx_free_mem_blks, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(mem, fwlog_free_mem_blks, "%u");
|
||||
WL18XX_DEBUGFS_FWSTATS_FILE(mem, fw_gen_free_mem_blks, "%u");
|
||||
|
||||
static ssize_t conf_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl18xx_priv *priv = wl->priv;
|
||||
struct wlcore_conf_header header;
|
||||
char *buf, *pos;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = WL18XX_CONF_SIZE;
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
header.magic = cpu_to_le32(WL18XX_CONF_MAGIC);
|
||||
header.version = cpu_to_le32(WL18XX_CONF_VERSION);
|
||||
header.checksum = 0;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
pos = buf;
|
||||
memcpy(pos, &header, sizeof(header));
|
||||
pos += sizeof(header);
|
||||
memcpy(pos, &wl->conf, sizeof(wl->conf));
|
||||
pos += sizeof(wl->conf);
|
||||
memcpy(pos, &priv->conf, sizeof(priv->conf));
|
||||
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations conf_ops = {
|
||||
.read = conf_read,
|
||||
.open = simple_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t clear_fw_stats_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
goto out;
|
||||
|
||||
ret = wl18xx_acx_clear_statistics(wl);
|
||||
if (ret < 0) {
|
||||
count = ret;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations clear_fw_stats_ops = {
|
||||
.write = clear_fw_stats_write,
|
||||
.open = simple_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
int wl18xx_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dentry *entry, *stats, *moddir;
|
||||
|
||||
moddir = debugfs_create_dir(KBUILD_MODNAME, rootdir);
|
||||
if (!moddir || IS_ERR(moddir)) {
|
||||
entry = moddir;
|
||||
goto err;
|
||||
}
|
||||
|
||||
stats = debugfs_create_dir("fw_stats", moddir);
|
||||
if (!stats || IS_ERR(stats)) {
|
||||
entry = stats;
|
||||
goto err;
|
||||
}
|
||||
|
||||
DEBUGFS_ADD(clear_fw_stats, stats);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug1);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug2);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug3);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug4);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug5);
|
||||
DEBUGFS_FWSTATS_ADD(debug, debug6);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(error, error_frame);
|
||||
DEBUGFS_FWSTATS_ADD(error, error_null_Frame_tx_start);
|
||||
DEBUGFS_FWSTATS_ADD(error, error_numll_frame_cts_start);
|
||||
DEBUGFS_FWSTATS_ADD(error, error_bar_retry);
|
||||
DEBUGFS_FWSTATS_ADD(error, error_frame_cts_nul_flid);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_prepared_descs);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_cmplt);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_template_prepared);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_data_prepared);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_template_programmed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_data_programmed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_burst_programmed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_starts);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_imm_resp);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_templates);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_int_templates);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_fw_gen);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_data);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_start_null_frame);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_exch);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_retry_template);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_retry_data);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_exch_pending);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_exch_expiry);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_done_template);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_done_data);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_done_int_template);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_frame_checksum);
|
||||
DEBUGFS_FWSTATS_ADD(tx, tx_checksum_result);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_called);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_mpdu_alloc_failed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_init_called);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_in_process_called);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_tkip_called);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_key_not_found);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_need_fragmentation);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_bad_mblk_num);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_failed);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_cache_hit);
|
||||
DEBUGFS_FWSTATS_ADD(tx, frag_cache_miss);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_beacon_early_term);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_out_of_mpdu_nodes);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_hdr_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_dropped_frame);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_done);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_defrag);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_defrag_end);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_cmplt);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_pre_complt);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_cmplt_task);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_phy_hdr);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_timeout);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_timeout_wa);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_wa_density_dropped_frame);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_wa_ba_not_expected);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_frame_checksum);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_checksum_result);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_called);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_init_called);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_in_process_called);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_tkip_called);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_need_defrag);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_decrypt_failed);
|
||||
DEBUGFS_FWSTATS_ADD(rx, decrypt_key_not_found);
|
||||
DEBUGFS_FWSTATS_ADD(rx, defrag_need_decrypt);
|
||||
DEBUGFS_FWSTATS_ADD(rx, rx_tkip_replays);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(isr, irqs);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(pwr, missing_bcns_cnt);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_bcns_cnt);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, connection_out_of_sync);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, cont_miss_bcns_spread);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_bcns_cnt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, upsd_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, upsd_max_ap_turn);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_max_ap_turn);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_utilization);
|
||||
DEBUGFS_FWSTATS_ADD(ps_poll, upsd_utilization);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, beacon_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, arp_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, mc_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, dup_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, data_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, ibss_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, protection_filter);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, accum_arp_pend_requests);
|
||||
DEBUGFS_FWSTATS_ADD(rx_filter, max_arp_queue_dep);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx_rate, rx_frames_per_rates);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_vs_rate);
|
||||
DEBUGFS_FWSTATS_ADD(aggr_size, rx_size);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, hs_tx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, tcp_tx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, tcp_rx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, enc_tx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, enc_rx_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, rx_complete_stat_fifo_int);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, pre_proc_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, post_proc_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, sec_frag_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, pre_to_defrag_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, defrag_to_csum_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, csum_to_rx_xfer_swi);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in_fifo_full);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_out);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_in);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_out);
|
||||
DEBUGFS_FWSTATS_ADD(pipeline, pipeline_fifo_full);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(mem, rx_free_mem_blks);
|
||||
DEBUGFS_FWSTATS_ADD(mem, tx_free_mem_blks);
|
||||
DEBUGFS_FWSTATS_ADD(mem, fwlog_free_mem_blks);
|
||||
DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks);
|
||||
|
||||
DEBUGFS_ADD(conf, moddir);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (IS_ERR(entry))
|
||||
ret = PTR_ERR(entry);
|
||||
else
|
||||
ret = -ENOMEM;
|
||||
|
||||
return ret;
|
||||
}
|
28
drivers/net/wireless/ti/wl18xx/debugfs.h
Normal file
28
drivers/net/wireless/ti/wl18xx/debugfs.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_DEBUGFS_H__
|
||||
#define __WL18XX_DEBUGFS_H__
|
||||
|
||||
int wl18xx_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir);
|
||||
|
||||
#endif /* __WL18XX_DEBUGFS_H__ */
|
60
drivers/net/wireless/ti/wl18xx/io.c
Normal file
60
drivers/net/wireless/ti/wl18xx/io.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
#include "../wlcore/io.h"
|
||||
|
||||
#include "io.h"
|
||||
|
||||
void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
if (WARN_ON(addr % 2))
|
||||
return;
|
||||
|
||||
if ((addr % 4) == 0) {
|
||||
tmp = wl1271_read32(wl, addr);
|
||||
tmp = (tmp & 0xffff0000) | val;
|
||||
wl1271_write32(wl, addr, tmp);
|
||||
} else {
|
||||
tmp = wl1271_read32(wl, addr - 2);
|
||||
tmp = (tmp & 0xffff) | (val << 16);
|
||||
wl1271_write32(wl, addr - 2, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (WARN_ON(addr % 2))
|
||||
return 0;
|
||||
|
||||
if ((addr % 4) == 0) {
|
||||
/* address is 4-bytes aligned */
|
||||
val = wl1271_read32(wl, addr);
|
||||
return val & 0xffff;
|
||||
} else {
|
||||
val = wl1271_read32(wl, addr - 2);
|
||||
return (val & 0xffff0000) >> 16;
|
||||
}
|
||||
}
|
28
drivers/net/wireless/ti/wl18xx/io.h
Normal file
28
drivers/net/wireless/ti/wl18xx/io.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_IO_H__
|
||||
#define __WL18XX_IO_H__
|
||||
|
||||
void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val);
|
||||
u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr);
|
||||
|
||||
#endif /* __WL18XX_IO_H__ */
|
1463
drivers/net/wireless/ti/wl18xx/main.c
Normal file
1463
drivers/net/wireless/ti/wl18xx/main.c
Normal file
File diff suppressed because it is too large
Load Diff
191
drivers/net/wireless/ti/wl18xx/reg.h
Normal file
191
drivers/net/wireless/ti/wl18xx/reg.h
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* This file is part of wlcore
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __REG_H__
|
||||
#define __REG_H__
|
||||
|
||||
#define WL18XX_REGISTERS_BASE 0x00800000
|
||||
#define WL18XX_CODE_BASE 0x00000000
|
||||
#define WL18XX_DATA_BASE 0x00400000
|
||||
#define WL18XX_DOUBLE_BUFFER_BASE 0x00600000
|
||||
#define WL18XX_MCU_KEY_SEARCH_BASE 0x00700000
|
||||
#define WL18XX_PHY_BASE 0x00900000
|
||||
#define WL18XX_TOP_OCP_BASE 0x00A00000
|
||||
#define WL18XX_PACKET_RAM_BASE 0x00B00000
|
||||
#define WL18XX_HOST_BASE 0x00C00000
|
||||
|
||||
#define WL18XX_REGISTERS_DOWN_SIZE 0x0000B000
|
||||
|
||||
#define WL18XX_REG_BOOT_PART_START 0x00802000
|
||||
#define WL18XX_REG_BOOT_PART_SIZE 0x00014578
|
||||
|
||||
#define WL18XX_PHY_INIT_MEM_ADDR 0x80926000
|
||||
|
||||
#define WL18XX_SDIO_WSPI_BASE (WL18XX_REGISTERS_BASE)
|
||||
#define WL18XX_REG_CONFIG_BASE (WL18XX_REGISTERS_BASE + 0x02000)
|
||||
#define WL18XX_WGCM_REGS_BASE (WL18XX_REGISTERS_BASE + 0x03000)
|
||||
#define WL18XX_ENC_BASE (WL18XX_REGISTERS_BASE + 0x04000)
|
||||
#define WL18XX_INTERRUPT_BASE (WL18XX_REGISTERS_BASE + 0x05000)
|
||||
#define WL18XX_UART_BASE (WL18XX_REGISTERS_BASE + 0x06000)
|
||||
#define WL18XX_WELP_BASE (WL18XX_REGISTERS_BASE + 0x07000)
|
||||
#define WL18XX_TCP_CKSM_BASE (WL18XX_REGISTERS_BASE + 0x08000)
|
||||
#define WL18XX_FIFO_BASE (WL18XX_REGISTERS_BASE + 0x09000)
|
||||
#define WL18XX_OCP_BRIDGE_BASE (WL18XX_REGISTERS_BASE + 0x0A000)
|
||||
#define WL18XX_PMAC_RX_BASE (WL18XX_REGISTERS_BASE + 0x14800)
|
||||
#define WL18XX_PMAC_ACM_BASE (WL18XX_REGISTERS_BASE + 0x14C00)
|
||||
#define WL18XX_PMAC_TX_BASE (WL18XX_REGISTERS_BASE + 0x15000)
|
||||
#define WL18XX_PMAC_CSR_BASE (WL18XX_REGISTERS_BASE + 0x15400)
|
||||
|
||||
#define WL18XX_REG_ECPU_CONTROL (WL18XX_REGISTERS_BASE + 0x02004)
|
||||
#define WL18XX_REG_INTERRUPT_NO_CLEAR (WL18XX_REGISTERS_BASE + 0x050E8)
|
||||
#define WL18XX_REG_INTERRUPT_ACK (WL18XX_REGISTERS_BASE + 0x050F0)
|
||||
#define WL18XX_REG_INTERRUPT_TRIG (WL18XX_REGISTERS_BASE + 0x5074)
|
||||
#define WL18XX_REG_INTERRUPT_TRIG_H (WL18XX_REGISTERS_BASE + 0x5078)
|
||||
#define WL18XX_REG_INTERRUPT_MASK (WL18XX_REGISTERS_BASE + 0x0050DC)
|
||||
|
||||
#define WL18XX_REG_CHIP_ID_B (WL18XX_REGISTERS_BASE + 0x01542C)
|
||||
|
||||
#define WL18XX_SLV_MEM_DATA (WL18XX_HOST_BASE + 0x0018)
|
||||
#define WL18XX_SLV_REG_DATA (WL18XX_HOST_BASE + 0x0008)
|
||||
|
||||
/* Scratch Pad registers*/
|
||||
#define WL18XX_SCR_PAD0 (WL18XX_REGISTERS_BASE + 0x0154EC)
|
||||
#define WL18XX_SCR_PAD1 (WL18XX_REGISTERS_BASE + 0x0154F0)
|
||||
#define WL18XX_SCR_PAD2 (WL18XX_REGISTERS_BASE + 0x0154F4)
|
||||
#define WL18XX_SCR_PAD3 (WL18XX_REGISTERS_BASE + 0x0154F8)
|
||||
#define WL18XX_SCR_PAD4 (WL18XX_REGISTERS_BASE + 0x0154FC)
|
||||
#define WL18XX_SCR_PAD4_SET (WL18XX_REGISTERS_BASE + 0x015504)
|
||||
#define WL18XX_SCR_PAD4_CLR (WL18XX_REGISTERS_BASE + 0x015500)
|
||||
#define WL18XX_SCR_PAD5 (WL18XX_REGISTERS_BASE + 0x015508)
|
||||
#define WL18XX_SCR_PAD5_SET (WL18XX_REGISTERS_BASE + 0x015510)
|
||||
#define WL18XX_SCR_PAD5_CLR (WL18XX_REGISTERS_BASE + 0x01550C)
|
||||
#define WL18XX_SCR_PAD6 (WL18XX_REGISTERS_BASE + 0x015514)
|
||||
#define WL18XX_SCR_PAD7 (WL18XX_REGISTERS_BASE + 0x015518)
|
||||
#define WL18XX_SCR_PAD8 (WL18XX_REGISTERS_BASE + 0x01551C)
|
||||
#define WL18XX_SCR_PAD9 (WL18XX_REGISTERS_BASE + 0x015520)
|
||||
|
||||
/* Spare registers*/
|
||||
#define WL18XX_SPARE_A1 (WL18XX_REGISTERS_BASE + 0x002194)
|
||||
#define WL18XX_SPARE_A2 (WL18XX_REGISTERS_BASE + 0x002198)
|
||||
#define WL18XX_SPARE_A3 (WL18XX_REGISTERS_BASE + 0x00219C)
|
||||
#define WL18XX_SPARE_A4 (WL18XX_REGISTERS_BASE + 0x0021A0)
|
||||
#define WL18XX_SPARE_A5 (WL18XX_REGISTERS_BASE + 0x0021A4)
|
||||
#define WL18XX_SPARE_A6 (WL18XX_REGISTERS_BASE + 0x0021A8)
|
||||
#define WL18XX_SPARE_A7 (WL18XX_REGISTERS_BASE + 0x0021AC)
|
||||
#define WL18XX_SPARE_A8 (WL18XX_REGISTERS_BASE + 0x0021B0)
|
||||
#define WL18XX_SPARE_B1 (WL18XX_REGISTERS_BASE + 0x015524)
|
||||
#define WL18XX_SPARE_B2 (WL18XX_REGISTERS_BASE + 0x015528)
|
||||
#define WL18XX_SPARE_B3 (WL18XX_REGISTERS_BASE + 0x01552C)
|
||||
#define WL18XX_SPARE_B4 (WL18XX_REGISTERS_BASE + 0x015530)
|
||||
#define WL18XX_SPARE_B5 (WL18XX_REGISTERS_BASE + 0x015534)
|
||||
#define WL18XX_SPARE_B6 (WL18XX_REGISTERS_BASE + 0x015538)
|
||||
#define WL18XX_SPARE_B7 (WL18XX_REGISTERS_BASE + 0x01553C)
|
||||
#define WL18XX_SPARE_B8 (WL18XX_REGISTERS_BASE + 0x015540)
|
||||
|
||||
#define WL18XX_REG_COMMAND_MAILBOX_PTR (WL18XX_SCR_PAD0)
|
||||
#define WL18XX_REG_EVENT_MAILBOX_PTR (WL18XX_SCR_PAD1)
|
||||
#define WL18XX_EEPROMLESS_IND (WL18XX_SCR_PAD4)
|
||||
|
||||
#define WL18XX_WELP_ARM_COMMAND (WL18XX_REGISTERS_BASE + 0x7100)
|
||||
#define WL18XX_ENABLE (WL18XX_REGISTERS_BASE + 0x01543C)
|
||||
|
||||
/* PRCM registers */
|
||||
#define PLATFORM_DETECTION 0xA0E3E0
|
||||
#define OCS_EN 0xA02080
|
||||
#define PRIMARY_CLK_DETECT 0xA020A6
|
||||
#define PLLSH_WCS_PLL_N 0xA02362
|
||||
#define PLLSH_WCS_PLL_M 0xA02360
|
||||
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1 0xA02364
|
||||
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_2 0xA02366
|
||||
#define PLLSH_WCS_PLL_P_FACTOR_CFG_1 0xA02368
|
||||
#define PLLSH_WCS_PLL_P_FACTOR_CFG_2 0xA0236A
|
||||
#define PLLSH_WCS_PLL_SWALLOW_EN 0xA0236C
|
||||
#define PLLSH_WL_PLL_EN 0xA02392
|
||||
|
||||
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK 0xFFFF
|
||||
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK 0x007F
|
||||
#define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK 0xFFFF
|
||||
#define PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK 0x000F
|
||||
|
||||
#define PLLSH_WCS_PLL_SWALLOW_EN_VAL1 0x1
|
||||
#define PLLSH_WCS_PLL_SWALLOW_EN_VAL2 0x12
|
||||
|
||||
#define WL18XX_REG_FUSE_DATA_1_3 0xA0260C
|
||||
#define WL18XX_PG_VER_MASK 0x70
|
||||
#define WL18XX_PG_VER_OFFSET 4
|
||||
|
||||
#define WL18XX_REG_FUSE_BD_ADDR_1 0xA02602
|
||||
#define WL18XX_REG_FUSE_BD_ADDR_2 0xA02606
|
||||
|
||||
#define WL18XX_CMD_MBOX_ADDRESS 0xB007B4
|
||||
|
||||
#define WL18XX_FW_STATUS_ADDR 0x50F8
|
||||
|
||||
#define CHIP_ID_185x_PG10 (0x06030101)
|
||||
#define CHIP_ID_185x_PG20 (0x06030111)
|
||||
|
||||
/*
|
||||
* Host Command Interrupt. Setting this bit masks
|
||||
* the interrupt that the host issues to inform
|
||||
* the FW that it has sent a command
|
||||
* to the Wlan hardware Command Mailbox.
|
||||
*/
|
||||
#define WL18XX_INTR_TRIG_CMD BIT(28)
|
||||
|
||||
/*
|
||||
* Host Event Acknowlegde Interrupt. The host
|
||||
* sets this bit to acknowledge that it received
|
||||
* the unsolicited information from the event
|
||||
* mailbox.
|
||||
*/
|
||||
#define WL18XX_INTR_TRIG_EVENT_ACK BIT(29)
|
||||
|
||||
/*
|
||||
* To boot the firmware in PLT mode we need to write this value in
|
||||
* SCR_PAD8 before starting.
|
||||
*/
|
||||
#define WL18XX_SCR_PAD8_PLT 0xBABABEBE
|
||||
|
||||
enum {
|
||||
COMPONENT_NO_SWITCH = 0x0,
|
||||
COMPONENT_2_WAY_SWITCH = 0x1,
|
||||
COMPONENT_3_WAY_SWITCH = 0x2,
|
||||
COMPONENT_MATCHING = 0x3,
|
||||
};
|
||||
|
||||
enum {
|
||||
FEM_NONE = 0x0,
|
||||
FEM_VENDOR_1 = 0x1,
|
||||
FEM_VENDOR_2 = 0x2,
|
||||
FEM_VENDOR_3 = 0x3,
|
||||
};
|
||||
|
||||
enum {
|
||||
BOARD_TYPE_EVB_18XX = 0,
|
||||
BOARD_TYPE_DVP_18XX = 1,
|
||||
BOARD_TYPE_HDK_18XX = 2,
|
||||
BOARD_TYPE_FPGA_18XX = 3,
|
||||
BOARD_TYPE_COM8_18XX = 4,
|
||||
|
||||
NUM_BOARD_TYPES,
|
||||
};
|
||||
|
||||
#endif /* __REG_H__ */
|
127
drivers/net/wireless/ti/wl18xx/tx.c
Normal file
127
drivers/net/wireless/ti/wl18xx/tx.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
#include "../wlcore/cmd.h"
|
||||
#include "../wlcore/debug.h"
|
||||
#include "../wlcore/acx.h"
|
||||
#include "../wlcore/tx.h"
|
||||
|
||||
#include "wl18xx.h"
|
||||
#include "tx.h"
|
||||
|
||||
static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
struct sk_buff *skb;
|
||||
int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK;
|
||||
bool tx_success;
|
||||
|
||||
/* check for id legality */
|
||||
if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
|
||||
wl1271_warning("illegal id in tx completion: %d", id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* a zero bit indicates Tx success */
|
||||
tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX));
|
||||
|
||||
|
||||
skb = wl->tx_frames[id];
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (wl12xx_is_dummy_packet(wl, skb)) {
|
||||
wl1271_free_tx_id(wl, id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* update the TX status info */
|
||||
if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
/* no real data about Tx completion */
|
||||
info->status.rates[0].idx = -1;
|
||||
info->status.rates[0].count = 0;
|
||||
info->status.rates[0].flags = 0;
|
||||
info->status.ack_signal = -1;
|
||||
|
||||
if (!tx_success)
|
||||
wl->stats.retry_count++;
|
||||
|
||||
/*
|
||||
* TODO: update sequence number for encryption? seems to be
|
||||
* unsupported for now. needed for recovery with encryption.
|
||||
*/
|
||||
|
||||
/* remove private header from packet */
|
||||
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
|
||||
|
||||
/* remove TKIP header space if present */
|
||||
if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
|
||||
info->control.hw_key &&
|
||||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||
int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, hdrlen);
|
||||
skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p success %d",
|
||||
id, skb, tx_success);
|
||||
|
||||
/* return the packet to the stack */
|
||||
skb_queue_tail(&wl->deferred_tx_queue, skb);
|
||||
queue_work(wl->freezable_wq, &wl->netstack_work);
|
||||
wl1271_free_tx_id(wl, id);
|
||||
}
|
||||
|
||||
void wl18xx_tx_immediate_complete(struct wl1271 *wl)
|
||||
{
|
||||
struct wl18xx_fw_status_priv *status_priv =
|
||||
(struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
|
||||
struct wl18xx_priv *priv = wl->priv;
|
||||
u8 i;
|
||||
|
||||
/* nothing to do here */
|
||||
if (priv->last_fw_rls_idx == status_priv->fw_release_idx)
|
||||
return;
|
||||
|
||||
/* freed Tx descriptors */
|
||||
wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d",
|
||||
priv->last_fw_rls_idx, status_priv->fw_release_idx);
|
||||
|
||||
if (status_priv->fw_release_idx >= WL18XX_FW_MAX_TX_STATUS_DESC) {
|
||||
wl1271_error("invalid desc release index %d",
|
||||
status_priv->fw_release_idx);
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = priv->last_fw_rls_idx;
|
||||
i != status_priv->fw_release_idx;
|
||||
i = (i + 1) % WL18XX_FW_MAX_TX_STATUS_DESC) {
|
||||
wl18xx_tx_complete_packet(wl,
|
||||
status_priv->released_tx_desc[i]);
|
||||
|
||||
wl->tx_results_count++;
|
||||
}
|
||||
|
||||
priv->last_fw_rls_idx = status_priv->fw_release_idx;
|
||||
}
|
46
drivers/net/wireless/ti/wl18xx/tx.h
Normal file
46
drivers/net/wireless/ti/wl18xx/tx.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_TX_H__
|
||||
#define __WL18XX_TX_H__
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
|
||||
#define WL18XX_TX_HW_BLOCK_SPARE 1
|
||||
/* for special cases - namely, TKIP and GEM */
|
||||
#define WL18XX_TX_HW_EXTRA_BLOCK_SPARE 2
|
||||
#define WL18XX_TX_HW_BLOCK_SIZE 268
|
||||
|
||||
#define WL18XX_TX_STATUS_DESC_ID_MASK 0x7F
|
||||
#define WL18XX_TX_STATUS_STAT_BIT_IDX 7
|
||||
|
||||
/* Indicates this TX HW frame is not padded to SDIO block size */
|
||||
#define WL18XX_TX_CTRL_NOT_PADDED BIT(7)
|
||||
|
||||
/*
|
||||
* The FW uses a special bit to indicate a wide channel should be used in
|
||||
* the rate policy.
|
||||
*/
|
||||
#define CONF_TX_RATE_USE_WIDE_CHAN BIT(31)
|
||||
|
||||
void wl18xx_tx_immediate_complete(struct wl1271 *wl);
|
||||
|
||||
#endif /* __WL12XX_TX_H__ */
|
88
drivers/net/wireless/ti/wl18xx/wl18xx.h
Normal file
88
drivers/net/wireless/ti/wl18xx/wl18xx.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of wl18xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WL18XX_PRIV_H__
|
||||
#define __WL18XX_PRIV_H__
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
#define WL18XX_CMD_MAX_SIZE 740
|
||||
|
||||
struct wl18xx_priv {
|
||||
/* buffer for sending commands to FW */
|
||||
u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
|
||||
|
||||
struct wl18xx_priv_conf conf;
|
||||
|
||||
/* Index of last released Tx desc in FW */
|
||||
u8 last_fw_rls_idx;
|
||||
|
||||
/* number of VIFs requiring extra spare mem-blocks */
|
||||
int extra_spare_vif_count;
|
||||
};
|
||||
|
||||
#define WL18XX_FW_MAX_TX_STATUS_DESC 33
|
||||
|
||||
struct wl18xx_fw_status_priv {
|
||||
/*
|
||||
* Index in released_tx_desc for first byte that holds
|
||||
* released tx host desc
|
||||
*/
|
||||
u8 fw_release_idx;
|
||||
|
||||
/*
|
||||
* Array of host Tx descriptors, where fw_release_idx
|
||||
* indicated the first released idx.
|
||||
*/
|
||||
u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC];
|
||||
|
||||
u8 padding[2];
|
||||
};
|
||||
|
||||
#define WL18XX_PHY_VERSION_MAX_LEN 20
|
||||
|
||||
struct wl18xx_static_data_priv {
|
||||
char phy_version[WL18XX_PHY_VERSION_MAX_LEN];
|
||||
};
|
||||
|
||||
struct wl18xx_clk_cfg {
|
||||
u32 n;
|
||||
u32 m;
|
||||
u32 p;
|
||||
u32 q;
|
||||
bool swallow;
|
||||
};
|
||||
|
||||
enum {
|
||||
CLOCK_CONFIG_16_2_M = 1,
|
||||
CLOCK_CONFIG_16_368_M,
|
||||
CLOCK_CONFIG_16_8_M,
|
||||
CLOCK_CONFIG_19_2_M,
|
||||
CLOCK_CONFIG_26_M,
|
||||
CLOCK_CONFIG_32_736_M,
|
||||
CLOCK_CONFIG_33_6_M,
|
||||
CLOCK_CONFIG_38_468_M,
|
||||
CLOCK_CONFIG_52_M,
|
||||
|
||||
NUM_CLOCK_CONFIGS,
|
||||
};
|
||||
|
||||
#endif /* __WL18XX_PRIV_H__ */
|
@ -86,6 +86,7 @@ out:
|
||||
kfree(auth);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_acx_sleep_auth);
|
||||
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
int power)
|
||||
@ -708,14 +709,14 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, void *stats)
|
||||
{
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx statistics");
|
||||
|
||||
ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats,
|
||||
sizeof(*stats));
|
||||
wl->stats.fw_stats_len);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("acx statistics failed: %d", ret);
|
||||
return -ENOMEM;
|
||||
@ -997,6 +998,7 @@ out:
|
||||
kfree(mem_conf);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl12xx_acx_mem_cfg);
|
||||
|
||||
int wl1271_acx_init_mem_config(struct wl1271 *wl)
|
||||
{
|
||||
@ -1027,6 +1029,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_acx_init_mem_config);
|
||||
|
||||
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl)
|
||||
{
|
||||
@ -1150,6 +1153,7 @@ out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_acx_pm_config);
|
||||
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
|
@ -51,21 +51,18 @@
|
||||
#define WL1271_ACX_INTR_TRACE_A BIT(7)
|
||||
/* Trace message on MBOX #B */
|
||||
#define WL1271_ACX_INTR_TRACE_B BIT(8)
|
||||
/* SW FW Initiated interrupt Watchdog timer expiration */
|
||||
#define WL1271_ACX_SW_INTR_WATCHDOG BIT(9)
|
||||
|
||||
#define WL1271_ACX_INTR_ALL 0xFFFFFFFF
|
||||
#define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_INIT_COMPLETE | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_CMD_COMPLETE | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
#define WL1271_ACX_INTR_ALL 0xFFFFFFFF
|
||||
|
||||
#define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA)
|
||||
/* all possible interrupts - only appropriate ones will be masked in */
|
||||
#define WLCORE_ALL_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \
|
||||
WL1271_ACX_INTR_EVENT_A | \
|
||||
WL1271_ACX_INTR_EVENT_B | \
|
||||
WL1271_ACX_INTR_HW_AVAILABLE | \
|
||||
WL1271_ACX_INTR_DATA | \
|
||||
WL1271_ACX_SW_INTR_WATCHDOG)
|
||||
|
||||
/* Target's information element */
|
||||
struct acx_header {
|
||||
@ -417,228 +414,6 @@ struct acx_ctsprotect {
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
struct acx_tx_statistics {
|
||||
__le32 internal_desc_overflow;
|
||||
} __packed;
|
||||
|
||||
struct acx_rx_statistics {
|
||||
__le32 out_of_mem;
|
||||
__le32 hdr_overflow;
|
||||
__le32 hw_stuck;
|
||||
__le32 dropped;
|
||||
__le32 fcs_err;
|
||||
__le32 xfr_hint_trig;
|
||||
__le32 path_reset;
|
||||
__le32 reset_counter;
|
||||
} __packed;
|
||||
|
||||
struct acx_dma_statistics {
|
||||
__le32 rx_requested;
|
||||
__le32 rx_errors;
|
||||
__le32 tx_requested;
|
||||
__le32 tx_errors;
|
||||
} __packed;
|
||||
|
||||
struct acx_isr_statistics {
|
||||
/* host command complete */
|
||||
__le32 cmd_cmplt;
|
||||
|
||||
/* fiqisr() */
|
||||
__le32 fiqs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_HEADER) */
|
||||
__le32 rx_headers;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
|
||||
__le32 rx_completes;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
|
||||
__le32 rx_mem_overflow;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
|
||||
__le32 rx_rdys;
|
||||
|
||||
/* irqisr() */
|
||||
__le32 irqs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_TX_PROC) */
|
||||
__le32 tx_procs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
|
||||
__le32 decrypt_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DMA0) */
|
||||
__le32 dma0_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_DMA1) */
|
||||
__le32 dma1_done;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
|
||||
__le32 tx_exch_complete;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_COMMAND) */
|
||||
__le32 commands;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_RX_PROC) */
|
||||
__le32 rx_procs;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_PM_802) */
|
||||
__le32 hw_pm_mode_changes;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
|
||||
__le32 host_acknowledges;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_PM_PCI) */
|
||||
__le32 pci_pm;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
|
||||
__le32 wakeups;
|
||||
|
||||
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
|
||||
__le32 low_rssi;
|
||||
} __packed;
|
||||
|
||||
struct acx_wep_statistics {
|
||||
/* WEP address keys configured */
|
||||
__le32 addr_key_count;
|
||||
|
||||
/* default keys configured */
|
||||
__le32 default_key_count;
|
||||
|
||||
__le32 reserved;
|
||||
|
||||
/* number of times that WEP key not found on lookup */
|
||||
__le32 key_not_found;
|
||||
|
||||
/* number of times that WEP key decryption failed */
|
||||
__le32 decrypt_fail;
|
||||
|
||||
/* WEP packets decrypted */
|
||||
__le32 packets;
|
||||
|
||||
/* WEP decrypt interrupts */
|
||||
__le32 interrupt;
|
||||
} __packed;
|
||||
|
||||
#define ACX_MISSED_BEACONS_SPREAD 10
|
||||
|
||||
struct acx_pwr_statistics {
|
||||
/* the amount of enters into power save mode (both PD & ELP) */
|
||||
__le32 ps_enter;
|
||||
|
||||
/* the amount of enters into ELP mode */
|
||||
__le32 elp_enter;
|
||||
|
||||
/* the amount of missing beacon interrupts to the host */
|
||||
__le32 missing_bcns;
|
||||
|
||||
/* the amount of wake on host-access times */
|
||||
__le32 wake_on_host;
|
||||
|
||||
/* the amount of wake on timer-expire */
|
||||
__le32 wake_on_timer_exp;
|
||||
|
||||
/* the number of packets that were transmitted with PS bit set */
|
||||
__le32 tx_with_ps;
|
||||
|
||||
/* the number of packets that were transmitted with PS bit clear */
|
||||
__le32 tx_without_ps;
|
||||
|
||||
/* the number of received beacons */
|
||||
__le32 rcvd_beacons;
|
||||
|
||||
/* the number of entering into PowerOn (power save off) */
|
||||
__le32 power_save_off;
|
||||
|
||||
/* the number of entries into power save mode */
|
||||
__le16 enable_ps;
|
||||
|
||||
/*
|
||||
* the number of exits from power save, not including failed PS
|
||||
* transitions
|
||||
*/
|
||||
__le16 disable_ps;
|
||||
|
||||
/*
|
||||
* the number of times the TSF counter was adjusted because
|
||||
* of drift
|
||||
*/
|
||||
__le32 fix_tsf_ps;
|
||||
|
||||
/* Gives statistics about the spread continuous missed beacons.
|
||||
* The 16 LSB are dedicated for the PS mode.
|
||||
* The 16 MSB are dedicated for the PS mode.
|
||||
* cont_miss_bcns_spread[0] - single missed beacon.
|
||||
* cont_miss_bcns_spread[1] - two continuous missed beacons.
|
||||
* cont_miss_bcns_spread[2] - three continuous missed beacons.
|
||||
* ...
|
||||
* cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
|
||||
*/
|
||||
__le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
|
||||
|
||||
/* the number of beacons in awake mode */
|
||||
__le32 rcvd_awake_beacons;
|
||||
} __packed;
|
||||
|
||||
struct acx_mic_statistics {
|
||||
__le32 rx_pkts;
|
||||
__le32 calc_failure;
|
||||
} __packed;
|
||||
|
||||
struct acx_aes_statistics {
|
||||
__le32 encrypt_fail;
|
||||
__le32 decrypt_fail;
|
||||
__le32 encrypt_packets;
|
||||
__le32 decrypt_packets;
|
||||
__le32 encrypt_interrupt;
|
||||
__le32 decrypt_interrupt;
|
||||
} __packed;
|
||||
|
||||
struct acx_event_statistics {
|
||||
__le32 heart_beat;
|
||||
__le32 calibration;
|
||||
__le32 rx_mismatch;
|
||||
__le32 rx_mem_empty;
|
||||
__le32 rx_pool;
|
||||
__le32 oom_late;
|
||||
__le32 phy_transmit_error;
|
||||
__le32 tx_stuck;
|
||||
} __packed;
|
||||
|
||||
struct acx_ps_statistics {
|
||||
__le32 pspoll_timeouts;
|
||||
__le32 upsd_timeouts;
|
||||
__le32 upsd_max_sptime;
|
||||
__le32 upsd_max_apturn;
|
||||
__le32 pspoll_max_apturn;
|
||||
__le32 pspoll_utilization;
|
||||
__le32 upsd_utilization;
|
||||
} __packed;
|
||||
|
||||
struct acx_rxpipe_statistics {
|
||||
__le32 rx_prep_beacon_drop;
|
||||
__le32 descr_host_int_trig_rx_data;
|
||||
__le32 beacon_buffer_thres_host_int_trig_rx_data;
|
||||
__le32 missed_beacon_host_int_trig_rx_data;
|
||||
__le32 tx_xfr_host_int_trig_rx_data;
|
||||
} __packed;
|
||||
|
||||
struct acx_statistics {
|
||||
struct acx_header header;
|
||||
|
||||
struct acx_tx_statistics tx;
|
||||
struct acx_rx_statistics rx;
|
||||
struct acx_dma_statistics dma;
|
||||
struct acx_isr_statistics isr;
|
||||
struct acx_wep_statistics wep;
|
||||
struct acx_pwr_statistics pwr;
|
||||
struct acx_aes_statistics aes;
|
||||
struct acx_mic_statistics mic;
|
||||
struct acx_event_statistics event;
|
||||
struct acx_ps_statistics ps;
|
||||
struct acx_rxpipe_statistics rxpipe;
|
||||
} __packed;
|
||||
|
||||
struct acx_rate_class {
|
||||
__le32 enabled_rates;
|
||||
u8 short_retry_limit;
|
||||
@ -828,6 +603,8 @@ struct wl1271_acx_keep_alive_config {
|
||||
#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
|
||||
#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
|
||||
#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
|
||||
#define HOST_IF_CFG_RX_PAD_TO_SDIO_BLK BIT(4)
|
||||
#define HOST_IF_CFG_ADD_RX_ALIGNMENT BIT(6)
|
||||
|
||||
enum {
|
||||
WL1271_ACX_TRIG_TYPE_LEVEL = 0,
|
||||
@ -946,7 +723,7 @@ struct wl1271_acx_ht_information {
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
#define RX_BA_MAX_SESSIONS 2
|
||||
#define RX_BA_MAX_SESSIONS 3
|
||||
|
||||
struct wl1271_acx_ba_initiator_policy {
|
||||
struct acx_header header;
|
||||
@ -1243,6 +1020,7 @@ enum {
|
||||
ACX_CONFIG_HANGOVER = 0x0042,
|
||||
ACX_FEATURE_CFG = 0x0043,
|
||||
ACX_PROTECTION_CFG = 0x0044,
|
||||
ACX_CHECKSUM_CONFIG = 0x0045,
|
||||
};
|
||||
|
||||
|
||||
@ -1281,7 +1059,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_preamble_type preamble);
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_ctsprotect_type ctsprotect);
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, void *stats);
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
|
||||
u8 idx);
|
||||
|
@ -45,10 +45,17 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
|
||||
wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
|
||||
}
|
||||
|
||||
static int wlcore_parse_fw_ver(struct wl1271 *wl)
|
||||
static int wlcore_boot_parse_fw_ver(struct wl1271 *wl,
|
||||
struct wl1271_static_data *static_data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
strncpy(wl->chip.fw_ver_str, static_data->fw_version,
|
||||
sizeof(wl->chip.fw_ver_str));
|
||||
|
||||
/* make sure the string is NULL-terminated */
|
||||
wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
|
||||
|
||||
ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
|
||||
&wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
|
||||
&wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
|
||||
@ -57,43 +64,43 @@ static int wlcore_parse_fw_ver(struct wl1271 *wl)
|
||||
if (ret != 5) {
|
||||
wl1271_warning("fw version incorrect value");
|
||||
memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wlcore_identify_fw(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
goto out;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wlcore_boot_fw_version(struct wl1271 *wl)
|
||||
static int wlcore_boot_static_data(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271_static_data *static_data;
|
||||
size_t len = sizeof(*static_data) + wl->static_data_priv_len;
|
||||
int ret;
|
||||
|
||||
static_data = kmalloc(sizeof(*static_data), GFP_KERNEL | GFP_DMA);
|
||||
static_data = kmalloc(len, GFP_KERNEL);
|
||||
if (!static_data) {
|
||||
wl1271_error("Couldn't allocate memory for static data!");
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_read(wl, wl->cmd_box_addr, static_data, sizeof(*static_data),
|
||||
false);
|
||||
wl1271_read(wl, wl->cmd_box_addr, static_data, len, false);
|
||||
|
||||
strncpy(wl->chip.fw_ver_str, static_data->fw_version,
|
||||
sizeof(wl->chip.fw_ver_str));
|
||||
|
||||
kfree(static_data);
|
||||
|
||||
/* make sure the string is NULL-terminated */
|
||||
wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
|
||||
|
||||
ret = wlcore_parse_fw_ver(wl);
|
||||
ret = wlcore_boot_parse_fw_ver(wl, static_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto out_free;
|
||||
|
||||
return 0;
|
||||
ret = wlcore_handle_static_data(wl, static_data);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
|
||||
out_free:
|
||||
kfree(static_data);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
|
||||
@ -204,8 +211,10 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
|
||||
u32 dest_addr, val;
|
||||
u8 *nvs_ptr, *nvs_aligned;
|
||||
|
||||
if (wl->nvs == NULL)
|
||||
if (wl->nvs == NULL) {
|
||||
wl1271_error("NVS file is needed during boot");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) {
|
||||
struct wl1271_nvs_file *nvs =
|
||||
@ -400,9 +409,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
|
||||
wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
|
||||
wl->mbox_ptr[0], wl->mbox_ptr[1]);
|
||||
|
||||
ret = wlcore_boot_fw_version(wl);
|
||||
ret = wlcore_boot_static_data(wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("couldn't boot firmware");
|
||||
wl1271_error("error getting static data");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ struct wl1271_static_data {
|
||||
u8 fw_version[WL1271_FW_VERSION_MAX_LEN];
|
||||
u32 hw_version;
|
||||
u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS];
|
||||
u8 priv[0];
|
||||
};
|
||||
|
||||
/* number of times we try to read the INIT interrupt */
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "cmd.h"
|
||||
#include "event.h"
|
||||
#include "tx.h"
|
||||
#include "hw_ops.h"
|
||||
|
||||
#define WL1271_CMD_FAST_POLL_COUNT 50
|
||||
|
||||
@ -291,6 +292,23 @@ static int wl12xx_get_new_session_id(struct wl1271 *wl,
|
||||
return wlvif->session_counter;
|
||||
}
|
||||
|
||||
static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
|
||||
{
|
||||
switch (nl_channel_type) {
|
||||
case NL80211_CHAN_NO_HT:
|
||||
return WLCORE_CHAN_NO_HT;
|
||||
case NL80211_CHAN_HT20:
|
||||
return WLCORE_CHAN_HT20;
|
||||
case NL80211_CHAN_HT40MINUS:
|
||||
return WLCORE_CHAN_HT40MINUS;
|
||||
case NL80211_CHAN_HT40PLUS:
|
||||
return WLCORE_CHAN_HT40PLUS;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return WLCORE_CHAN_NO_HT;
|
||||
}
|
||||
}
|
||||
|
||||
static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
@ -407,6 +425,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len);
|
||||
memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN);
|
||||
cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
|
||||
cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
|
||||
|
||||
if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
@ -482,6 +501,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
u32 supported_rates;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id);
|
||||
@ -519,6 +539,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
/* FIXME: Change when adding DFS */
|
||||
cmd->ap.reset_tsf = 1; /* By default reset AP TSF */
|
||||
cmd->channel = wlvif->channel;
|
||||
cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
|
||||
|
||||
if (!bss_conf->hidden_ssid) {
|
||||
/* take the SSID from the beacon for backward compatibility */
|
||||
@ -531,7 +552,13 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
|
||||
}
|
||||
|
||||
cmd->ap.local_rates = cpu_to_le32(0xffffffff);
|
||||
supported_rates = CONF_TX_AP_ENABLED_RATES | CONF_TX_MCS_RATES |
|
||||
wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x",
|
||||
supported_rates);
|
||||
|
||||
cmd->ap.local_rates = cpu_to_le32(supported_rates);
|
||||
|
||||
switch (wlvif->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
@ -797,6 +824,7 @@ out:
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_cmd_data_path);
|
||||
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ps_mode, u16 auto_ps_timeout)
|
||||
@ -1018,7 +1046,7 @@ out:
|
||||
|
||||
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret, extra;
|
||||
int ret, extra = 0;
|
||||
u16 fc;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct sk_buff *skb;
|
||||
@ -1057,7 +1085,8 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
/* encryption space */
|
||||
switch (wlvif->encryption_type) {
|
||||
case KEY_TKIP:
|
||||
extra = WL1271_EXTRA_SPACE_TKIP;
|
||||
if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
|
||||
extra = WL1271_EXTRA_SPACE_TKIP;
|
||||
break;
|
||||
case KEY_AES:
|
||||
extra = WL1271_EXTRA_SPACE_AES;
|
||||
@ -1346,13 +1375,18 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
|
||||
for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
|
||||
if (sta->wme && (sta->uapsd_queues & BIT(i)))
|
||||
cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER;
|
||||
cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY-1-i] =
|
||||
WL1271_PSD_UPSD_TRIGGER;
|
||||
else
|
||||
cmd->psd_type[i] = WL1271_PSD_LEGACY;
|
||||
cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY-1-i] =
|
||||
WL1271_PSD_LEGACY;
|
||||
|
||||
|
||||
sta_rates = sta->supp_rates[wlvif->band];
|
||||
if (sta->ht_cap.ht_supported)
|
||||
sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
|
||||
sta_rates |=
|
||||
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
|
||||
(sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
|
||||
|
||||
cmd->supported_rates =
|
||||
cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
|
||||
@ -1573,19 +1607,25 @@ out:
|
||||
int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id)
|
||||
{
|
||||
int ret = 0;
|
||||
bool is_first_roc;
|
||||
|
||||
if (WARN_ON(test_bit(role_id, wl->roc_map)))
|
||||
return 0;
|
||||
|
||||
is_first_roc = (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >=
|
||||
WL12XX_MAX_ROLES);
|
||||
|
||||
ret = wl12xx_cmd_roc(wl, wlvif, role_id);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_cmd_wait_for_event(wl,
|
||||
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
|
||||
if (ret < 0) {
|
||||
wl1271_error("cmd roc event completion error");
|
||||
goto out;
|
||||
if (is_first_roc) {
|
||||
ret = wl1271_cmd_wait_for_event(wl,
|
||||
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
|
||||
if (ret < 0) {
|
||||
wl1271_error("cmd roc event completion error");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
__set_bit(role_id, wl->roc_map);
|
||||
|
@ -192,7 +192,7 @@ enum cmd_templ {
|
||||
#define WL1271_COMMAND_TIMEOUT 2000
|
||||
#define WL1271_CMD_TEMPL_DFLT_SIZE 252
|
||||
#define WL1271_CMD_TEMPL_MAX_SIZE 512
|
||||
#define WL1271_EVENT_TIMEOUT 750
|
||||
#define WL1271_EVENT_TIMEOUT 1000
|
||||
|
||||
struct wl1271_cmd_header {
|
||||
__le16 id;
|
||||
@ -266,13 +266,22 @@ enum wlcore_band {
|
||||
WLCORE_BAND_MAX_RADIO = 0x7F,
|
||||
};
|
||||
|
||||
enum wlcore_channel_type {
|
||||
WLCORE_CHAN_NO_HT,
|
||||
WLCORE_CHAN_HT20,
|
||||
WLCORE_CHAN_HT40MINUS,
|
||||
WLCORE_CHAN_HT40PLUS
|
||||
};
|
||||
|
||||
struct wl12xx_cmd_role_start {
|
||||
struct wl1271_cmd_header header;
|
||||
|
||||
u8 role_id;
|
||||
u8 band;
|
||||
u8 channel;
|
||||
u8 padding;
|
||||
|
||||
/* enum wlcore_channel_type */
|
||||
u8 channel_type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
|
@ -45,7 +45,15 @@ enum {
|
||||
CONF_HW_BIT_RATE_MCS_4 = BIT(17),
|
||||
CONF_HW_BIT_RATE_MCS_5 = BIT(18),
|
||||
CONF_HW_BIT_RATE_MCS_6 = BIT(19),
|
||||
CONF_HW_BIT_RATE_MCS_7 = BIT(20)
|
||||
CONF_HW_BIT_RATE_MCS_7 = BIT(20),
|
||||
CONF_HW_BIT_RATE_MCS_8 = BIT(21),
|
||||
CONF_HW_BIT_RATE_MCS_9 = BIT(22),
|
||||
CONF_HW_BIT_RATE_MCS_10 = BIT(23),
|
||||
CONF_HW_BIT_RATE_MCS_11 = BIT(24),
|
||||
CONF_HW_BIT_RATE_MCS_12 = BIT(25),
|
||||
CONF_HW_BIT_RATE_MCS_13 = BIT(26),
|
||||
CONF_HW_BIT_RATE_MCS_14 = BIT(27),
|
||||
CONF_HW_BIT_RATE_MCS_15 = BIT(28),
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -310,7 +318,7 @@ enum {
|
||||
struct conf_sg_settings {
|
||||
u32 params[CONF_SG_PARAMS_MAX];
|
||||
u8 state;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum conf_rx_queue_type {
|
||||
CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */
|
||||
@ -394,7 +402,7 @@ struct conf_rx_settings {
|
||||
* Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY,
|
||||
*/
|
||||
u8 queue_type;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define CONF_TX_MAX_RATE_CLASSES 10
|
||||
|
||||
@ -435,6 +443,12 @@ struct conf_rx_settings {
|
||||
CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \
|
||||
CONF_HW_BIT_RATE_MCS_7)
|
||||
|
||||
#define CONF_TX_MIMO_RATES (CONF_HW_BIT_RATE_MCS_8 | \
|
||||
CONF_HW_BIT_RATE_MCS_9 | CONF_HW_BIT_RATE_MCS_10 | \
|
||||
CONF_HW_BIT_RATE_MCS_11 | CONF_HW_BIT_RATE_MCS_12 | \
|
||||
CONF_HW_BIT_RATE_MCS_13 | CONF_HW_BIT_RATE_MCS_14 | \
|
||||
CONF_HW_BIT_RATE_MCS_15)
|
||||
|
||||
/*
|
||||
* Default rates for management traffic when operating in AP mode. This
|
||||
* should be configured according to the basic rate set of the AP
|
||||
@ -487,7 +501,7 @@ struct conf_tx_rate_class {
|
||||
* the policy (0 - long preamble, 1 - short preamble.
|
||||
*/
|
||||
u8 aflags;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define CONF_TX_MAX_AC_COUNT 4
|
||||
|
||||
@ -504,7 +518,7 @@ enum conf_tx_ac {
|
||||
CONF_TX_AC_VI = 2, /* video */
|
||||
CONF_TX_AC_VO = 3, /* voice */
|
||||
CONF_TX_AC_CTS2SELF = 4, /* fictitious AC, follows AC_VO */
|
||||
CONF_TX_AC_ANY_TID = 0x1f
|
||||
CONF_TX_AC_ANY_TID = 0xff
|
||||
};
|
||||
|
||||
struct conf_tx_ac_category {
|
||||
@ -544,7 +558,7 @@ struct conf_tx_ac_category {
|
||||
* Range: u16
|
||||
*/
|
||||
u16 tx_op_limit;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define CONF_TX_MAX_TID_COUNT 8
|
||||
|
||||
@ -578,7 +592,7 @@ struct conf_tx_tid {
|
||||
u8 ps_scheme;
|
||||
u8 ack_policy;
|
||||
u32 apsd_conf[2];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_tx_settings {
|
||||
/*
|
||||
@ -664,7 +678,7 @@ struct conf_tx_settings {
|
||||
|
||||
/* Time in ms for Tx watchdog timer to expire */
|
||||
u32 tx_watchdog_timeout;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/
|
||||
@ -711,7 +725,7 @@ struct conf_bcn_filt_rule {
|
||||
* Version for the vendor specifie IE (221)
|
||||
*/
|
||||
u8 version[CONF_BCN_IE_VER_LEN];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define CONF_MAX_RSSI_SNR_TRIGGERS 8
|
||||
|
||||
@ -762,7 +776,7 @@ struct conf_sig_weights {
|
||||
* Range: u8
|
||||
*/
|
||||
u8 snr_pkt_avg_weight;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum conf_bcn_filt_mode {
|
||||
CONF_BCN_FILT_MODE_DISABLED = 0,
|
||||
@ -810,7 +824,7 @@ struct conf_conn_settings {
|
||||
*
|
||||
* Range: CONF_BCN_FILT_MODE_*
|
||||
*/
|
||||
enum conf_bcn_filt_mode bcn_filt_mode;
|
||||
u8 bcn_filt_mode;
|
||||
|
||||
/*
|
||||
* Configure Beacon filter pass-thru rules.
|
||||
@ -937,7 +951,7 @@ struct conf_conn_settings {
|
||||
* Range: u16
|
||||
*/
|
||||
u8 max_listen_interval;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
CONF_REF_CLK_19_2_E,
|
||||
@ -965,6 +979,11 @@ struct conf_itrim_settings {
|
||||
|
||||
/* moderation timeout in microsecs from the last TX */
|
||||
u32 timeout;
|
||||
} __packed;
|
||||
|
||||
enum conf_fast_wakeup {
|
||||
CONF_FAST_WAKEUP_ENABLE,
|
||||
CONF_FAST_WAKEUP_DISABLE,
|
||||
};
|
||||
|
||||
struct conf_pm_config_settings {
|
||||
@ -978,10 +997,10 @@ struct conf_pm_config_settings {
|
||||
/*
|
||||
* Host fast wakeup support
|
||||
*
|
||||
* Range: true, false
|
||||
* Range: enum conf_fast_wakeup
|
||||
*/
|
||||
bool host_fast_wakeup_support;
|
||||
};
|
||||
u8 host_fast_wakeup_support;
|
||||
} __packed;
|
||||
|
||||
struct conf_roam_trigger_settings {
|
||||
/*
|
||||
@ -1018,7 +1037,7 @@ struct conf_roam_trigger_settings {
|
||||
* Range: 0 - 255
|
||||
*/
|
||||
u8 avg_weight_snr_data;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_scan_settings {
|
||||
/*
|
||||
@ -1064,7 +1083,7 @@ struct conf_scan_settings {
|
||||
* Range: u32 Microsecs
|
||||
*/
|
||||
u32 split_scan_timeout;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_sched_scan_settings {
|
||||
/*
|
||||
@ -1102,7 +1121,7 @@ struct conf_sched_scan_settings {
|
||||
|
||||
/* SNR threshold to be used for filtering */
|
||||
s8 snr_threshold;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_ht_setting {
|
||||
u8 rx_ba_win_size;
|
||||
@ -1111,7 +1130,7 @@ struct conf_ht_setting {
|
||||
|
||||
/* bitmap of enabled TIDs for TX BA sessions */
|
||||
u8 tx_ba_tid_bitmap;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_memory_settings {
|
||||
/* Number of stations supported in IBSS mode */
|
||||
@ -1151,7 +1170,7 @@ struct conf_memory_settings {
|
||||
* Range: 0-120
|
||||
*/
|
||||
u8 tx_min;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_fm_coex {
|
||||
u8 enable;
|
||||
@ -1164,7 +1183,7 @@ struct conf_fm_coex {
|
||||
u16 ldo_stabilization_time;
|
||||
u8 fm_disturbed_band_margin;
|
||||
u8 swallow_clk_diff;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_rx_streaming_settings {
|
||||
/*
|
||||
@ -1193,7 +1212,7 @@ struct conf_rx_streaming_settings {
|
||||
* enable rx streaming also when there is no coex activity
|
||||
*/
|
||||
u8 always;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_fwlog {
|
||||
/* Continuous or on-demand */
|
||||
@ -1217,7 +1236,7 @@ struct conf_fwlog {
|
||||
|
||||
/* Regulates the frequency of log messages */
|
||||
u8 threshold;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define ACX_RATE_MGMT_NUM_OF_RATES 13
|
||||
struct conf_rate_policy_settings {
|
||||
@ -1236,7 +1255,7 @@ struct conf_rate_policy_settings {
|
||||
u8 rate_check_up;
|
||||
u8 rate_check_down;
|
||||
u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct conf_hangover_settings {
|
||||
u32 recover_time;
|
||||
@ -1250,7 +1269,23 @@ struct conf_hangover_settings {
|
||||
u8 quiet_time;
|
||||
u8 increase_time;
|
||||
u8 window_size;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* The conf version consists of 4 bytes. The two MSB are the wlcore
|
||||
* version, the two LSB are the lower driver's private conf
|
||||
* version.
|
||||
*/
|
||||
#define WLCORE_CONF_VERSION (0x0001 << 16)
|
||||
#define WLCORE_CONF_MASK 0xffff0000
|
||||
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
|
||||
sizeof(struct wlcore_conf))
|
||||
|
||||
struct wlcore_conf_header {
|
||||
__le32 magic;
|
||||
__le32 version;
|
||||
__le32 checksum;
|
||||
} __packed;
|
||||
|
||||
struct wlcore_conf {
|
||||
struct conf_sg_settings sg;
|
||||
@ -1269,6 +1304,12 @@ struct wlcore_conf {
|
||||
struct conf_fwlog fwlog;
|
||||
struct conf_rate_policy_settings rate;
|
||||
struct conf_hangover_settings hangover;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct wlcore_conf_file {
|
||||
struct wlcore_conf_header header;
|
||||
struct wlcore_conf core;
|
||||
u8 priv[0];
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "wlcore.h"
|
||||
#include "debug.h"
|
||||
@ -32,14 +33,14 @@
|
||||
#include "ps.h"
|
||||
#include "io.h"
|
||||
#include "tx.h"
|
||||
#include "hw_ops.h"
|
||||
|
||||
/* ms */
|
||||
#define WL1271_DEBUGFS_STATS_LIFETIME 1000
|
||||
|
||||
/* debugfs macros idea from mac80211 */
|
||||
#define DEBUGFS_FORMAT_BUFFER_SIZE 100
|
||||
static int wl1271_format_buffer(char __user *userbuf, size_t count,
|
||||
loff_t *ppos, char *fmt, ...)
|
||||
int wl1271_format_buffer(char __user *userbuf, size_t count,
|
||||
loff_t *ppos, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
|
||||
@ -51,59 +52,9 @@ static int wl1271_format_buffer(char __user *userbuf, size_t count,
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_format_buffer);
|
||||
|
||||
#define DEBUGFS_READONLY_FILE(name, fmt, value...) \
|
||||
static ssize_t name## _read(struct file *file, char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
return wl1271_format_buffer(userbuf, count, ppos, \
|
||||
fmt "\n", ##value); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations name## _ops = { \
|
||||
.read = name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_ADD(name, parent) \
|
||||
entry = debugfs_create_file(#name, 0400, parent, \
|
||||
wl, &name## _ops); \
|
||||
if (!entry || IS_ERR(entry)) \
|
||||
goto err; \
|
||||
|
||||
#define DEBUGFS_ADD_PREFIX(prefix, name, parent) \
|
||||
do { \
|
||||
entry = debugfs_create_file(#name, 0400, parent, \
|
||||
wl, &prefix## _## name## _ops); \
|
||||
if (!entry || IS_ERR(entry)) \
|
||||
goto err; \
|
||||
} while (0);
|
||||
|
||||
#define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \
|
||||
static ssize_t sub## _ ##name## _read(struct file *file, \
|
||||
char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
\
|
||||
wl1271_debugfs_update_stats(wl); \
|
||||
\
|
||||
return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \
|
||||
wl->stats.fw_stats->sub.name); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations sub## _ ##name## _ops = { \
|
||||
.read = sub## _ ##name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_FWSTATS_ADD(sub, name) \
|
||||
DEBUGFS_ADD(sub## _ ##name, stats)
|
||||
|
||||
static void wl1271_debugfs_update_stats(struct wl1271 *wl)
|
||||
void wl1271_debugfs_update_stats(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -125,97 +76,7 @@ static void wl1271_debugfs_update_stats(struct wl1271 *wl)
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, dropped, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, commands, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u");
|
||||
/* skipping wep.reserved */
|
||||
DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(wep, packets, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u");
|
||||
/* skipping cont_miss_bcns_spread for now */
|
||||
DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, calibration, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, oom_late, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u");
|
||||
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u");
|
||||
DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u");
|
||||
EXPORT_SYMBOL_GPL(wl1271_debugfs_update_stats);
|
||||
|
||||
DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count);
|
||||
DEBUGFS_READONLY_FILE(excessive_retries, "%u",
|
||||
@ -241,6 +102,89 @@ static const struct file_operations tx_queue_len_ops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static void chip_op_handler(struct wl1271 *wl, unsigned long value,
|
||||
void *arg)
|
||||
{
|
||||
int ret;
|
||||
int (*chip_op) (struct wl1271 *wl);
|
||||
|
||||
if (!arg) {
|
||||
wl1271_warning("debugfs chip_op_handler with no callback");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
chip_op = arg;
|
||||
chip_op(wl);
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
}
|
||||
|
||||
|
||||
static inline void no_write_handler(struct wl1271 *wl,
|
||||
unsigned long value,
|
||||
unsigned long param)
|
||||
{
|
||||
}
|
||||
|
||||
#define WL12XX_CONF_DEBUGFS(param, conf_sub_struct, \
|
||||
min_val, max_val, write_handler_locked, \
|
||||
write_handler_arg) \
|
||||
static ssize_t param##_read(struct file *file, \
|
||||
char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
return wl1271_format_buffer(user_buf, count, \
|
||||
ppos, "%d\n", \
|
||||
wl->conf.conf_sub_struct.param); \
|
||||
} \
|
||||
\
|
||||
static ssize_t param##_write(struct file *file, \
|
||||
const char __user *user_buf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
unsigned long value; \
|
||||
int ret; \
|
||||
\
|
||||
ret = kstrtoul_from_user(user_buf, count, 10, &value); \
|
||||
if (ret < 0) { \
|
||||
wl1271_warning("illegal value for " #param); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
\
|
||||
if (value < min_val || value > max_val) { \
|
||||
wl1271_warning(#param " is not in valid range"); \
|
||||
return -ERANGE; \
|
||||
} \
|
||||
\
|
||||
mutex_lock(&wl->mutex); \
|
||||
wl->conf.conf_sub_struct.param = value; \
|
||||
\
|
||||
write_handler_locked(wl, value, write_handler_arg); \
|
||||
\
|
||||
mutex_unlock(&wl->mutex); \
|
||||
return count; \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations param##_ops = { \
|
||||
.read = param##_read, \
|
||||
.write = param##_write, \
|
||||
.open = simple_open, \
|
||||
.llseek = default_llseek, \
|
||||
};
|
||||
|
||||
WL12XX_CONF_DEBUGFS(irq_pkt_threshold, rx, 0, 65535,
|
||||
chip_op_handler, wl1271_acx_init_rx_interrupt)
|
||||
WL12XX_CONF_DEBUGFS(irq_blk_threshold, rx, 0, 65535,
|
||||
chip_op_handler, wl1271_acx_init_rx_interrupt)
|
||||
WL12XX_CONF_DEBUGFS(irq_timeout, rx, 0, 100,
|
||||
chip_op_handler, wl1271_acx_init_rx_interrupt)
|
||||
|
||||
static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@ -535,8 +479,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
|
||||
DRIVER_STATE_PRINT_LHEX(ap_ps_map);
|
||||
DRIVER_STATE_PRINT_HEX(quirks);
|
||||
DRIVER_STATE_PRINT_HEX(irq);
|
||||
DRIVER_STATE_PRINT_HEX(ref_clock);
|
||||
DRIVER_STATE_PRINT_HEX(tcxo_clock);
|
||||
/* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */
|
||||
DRIVER_STATE_PRINT_HEX(hw_pg_ver);
|
||||
DRIVER_STATE_PRINT_HEX(platform_quirks);
|
||||
DRIVER_STATE_PRINT_HEX(chip.id);
|
||||
@ -647,7 +590,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
|
||||
VIF_STATE_PRINT_INT(last_rssi_event);
|
||||
VIF_STATE_PRINT_INT(ba_support);
|
||||
VIF_STATE_PRINT_INT(ba_allowed);
|
||||
VIF_STATE_PRINT_INT(is_gem);
|
||||
VIF_STATE_PRINT_LLHEX(tx_security_seq);
|
||||
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
|
||||
}
|
||||
@ -1002,108 +944,30 @@ static const struct file_operations beacon_filtering_ops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t fw_stats_raw_read(struct file *file,
|
||||
char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
|
||||
wl1271_debugfs_update_stats(wl);
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos,
|
||||
wl->stats.fw_stats,
|
||||
wl->stats.fw_stats_len);
|
||||
}
|
||||
|
||||
static const struct file_operations fw_stats_raw_ops = {
|
||||
.read = fw_stats_raw_read,
|
||||
.open = simple_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
||||
struct dentry *rootdir)
|
||||
struct dentry *rootdir)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dentry *entry, *stats, *streaming;
|
||||
|
||||
stats = debugfs_create_dir("fw-statistics", rootdir);
|
||||
if (!stats || IS_ERR(stats)) {
|
||||
entry = stats;
|
||||
goto err;
|
||||
}
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
|
||||
DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
|
||||
DEBUGFS_FWSTATS_ADD(rx, dropped);
|
||||
DEBUGFS_FWSTATS_ADD(rx, fcs_err);
|
||||
DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
|
||||
DEBUGFS_FWSTATS_ADD(rx, path_reset);
|
||||
DEBUGFS_FWSTATS_ADD(rx, reset_counter);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(dma, rx_requested);
|
||||
DEBUGFS_FWSTATS_ADD(dma, rx_errors);
|
||||
DEBUGFS_FWSTATS_ADD(dma, tx_requested);
|
||||
DEBUGFS_FWSTATS_ADD(dma, tx_errors);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
|
||||
DEBUGFS_FWSTATS_ADD(isr, fiqs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_headers);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
|
||||
DEBUGFS_FWSTATS_ADD(isr, irqs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, tx_procs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, dma0_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, dma1_done);
|
||||
DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
|
||||
DEBUGFS_FWSTATS_ADD(isr, commands);
|
||||
DEBUGFS_FWSTATS_ADD(isr, rx_procs);
|
||||
DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
|
||||
DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
|
||||
DEBUGFS_FWSTATS_ADD(isr, pci_pm);
|
||||
DEBUGFS_FWSTATS_ADD(isr, wakeups);
|
||||
DEBUGFS_FWSTATS_ADD(isr, low_rssi);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
|
||||
DEBUGFS_FWSTATS_ADD(wep, default_key_count);
|
||||
/* skipping wep.reserved */
|
||||
DEBUGFS_FWSTATS_ADD(wep, key_not_found);
|
||||
DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(wep, packets);
|
||||
DEBUGFS_FWSTATS_ADD(wep, interrupt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
|
||||
DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
|
||||
/* skipping cont_miss_bcns_spread for now */
|
||||
DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
|
||||
DEBUGFS_FWSTATS_ADD(mic, calc_failure);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
|
||||
DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
|
||||
DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(event, heart_beat);
|
||||
DEBUGFS_FWSTATS_ADD(event, calibration);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
|
||||
DEBUGFS_FWSTATS_ADD(event, rx_pool);
|
||||
DEBUGFS_FWSTATS_ADD(event, oom_late);
|
||||
DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
|
||||
DEBUGFS_FWSTATS_ADD(event, tx_stuck);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
|
||||
DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
|
||||
DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
|
||||
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
|
||||
DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
|
||||
struct dentry *entry, *streaming;
|
||||
|
||||
DEBUGFS_ADD(tx_queue_len, rootdir);
|
||||
DEBUGFS_ADD(retry_count, rootdir);
|
||||
@ -1120,6 +984,10 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
||||
DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
|
||||
DEBUGFS_ADD(forced_ps, rootdir);
|
||||
DEBUGFS_ADD(split_scan_timeout, rootdir);
|
||||
DEBUGFS_ADD(irq_pkt_threshold, rootdir);
|
||||
DEBUGFS_ADD(irq_blk_threshold, rootdir);
|
||||
DEBUGFS_ADD(irq_timeout, rootdir);
|
||||
DEBUGFS_ADD(fw_stats_raw, rootdir);
|
||||
|
||||
streaming = debugfs_create_dir("rx_streaming", rootdir);
|
||||
if (!streaming || IS_ERR(streaming))
|
||||
@ -1145,7 +1013,7 @@ void wl1271_debugfs_reset(struct wl1271 *wl)
|
||||
if (!wl->stats.fw_stats)
|
||||
return;
|
||||
|
||||
memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
|
||||
memset(wl->stats.fw_stats, 0, wl->stats.fw_stats_len);
|
||||
wl->stats.retry_count = 0;
|
||||
wl->stats.excessive_retries = 0;
|
||||
}
|
||||
@ -1160,34 +1028,34 @@ int wl1271_debugfs_init(struct wl1271 *wl)
|
||||
|
||||
if (IS_ERR(rootdir)) {
|
||||
ret = PTR_ERR(rootdir);
|
||||
goto err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats),
|
||||
GFP_KERNEL);
|
||||
|
||||
wl->stats.fw_stats = kzalloc(wl->stats.fw_stats_len, GFP_KERNEL);
|
||||
if (!wl->stats.fw_stats) {
|
||||
ret = -ENOMEM;
|
||||
goto err_fw;
|
||||
goto out_remove;
|
||||
}
|
||||
|
||||
wl->stats.fw_stats_update = jiffies;
|
||||
|
||||
ret = wl1271_debugfs_add_files(wl, rootdir);
|
||||
|
||||
if (ret < 0)
|
||||
goto err_file;
|
||||
goto out_exit;
|
||||
|
||||
return 0;
|
||||
ret = wlcore_debugfs_init(wl, rootdir);
|
||||
if (ret < 0)
|
||||
goto out_exit;
|
||||
|
||||
err_file:
|
||||
kfree(wl->stats.fw_stats);
|
||||
wl->stats.fw_stats = NULL;
|
||||
goto out;
|
||||
|
||||
err_fw:
|
||||
out_exit:
|
||||
wl1271_debugfs_exit(wl);
|
||||
|
||||
out_remove:
|
||||
debugfs_remove_recursive(rootdir);
|
||||
|
||||
err:
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,95 @@
|
||||
|
||||
#include "wlcore.h"
|
||||
|
||||
int wl1271_format_buffer(char __user *userbuf, size_t count,
|
||||
loff_t *ppos, char *fmt, ...);
|
||||
|
||||
int wl1271_debugfs_init(struct wl1271 *wl);
|
||||
void wl1271_debugfs_exit(struct wl1271 *wl);
|
||||
void wl1271_debugfs_reset(struct wl1271 *wl);
|
||||
void wl1271_debugfs_update_stats(struct wl1271 *wl);
|
||||
|
||||
#define DEBUGFS_FORMAT_BUFFER_SIZE 256
|
||||
|
||||
#define DEBUGFS_READONLY_FILE(name, fmt, value...) \
|
||||
static ssize_t name## _read(struct file *file, char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
return wl1271_format_buffer(userbuf, count, ppos, \
|
||||
fmt "\n", ##value); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations name## _ops = { \
|
||||
.read = name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_ADD(name, parent) \
|
||||
do { \
|
||||
entry = debugfs_create_file(#name, 0400, parent, \
|
||||
wl, &name## _ops); \
|
||||
if (!entry || IS_ERR(entry)) \
|
||||
goto err; \
|
||||
} while (0);
|
||||
|
||||
|
||||
#define DEBUGFS_ADD_PREFIX(prefix, name, parent) \
|
||||
do { \
|
||||
entry = debugfs_create_file(#name, 0400, parent, \
|
||||
wl, &prefix## _## name## _ops); \
|
||||
if (!entry || IS_ERR(entry)) \
|
||||
goto err; \
|
||||
} while (0);
|
||||
|
||||
#define DEBUGFS_FWSTATS_FILE(sub, name, fmt, struct_type) \
|
||||
static ssize_t sub## _ ##name## _read(struct file *file, \
|
||||
char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
struct struct_type *stats = wl->stats.fw_stats; \
|
||||
\
|
||||
wl1271_debugfs_update_stats(wl); \
|
||||
\
|
||||
return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \
|
||||
stats->sub.name); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations sub## _ ##name## _ops = { \
|
||||
.read = sub## _ ##name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_FWSTATS_FILE_ARRAY(sub, name, len, struct_type) \
|
||||
static ssize_t sub## _ ##name## _read(struct file *file, \
|
||||
char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wl1271 *wl = file->private_data; \
|
||||
struct struct_type *stats = wl->stats.fw_stats; \
|
||||
char buf[DEBUGFS_FORMAT_BUFFER_SIZE] = ""; \
|
||||
int res, i; \
|
||||
\
|
||||
wl1271_debugfs_update_stats(wl); \
|
||||
\
|
||||
for (i = 0; i < len; i++) \
|
||||
res = snprintf(buf, sizeof(buf), "%s[%d] = %d\n", \
|
||||
buf, i, stats->sub.name[i]); \
|
||||
\
|
||||
return wl1271_format_buffer(userbuf, count, ppos, "%s", buf); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations sub## _ ##name## _ops = { \
|
||||
.read = sub## _ ##name## _read, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_FWSTATS_ADD(sub, name) \
|
||||
DEBUGFS_ADD(sub## _ ##name, stats)
|
||||
|
||||
|
||||
#endif /* WL1271_DEBUGFS_H */
|
||||
|
@ -148,15 +148,33 @@ static int wl1271_event_process(struct wl1271 *wl)
|
||||
int delay = wl->conf.conn.synch_fail_thold *
|
||||
wl->conf.conn.bss_lose_timeout;
|
||||
wl1271_info("Beacon loss detected.");
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
|
||||
/*
|
||||
* if the work is already queued, it should take place. We
|
||||
* don't want to delay the connection loss indication
|
||||
* any more.
|
||||
*/
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
|
||||
msecs_to_jiffies(delay));
|
||||
msecs_to_jiffies(delay));
|
||||
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
ieee80211_cqm_rssi_notify(
|
||||
vif,
|
||||
NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
|
||||
if (vector & REGAINED_BSS_EVENT_ID) {
|
||||
/* TODO: check for multi-role */
|
||||
wl1271_info("Beacon regained.");
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
cancel_delayed_work(&wl->connection_loss_work);
|
||||
|
||||
/* sanity check - we can't lose and gain the beacon together */
|
||||
WARN(vector & BSS_LOSE_EVENT_ID,
|
||||
"Concurrent beacon loss and gain from FW");
|
||||
}
|
||||
|
||||
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
|
||||
|
@ -119,4 +119,82 @@ static inline int wlcore_identify_fw(struct wl1271 *wl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
wlcore_hw_set_tx_desc_csum(struct wl1271 *wl,
|
||||
struct wl1271_tx_hw_descr *desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (!wl->ops->set_tx_desc_csum)
|
||||
BUG_ON(1);
|
||||
|
||||
wl->ops->set_tx_desc_csum(wl, desc, skb);
|
||||
}
|
||||
|
||||
static inline void
|
||||
wlcore_hw_set_rx_csum(struct wl1271 *wl,
|
||||
struct wl1271_rx_descriptor *desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (wl->ops->set_rx_csum)
|
||||
wl->ops->set_rx_csum(wl, desc, skb);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
wlcore_hw_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
if (wl->ops->ap_get_mimo_wide_rate_mask)
|
||||
return wl->ops->ap_get_mimo_wide_rate_mask(wl, wlvif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
wlcore_debugfs_init(struct wl1271 *wl, struct dentry *rootdir)
|
||||
{
|
||||
if (wl->ops->debugfs_init)
|
||||
return wl->ops->debugfs_init(wl, rootdir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
wlcore_handle_static_data(struct wl1271 *wl, void *static_data)
|
||||
{
|
||||
if (wl->ops->handle_static_data)
|
||||
return wl->ops->handle_static_data(wl, static_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
wlcore_hw_get_spare_blocks(struct wl1271 *wl, bool is_gem)
|
||||
{
|
||||
if (!wl->ops->get_spare_blocks)
|
||||
BUG_ON(1);
|
||||
|
||||
return wl->ops->get_spare_blocks(wl, is_gem);
|
||||
}
|
||||
|
||||
static inline int
|
||||
wlcore_hw_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
if (!wl->ops->set_key)
|
||||
BUG_ON(1);
|
||||
|
||||
return wl->ops->set_key(wl, cmd, vif, sta, key_conf);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
|
||||
{
|
||||
if (wl->ops->pre_pkt_send)
|
||||
return wl->ops->pre_pkt_send(wl, buf_offset, last_len);
|
||||
|
||||
return buf_offset;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -460,6 +460,9 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
/* unconditionally enable HT rates */
|
||||
supported_rates |= CONF_TX_MCS_RATES;
|
||||
|
||||
/* get extra MIMO or wide-chan rates where the HW supports it */
|
||||
supported_rates |= wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
|
||||
|
||||
/* configure unicast TX rate classes */
|
||||
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
|
||||
rc.enabled_rates = supported_rates;
|
||||
|
@ -320,46 +320,6 @@ static void wlcore_adjust_conf(struct wl1271 *wl)
|
||||
}
|
||||
}
|
||||
|
||||
static int wl1271_plt_init(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl->ops->hw_init(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_init_mem_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Enable data path */
|
||||
ret = wl1271_cmd_data_path(wl, 1);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure for CAM power saving (ie. always active) */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* configure PM */
|
||||
ret = wl1271_acx_pm_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_memmap:
|
||||
kfree(wl->target_mem_map);
|
||||
wl->target_mem_map = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u8 hlid, u8 tx_pkts)
|
||||
@ -387,7 +347,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
|
||||
|
||||
static void wl12xx_irq_update_links_status(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct wl_fw_status *status)
|
||||
struct wl_fw_status_2 *status)
|
||||
{
|
||||
struct wl1271_link *lnk;
|
||||
u32 cur_fw_ps_map;
|
||||
@ -419,7 +379,8 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
|
||||
}
|
||||
|
||||
static void wl12xx_fw_status(struct wl1271 *wl,
|
||||
struct wl_fw_status *status)
|
||||
struct wl_fw_status_1 *status_1,
|
||||
struct wl_fw_status_2 *status_2)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
struct timespec ts;
|
||||
@ -428,37 +389,38 @@ static void wl12xx_fw_status(struct wl1271 *wl,
|
||||
int i;
|
||||
size_t status_len;
|
||||
|
||||
status_len = sizeof(*status) + wl->fw_status_priv_len;
|
||||
status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
|
||||
sizeof(*status_2) + wl->fw_status_priv_len;
|
||||
|
||||
wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status,
|
||||
wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
|
||||
status_len, false);
|
||||
|
||||
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
|
||||
"drv_rx_counter = %d, tx_results_counter = %d)",
|
||||
status->intr,
|
||||
status->fw_rx_counter,
|
||||
status->drv_rx_counter,
|
||||
status->tx_results_counter);
|
||||
status_1->intr,
|
||||
status_1->fw_rx_counter,
|
||||
status_1->drv_rx_counter,
|
||||
status_1->tx_results_counter);
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
/* prevent wrap-around in freed-packets counter */
|
||||
wl->tx_allocated_pkts[i] -=
|
||||
(status->counters.tx_released_pkts[i] -
|
||||
(status_2->counters.tx_released_pkts[i] -
|
||||
wl->tx_pkts_freed[i]) & 0xff;
|
||||
|
||||
wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];
|
||||
wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
|
||||
}
|
||||
|
||||
/* prevent wrap-around in total blocks counter */
|
||||
if (likely(wl->tx_blocks_freed <=
|
||||
le32_to_cpu(status->total_released_blks)))
|
||||
freed_blocks = le32_to_cpu(status->total_released_blks) -
|
||||
le32_to_cpu(status_2->total_released_blks)))
|
||||
freed_blocks = le32_to_cpu(status_2->total_released_blks) -
|
||||
wl->tx_blocks_freed;
|
||||
else
|
||||
freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
|
||||
le32_to_cpu(status->total_released_blks);
|
||||
le32_to_cpu(status_2->total_released_blks);
|
||||
|
||||
wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
|
||||
wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
|
||||
|
||||
wl->tx_allocated_blocks -= freed_blocks;
|
||||
|
||||
@ -474,7 +436,7 @@ static void wl12xx_fw_status(struct wl1271 *wl,
|
||||
cancel_delayed_work(&wl->tx_watchdog_work);
|
||||
}
|
||||
|
||||
avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
|
||||
avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
|
||||
|
||||
/*
|
||||
* The FW might change the total number of TX memblocks before
|
||||
@ -493,13 +455,13 @@ static void wl12xx_fw_status(struct wl1271 *wl,
|
||||
|
||||
/* for AP update num of allocated TX blocks per link and ps status */
|
||||
wl12xx_for_each_wlvif_ap(wl, wlvif) {
|
||||
wl12xx_irq_update_links_status(wl, wlvif, status);
|
||||
wl12xx_irq_update_links_status(wl, wlvif, status_2);
|
||||
}
|
||||
|
||||
/* update the host-chipset time offset */
|
||||
getnstimeofday(&ts);
|
||||
wl->time_offset = (timespec_to_ns(&ts) >> 10) -
|
||||
(s64)le32_to_cpu(status->fw_localtime);
|
||||
(s64)le32_to_cpu(status_2->fw_localtime);
|
||||
}
|
||||
|
||||
static void wl1271_flush_deferred_work(struct wl1271 *wl)
|
||||
@ -568,20 +530,30 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
|
||||
clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
|
||||
smp_mb__after_clear_bit();
|
||||
|
||||
wl12xx_fw_status(wl, wl->fw_status);
|
||||
wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
|
||||
|
||||
wlcore_hw_tx_immediate_compl(wl);
|
||||
|
||||
intr = le32_to_cpu(wl->fw_status->intr);
|
||||
intr &= WL1271_INTR_MASK;
|
||||
intr = le32_to_cpu(wl->fw_status_1->intr);
|
||||
intr &= WLCORE_ALL_INTR_MASK;
|
||||
if (!intr) {
|
||||
done = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
|
||||
wl1271_error("watchdog interrupt received! "
|
||||
wl1271_error("HW watchdog interrupt received! starting recovery.");
|
||||
wl->watchdog_recovery = true;
|
||||
wl12xx_queue_recovery_work(wl);
|
||||
|
||||
/* restarting the chip. ignore any other interrupt. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(intr & WL1271_ACX_SW_INTR_WATCHDOG)) {
|
||||
wl1271_error("SW watchdog interrupt received! "
|
||||
"starting recovery.");
|
||||
wl->watchdog_recovery = true;
|
||||
wl12xx_queue_recovery_work(wl);
|
||||
|
||||
/* restarting the chip. ignore any other interrupt. */
|
||||
@ -591,7 +563,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
|
||||
if (likely(intr & WL1271_ACX_INTR_DATA)) {
|
||||
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
|
||||
|
||||
wl12xx_rx(wl, wl->fw_status);
|
||||
wl12xx_rx(wl, wl->fw_status_1);
|
||||
|
||||
/* Check if any tx blocks were freed */
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
@ -743,7 +715,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
static void wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
@ -751,16 +723,15 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
|
||||
|
||||
if (ret < 0) {
|
||||
wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
|
||||
ret);
|
||||
return ret;
|
||||
wl1271_debug(DEBUG_BOOT, "could not get nvs file %s: %d",
|
||||
WL12XX_NVS_NAME, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
|
||||
if (!wl->nvs) {
|
||||
wl1271_error("could not allocate memory for the nvs file");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -768,8 +739,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wl12xx_queue_recovery_work(struct wl1271 *wl)
|
||||
@ -820,14 +789,16 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
||||
|
||||
/*
|
||||
* Make sure the chip is awake and the logger isn't active.
|
||||
* This might fail if the firmware hanged.
|
||||
* Do not send a stop fwlog command if the fw is hanged.
|
||||
*/
|
||||
if (!wl1271_ps_elp_wakeup(wl))
|
||||
if (!wl1271_ps_elp_wakeup(wl) && !wl->watchdog_recovery)
|
||||
wl12xx_cmd_stop_fwlog(wl);
|
||||
else
|
||||
goto out;
|
||||
|
||||
/* Read the first memory block address */
|
||||
wl12xx_fw_status(wl, wl->fw_status);
|
||||
first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
|
||||
wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
|
||||
first_addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
|
||||
if (!first_addr)
|
||||
goto out;
|
||||
|
||||
@ -872,9 +843,14 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
|
||||
wl12xx_read_fwlog_panic(wl);
|
||||
|
||||
wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
|
||||
/* change partitions momentarily so we can read the FW pc */
|
||||
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
|
||||
wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x "
|
||||
"hint_sts: 0x%08x",
|
||||
wl->chip.fw_ver_str,
|
||||
wlcore_read_reg(wl, REG_PC_ON_RECOVERY));
|
||||
wlcore_read_reg(wl, REG_PC_ON_RECOVERY),
|
||||
wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR));
|
||||
wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
|
||||
|
||||
BUG_ON(bug_on_recovery &&
|
||||
!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
|
||||
@ -885,8 +861,6 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
BUG_ON(bug_on_recovery);
|
||||
|
||||
/*
|
||||
* Advance security sequence number to overcome potential progress
|
||||
* in the firmware during recovery. This doens't hurt if the network is
|
||||
@ -900,7 +874,7 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
/* Prevent spurious TX during FW restart */
|
||||
ieee80211_stop_queues(wl->hw);
|
||||
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
|
||||
|
||||
if (wl->sched_scanning) {
|
||||
ieee80211_sched_scan_stopped(wl->hw);
|
||||
@ -914,6 +888,7 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
__wl1271_op_remove_interface(wl, vif, false);
|
||||
}
|
||||
wl->watchdog_recovery = false;
|
||||
mutex_unlock(&wl->mutex);
|
||||
wl1271_op_stop(wl->hw);
|
||||
|
||||
@ -925,9 +900,10 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
* Its safe to enable TX now - the queues are stopped after a request
|
||||
* to restart the HW.
|
||||
*/
|
||||
ieee80211_wake_queues(wl->hw);
|
||||
wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
|
||||
return;
|
||||
out_unlock:
|
||||
wl->watchdog_recovery = false;
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
@ -938,13 +914,19 @@ static void wl1271_fw_wakeup(struct wl1271 *wl)
|
||||
|
||||
static int wl1271_setup(struct wl1271 *wl)
|
||||
{
|
||||
wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
|
||||
if (!wl->fw_status)
|
||||
wl->fw_status_1 = kmalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
|
||||
sizeof(*wl->fw_status_2) +
|
||||
wl->fw_status_priv_len, GFP_KERNEL);
|
||||
if (!wl->fw_status_1)
|
||||
return -ENOMEM;
|
||||
|
||||
wl->fw_status_2 = (struct wl_fw_status_2 *)
|
||||
(((u8 *) wl->fw_status_1) +
|
||||
WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
|
||||
|
||||
wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
|
||||
if (!wl->tx_res_if) {
|
||||
kfree(wl->fw_status);
|
||||
kfree(wl->fw_status_1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -987,13 +969,12 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
|
||||
* simplify the code and since the performance impact is
|
||||
* negligible, we use the same block size for all different
|
||||
* chip types.
|
||||
*
|
||||
* Check if the bus supports blocksize alignment and, if it
|
||||
* doesn't, make sure we don't have the quirk.
|
||||
*/
|
||||
if (wl1271_set_block_size(wl))
|
||||
wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
|
||||
|
||||
ret = wl->ops->identify_chip(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (!wl1271_set_block_size(wl))
|
||||
wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
|
||||
|
||||
/* TODO: make sure the lower driver has set things up correctly */
|
||||
|
||||
@ -1005,13 +986,6 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* No NVS from netlink, try to get it from the filesystem */
|
||||
if (wl->nvs == NULL) {
|
||||
ret = wl1271_fetch_nvs(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@ -1039,14 +1013,10 @@ int wl1271_plt_start(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
goto power_off;
|
||||
|
||||
ret = wl->ops->boot(wl);
|
||||
ret = wl->ops->plt_init(wl);
|
||||
if (ret < 0)
|
||||
goto power_off;
|
||||
|
||||
ret = wl1271_plt_init(wl);
|
||||
if (ret < 0)
|
||||
goto irq_disable;
|
||||
|
||||
wl->plt = true;
|
||||
wl->state = WL1271_STATE_ON;
|
||||
wl1271_notice("firmware booted in PLT mode (%s)",
|
||||
@ -1059,19 +1029,6 @@ int wl1271_plt_start(struct wl1271 *wl)
|
||||
|
||||
goto out;
|
||||
|
||||
irq_disable:
|
||||
mutex_unlock(&wl->mutex);
|
||||
/* Unlocking the mutex in the middle of handling is
|
||||
inherently unsafe. In this case we deem it safe to do,
|
||||
because we need to let any possibly pending IRQ out of
|
||||
the system (and while we are WL1271_STATE_OFF the IRQ
|
||||
work function will not do anything.) Also, any other
|
||||
possible concurrent operations will fail due to the
|
||||
current state, hence the wl1271 struct should be safe. */
|
||||
wlcore_disable_interrupts(wl);
|
||||
wl1271_flush_deferred_work(wl);
|
||||
cancel_work_sync(&wl->netstack_work);
|
||||
mutex_lock(&wl->mutex);
|
||||
power_off:
|
||||
wl1271_power_off(wl);
|
||||
}
|
||||
@ -1154,9 +1111,16 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
|
||||
/* queue the packet */
|
||||
/*
|
||||
* drop the packet if the link is invalid or the queue is stopped
|
||||
* for any reason but watermark. Watermark is a "soft"-stop so we
|
||||
* allow these packets through.
|
||||
*/
|
||||
if (hlid == WL12XX_INVALID_LINK_ID ||
|
||||
(wlvif && !test_bit(hlid, wlvif->links_map))) {
|
||||
(wlvif && !test_bit(hlid, wlvif->links_map)) ||
|
||||
(wlcore_is_queue_stopped(wl, q) &&
|
||||
!wlcore_is_queue_stopped_by_reason(wl, q,
|
||||
WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
|
||||
wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
goto out;
|
||||
@ -1174,8 +1138,8 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
*/
|
||||
if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
|
||||
wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
|
||||
ieee80211_stop_queue(wl->hw, mapping);
|
||||
set_bit(q, &wl->stopped_queues_map);
|
||||
wlcore_stop_queue_locked(wl, q,
|
||||
WLCORE_QUEUE_STOP_REASON_WATERMARK);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1758,7 +1722,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
|
||||
/* let's notify MAC80211 about the remaining pending TX frames */
|
||||
wl12xx_tx_reset(wl, true);
|
||||
wl12xx_tx_reset(wl);
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
wl1271_power_off(wl);
|
||||
@ -1767,6 +1731,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
|
||||
|
||||
wl->rx_counter = 0;
|
||||
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
|
||||
wl->channel_type = NL80211_CHAN_NO_HT;
|
||||
wl->tx_blocks_available = 0;
|
||||
wl->tx_allocated_blocks = 0;
|
||||
wl->tx_results_count = 0;
|
||||
@ -1799,8 +1764,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
|
||||
|
||||
wl1271_debugfs_reset(wl);
|
||||
|
||||
kfree(wl->fw_status);
|
||||
wl->fw_status = NULL;
|
||||
kfree(wl->fw_status_1);
|
||||
wl->fw_status_1 = NULL;
|
||||
wl->fw_status_2 = NULL;
|
||||
kfree(wl->tx_res_if);
|
||||
wl->tx_res_if = NULL;
|
||||
kfree(wl->target_mem_map);
|
||||
@ -1894,6 +1860,9 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
|
||||
wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
|
||||
wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
|
||||
wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
} else {
|
||||
/* init ap data */
|
||||
wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
|
||||
@ -1903,13 +1872,19 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
|
||||
wl12xx_allocate_rate_policy(wl,
|
||||
&wlvif->ap.ucast_rate_idx[i]);
|
||||
wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES;
|
||||
/*
|
||||
* TODO: check if basic_rate shouldn't be
|
||||
* wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
* instead (the same thing for STA above).
|
||||
*/
|
||||
wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES;
|
||||
/* TODO: this seems to be used only for STA, check it */
|
||||
wlvif->rate_set = CONF_TX_AP_ENABLED_RATES;
|
||||
}
|
||||
|
||||
wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
|
||||
wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
|
||||
wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
|
||||
|
||||
/*
|
||||
@ -1919,6 +1894,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
wlvif->band = wl->band;
|
||||
wlvif->channel = wl->channel;
|
||||
wlvif->power_level = wl->power_level;
|
||||
wlvif->channel_type = wl->channel_type;
|
||||
|
||||
INIT_WORK(&wlvif->rx_streaming_enable_work,
|
||||
wl1271_rx_streaming_enable_work);
|
||||
@ -2444,7 +2420,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
} else {
|
||||
/* The current firmware only supports sched_scan in idle */
|
||||
if (wl->sched_scanning) {
|
||||
wl1271_scan_sched_scan_stop(wl);
|
||||
wl1271_scan_sched_scan_stop(wl, wlvif);
|
||||
ieee80211_sched_scan_stopped(wl->hw);
|
||||
}
|
||||
|
||||
@ -2469,13 +2445,20 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
/* if the channel changes while joined, join again */
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
|
||||
((wlvif->band != conf->channel->band) ||
|
||||
(wlvif->channel != channel))) {
|
||||
(wlvif->channel != channel) ||
|
||||
(wlvif->channel_type != conf->channel_type))) {
|
||||
/* send all pending packets */
|
||||
wl1271_tx_work_locked(wl);
|
||||
wlvif->band = conf->channel->band;
|
||||
wlvif->channel = channel;
|
||||
wlvif->channel_type = conf->channel_type;
|
||||
|
||||
if (!is_ap) {
|
||||
if (is_ap) {
|
||||
ret = wl1271_init_ap_rates(wl, wlvif);
|
||||
if (ret < 0)
|
||||
wl1271_error("AP rate policy change failed %d",
|
||||
ret);
|
||||
} else {
|
||||
/*
|
||||
* FIXME: the mac80211 should really provide a fixed
|
||||
* rate to use here. for now, just use the smallest
|
||||
@ -2583,8 +2566,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
* frames, such as the deauth. To make sure those frames reach the air,
|
||||
* wait here until the TX queue is fully flushed.
|
||||
*/
|
||||
if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
|
||||
(conf->flags & IEEE80211_CONF_IDLE))
|
||||
if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
|
||||
((changed & IEEE80211_CONF_CHANGE_IDLE) &&
|
||||
(conf->flags & IEEE80211_CONF_IDLE)))
|
||||
wl1271_tx_flush(wl);
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
@ -2593,6 +2577,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
wl->band = conf->channel->band;
|
||||
wl->channel = channel;
|
||||
wl->channel_type = conf->channel_type;
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_POWER)
|
||||
@ -2825,17 +2810,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
int ret;
|
||||
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||
|
||||
/*
|
||||
* A role set to GEM cipher requires different Tx settings (namely
|
||||
* spare blocks). Note when we are in this mode so the HW can adjust.
|
||||
*/
|
||||
if (key_type == KEY_GEM) {
|
||||
if (action == KEY_ADD_OR_REPLACE)
|
||||
wlvif->is_gem = true;
|
||||
else if (action == KEY_REMOVE)
|
||||
wlvif->is_gem = false;
|
||||
}
|
||||
|
||||
if (is_ap) {
|
||||
struct wl1271_station *wl_sta;
|
||||
u8 hlid;
|
||||
@ -2913,12 +2887,21 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
|
||||
return wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
|
||||
}
|
||||
|
||||
int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret;
|
||||
u32 tx_seq_32 = 0;
|
||||
@ -3029,6 +3012,7 @@ out_unlock:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wlcore_set_key);
|
||||
|
||||
static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
@ -3167,6 +3151,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
|
||||
@ -3180,7 +3165,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_scan_sched_scan_stop(wl);
|
||||
wl1271_scan_sched_scan_stop(wl, wlvif);
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
@ -3316,8 +3301,15 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
|
||||
skb->data,
|
||||
skb->len, 0,
|
||||
rates);
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_debug(DEBUG_AP, "probe response updated");
|
||||
set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3422,6 +3414,87 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wlcore_set_beacon_template(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif,
|
||||
bool is_ap)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct ieee80211_hdr *hdr;
|
||||
u32 min_rate;
|
||||
int ret;
|
||||
int ieoffset = offsetof(struct ieee80211_mgmt,
|
||||
u.beacon.variable);
|
||||
struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
|
||||
u16 tmpl_id;
|
||||
|
||||
if (!beacon) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_MASTER, "beacon updated");
|
||||
|
||||
ret = wl1271_ssid_set(vif, beacon, ieoffset);
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(beacon);
|
||||
goto out;
|
||||
}
|
||||
min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
|
||||
CMD_TEMPL_BEACON;
|
||||
ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
|
||||
beacon->data,
|
||||
beacon->len, 0,
|
||||
min_rate);
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(beacon);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case we already have a probe-resp beacon set explicitly
|
||||
* by usermode, don't use the beacon data.
|
||||
*/
|
||||
if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
|
||||
goto end_bcn;
|
||||
|
||||
/* remove TIM ie from probe response */
|
||||
wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
|
||||
|
||||
/*
|
||||
* remove p2p ie from probe response.
|
||||
* the fw reponds to probe requests that don't include
|
||||
* the p2p ie. probe requests with p2p ie will be passed,
|
||||
* and will be responded by the supplicant (the spec
|
||||
* forbids including the p2p ie when responding to probe
|
||||
* requests that didn't include it).
|
||||
*/
|
||||
wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
|
||||
WLAN_OUI_TYPE_WFA_P2P, ieoffset);
|
||||
|
||||
hdr = (struct ieee80211_hdr *) beacon->data;
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
|
||||
beacon->data,
|
||||
beacon->len,
|
||||
min_rate);
|
||||
else
|
||||
ret = wl1271_cmd_template_set(wl, wlvif->role_id,
|
||||
CMD_TEMPL_PROBE_RESPONSE,
|
||||
beacon->data,
|
||||
beacon->len, 0,
|
||||
min_rate);
|
||||
end_bcn:
|
||||
dev_kfree_skb(beacon);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
@ -3440,81 +3513,12 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
|
||||
|
||||
if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
|
||||
u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
|
||||
wl1271_debug(DEBUG_AP, "probe response updated");
|
||||
set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
|
||||
}
|
||||
|
||||
wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
|
||||
}
|
||||
|
||||
if ((changed & BSS_CHANGED_BEACON)) {
|
||||
struct ieee80211_hdr *hdr;
|
||||
u32 min_rate;
|
||||
int ieoffset = offsetof(struct ieee80211_mgmt,
|
||||
u.beacon.variable);
|
||||
struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
|
||||
u16 tmpl_id;
|
||||
|
||||
if (!beacon) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_MASTER, "beacon updated");
|
||||
|
||||
ret = wl1271_ssid_set(vif, beacon, ieoffset);
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(beacon);
|
||||
goto out;
|
||||
}
|
||||
min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
|
||||
CMD_TEMPL_BEACON;
|
||||
ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
|
||||
beacon->data,
|
||||
beacon->len, 0,
|
||||
min_rate);
|
||||
if (ret < 0) {
|
||||
dev_kfree_skb(beacon);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case we already have a probe-resp beacon set explicitly
|
||||
* by usermode, don't use the beacon data.
|
||||
*/
|
||||
if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
|
||||
goto end_bcn;
|
||||
|
||||
/* remove TIM ie from probe response */
|
||||
wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
|
||||
|
||||
/*
|
||||
* remove p2p ie from probe response.
|
||||
* the fw reponds to probe requests that don't include
|
||||
* the p2p ie. probe requests with p2p ie will be passed,
|
||||
* and will be responded by the supplicant (the spec
|
||||
* forbids including the p2p ie when responding to probe
|
||||
* requests that didn't include it).
|
||||
*/
|
||||
wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
|
||||
WLAN_OUI_TYPE_WFA_P2P, ieoffset);
|
||||
|
||||
hdr = (struct ieee80211_hdr *) beacon->data;
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
|
||||
beacon->data,
|
||||
beacon->len,
|
||||
min_rate);
|
||||
else
|
||||
ret = wl1271_cmd_template_set(wl, wlvif->role_id,
|
||||
CMD_TEMPL_PROBE_RESPONSE,
|
||||
beacon->data,
|
||||
beacon->len, 0,
|
||||
min_rate);
|
||||
end_bcn:
|
||||
dev_kfree_skb(beacon);
|
||||
ret = wlcore_set_beacon_template(wl, vif, is_ap);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
@ -3551,6 +3555,14 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
|
||||
ret = wl1271_ap_init_templates(wl, vif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wlcore_set_beacon_template(wl, vif, true);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
|
||||
@ -3691,7 +3703,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
|
||||
sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
|
||||
if (sta->ht_cap.ht_supported)
|
||||
sta_rate_set |=
|
||||
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
|
||||
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
|
||||
(sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
|
||||
sta_ht_cap = sta->ht_cap;
|
||||
sta_exists = true;
|
||||
|
||||
@ -3704,13 +3717,11 @@ sta_not_found:
|
||||
u32 rates;
|
||||
int ieoffset;
|
||||
wlvif->aid = bss_conf->aid;
|
||||
wlvif->channel_type = bss_conf->channel_type;
|
||||
wlvif->beacon_int = bss_conf->beacon_int;
|
||||
do_join = true;
|
||||
set_assoc = true;
|
||||
|
||||
/* Cancel connection_loss_work */
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
|
||||
/*
|
||||
* use basic rates from AP, and determine lowest rate
|
||||
* to use with control frames.
|
||||
@ -3960,6 +3971,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
|
||||
wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
|
||||
(int)changed);
|
||||
|
||||
/*
|
||||
* make sure to cancel pending disconnections if our association
|
||||
* state changed
|
||||
*/
|
||||
if (!is_ap && (changed & BSS_CHANGED_ASSOC))
|
||||
cancel_delayed_work_sync(&wl->connection_loss_work);
|
||||
|
||||
if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
|
||||
!bss_conf->enable_beacon)
|
||||
wl1271_tx_flush(wl);
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
@ -4636,7 +4658,7 @@ static const struct ieee80211_ops wl1271_ops = {
|
||||
.prepare_multicast = wl1271_op_prepare_multicast,
|
||||
.configure_filter = wl1271_op_configure_filter,
|
||||
.tx = wl1271_op_tx,
|
||||
.set_key = wl1271_op_set_key,
|
||||
.set_key = wlcore_op_set_key,
|
||||
.hw_scan = wl1271_op_hw_scan,
|
||||
.cancel_hw_scan = wl1271_op_cancel_hw_scan,
|
||||
.sched_scan_start = wl1271_op_sched_scan_start,
|
||||
@ -4905,14 +4927,8 @@ static int wl1271_register_hw(struct wl1271 *wl)
|
||||
if (wl->mac80211_registered)
|
||||
return 0;
|
||||
|
||||
ret = wl12xx_get_hw_info(wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("couldn't get hw info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_fetch_nvs(wl);
|
||||
if (ret == 0) {
|
||||
wl1271_fetch_nvs(wl);
|
||||
if (wl->nvs != NULL) {
|
||||
/* NOTE: The wl->nvs->nvs element must be first, in
|
||||
* order to simplify the casting, we assume it is at
|
||||
* the beginning of the wl->nvs structure.
|
||||
@ -4970,9 +4986,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
WL1271_CIPHER_SUITE_GEM,
|
||||
};
|
||||
|
||||
/* The tx descriptor buffer and the TKIP space. */
|
||||
wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
|
||||
sizeof(struct wl1271_tx_hw_descr);
|
||||
/* The tx descriptor buffer */
|
||||
wl->hw->extra_tx_headroom = sizeof(struct wl1271_tx_hw_descr);
|
||||
|
||||
if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
|
||||
wl->hw->extra_tx_headroom += WL1271_EXTRA_SPACE_TKIP;
|
||||
|
||||
/* unit us */
|
||||
/* FIXME: find a proper value */
|
||||
@ -5025,12 +5043,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
*/
|
||||
memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
|
||||
sizeof(wl1271_band_2ghz));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap, &wl->ht_cap,
|
||||
sizeof(wl->ht_cap));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap,
|
||||
&wl->ht_cap[IEEE80211_BAND_2GHZ],
|
||||
sizeof(*wl->ht_cap));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
|
||||
sizeof(wl1271_band_5ghz));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap, &wl->ht_cap,
|
||||
sizeof(wl->ht_cap));
|
||||
memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap,
|
||||
&wl->ht_cap[IEEE80211_BAND_5GHZ],
|
||||
sizeof(*wl->ht_cap));
|
||||
|
||||
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
|
||||
&wl->bands[IEEE80211_BAND_2GHZ];
|
||||
@ -5117,6 +5137,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
|
||||
wl->rx_counter = 0;
|
||||
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
|
||||
wl->band = IEEE80211_BAND_2GHZ;
|
||||
wl->channel_type = NL80211_CHAN_NO_HT;
|
||||
wl->flags = 0;
|
||||
wl->sg_enabled = true;
|
||||
wl->hw_pg_ver = -1;
|
||||
@ -5142,6 +5163,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
|
||||
wl->state = WL1271_STATE_OFF;
|
||||
wl->fw_type = WL12XX_FW_TYPE_NONE;
|
||||
mutex_init(&wl->mutex);
|
||||
mutex_init(&wl->flush_mutex);
|
||||
|
||||
order = get_order(WL1271_AGGR_BUFFER_SIZE);
|
||||
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
|
||||
@ -5222,7 +5244,7 @@ int wlcore_free_hw(struct wl1271 *wl)
|
||||
kfree(wl->nvs);
|
||||
wl->nvs = NULL;
|
||||
|
||||
kfree(wl->fw_status);
|
||||
kfree(wl->fw_status_1);
|
||||
kfree(wl->tx_res_if);
|
||||
destroy_workqueue(wl->freezable_wq);
|
||||
|
||||
@ -5279,8 +5301,6 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
||||
wlcore_adjust_conf(wl);
|
||||
|
||||
wl->irq = platform_get_irq(pdev, 0);
|
||||
wl->ref_clock = pdata->board_ref_clock;
|
||||
wl->tcxo_clock = pdata->board_tcxo_clock;
|
||||
wl->platform_quirks = pdata->platform_quirks;
|
||||
wl->set_power = pdata->set_power;
|
||||
wl->dev = &pdev->dev;
|
||||
@ -5316,6 +5336,16 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
||||
}
|
||||
disable_irq(wl->irq);
|
||||
|
||||
ret = wl12xx_get_hw_info(wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("couldn't get hw info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl->ops->identify_chip(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_init_ieee80211(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#define WL1271_WAKEUP_TIMEOUT 500
|
||||
|
||||
#define ELP_ENTRY_DELAY 5
|
||||
|
||||
void wl1271_elp_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork;
|
||||
@ -72,6 +74,7 @@ out:
|
||||
void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
u32 timeout;
|
||||
|
||||
if (wl->quirks & WLCORE_QUIRK_NO_ELP)
|
||||
return;
|
||||
@ -89,8 +92,13 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
||||
return;
|
||||
}
|
||||
|
||||
if (wl->conf.conn.forced_ps)
|
||||
timeout = ELP_ENTRY_DELAY;
|
||||
else
|
||||
timeout = wl->conf.conn.dynamic_ps_timeout;
|
||||
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
|
||||
msecs_to_jiffies(wl->conf.conn.dynamic_ps_timeout));
|
||||
msecs_to_jiffies(timeout));
|
||||
}
|
||||
|
||||
int wl1271_ps_elp_wakeup(struct wl1271 *wl)
|
||||
@ -185,8 +193,12 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
|
||||
set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
|
||||
|
||||
/* enable beacon early termination. Not relevant for 5GHz */
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ) {
|
||||
/*
|
||||
* enable beacon early termination.
|
||||
* Not relevant for 5GHz and for high rates.
|
||||
*/
|
||||
if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
|
||||
(wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
|
||||
ret = wl1271_acx_bet_enable(wl, wlvif, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -196,7 +208,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
wl1271_debug(DEBUG_PSM, "leaving psm");
|
||||
|
||||
/* disable beacon early termination */
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ) {
|
||||
if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
|
||||
(wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
|
||||
ret = wl1271_acx_bet_enable(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -186,6 +186,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||
is_data = 1;
|
||||
|
||||
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
|
||||
wlcore_hw_set_rx_csum(wl, desc, skb);
|
||||
|
||||
seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
|
||||
wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb,
|
||||
@ -199,12 +200,12 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||
return is_data;
|
||||
}
|
||||
|
||||
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
|
||||
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
|
||||
{
|
||||
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
|
||||
u32 buf_size;
|
||||
u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
||||
u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
||||
u32 fw_rx_counter = status->fw_rx_counter % wl->num_rx_desc;
|
||||
u32 drv_rx_counter = wl->rx_counter % wl->num_rx_desc;
|
||||
u32 rx_counter;
|
||||
u32 pkt_len, align_pkt_len;
|
||||
u32 pkt_offset, des;
|
||||
@ -223,7 +224,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
|
||||
break;
|
||||
buf_size += align_pkt_len;
|
||||
rx_counter++;
|
||||
rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
|
||||
rx_counter %= wl->num_rx_desc;
|
||||
}
|
||||
|
||||
if (buf_size == 0) {
|
||||
@ -263,7 +264,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
|
||||
|
||||
wl->rx_counter++;
|
||||
drv_rx_counter++;
|
||||
drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
|
||||
drv_rx_counter %= wl->num_rx_desc;
|
||||
pkt_offset += wlcore_rx_get_align_buf_size(wl, pkt_len);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user