提交 627ae3dd 编写于 作者: J Johannes Berg

Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next

...@@ -329,7 +329,7 @@ F: drivers/hwmon/adm1029.c ...@@ -329,7 +329,7 @@ F: drivers/hwmon/adm1029.c
ADM8211 WIRELESS DRIVER ADM8211 WIRELESS DRIVER
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/ W: http://wireless.kernel.org/
S: Orphan S: Orphan
F: drivers/net/wireless/adm8211.* F: drivers/net/wireless/adm8211.*
...@@ -1423,7 +1423,7 @@ B43 WIRELESS DRIVER ...@@ -1423,7 +1423,7 @@ B43 WIRELESS DRIVER
M: Stefano Brivio <stefano.brivio@polimi.it> M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
L: b43-dev@lists.infradead.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 S: Maintained
F: drivers/net/wireless/b43/ F: drivers/net/wireless/b43/
...@@ -1432,7 +1432,7 @@ M: Larry Finger <Larry.Finger@lwfinger.net> ...@@ -1432,7 +1432,7 @@ M: Larry Finger <Larry.Finger@lwfinger.net>
M: Stefano Brivio <stefano.brivio@polimi.it> M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
L: b43-dev@lists.infradead.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 S: Maintained
F: drivers/net/wireless/b43legacy/ F: drivers/net/wireless/b43legacy/
...@@ -1800,6 +1800,9 @@ F: include/linux/cfag12864b.h ...@@ -1800,6 +1800,9 @@ F: include/linux/cfag12864b.h
CFG80211 and NL80211 CFG80211 and NL80211
M: Johannes Berg <johannes@sipsolutions.net> M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org 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 S: Maintained
F: include/linux/nl80211.h F: include/linux/nl80211.h
F: include/net/cfg80211.h F: include/net/cfg80211.h
...@@ -4339,8 +4342,9 @@ F: arch/m68k/hp300/ ...@@ -4339,8 +4342,9 @@ F: arch/m68k/hp300/
MAC80211 MAC80211
M: Johannes Berg <johannes@sipsolutions.net> M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/ W: http://wireless.kernel.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git 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 S: Maintained
F: Documentation/networking/mac80211-injection.txt F: Documentation/networking/mac80211-injection.txt
F: include/net/mac80211.h F: include/net/mac80211.h
...@@ -4350,8 +4354,9 @@ MAC80211 PID RATE CONTROL ...@@ -4350,8 +4354,9 @@ MAC80211 PID RATE CONTROL
M: Stefano Brivio <stefano.brivio@polimi.it> M: Stefano Brivio <stefano.brivio@polimi.it>
M: Mattias Nissler <mattias.nissler@gmx.de> M: Mattias Nissler <mattias.nissler@gmx.de>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID W: http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git 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 S: Maintained
F: net/mac80211/rc80211_pid* F: net/mac80211/rc80211_pid*
...@@ -5027,7 +5032,7 @@ F: fs/ocfs2/ ...@@ -5027,7 +5032,7 @@ F: fs/ocfs2/
ORINOCO DRIVER ORINOCO DRIVER
L: linux-wireless@vger.kernel.org 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/ W: http://www.nongnu.org/orinoco/
S: Orphan S: Orphan
F: drivers/net/wireless/orinoco/ F: drivers/net/wireless/orinoco/
...@@ -5695,6 +5700,9 @@ F: include/linux/remoteproc.h ...@@ -5695,6 +5700,9 @@ F: include/linux/remoteproc.h
RFKILL RFKILL
M: Johannes Berg <johannes@sipsolutions.net> M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org 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 S: Maintained
F: Documentation/rfkill.txt F: Documentation/rfkill.txt
F: net/rfkill/ F: net/rfkill/
...@@ -5729,7 +5737,7 @@ F: net/rose/ ...@@ -5729,7 +5737,7 @@ F: net/rose/
RTL8180 WIRELESS DRIVER RTL8180 WIRELESS DRIVER
M: "John W. Linville" <linville@tuxdriver.com> M: "John W. Linville" <linville@tuxdriver.com>
L: linux-wireless@vger.kernel.org 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 T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained S: Maintained
F: drivers/net/wireless/rtl818x/rtl8180/ F: drivers/net/wireless/rtl818x/rtl8180/
...@@ -5739,7 +5747,7 @@ M: Herton Ronaldo Krzesinski <herton@canonical.com> ...@@ -5739,7 +5747,7 @@ M: Herton Ronaldo Krzesinski <herton@canonical.com>
M: Hin-Tak Leung <htl10@users.sourceforge.net> M: Hin-Tak Leung <htl10@users.sourceforge.net>
M: Larry Finger <Larry.Finger@lwfinger.net> M: Larry Finger <Larry.Finger@lwfinger.net>
L: linux-wireless@vger.kernel.org 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 T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained S: Maintained
F: drivers/net/wireless/rtl818x/rtl8187/ F: drivers/net/wireless/rtl818x/rtl8187/
...@@ -5748,7 +5756,7 @@ RTL8192CE WIRELESS DRIVER ...@@ -5748,7 +5756,7 @@ RTL8192CE WIRELESS DRIVER
M: Larry Finger <Larry.Finger@lwfinger.net> M: Larry Finger <Larry.Finger@lwfinger.net>
M: Chaoming Li <chaoming_li@realsil.com.cn> M: Chaoming Li <chaoming_li@realsil.com.cn>
L: linux-wireless@vger.kernel.org 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 T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained S: Maintained
F: drivers/net/wireless/rtlwifi/ F: drivers/net/wireless/rtlwifi/
......
...@@ -139,7 +139,9 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc) ...@@ -139,7 +139,9 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
break; break;
case 0x4331: 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; break;
case 43224: case 43224:
if (bus->chipinfo.rev == 0) { if (bus->chipinfo.rev == 0) {
......
...@@ -232,17 +232,19 @@ void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc) ...@@ -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, int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
bool enable) bool enable)
{ {
struct pci_dev *pdev = pc->core->bus->host_pci; struct pci_dev *pdev;
u32 coremask, tmp; u32 coremask, tmp;
int err = 0; 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 /* This bcma device is not on a PCI host-bus. So the IRQs are
* not routed through the PCI core. * not routed through the PCI core.
* So we must not enable routing through the PCI core. */ * So we must not enable routing through the PCI core. */
goto out; goto out;
} }
pdev = pc->core->bus->host_pci;
err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
if (err) if (err)
goto out; goto out;
......
...@@ -579,13 +579,13 @@ int bcma_sprom_get(struct bcma_bus *bus) ...@@ -579,13 +579,13 @@ int bcma_sprom_get(struct bcma_bus *bus)
if (!sprom) if (!sprom)
return -ENOMEM; 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); bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
pr_debug("SPROM offset 0x%x\n", offset); pr_debug("SPROM offset 0x%x\n", offset);
bcma_sprom_read(bus, offset, sprom); 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); bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
err = bcma_sprom_valid(sprom); err = bcma_sprom_valid(sprom);
......
...@@ -3,7 +3,9 @@ ath9k-y += beacon.o \ ...@@ -3,7 +3,9 @@ ath9k-y += beacon.o \
init.o \ init.o \
main.o \ main.o \
recv.o \ recv.o \
xmit.o xmit.o \
link.o \
antenna.o
ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
......
...@@ -126,7 +126,7 @@ static int ath_ahb_probe(struct platform_device *pdev) ...@@ -126,7 +126,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
sc->irq = irq; sc->irq = irq;
/* Will be cleared in ath9k_start() */ /* 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); ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
if (ret) { if (ret) {
......
此差异已折叠。
...@@ -653,7 +653,6 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, ...@@ -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, static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
u8 num_chains,
struct coeff *coeff, struct coeff *coeff,
bool is_reusable) bool is_reusable)
{ {
...@@ -677,7 +676,9 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, ...@@ -677,7 +676,9 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
} }
/* Load the average of 2 passes */ /* 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, nmeasurement = REG_READ_FIELD(ah,
AR_PHY_TX_IQCAL_STATUS_B0, AR_PHY_TX_IQCAL_STATUS_B0,
AR_PHY_CALIBRATED_GAINS_0); 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) ...@@ -767,16 +768,13 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
}; };
struct coeff coeff; struct coeff coeff;
s32 iq_res[6]; s32 iq_res[6];
u8 num_chains = 0;
int i, im, j; int i, im, j;
int nmeasurement; int nmeasurement;
for (i = 0; i < AR9300_MAX_CHAINS; i++) { for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (ah->txchainmask & (1 << i)) if (!(ah->txchainmask & (1 << i)))
num_chains++; continue;
}
for (i = 0; i < num_chains; i++) {
nmeasurement = REG_READ_FIELD(ah, nmeasurement = REG_READ_FIELD(ah,
AR_PHY_TX_IQCAL_STATUS_B0, AR_PHY_TX_IQCAL_STATUS_B0,
AR_PHY_CALIBRATED_GAINS_0); 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) ...@@ -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; coeff.phs_coeff[i][im] -= 128;
} }
} }
ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
&coeff, is_reusable);
return; return;
...@@ -901,7 +898,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, ...@@ -901,7 +898,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
bool is_reusable = true, status = true; bool is_reusable = true, status = true;
bool run_rtt_cal = false, run_agc_cal; bool run_rtt_cal = false, run_agc_cal;
bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); 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 | u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
AR_PHY_AGC_CONTROL_FLTR_CAL | AR_PHY_AGC_CONTROL_FLTR_CAL |
AR_PHY_AGC_CONTROL_PKDET_CAL; AR_PHY_AGC_CONTROL_PKDET_CAL;
...@@ -970,7 +966,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, ...@@ -970,7 +966,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
} else if (caldata && !caldata->done_txiqcal_once) } else if (caldata && !caldata->done_txiqcal_once)
run_agc_cal = true; 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); ar9003_mci_init_cal_req(ah, &is_reusable);
if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) { if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
...@@ -993,7 +989,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, ...@@ -993,7 +989,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
0, AH_WAIT_TIMEOUT); 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); ar9003_mci_init_cal_done(ah);
if (rtt && !run_rtt_cal) { if (rtt && !run_rtt_cal) {
......
...@@ -3613,6 +3613,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) ...@@ -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); value = ar9003_switch_com_spdt_get(ah, is2ghz);
REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
AR_SWITCH_TABLE_COM_SPDT_ALL, value); 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); 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, ...@@ -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); struct ath_common *common = ath9k_hw_common(ah);
while (time_out) { while (time_out) {
if (REG_READ(ah, address) & bit_position) { if (!(REG_READ(ah, address) & bit_position)) {
REG_WRITE(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;
}
udelay(10); if (time_out < 0)
time_out -= 10; break;
else
continue;
}
REG_WRITE(ah, address, bit_position);
if (time_out < 0) if (address != AR_MCI_INTERRUPT_RX_MSG_RAW)
break; 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) { if (time_out <= 0) {
...@@ -127,14 +126,13 @@ static void ar9003_mci_send_coex_version_query(struct ath_hw *ah, ...@@ -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; struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 payload[4] = {0, 0, 0, 0}; u32 payload[4] = {0, 0, 0, 0};
if (!mci->bt_version_known && if (mci->bt_version_known ||
(mci->bt_state != MCI_BT_SLEEP)) { (mci->bt_state == MCI_BT_SLEEP))
MCI_GPM_SET_TYPE_OPCODE(payload, return;
MCI_GPM_COEX_AGENT,
MCI_GPM_COEX_VERSION_QUERY); MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, MCI_GPM_COEX_VERSION_QUERY);
wait_done, true); 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, 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, ...@@ -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; struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 *payload = &mci->wlan_channels[0]; u32 *payload = &mci->wlan_channels[0];
if ((mci->wlan_channels_update == true) && if (!mci->wlan_channels_update ||
(mci->bt_state != MCI_BT_SLEEP)) { (mci->bt_state == MCI_BT_SLEEP))
MCI_GPM_SET_TYPE_OPCODE(payload, return;
MCI_GPM_COEX_AGENT,
MCI_GPM_COEX_WLAN_CHANNELS); MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, MCI_GPM_COEX_WLAN_CHANNELS);
wait_done, true); ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff); MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
}
} }
static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah, 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, ...@@ -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; struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 payload[4] = {0, 0, 0, 0}; u32 payload[4] = {0, 0, 0, 0};
bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO | bool query_btinfo;
MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
if (mci->bt_state != MCI_BT_SLEEP) {
MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, if (mci->bt_state == MCI_BT_SLEEP)
MCI_GPM_COEX_STATUS_QUERY); return;
*(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type; 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;
}
/*
* 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) 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, 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) ...@@ -241,73 +239,73 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah)
ar9003_mci_remote_reset(ah, true); ar9003_mci_remote_reset(ah, true);
ar9003_mci_send_req_wake(ah, true); ar9003_mci_send_req_wake(ah, true);
if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, if (!ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) { 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. * we don't need to send more remote_reset at this moment.
* If BT receive first remote_reset, then BT HW will * If BT receive first remote_reset, then BT HW will
* be cleaned up and will be able to receive req_wake * be cleaned up and will be able to receive req_wake
* and BT HW will respond sys_waking. * and BT HW will respond sys_waking.
* In this case, WLAN will receive BT's HW sys_waking. * In this case, WLAN will receive BT's HW sys_waking.
* Otherwise, if BT SW missed initial remote_reset, * Otherwise, if BT SW missed initial remote_reset,
* that remote_reset will still clean up BT MCI RX, * that remote_reset will still clean up BT MCI RX,
* and the req_wake will wake BT up, * and the req_wake will wake BT up,
* and BT SW will respond this req_wake with a remote_reset and * 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 this case, WLAN will receive BT's SW
* sys_waking. In either case, BT's RX is cleaned up. So we * 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. * don't need to reply BT's remote_reset now, if any.
* Similarly, if in any case, WLAN can receive BT's sys_waking, * Similarly, if in any case, WLAN can receive BT's sys_waking,
* that means WLAN's RX is also fine. * that means WLAN's RX is also fine.
*/ */
ar9003_mci_send_sys_waking(ah, true); ar9003_mci_send_sys_waking(ah, true);
udelay(10); udelay(10);
/* /*
* Set BT priority interrupt value to be 0xff to * Set BT priority interrupt value to be 0xff to
* avoid having too many BT PRIORITY interrupts. * avoid having too many BT PRIORITY interrupts.
*/ */
REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF); REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF); REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF); REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF); REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF); REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
/* /*
* A contention reset will be received after send out * A contention reset will be received after send out
* sys_waking. Also BT priority interrupt bits will be set. * sys_waking. Also BT priority interrupt bits will be set.
* Clear those bits before the next step. * Clear those bits before the next step.
*/ */
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
AR_MCI_INTERRUPT_RX_MSG_CONT_RST); AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI);
AR_MCI_INTERRUPT_BT_PRI);
if (mci->is_2g) { if (mci->is_2g) {
ar9003_mci_send_lna_transfer(ah, true); ar9003_mci_send_lna_transfer(ah, true);
udelay(5); udelay(5);
} }
if ((mci->is_2g && !mci->update_2g5g)) { if ((mci->is_2g && !mci->update_2g5g)) {
if (ar9003_mci_wait_for_interrupt(ah, if (ar9003_mci_wait_for_interrupt(ah,
AR_MCI_INTERRUPT_RX_MSG_RAW, AR_MCI_INTERRUPT_RX_MSG_RAW,
AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
mci_timeout)) mci_timeout))
ath_dbg(common, MCI, ath_dbg(common, MCI,
"MCI WLAN has control over the LNA & BT obeys it\n"); "MCI WLAN has control over the LNA & BT obeys it\n");
else else
ath_dbg(common, MCI, ath_dbg(common, MCI,
"MCI BT didn't respond to LNA_TRANS\n"); "MCI BT didn't respond to LNA_TRANS\n");
}
} }
clear_redunt:
/* Clear the extra redundant SYS_WAKING from BT */ /* Clear the extra redundant SYS_WAKING from BT */
if ((mci->bt_state == MCI_BT_AWAKE) && if ((mci->bt_state == MCI_BT_AWAKE) &&
(REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) && AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
(REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) { AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
...@@ -330,7 +328,6 @@ void ar9003_mci_set_full_sleep(struct ath_hw *ah) ...@@ -330,7 +328,6 @@ void ar9003_mci_set_full_sleep(struct ath_hw *ah)
} }
mci->ready = false; mci->ready = false;
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
} }
static void ar9003_mci_disable_interrupt(struct ath_hw *ah) 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, ...@@ -615,9 +612,9 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
} }
break; break;
} }
} else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) { } else if ((recv_type == gpm_type) &&
(recv_opcode == gpm_opcode))
break; break;
}
/* /*
* check if it's cal_grant * check if it's cal_grant
...@@ -731,38 +728,38 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -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)) if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP))
goto exit; goto exit;
if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) || 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)) { !ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE))
goto exit;
/* /*
* BT is sleeping. Check if BT wakes up during * BT is sleeping. Check if BT wakes up during
* WLAN calibration. If BT wakes up during * WLAN calibration. If BT wakes up during
* WLAN calibration, need to go through all * WLAN calibration, need to go through all
* message exchanges again and recal. * message exchanges again and recal.
*/ */
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE); AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE));
ar9003_mci_remote_reset(ah, true); ar9003_mci_remote_reset(ah, true);
ar9003_mci_send_sys_waking(ah, true); ar9003_mci_send_sys_waking(ah, true);
udelay(1); udelay(1);
if (IS_CHAN_2GHZ(chan)) if (IS_CHAN_2GHZ(chan))
ar9003_mci_send_lna_transfer(ah, true); ar9003_mci_send_lna_transfer(ah, true);
mci_hw->bt_state = MCI_BT_AWAKE; mci_hw->bt_state = MCI_BT_AWAKE;
if (caldata) { if (caldata) {
caldata->done_txiqcal_once = false; caldata->done_txiqcal_once = false;
caldata->done_txclcal_once = false; caldata->done_txclcal_once = false;
caldata->rtt_done = false; caldata->rtt_done = false;
} }
if (!ath9k_hw_init_cal(ah, chan)) if (!ath9k_hw_init_cal(ah, chan))
return -EIO; return -EIO;
}
exit: exit:
ar9003_mci_enable_interrupt(ah); ar9003_mci_enable_interrupt(ah);
return 0; return 0;
...@@ -798,29 +795,27 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable) ...@@ -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; struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 thresh; u32 thresh;
if (enable) { 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 {
REG_CLR_BIT(ah, AR_BTCOEX_CTRL, REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 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, 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) ...@@ -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; struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 new_flags, to_set, to_clear; u32 new_flags, to_set, to_clear;
if (mci->update_2g5g && (mci->bt_state != MCI_BT_SLEEP)) { if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP))
if (mci->is_2g) { return;
new_flags = MCI_2G_FLAGS;
to_clear = MCI_2G_FLAGS_CLEAR_MASK; if (mci->is_2g) {
to_set = MCI_2G_FLAGS_SET_MASK; new_flags = MCI_2G_FLAGS;
} else { to_clear = MCI_2G_FLAGS_CLEAR_MASK;
new_flags = MCI_5G_FLAGS; to_set = MCI_2G_FLAGS_SET_MASK;
to_clear = MCI_5G_FLAGS_CLEAR_MASK; } else {
to_set = MCI_5G_FLAGS_SET_MASK; new_flags = MCI_5G_FLAGS;
} to_clear = MCI_5G_FLAGS_CLEAR_MASK;
to_set = MCI_5G_FLAGS_SET_MASK;
}
if (to_clear) if (to_clear)
ar9003_mci_send_coex_bt_flags(ah, wait_done, ar9003_mci_send_coex_bt_flags(ah, wait_done,
MCI_GPM_COEX_BT_FLAGS_CLEAR, MCI_GPM_COEX_BT_FLAGS_CLEAR,
to_clear); to_clear);
if (to_set) if (to_set)
ar9003_mci_send_coex_bt_flags(ah, wait_done, ar9003_mci_send_coex_bt_flags(ah, wait_done,
MCI_GPM_COEX_BT_FLAGS_SET, MCI_GPM_COEX_BT_FLAGS_SET,
to_set); to_set);
}
} }
static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header, 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) ...@@ -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; struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
if (mci->update_2g5g) { if (!mci->update_2g5g)
if (mci->is_2g) { return;
ar9003_mci_send_2g5g_status(ah, true);
ar9003_mci_send_lna_transfer(ah, true);
udelay(5);
REG_CLR_BIT(ah, AR_MCI_TX_CTRL, if (mci->is_2g) {
AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); ar9003_mci_send_2g5g_status(ah, true);
REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL, ar9003_mci_send_lna_transfer(ah, true);
AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); udelay(5);
if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) { REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
} AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
} else {
ar9003_mci_send_lna_take(ah, true); if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
udelay(5); REG_SET_BIT(ah, AR_BTCOEX_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,
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); 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) ...@@ -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)) { if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {
ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n"); ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n");
} else { } else {
is_reusable = false; *is_reusable = false;
ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n"); 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) ...@@ -1259,12 +1255,12 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
} }
if (p_data) if (p_data)
*p_data = more_gpm; *p_data = more_gpm;
} }
if (value != MCI_GPM_INVALID) if (value != MCI_GPM_INVALID)
value <<= 4; value <<= 4;
break; break;
case MCI_STATE_LAST_SCHD_MSG_OFFSET: case MCI_STATE_LAST_SCHD_MSG_OFFSET:
value = MS(REG_READ(ah, AR_MCI_RX_STATUS), value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
AR_MCI_RX_LAST_SCHD_MSG_INDEX); 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) ...@@ -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); ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
break; break;
case MCI_STATE_NEED_FLUSH_BT_INFO: case MCI_STATE_NEED_FLUSH_BT_INFO:
/* /*
* btcoex_hw.mci.unhalt_bt_gpm means whether it's * btcoex_hw.mci.unhalt_bt_gpm means whether it's
* needed to send UNHALT message. It's set whenever * needed to send UNHALT message. It's set whenever
* there's a request to send HALT message. * there's a request to send HALT message.
* mci_halted_bt_gpm means whether HALT message is sent * mci_halted_bt_gpm means whether HALT message is sent
* out successfully. * out successfully.
* *
* Checking (mci_unhalt_bt_gpm == false) instead of * Checking (mci_unhalt_bt_gpm == false) instead of
* checking (ah->mci_halted_bt_gpm == false) will make * checking (ah->mci_halted_bt_gpm == false) will make
* sure currently is in UNHALT-ed mode and BT can * sure currently is in UNHALT-ed mode and BT can
* respond to status query. * respond to status query.
*/ */
value = (!mci->unhalt_bt_gpm && value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0;
mci->need_flush_btinfo) ? 1 : 0; if (p_data)
if (p_data) mci->need_flush_btinfo = (*p_data != 0) ? true : false;
mci->need_flush_btinfo = break;
(*p_data != 0) ? true : false;
break;
case MCI_STATE_RECOVER_RX: case MCI_STATE_RECOVER_RX:
ar9003_mci_prep_interface(ah); ar9003_mci_prep_interface(ah);
mci->query_bt = true; mci->query_bt = true;
...@@ -1387,9 +1381,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) ...@@ -1387,9 +1381,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
case MCI_STATE_NEED_FTP_STOMP: case MCI_STATE_NEED_FTP_STOMP:
value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
break; break;
case MCI_STATE_NEED_TUNING:
value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
break;
default: default:
break; break;
} }
...@@ -1397,3 +1388,19 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) ...@@ -1397,3 +1388,19 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
return value; return value;
} }
EXPORT_SYMBOL(ar9003_mci_state); 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 { ...@@ -212,7 +212,6 @@ enum mci_state_type {
MCI_STATE_SET_CONCUR_TX_PRI, MCI_STATE_SET_CONCUR_TX_PRI,
MCI_STATE_RECOVER_RX, MCI_STATE_RECOVER_RX,
MCI_STATE_NEED_FTP_STOMP, MCI_STATE_NEED_FTP_STOMP,
MCI_STATE_NEED_TUNING,
MCI_STATE_DEBUG, MCI_STATE_DEBUG,
MCI_STATE_MAX MCI_STATE_MAX
}; };
...@@ -266,6 +265,7 @@ void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, ...@@ -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_cleanup(struct ath_hw *ah);
void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
u32 *rx_msg_intr); u32 *rx_msg_intr);
void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
/* /*
* These functions are used by ath9k_hw. * These functions are used by ath9k_hw.
...@@ -273,10 +273,6 @@ void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, ...@@ -273,10 +273,6 @@ void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT #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_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_req(struct ath_hw *ah, bool *is_reusable);
void ar9003_mci_init_cal_done(struct ath_hw *ah); 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); ...@@ -292,10 +288,6 @@ void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
#else #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) 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, ...@@ -676,6 +676,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
if (chan->channel == 2484) if (chan->channel == 2484)
ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1); 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; ah->modes_index = modesIndex;
ar9003_hw_override_ini(ah); ar9003_hw_override_ini(ah);
ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_channel_regs(ah, chan);
......
...@@ -820,18 +820,26 @@ ...@@ -820,18 +820,26 @@
#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001 #define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001
#define AR_PHY_RX_DELAY_DELAY 0x00003FFF #define AR_PHY_RX_DELAY_DELAY 0x00003FFF
#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 #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_ENABLE 0x00000001
#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002 #define AR_PHY_SPECTRAL_SCAN_ENABLE_S 0
#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1 #define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002
#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0 #define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1
#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4 #define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0
#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00 #define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4
#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8 #define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00
#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 #define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8
#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16 #define AR_PHY_SPECTRAL_SCAN_COUNT 0x0FFF0000
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 #define AR_PHY_SPECTRAL_SCAN_COUNT_S 16
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 #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_CHANNEL_STATUS_RX_CLEAR 0x00000004
#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION 0x00000001 #define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION 0x00000001
#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION_S 0 #define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION_S 0
......
...@@ -958,7 +958,7 @@ static const u32 ar9462_2p0_radio_core[][2] = { ...@@ -958,7 +958,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
{0x0001604c, 0x2699e04f}, {0x0001604c, 0x2699e04f},
{0x00016050, 0x6db6db6c}, {0x00016050, 0x6db6db6c},
{0x00016058, 0x6c200000}, {0x00016058, 0x6c200000},
{0x00016080, 0x00040000}, {0x00016080, 0x000c0000},
{0x00016084, 0x9a68048c}, {0x00016084, 0x9a68048c},
{0x00016088, 0x54214514}, {0x00016088, 0x54214514},
{0x0001608c, 0x1203040b}, {0x0001608c, 0x1203040b},
...@@ -981,7 +981,7 @@ static const u32 ar9462_2p0_radio_core[][2] = { ...@@ -981,7 +981,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
{0x00016144, 0x02084080}, {0x00016144, 0x02084080},
{0x00016148, 0x000080c0}, {0x00016148, 0x000080c0},
{0x00016280, 0x050a0001}, {0x00016280, 0x050a0001},
{0x00016284, 0x3d841400}, {0x00016284, 0x3d841418},
{0x00016288, 0x00000000}, {0x00016288, 0x00000000},
{0x0001628c, 0xe3000000}, {0x0001628c, 0xe3000000},
{0x00016290, 0xa1005080}, {0x00016290, 0xa1005080},
...@@ -1007,6 +1007,7 @@ static const u32 ar9462_2p0_radio_core[][2] = { ...@@ -1007,6 +1007,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
static const u32 ar9462_2p0_soc_preamble[][2] = { static const u32 ar9462_2p0_soc_preamble[][2] = {
/* Addr allmodes */ /* Addr allmodes */
{0x000040a4 ,0x00a0c1c9},
{0x00007020, 0x00000000}, {0x00007020, 0x00000000},
{0x00007034, 0x00000002}, {0x00007034, 0x00000002},
{0x00007038, 0x000004c2}, {0x00007038, 0x000004c2},
......
...@@ -307,6 +307,7 @@ struct ath_rx { ...@@ -307,6 +307,7 @@ struct ath_rx {
u8 defant; u8 defant;
u8 rxotherant; u8 rxotherant;
u32 *rxlink; u32 *rxlink;
u32 num_pkts;
unsigned int rxfilter; unsigned int rxfilter;
spinlock_t rxbuflock; spinlock_t rxbuflock;
struct list_head rxbuf; struct list_head rxbuf;
...@@ -325,6 +326,9 @@ int ath_rx_init(struct ath_softc *sc, int nbufs); ...@@ -325,6 +326,9 @@ int ath_rx_init(struct ath_softc *sc, int nbufs);
void ath_rx_cleanup(struct ath_softc *sc); void ath_rx_cleanup(struct ath_softc *sc);
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp); 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); 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); void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
void ath_draintxq(struct ath_softc *sc, void ath_draintxq(struct ath_softc *sc,
...@@ -414,9 +418,9 @@ int ath_beaconq_config(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 ath_set_beacon(struct ath_softc *sc);
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
/*******/ /*******************/
/* ANI */ /* Link Monitoring */
/*******/ /*******************/
#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */ #define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */
#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */ #define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */
...@@ -427,7 +431,9 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); ...@@ -427,7 +431,9 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
#define ATH_PAPRD_TIMEOUT 100 /* msecs */ #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_reset_work(struct work_struct *work);
void ath_hw_check(struct work_struct *work); void ath_hw_check(struct work_struct *work);
void ath_hw_pll_work(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); ...@@ -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_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data); void ath_ani_calibrate(unsigned long data);
void ath_start_ani(struct ath_common *common); 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 */ /* BTCOEX */
/**********/ /**********/
enum bt_op_flags {
BT_OP_PRIORITY_DETECTED,
BT_OP_SCAN,
};
struct ath_btcoex { struct ath_btcoex {
bool hw_timer_enabled; bool hw_timer_enabled;
spinlock_t btcoex_lock; spinlock_t btcoex_lock;
struct timer_list period_timer; /* Timer for BT period */ struct timer_list period_timer; /* Timer for BT period */
u32 bt_priority_cnt; u32 bt_priority_cnt;
unsigned long bt_priority_time; unsigned long bt_priority_time;
unsigned long op_flags;
int bt_stomp_type; /* Types of BT stomping */ int bt_stomp_type; /* Types of BT stomping */
u32 btcoex_no_stomp; /* in usec */ u32 btcoex_no_stomp; /* in usec */
u32 btcoex_period; /* in usec */ u32 btcoex_period; /* in usec */
u32 btscan_no_stomp; /* in usec */ u32 btscan_no_stomp; /* in usec */
u32 duty_cycle; u32 duty_cycle;
u32 bt_wait_time;
struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
struct ath_mci_profile mci; struct ath_mci_profile mci;
}; };
...@@ -513,8 +528,10 @@ static inline void ath_deinit_leds(struct ath_softc *sc) ...@@ -513,8 +528,10 @@ static inline void ath_deinit_leds(struct ath_softc *sc)
} }
#endif #endif
/*******************************/
/* Antenna diversity/combining */ /* Antenna diversity/combining */
/*******************************/
#define ATH_ANT_RX_CURRENT_SHIFT 4 #define ATH_ANT_RX_CURRENT_SHIFT 4
#define ATH_ANT_RX_MAIN_SHIFT 2 #define ATH_ANT_RX_MAIN_SHIFT 2
#define ATH_ANT_RX_MASK 0x3 #define ATH_ANT_RX_MASK 0x3
...@@ -567,6 +584,9 @@ struct ath_ant_comb { ...@@ -567,6 +584,9 @@ struct ath_ant_comb {
unsigned long scan_start_time; 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 */ /* Main driver core */
/********************/ /********************/
...@@ -584,15 +604,15 @@ struct ath_ant_comb { ...@@ -584,15 +604,15 @@ struct ath_ant_comb {
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define ATH_TXPOWER_MAX 100 /* .5 dBm units */
#define ATH_RATE_DUMMY_MARKER 0 #define ATH_RATE_DUMMY_MARKER 0
#define SC_OP_INVALID BIT(0) enum sc_op_flags {
#define SC_OP_BEACONS BIT(1) SC_OP_INVALID,
#define SC_OP_OFFCHANNEL BIT(2) SC_OP_BEACONS,
#define SC_OP_RXFLUSH BIT(3) SC_OP_RXFLUSH,
#define SC_OP_TSF_RESET BIT(4) SC_OP_TSF_RESET,
#define SC_OP_BT_PRIORITY_DETECTED BIT(5) SC_OP_ANI_RUN,
#define SC_OP_BT_SCAN BIT(6) SC_OP_PRIM_STA_VIF,
#define SC_OP_ANI_RUN BIT(7) SC_OP_HW_RESET,
#define SC_OP_PRIM_STA_VIF BIT(8) };
/* Powersave flags */ /* Powersave flags */
#define PS_WAIT_FOR_BEACON BIT(0) #define PS_WAIT_FOR_BEACON BIT(0)
...@@ -638,9 +658,9 @@ struct ath_softc { ...@@ -638,9 +658,9 @@ struct ath_softc {
struct completion paprd_complete; struct completion paprd_complete;
unsigned int hw_busy_count; unsigned int hw_busy_count;
unsigned long sc_flags;
u32 intrstatus; u32 intrstatus;
u32 sc_flags; /* SC_OP_* */
u16 ps_flags; /* PS_* */ u16 ps_flags; /* PS_* */
u16 curtxpow; u16 curtxpow;
bool ps_enabled; bool ps_enabled;
...@@ -736,5 +756,4 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, ...@@ -736,5 +756,4 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ath9k_vif_iter_data *iter_data); struct ath9k_vif_iter_data *iter_data);
#endif /* ATH9K_H */ #endif /* ATH9K_H */
...@@ -48,7 +48,10 @@ int ath_beaconq_config(struct ath_softc *sc) ...@@ -48,7 +48,10 @@ int ath_beaconq_config(struct ath_softc *sc)
txq = sc->tx.txq_map[WME_AC_BE]; txq = sc->tx.txq_map[WME_AC_BE];
ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs; 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; qi.tqi_cwmax = qi_be.tqi_cwmax;
} }
...@@ -387,7 +390,7 @@ void ath_beacon_tasklet(unsigned long data) ...@@ -387,7 +390,7 @@ void ath_beacon_tasklet(unsigned long data)
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
ath_dbg(common, BSTUCK, "beacon is officially stuck\n"); ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
sc->beacon.bmisscnt = 0; 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); ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
} }
...@@ -477,16 +480,16 @@ static void ath9k_beacon_init(struct ath_softc *sc, ...@@ -477,16 +480,16 @@ static void ath9k_beacon_init(struct ath_softc *sc,
u32 next_beacon, u32 next_beacon,
u32 beacon_period) 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_ps_wakeup(sc);
ath9k_hw_reset_tsf(sc->sc_ah); ath9k_hw_reset_tsf(sc->sc_ah);
} }
ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); 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); 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, ...@@ -516,7 +519,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
/* Set the computed AP beacon timers */ /* Set the computed AP beacon timers */
ath9k_hw_disable_interrupts(ah); 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); ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0; sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah); ath9k_hw_set_interrupts(ah);
...@@ -659,7 +662,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, ...@@ -659,7 +662,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
u32 tsf, intval, nexttbtt; u32 tsf, intval, nexttbtt;
ath9k_reset_beacon_status(sc); 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); ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
intval = TU_TO_USEC(conf->beacon_interval); intval = TU_TO_USEC(conf->beacon_interval);
...@@ -724,7 +727,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, ...@@ -724,7 +727,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
*/ */
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
(vif->type == 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) { !avp->primary_sta_vif) {
ath_dbg(common, CONFIG, ath_dbg(common, CONFIG,
"Beacon already configured for a station interface\n"); "Beacon already configured for a station interface\n");
...@@ -810,7 +813,7 @@ void ath_set_beacon(struct ath_softc *sc) ...@@ -810,7 +813,7 @@ void ath_set_beacon(struct ath_softc *sc)
return; 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) 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) ...@@ -818,7 +821,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
if (!ath_has_valid_bslot(sc)) { if (!ath_has_valid_bslot(sc)) {
sc->sc_flags &= ~SC_OP_BEACONS; clear_bit(SC_OP_BEACONS, &sc->sc_flags);
return; return;
} }
......
...@@ -336,10 +336,16 @@ static void ar9003_btcoex_bt_stomp(struct ath_hw *ah, ...@@ -336,10 +336,16 @@ static void ar9003_btcoex_bt_stomp(struct ath_hw *ah,
enum ath_stomp_type stomp_type) enum ath_stomp_type stomp_type)
{ {
struct ath_btcoex_hw *btcoex = &ah->btcoex_hw; struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
const u32 *weight = AR_SREV_9462(ah) ? ar9003_wlan_weights[stomp_type] : const u32 *weight = ar9003_wlan_weights[stomp_type];
ar9462_wlan_weights[stomp_type];
int i; 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++) { for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
btcoex->bt_weight[i] = AR9300_BT_WGHT; btcoex->bt_weight[i] = AR9300_BT_WGHT;
btcoex->wlan_weight[i] = weight[i]; btcoex->wlan_weight[i] = weight[i];
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#define ATH_BT_CNT_THRESHOLD 3 #define ATH_BT_CNT_THRESHOLD 3
#define ATH_BT_CNT_SCAN_THRESHOLD 15 #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_BT_WEIGHTS 4
#define AR9300_NUM_WLAN_WEIGHTS 4 #define AR9300_NUM_WLAN_WEIGHTS 4
/* Defines the BT AR_BT_COEX_WGHT used */ /* Defines the BT AR_BT_COEX_WGHT used */
...@@ -80,6 +83,7 @@ struct ath9k_hw_mci { ...@@ -80,6 +83,7 @@ struct ath9k_hw_mci {
u8 bt_ver_major; u8 bt_ver_major;
u8 bt_ver_minor; u8 bt_ver_minor;
u8 bt_state; u8 bt_state;
u8 stomp_ftp;
}; };
struct ath_btcoex_hw { struct ath_btcoex_hw {
......
...@@ -205,10 +205,10 @@ static ssize_t write_file_disable_ani(struct file *file, ...@@ -205,10 +205,10 @@ static ssize_t write_file_disable_ani(struct file *file,
common->disable_ani = !!disable_ani; common->disable_ani = !!disable_ani;
if (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); del_timer_sync(&common->ani.timer);
} else { } else {
sc->sc_flags |= SC_OP_ANI_RUN; set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
ath_start_ani(common); ath_start_ani(common);
} }
...@@ -374,6 +374,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) ...@@ -374,6 +374,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
sc->debug.stats.istats.dtim++; sc->debug.stats.istats.dtim++;
if (status & ATH9K_INT_TSFOOR) if (status & ATH9K_INT_TSFOOR)
sc->debug.stats.istats.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, 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, ...@@ -418,6 +420,7 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
PR_IS("DTIMSYNC", dtimsync); PR_IS("DTIMSYNC", dtimsync);
PR_IS("DTIM", dtim); PR_IS("DTIM", dtim);
PR_IS("TSFOOR", tsfoor); PR_IS("TSFOOR", tsfoor);
PR_IS("MCI", mci);
PR_IS("TOTAL", total); PR_IS("TOTAL", total);
len += snprintf(buf + len, mxlen - len, len += snprintf(buf + len, mxlen - len,
...@@ -1318,7 +1321,7 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file) ...@@ -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 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
u8 nread; u8 nread;
if (sc->sc_flags & SC_OP_INVALID) if (test_bit(SC_OP_INVALID, &sc->sc_flags))
return -EAGAIN; return -EAGAIN;
buf = vmalloc(size); buf = vmalloc(size);
......
...@@ -86,6 +86,7 @@ struct ath_interrupt_stats { ...@@ -86,6 +86,7 @@ struct ath_interrupt_stats {
u32 dtim; u32 dtim;
u32 bb_watchdog; u32 bb_watchdog;
u32 tsfoor; u32 tsfoor;
u32 mci;
/* Sync-cause stats */ /* Sync-cause stats */
u32 sync_cause_all; u32 sync_cause_all;
......
...@@ -132,17 +132,18 @@ static void ath_detect_bt_priority(struct ath_softc *sc) ...@@ -132,17 +132,18 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
if (time_after(jiffies, btcoex->bt_priority_time + if (time_after(jiffies, btcoex->bt_priority_time +
msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { 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 */ /* Detect if colocated bt started scanning */
if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX, ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
"BT scan detected\n"); "BT scan detected\n");
sc->sc_flags |= (SC_OP_BT_SCAN | set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
SC_OP_BT_PRIORITY_DETECTED); set_bit(BT_OP_SCAN, &btcoex->op_flags);
} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX, ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
"BT priority traffic detected\n"); "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; btcoex->bt_priority_cnt = 0;
...@@ -190,13 +191,26 @@ static void ath_btcoex_period_timer(unsigned long data) ...@@ -190,13 +191,26 @@ static void ath_btcoex_period_timer(unsigned long data)
struct ath_softc *sc = (struct ath_softc *) data; struct ath_softc *sc = (struct ath_softc *) data;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex *btcoex = &sc->btcoex; struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_mci_profile *mci = &btcoex->mci;
u32 timer_period; u32 timer_period;
bool is_btscan; bool is_btscan;
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
ath_detect_bt_priority(sc); 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); spin_lock_bh(&btcoex->btcoex_lock);
...@@ -219,8 +233,7 @@ static void ath_btcoex_period_timer(unsigned long data) ...@@ -219,8 +233,7 @@ static void ath_btcoex_period_timer(unsigned long data)
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
timer_period = btcoex->btcoex_period / 1000; timer_period = btcoex->btcoex_period / 1000;
mod_timer(&btcoex->period_timer, jiffies + mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
msecs_to_jiffies(timer_period));
} }
/* /*
...@@ -233,14 +246,14 @@ static void ath_btcoex_no_stomp_timer(void *arg) ...@@ -233,14 +246,14 @@ static void ath_btcoex_no_stomp_timer(void *arg)
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex *btcoex = &sc->btcoex; struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_common *common = ath9k_hw_common(ah); 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"); ath_dbg(common, BTCOEX, "no stomp timer running\n");
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
spin_lock_bh(&btcoex->btcoex_lock); 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); ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
...@@ -292,7 +305,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) ...@@ -292,7 +305,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
btcoex->bt_priority_cnt = 0; btcoex->bt_priority_cnt = 0;
btcoex->bt_priority_time = jiffies; 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); mod_timer(&btcoex->period_timer, jiffies);
} }
...@@ -316,12 +329,13 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc) ...@@ -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) 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; struct ath_mci_profile *mci = &sc->btcoex.mci;
u16 aggr_limit = 0; u16 aggr_limit = 0;
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit) if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4; 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, aggr_limit = min((max_4ms_framelen * 3) / 8,
(u32)ATH_AMPDU_LIMIT_MAX); (u32)ATH_AMPDU_LIMIT_MAX);
......
...@@ -390,14 +390,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah) ...@@ -390,14 +390,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); 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 */ /* This should work for all families including legacy */
static bool ath9k_hw_chip_test(struct ath_hw *ah) static bool ath9k_hw_chip_test(struct ath_hw *ah)
{ {
...@@ -693,9 +685,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) ...@@ -693,9 +685,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
if (r) if (r)
return r; return r;
if (ah->is_pciexpress)
ath9k_hw_aspm_init(ah);
r = ath9k_hw_init_macaddr(ah); r = ath9k_hw_init_macaddr(ah);
if (r) { if (r) {
ath_err(common, "Failed to initialize MAC address\n"); 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) ...@@ -1443,9 +1432,6 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
break; break;
} }
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
return ret; return ret;
} }
...@@ -1721,7 +1707,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -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_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah, true); 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); ar9003_mci_2g5g_switch(ah, true);
if (AR_SREV_9271(ah)) if (AR_SREV_9271(ah))
...@@ -1742,10 +1728,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -1742,10 +1728,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u64 tsf = 0; u64 tsf = 0;
int i, r; int i, r;
bool start_mci_reset = false; bool start_mci_reset = false;
bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
bool save_fullsleep = ah->chip_fullsleep; bool save_fullsleep = ah->chip_fullsleep;
if (mci) { if (ath9k_hw_mci_is_enabled(ah)) {
start_mci_reset = ar9003_mci_start_reset(ah, chan); start_mci_reset = ar9003_mci_start_reset(ah, chan);
if (start_mci_reset) if (start_mci_reset)
return 0; return 0;
...@@ -1774,7 +1759,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -1774,7 +1759,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
return r; return r;
} }
if (mci) if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_stop_bt(ah, save_fullsleep); ar9003_mci_stop_bt(ah, save_fullsleep);
saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA); saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
...@@ -1832,7 +1817,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -1832,7 +1817,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (r) if (r)
return r; return r;
if (mci) if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep); 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, ...@@ -1951,7 +1936,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_loadnf(ah, chan); ath9k_hw_loadnf(ah, chan);
ath9k_hw_start_nfcal(ah, true); 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; return -EIO;
ENABLE_REGWRITE_BUFFER(ah); ENABLE_REGWRITE_BUFFER(ah);
...@@ -1996,7 +1981,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -1996,7 +1981,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (ath9k_hw_btcoex_is_enabled(ah)) if (ath9k_hw_btcoex_is_enabled(ah))
ath9k_hw_btcoex_enable(ah); ath9k_hw_btcoex_enable(ah);
if (mci) if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_check_bt(ah); ar9003_mci_check_bt(ah);
if (AR_SREV_9300_20_OR_LATER(ah)) { if (AR_SREV_9300_20_OR_LATER(ah)) {
...@@ -2019,39 +2004,35 @@ EXPORT_SYMBOL(ath9k_hw_reset); ...@@ -2019,39 +2004,35 @@ EXPORT_SYMBOL(ath9k_hw_reset);
* Notify Power Mgt is disabled in self-generated frames. * Notify Power Mgt is disabled in self-generated frames.
* If requested, force chip to sleep. * 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); 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);
}
/* if (AR_SREV_9462(ah)) {
* Clear the RTC force wake bit to allow the REG_CLR_BIT(ah, AR_TIMER_MODE, 0xff);
* mac to go to sleep. REG_CLR_BIT(ah, AR_NDP2_TIMER_MODE, 0xff);
*/ REG_CLR_BIT(ah, AR_SLP32_INC, 0xfffff);
REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); /* 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 (ath9k_hw_mci_is_enabled(ah))
udelay(100);
if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah)) if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
/* Shutdown chip. Active low */ /* Shutdown chip. Active low */
if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) { if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
udelay(2); udelay(2);
}
} }
/* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ /* 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) ...@@ -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 * frames. If request, set power mode of chip to
* auto/normal. Duration in units of 128us (1/8 TU). * 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); 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)) { if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
/* Set WakeOnInterrupt bit; clear ForceWake bit */ /* Set WakeOnInterrupt bit; clear ForceWake bit */
REG_WRITE(ah, AR_RTC_FORCE_WAKE, REG_WRITE(ah, AR_RTC_FORCE_WAKE,
AR_RTC_FORCE_WAKE_ON_INT); AR_RTC_FORCE_WAKE_ON_INT);
} else { } else {
/* When chip goes into network sleep, it could be waken /* When chip goes into network sleep, it could be waken
* up by MCI_INT interrupt caused by BT's HW messages * up by MCI_INT interrupt caused by BT's HW messages
* (LNA_xxx, CONT_xxx) which chould be in a very fast * (LNA_xxx, CONT_xxx) which chould be in a very fast
* rate (~100us). This will cause chip to leave and * rate (~100us). This will cause chip to leave and
* re-enter network sleep mode frequently, which in * re-enter network sleep mode frequently, which in
* consequence will have WLAN MCI HW to generate lots of * consequence will have WLAN MCI HW to generate lots of
* SYS_WAKING and SYS_SLEEPING messages which will make * SYS_WAKING and SYS_SLEEPING messages which will make
* BT CPU to busy to process. * BT CPU to busy to process.
*/ */
if (AR_SREV_9462(ah)) { if (ath9k_hw_mci_is_enabled(ah))
val = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) & REG_CLR_BIT(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
~AR_MCI_INTERRUPT_RX_HW_MSG_MASK; 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.
* 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);
*/
REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, if (ath9k_hw_mci_is_enabled(ah))
AR_RTC_FORCE_WAKE_EN); udelay(30);
if (AR_SREV_9462(ah))
udelay(30);
}
} }
/* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */ /* 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) ...@@ -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); 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; u32 val;
int i; int i;
...@@ -2120,37 +2095,35 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) ...@@ -2120,37 +2095,35 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
udelay(10); udelay(10);
} }
if (setChip) { if ((REG_READ(ah, AR_RTC_STATUS) &
if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { return false;
return false;
}
if (!AR_SREV_9300_20_OR_LATER(ah))
ath9k_hw_init_pll(ah, NULL);
} }
if (AR_SREV_9100(ah)) if (!AR_SREV_9300_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_RTC_RESET, ath9k_hw_init_pll(ah, NULL);
AR_RTC_RESET_EN); }
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, REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
AR_RTC_FORCE_WAKE_EN); AR_RTC_FORCE_WAKE_EN);
udelay(50); }
if (i == 0) {
for (i = POWER_UP_TIME / 50; i > 0; i--) { ath_err(ath9k_hw_common(ah),
val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; "Failed to wakeup in %uus\n",
if (val == AR_RTC_STATUS_ON) POWER_UP_TIME / 20);
break; return false;
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); 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) ...@@ -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) bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
int status = true, setChip = true; int status = true;
static const char *modes[] = { static const char *modes[] = {
"AWAKE", "AWAKE",
"FULL-SLEEP", "FULL-SLEEP",
...@@ -2177,25 +2150,17 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) ...@@ -2177,25 +2150,17 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
switch (mode) { switch (mode) {
case ATH9K_PM_AWAKE: case ATH9K_PM_AWAKE:
status = ath9k_hw_set_power_awake(ah, setChip); status = ath9k_hw_set_power_awake(ah);
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
break; break;
case ATH9K_PM_FULL_SLEEP: 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); ar9003_mci_set_full_sleep(ah);
ath9k_set_power_sleep(ah, setChip); ath9k_set_power_sleep(ah);
ah->chip_fullsleep = true; ah->chip_fullsleep = true;
break; break;
case ATH9K_PM_NETWORK_SLEEP: case ATH9K_PM_NETWORK_SLEEP:
ath9k_set_power_network_sleep(ah);
if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
ath9k_set_power_network_sleep(ah, setChip);
break; break;
default: default:
ath_err(common, "Unknown power mode %u\n", mode); ath_err(common, "Unknown power mode %u\n", mode);
...@@ -2765,6 +2730,9 @@ EXPORT_SYMBOL(ath9k_hw_setrxfilter); ...@@ -2765,6 +2730,9 @@ EXPORT_SYMBOL(ath9k_hw_setrxfilter);
bool ath9k_hw_phy_disable(struct ath_hw *ah) 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)) if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
return false; return false;
......
...@@ -824,7 +824,6 @@ struct ath_hw { ...@@ -824,7 +824,6 @@ struct ath_hw {
struct ar5416IniArray ini_japan2484; struct ar5416IniArray ini_japan2484;
struct ar5416IniArray iniModes_9271_ANI_reg; struct ar5416IniArray iniModes_9271_ANI_reg;
struct ar5416IniArray ini_radio_post_sys2ant; struct ar5416IniArray ini_radio_post_sys2ant;
struct ar5416IniArray ini_BTCOEX_MAX_TXPWR;
struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT]; struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT];
struct ar5416IniArray iniBB[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) ...@@ -1037,6 +1036,11 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
{ {
return ah->btcoex_hw.enabled; 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); void ath9k_hw_btcoex_enable(struct ath_hw *ah);
static inline enum ath_btcoex_scheme static inline enum ath_btcoex_scheme
ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) 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) ...@@ -1048,6 +1052,10 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
{ {
return false; 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) static inline void ath9k_hw_btcoex_enable(struct ath_hw *ah)
{ {
} }
......
...@@ -489,6 +489,7 @@ static void ath9k_init_misc(struct ath_softc *sc) ...@@ -489,6 +489,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)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; sc->config.txpowlimit = ATH_TXPOWER_MAX;
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9; sc->beacon.slottime = ATH9K_SLOT_TIME_9;
...@@ -560,6 +561,12 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ...@@ -560,6 +561,12 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
(unsigned long)sc); (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 * Cache line size is used to size and align various
* structures used to communicate with the hardware. * structures used to communicate with the hardware.
...@@ -590,6 +597,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ...@@ -590,6 +597,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ath9k_cmn_init_crypto(sc->sc_ah); ath9k_cmn_init_crypto(sc->sc_ah);
ath9k_init_misc(sc); ath9k_init_misc(sc);
if (common->bus_ops->aspm_init)
common->bus_ops->aspm_init(common);
return 0; return 0;
err_btcoex: err_btcoex:
...@@ -782,11 +792,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, ...@@ -782,11 +792,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
ARRAY_SIZE(ath9k_tpt_blink)); ARRAY_SIZE(ath9k_tpt_blink));
#endif #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 */ /* Register with mac80211 */
error = ieee80211_register_hw(hw); error = ieee80211_register_hw(hw);
if (error) if (error)
...@@ -805,9 +810,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, ...@@ -805,9 +810,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
goto error_world; 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_init_leds(sc);
ath_start_rfkill_poll(sc); ath_start_rfkill_poll(sc);
......
/*
* 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;
}
...@@ -116,42 +116,58 @@ static void ath_mci_update_scheme(struct ath_softc *sc) ...@@ -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_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_btcoex *btcoex = &sc->btcoex; struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_mci_profile *mci = &btcoex->mci; 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; struct ath_mci_profile_info *info;
u32 num_profile = NUM_PROF(mci); u32 num_profile = NUM_PROF(mci);
if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING)
goto skip_tuning;
if (num_profile == 1) { if (num_profile == 1) {
info = list_first_entry(&mci->info, info = list_first_entry(&mci->info,
struct ath_mci_profile_info, struct ath_mci_profile_info,
list); list);
if (mci->num_sco && info->T == 12) { if (mci->num_sco) {
mci->aggr_limit = 8; 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, ath_dbg(common, MCI,
"Single SCO, aggregation limit 2 ms\n"); "Single SCO, aggregation limit %d 1/4 ms\n",
} else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) && mci->aggr_limit);
!info->master) { } else if (mci->num_pan || mci->num_other_acl) {
btcoex->btcoex_period = 60; /*
* 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, ath_dbg(common, MCI,
"Single slave PAN/FTP, bt period 60 ms\n"); "Single PAN/FTP bt period %d ms dutycycle %d\n",
} else if ((info->type == MCI_GPM_COEX_PROFILE_HID) && btcoex->duty_cycle, btcoex->btcoex_period);
(info->T > 0 && info->T < 50) && } else if (mci->num_hid) {
(info->A > 1 || info->W > 1)) {
btcoex->duty_cycle = 30; btcoex->duty_cycle = 30;
mci->aggr_limit = 8; mci->aggr_limit = 6;
ath_dbg(common, MCI, ath_dbg(common, MCI,
"Multiple attempt/timeout single HID " "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)) { } else if (num_profile == 2) {
btcoex->duty_cycle = 30; if (mci->num_hid == 2)
mci->aggr_limit = 8; btcoex->duty_cycle = 30;
ath_dbg(common, MCI,
"Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
} else if (num_profile > 3) {
mci->aggr_limit = 6; mci->aggr_limit = 6;
ath_dbg(common, MCI, 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_2GHZ(sc->sc_ah->curchan)) {
if (IS_CHAN_HT(sc->sc_ah->curchan)) if (IS_CHAN_HT(sc->sc_ah->curchan))
ath_mci_adjust_aggr_limit(btcoex); ath_mci_adjust_aggr_limit(btcoex);
...@@ -538,3 +554,14 @@ void ath_mci_intr(struct ath_softc *sc) ...@@ -538,3 +554,14 @@ void ath_mci_intr(struct ath_softc *sc)
mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR | mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT); 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); ...@@ -130,4 +130,13 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci);
int ath_mci_setup(struct ath_softc *sc); int ath_mci_setup(struct ath_softc *sc);
void ath_mci_cleanup(struct ath_softc *sc); void ath_mci_cleanup(struct ath_softc *sc);
void ath_mci_intr(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) ...@@ -115,6 +115,9 @@ static void ath_pci_aspm_init(struct ath_common *common)
int pos; int pos;
u8 aspm; u8 aspm;
if (!ah->is_pciexpress)
return;
pos = pci_pcie_cap(pdev); pos = pci_pcie_cap(pdev);
if (!pos) if (!pos)
return; return;
...@@ -138,6 +141,7 @@ static void ath_pci_aspm_init(struct ath_common *common) ...@@ -138,6 +141,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm); pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm);
ath_info(common, "Disabling ASPM since BTCOEX is enabled\n");
return; return;
} }
...@@ -147,6 +151,7 @@ static void ath_pci_aspm_init(struct ath_common *common) ...@@ -147,6 +151,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
ah->aspm_enabled = true; ah->aspm_enabled = true;
/* Initialize PCIe PM and SERDES registers. */ /* Initialize PCIe PM and SERDES registers. */
ath9k_hw_configpcipowersave(ah, false); 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) ...@@ -246,7 +251,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->mem = mem; sc->mem = mem;
/* Will be cleared in ath9k_start() */ /* 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); ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
if (ret) { if (ret) {
......
...@@ -2211,5 +2211,7 @@ enum { ...@@ -2211,5 +2211,7 @@ enum {
#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff #define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff
#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0 #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 #endif
...@@ -105,19 +105,19 @@ static int ath_max_4ms_framelen[4][32] = { ...@@ -105,19 +105,19 @@ static int ath_max_4ms_framelen[4][32] = {
/* Aggregation logic */ /* 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) __acquires(&txq->axq_lock)
{ {
spin_lock_bh(&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) __releases(&txq->axq_lock)
{ {
spin_unlock_bh(&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) __releases(&txq->axq_lock)
{ {
struct sk_buff_head q; struct sk_buff_head q;
...@@ -1536,7 +1536,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) ...@@ -1536,7 +1536,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
int i; int i;
u32 npend = 0; u32 npend = 0;
if (sc->sc_flags & SC_OP_INVALID) if (test_bit(SC_OP_INVALID, &sc->sc_flags))
return true; return true;
ath9k_hw_abort_tx_dma(ah); ath9k_hw_abort_tx_dma(ah);
...@@ -1994,6 +1994,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ...@@ -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 ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
int q, padpos, padsize; int q, padpos, padsize;
unsigned long flags;
ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); 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, ...@@ -2012,6 +2013,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
skb_pull(skb, padsize); skb_pull(skb, padsize);
} }
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) { if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
ath_dbg(common, PS, ath_dbg(common, PS,
...@@ -2021,6 +2023,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ...@@ -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_PSPOLL_DATA |
PS_WAIT_FOR_TX_ACK)); PS_WAIT_FOR_TX_ACK));
} }
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
q = skb_get_queue_mapping(skb); q = skb_get_queue_mapping(skb);
if (txq == sc->tx.txq_map[q]) { if (txq == sc->tx.txq_map[q]) {
...@@ -2231,46 +2234,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ...@@ -2231,46 +2234,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
ath_txq_unlock_complete(sc, 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) void ath_tx_tasklet(struct ath_softc *sc)
{ {
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
......
...@@ -877,6 +877,10 @@ struct b43_wl { ...@@ -877,6 +877,10 @@ struct b43_wl {
* from the mac80211 subsystem. */ * from the mac80211 subsystem. */
u16 mac80211_initially_registered_queues; 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) /* We can only have one operating interface (802.11 core)
* at a time. General information about this interface follows. * at a time. General information about this interface follows.
*/ */
......
...@@ -2437,6 +2437,7 @@ static void b43_request_firmware(struct work_struct *work) ...@@ -2437,6 +2437,7 @@ static void b43_request_firmware(struct work_struct *work)
err = ieee80211_register_hw(wl->hw); err = ieee80211_register_hw(wl->hw);
if (err) if (err)
goto err_one_core_detach; goto err_one_core_detach;
wl->hw_registred = true;
b43_leds_register(wl->current_dev); b43_leds_register(wl->current_dev);
goto out; goto out;
...@@ -5299,6 +5300,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) ...@@ -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; hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1;
wl->mac80211_initially_registered_queues = hw->queues; wl->mac80211_initially_registered_queues = hw->queues;
wl->hw_registred = false;
hw->max_rates = 2; hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev); SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac)) if (is_valid_ether_addr(sprom->et1mac))
...@@ -5370,12 +5372,15 @@ static void b43_bcma_remove(struct bcma_device *core) ...@@ -5370,12 +5372,15 @@ static void b43_bcma_remove(struct bcma_device *core)
* as the ieee80211 unreg will destroy the workqueue. */ * as the ieee80211 unreg will destroy the workqueue. */
cancel_work_sync(&wldev->restart_work); cancel_work_sync(&wldev->restart_work);
/* Restore the queues count before unregistering, because firmware detect B43_WARN_ON(!wl);
* might have modified it. Restoring is important, so the networking if (wl->current_dev == wldev && wl->hw_registred) {
* stack can properly free resources. */ /* Restore the queues count before unregistering, because firmware detect
wl->hw->queues = wl->mac80211_initially_registered_queues; * might have modified it. Restoring is important, so the networking
b43_leds_stop(wldev); * stack can properly free resources. */
ieee80211_unregister_hw(wl->hw); wl->hw->queues = wl->mac80211_initially_registered_queues;
b43_leds_stop(wldev);
ieee80211_unregister_hw(wl->hw);
}
b43_one_core_detach(wldev->dev); b43_one_core_detach(wldev->dev);
...@@ -5446,7 +5451,7 @@ static void b43_ssb_remove(struct ssb_device *sdev) ...@@ -5446,7 +5451,7 @@ static void b43_ssb_remove(struct ssb_device *sdev)
cancel_work_sync(&wldev->restart_work); cancel_work_sync(&wldev->restart_work);
B43_WARN_ON(!wl); 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 /* Restore the queues count before unregistering, because firmware detect
* might have modified it. Restoring is important, so the networking * might have modified it. Restoring is important, so the networking
* stack can properly free resources. */ * stack can properly free resources. */
......
...@@ -1508,7 +1508,7 @@ static void b43legacy_release_firmware(struct b43legacy_wldev *dev) ...@@ -1508,7 +1508,7 @@ static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl) 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 " "Drivers/b43#devicefirmware "
"and download the correct firmware (version 3).\n"); "and download the correct firmware (version 3).\n");
} }
......
...@@ -89,9 +89,9 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) ...@@ -89,9 +89,9 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1; data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret); 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; 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; data |= SDIO_SEPINT_ACT_HI;
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret); 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) ...@@ -631,9 +631,8 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val)
cc = sii->icbus->drv_cc.core; cc = sii->icbus->drv_cc.core;
/* mask and set */ /* mask and set */
if (mask || val) { if (mask || val)
bcma_maskset32(cc, regoff, ~mask, val); bcma_maskset32(cc, regoff, ~mask, val);
}
/* readback */ /* readback */
w = bcma_read32(cc, regoff); w = bcma_read32(cc, regoff);
......
...@@ -193,7 +193,7 @@ extern void ai_detach(struct si_pub *sih); ...@@ -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 uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val);
extern void ai_clkctl_init(struct si_pub *sih); extern void ai_clkctl_init(struct si_pub *sih);
extern u16 ai_clkctl_fast_pwrup_delay(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 bool ai_deviceremoved(struct si_pub *sih);
extern void ai_pci_down(struct si_pub *sih); extern void ai_pci_down(struct si_pub *sih);
......
...@@ -5724,7 +5724,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) ...@@ -5724,7 +5724,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->flags |= 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 * 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, ...@@ -5873,6 +5874,16 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return -EOPNOTSUPP; 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); sta_id = il_sta_id_or_broadcast(il, sta);
if (sta_id == IL_INVALID_STATION) if (sta_id == IL_INVALID_STATION)
return -EINVAL; return -EINVAL;
......
...@@ -1251,7 +1251,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, ...@@ -1251,7 +1251,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
key_flags |= STA_KEY_MULTICAST_MSK; key_flags |= STA_KEY_MULTICAST_MSK;
sta_cmd.key.key_flags = key_flags; 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.sta.modify_mask = STA_MODIFY_KEY_MASK;
sta_cmd.mode = STA_CONTROL_MODIFY_MSK; sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
......
...@@ -224,6 +224,7 @@ ...@@ -224,6 +224,7 @@
#define SCD_TXFACT (SCD_BASE + 0x10) #define SCD_TXFACT (SCD_BASE + 0x10)
#define SCD_ACTIVE (SCD_BASE + 0x14) #define SCD_ACTIVE (SCD_BASE + 0x14)
#define SCD_QUEUECHAIN_SEL (SCD_BASE + 0xe8) #define SCD_QUEUECHAIN_SEL (SCD_BASE + 0xe8)
#define SCD_CHAINEXT_EN (SCD_BASE + 0x244)
#define SCD_AGGR_SEL (SCD_BASE + 0x248) #define SCD_AGGR_SEL (SCD_BASE + 0x248)
#define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册