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

John W. Linville says:

====================
Please pull this batch of updates intended for the 3.14 stream...

For the mac80211 bits, Johannes says:

"I have various improvements/cleanups/fixes all over, but the shortlog
shows that Luis's regulatory work and mesh work from the cozybit folks
are the biggest ones, along with the CSA fixes."

Along with that, we have big batches of updates to brcmfmac, rtlwifi,
and ath9k.  There are updates to wcn36xx, rt2x00, and a handful of
others as well.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2013-12-06 14:25:23 -05:00
commit f1abb346d8
161 changed files with 7437 additions and 6533 deletions

View file

@ -159,10 +159,10 @@ struct ieee80211_regdomain mydriver_jp_regdom = {
REG_RULE(2412-20, 2484+20, 40, 6, 20, 0),
/* IEEE 802.11a, channels 34..48 */
REG_RULE(5170-20, 5240+20, 40, 6, 20,
NL80211_RRF_PASSIVE_SCAN),
NL80211_RRF_NO_IR),
/* IEEE 802.11a, channels 52..64 */
REG_RULE(5260-20, 5320+20, 40, 6, 20,
NL80211_RRF_NO_IBSS |
NL80211_RRF_NO_IR|
NL80211_RRF_DFS),
}
};

View file

@ -1458,17 +1458,6 @@ T: git git://github.com/kvalo/ath.git
S: Supported
F: drivers/net/wireless/ath/ath6kl/
ATHEROS ATH9K WIRELESS DRIVER
M: "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
M: Jouni Malinen <jouni@qca.qualcomm.com>
M: Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
M: Senthil Balasubramanian <senthilb@qca.qualcomm.com>
L: linux-wireless@vger.kernel.org
L: ath9k-devel@lists.ath9k.org
W: http://wireless.kernel.org/en/users/Drivers/ath9k
S: Supported
F: drivers/net/wireless/ath/ath9k/
WILOCITY WIL6210 WIRELESS DRIVER
M: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
L: linux-wireless@vger.kernel.org
@ -6928,6 +6917,14 @@ T: git git://linuxtv.org/anttip/media_tree.git
S: Maintained
F: drivers/media/tuners/qt1010*
QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
M: QCA ath9k Development <ath9k-devel@qca.qualcomm.com>
L: linux-wireless@vger.kernel.org
L: ath9k-devel@lists.ath9k.org
W: http://wireless.kernel.org/en/users/Drivers/ath9k
S: Supported
F: drivers/net/wireless/ath/ath9k/
QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
M: Kalle Valo <kvalo@qca.qualcomm.com>
L: ath10k@lists.infradead.org

View file

@ -238,7 +238,6 @@ static void bcma_host_pci_remove(struct pci_dev *dev)
pci_release_regions(dev);
pci_disable_device(dev);
kfree(bus);
pci_set_drvdata(dev, NULL);
}
#ifdef CONFIG_PM_SLEEP

View file

@ -1351,12 +1351,12 @@ static int ath10k_update_channel_list(struct ath10k *ar)
ch->allow_vht = true;
ch->allow_ibss =
!(channel->flags & IEEE80211_CHAN_NO_IBSS);
!(channel->flags & IEEE80211_CHAN_NO_IR);
ch->ht40plus =
!(channel->flags & IEEE80211_CHAN_NO_HT40PLUS);
passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN;
passive = channel->flags & IEEE80211_CHAN_NO_IR;
ch->passive = passive;
ch->freq = channel->center_freq;

View file

@ -1109,7 +1109,9 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
(mode == WMI_11G_HT20) ?
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
mutex_lock(&vif->wdev.mtx);
cfg80211_ch_switch_notify(vif->ndev, &chandef);
mutex_unlock(&vif->wdev.mtx);
}
static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
@ -3169,12 +3171,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
}
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
{
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
struct ath6kl *ar = ath6kl_priv(vif->ndev);
struct ieee80211_channel *chan = params->chan;
const u8 *buf = params->buf;
size_t len = params->len;
unsigned int wait = params->wait;
bool no_cck = params->no_cck;
u32 id, freq;
const struct ieee80211_mgmt *mgmt;
bool more_data, queued;

View file

@ -86,7 +86,7 @@ config ATH9K_DFS_CERTIFIED
config ATH9K_TX99
bool "Atheros ath9k TX99 testing support"
depends on CFG80211_CERTIFICATION_ONUS
depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS
default n
---help---
Say N. This should only be enabled on systems undergoing
@ -104,6 +104,14 @@ config ATH9K_TX99
be evaluated to meet the RF exposure limits set forth in the
governmental SAR regulations.
config ATH9K_WOW
bool "Wake on Wireless LAN support (EXPERIMENTAL)"
depends on ATH9K && PM
default n
---help---
This option enables Wake on Wireless LAN support for certain cards.
Currently, AR9462 is supported.
config ATH9K_LEGACY_RATE_CONTROL
bool "Atheros ath9k rate control"
depends on ATH9K

View file

@ -13,9 +13,9 @@ ath9k-$(CONFIG_ATH9K_PCI) += pci.o
ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \
dfs.o
ath9k-$(CONFIG_PM_SLEEP) += wow.o
ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o
ath9k-$(CONFIG_ATH9K_TX99) += tx99.o
ath9k-$(CONFIG_ATH9K_WOW) += wow.o
obj-$(CONFIG_ATH9K) += ath9k.o
@ -41,6 +41,8 @@ ath9k_hw-y:= \
ar9003_eeprom.o \
ar9003_paprd.o
ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o
ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
ar9003_mci.o
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o

View file

@ -352,7 +352,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
{0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982},
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
@ -378,9 +378,9 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x00009814, 0x9280c00a},
{0x00009818, 0x00000000},
{0x0000981c, 0x00020028},
{0x00009834, 0x6400a290},
{0x00009834, 0x6400a190},
{0x00009838, 0x0108ecff},
{0x0000983c, 0x0d000600},
{0x0000983c, 0x14000600},
{0x00009880, 0x201fff00},
{0x00009884, 0x00001042},
{0x000098a4, 0x00200400},
@ -401,7 +401,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x00009d04, 0x40206c10},
{0x00009d08, 0x009c4060},
{0x00009d0c, 0x9883800a},
{0x00009d10, 0x01834061},
{0x00009d10, 0x01884061},
{0x00009d14, 0x00c0040b},
{0x00009d18, 0x00000000},
{0x00009e08, 0x0038230c},
@ -459,7 +459,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000a3e8, 0x20202020},
{0x0000a3ec, 0x20202020},
{0x0000a3f0, 0x00000000},
{0x0000a3f4, 0x00000246},
{0x0000a3f4, 0x00000000},
{0x0000a3f8, 0x0c9bd380},
{0x0000a3fc, 0x000f0f01},
{0x0000a400, 0x8fa91f01},
@ -644,7 +644,7 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a410, 0x000050d4, 0x000050d4, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
@ -1086,8 +1086,8 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
{0x0000b074, 0x00000000},
{0x0000b078, 0x00000000},
{0x0000b07c, 0x00000000},
{0x0000b080, 0x2a2d2f32},
{0x0000b084, 0x21232328},
{0x0000b080, 0x23232323},
{0x0000b084, 0x21232323},
{0x0000b088, 0x19191c1e},
{0x0000b08c, 0x12141417},
{0x0000b090, 0x07070e0e},
@ -1385,9 +1385,9 @@ static const u32 ar9300_2p2_mac_core[][2] = {
{0x000081f8, 0x00000000},
{0x000081fc, 0x00000000},
{0x00008240, 0x00100000},
{0x00008244, 0x0010f424},
{0x00008244, 0x0010f400},
{0x00008248, 0x00000800},
{0x0000824c, 0x0001e848},
{0x0000824c, 0x0001e800},
{0x00008250, 0x00000000},
{0x00008254, 0x00000000},
{0x00008258, 0x00000000},
@ -1726,16 +1726,23 @@ static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = {
static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = {
/* Addr allmodes */
{0x00004040, 0x08253e5e},
{0x00004040, 0x0825365e},
{0x00004040, 0x0008003b},
{0x00004044, 0x00000000},
};
static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = {
/* Addr allmodes */
{0x00004040, 0x08213e5e},
{0x00004040, 0x0821365e},
{0x00004040, 0x0008003b},
{0x00004044, 0x00000000},
};
static const u32 ar9300_2p2_baseband_core_txfir_coeff_japan_2484[][2] = {
/* Addr allmodes */
{0x0000a398, 0x00000000},
{0x0000a39c, 0x6f7f0301},
{0x0000a3a0, 0xca9228ee},
};
#endif /* INITVALS_9003_2P2_H */

View file

@ -1040,14 +1040,14 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
}
}
static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_cal_data *caldata = ah->caldata;
bool txiqcal_done = false;
bool is_reusable = true, status = true;
bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false;
bool run_rtt_cal = false, run_agc_cal;
bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
u32 rx_delay = 0;
u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
@ -1119,22 +1119,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
txiqcal_done = run_agc_cal = true;
} else if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags)) {
run_agc_cal = true;
sep_iq_cal = true;
}
skip_tx_iqcal:
if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
ar9003_mci_init_cal_req(ah, &is_reusable);
if (sep_iq_cal) {
txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
udelay(5);
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
}
if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {
rx_delay = REG_READ(ah, AR_PHY_RX_DELAY);
/* Disable BB_active */
@ -1228,13 +1218,109 @@ skip_tx_iqcal:
return true;
}
static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_cal_data *caldata = ah->caldata;
bool txiqcal_done = false;
bool is_reusable = true, status = true;
bool run_agc_cal = false, sep_iq_cal = false;
/* Use chip chainmask only for calibration */
ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
if (ah->enabled_cals & TX_CL_CAL) {
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
run_agc_cal = true;
}
if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
goto skip_tx_iqcal;
/* Do Tx IQ Calibration */
REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
DELPT);
/*
* For AR9485 or later chips, TxIQ cal runs as part of
* AGC calibration. Specifically, AR9550 in SoC chips.
*/
if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
txiqcal_done = true;
run_agc_cal = true;
} else {
sep_iq_cal = true;
run_agc_cal = true;
}
/*
* In the SoC family, this will run for AR9300, AR9331 and AR9340.
*/
if (sep_iq_cal) {
txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
udelay(5);
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
}
skip_tx_iqcal:
if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
/* Calibrate the AGC */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
REG_READ(ah, AR_PHY_AGC_CONTROL) |
AR_PHY_AGC_CONTROL_CAL);
/* Poll for offset calibration complete */
status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT);
}
if (!status) {
ath_dbg(common, CALIBRATE,
"offset calibration failed to complete in %d ms; noisy environment?\n",
AH_WAIT_TIMEOUT / 1000);
return false;
}
if (txiqcal_done)
ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
/* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
/* Initialize list pointers */
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
/* Initialize current pointer to first element in list */
ah->cal_list_curr = ah->cal_list;
if (ah->cal_list_curr)
ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
if (caldata)
caldata->CalValid = 0;
return true;
}
void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
struct ath_hw_ops *ops = ath9k_hw_ops(ah);
if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9565(ah))
priv_ops->init_cal = ar9003_hw_init_cal_pcoem;
else
priv_ops->init_cal = ar9003_hw_init_cal_soc;
priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
priv_ops->init_cal = ar9003_hw_init_cal;
priv_ops->setup_calibration = ar9003_hw_setup_calibration;
ops->calibrate = ar9003_hw_calibrate;

View file

@ -26,6 +26,7 @@
#include "ar9462_2p0_initvals.h"
#include "ar9462_2p1_initvals.h"
#include "ar9565_1p0_initvals.h"
#include "ar9565_1p1_initvals.h"
/* General hardware code for the AR9003 hadware family */
@ -148,7 +149,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
ar9340Modes_high_ob_db_tx_gain_table_1p0);
INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9340Modes_fast_clock_1p0);
ar9340Modes_fast_clock_1p0);
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9340_1p0_baseband_core_txfir_coeff_japan_2484);
if (!ah->is_clk_25mhz)
INIT_INI_ARRAY(&ah->iniAdditional,
@ -223,6 +226,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
ar9462_2p1_modes_fast_clock);
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9462_2p1_baseband_core_txfir_coeff_japan_2484);
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9462_2p1_pciephy_clkreq_disable_L1);
INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
ar9462_2p1_pciephy_clkreq_disable_L1);
} else if (AR_SREV_9462_20(ah)) {
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core);
@ -247,18 +254,18 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
ar9462_2p0_soc_postamble);
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9462_common_rx_gain_table_2p0);
ar9462_2p0_common_rx_gain);
/* Awake -> Sleep Setting */
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9462_pciephy_clkreq_disable_L1_2p0);
ar9462_2p0_pciephy_clkreq_disable_L1);
/* Sleep -> Awake Setting */
INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
ar9462_pciephy_clkreq_disable_L1_2p0);
ar9462_2p0_pciephy_clkreq_disable_L1);
/* Fast clock modal settings */
INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9462_modes_fast_clock_2p0);
ar9462_2p0_modes_fast_clock);
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9462_2p0_baseband_core_txfir_coeff_japan_2484);
@ -330,7 +337,44 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
ar9580_1p0_low_ob_db_tx_gain_table);
INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9580_1p0_modes_fast_clock);
ar9580_1p0_modes_fast_clock);
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9580_1p0_baseband_core_txfir_coeff_japan_2484);
} else if (AR_SREV_9565_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
ar9565_1p1_mac_core);
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
ar9565_1p1_mac_postamble);
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
ar9565_1p1_baseband_core);
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
ar9565_1p1_baseband_postamble);
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
ar9565_1p1_radio_core);
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
ar9565_1p1_radio_postamble);
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
ar9565_1p1_soc_preamble);
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
ar9565_1p1_soc_postamble);
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9565_1p1_Common_rx_gain_table);
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p1_Modes_lowest_ob_db_tx_gain_table);
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9565_1p1_pciephy_clkreq_disable_L1);
INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
ar9565_1p1_pciephy_clkreq_disable_L1);
INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9565_1p1_modes_fast_clock);
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9565_1p1_baseband_core_txfir_coeff_japan_2484);
} else if (AR_SREV_9565(ah)) {
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
ar9565_1p0_mac_core);
@ -411,7 +455,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
/* Fast clock modal settings */
INIT_INI_ARRAY(&ah->iniModesFastClock,
ar9300Modes_fast_clock_2p2);
ar9300Modes_fast_clock_2p2);
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9300_2p2_baseband_core_txfir_coeff_japan_2484);
}
}
@ -440,7 +486,10 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)
ar9462_2p1_modes_low_ob_db_tx_gain);
else if (AR_SREV_9462_20(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9462_modes_low_ob_db_tx_gain_table_2p0);
ar9462_2p0_modes_low_ob_db_tx_gain);
else if (AR_SREV_9565_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p1_modes_low_ob_db_tx_gain_table);
else if (AR_SREV_9565(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p0_modes_low_ob_db_tx_gain_table);
@ -474,7 +523,10 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)
ar9462_2p1_modes_high_ob_db_tx_gain);
else if (AR_SREV_9462_20(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9462_modes_high_ob_db_tx_gain_table_2p0);
ar9462_2p0_modes_high_ob_db_tx_gain);
else if (AR_SREV_9565_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p1_modes_high_ob_db_tx_gain_table);
else if (AR_SREV_9565(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p0_modes_high_ob_db_tx_gain_table);
@ -500,6 +552,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah)
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_low_ob_db_tx_gain_table);
else if (AR_SREV_9565_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p1_modes_low_ob_db_tx_gain_table);
else if (AR_SREV_9565(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p0_modes_low_ob_db_tx_gain_table);
@ -525,6 +580,9 @@ static void ar9003_tx_gain_table_mode3(struct ath_hw *ah)
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_high_power_tx_gain_table);
else if (AR_SREV_9565_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p1_modes_high_power_tx_gain_table);
else if (AR_SREV_9565(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p0_modes_high_power_tx_gain_table);
@ -546,7 +604,7 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah)
ar9462_2p1_modes_mix_ob_db_tx_gain);
else if (AR_SREV_9462_20(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9462_modes_mix_ob_db_tx_gain_table_2p0);
ar9462_2p0_modes_mix_ob_db_tx_gain);
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9300Modes_mixed_ob_db_tx_gain_table_2p2);
@ -581,6 +639,13 @@ static void ar9003_tx_gain_table_mode6(struct ath_hw *ah)
ar9580_1p0_type6_tx_gain_table);
}
static void ar9003_tx_gain_table_mode7(struct ath_hw *ah)
{
if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9340_cus227_tx_gain_table_1p0);
}
typedef void (*ath_txgain_tab)(struct ath_hw *ah);
static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
@ -593,6 +658,7 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
ar9003_tx_gain_table_mode4,
ar9003_tx_gain_table_mode5,
ar9003_tx_gain_table_mode6,
ar9003_tx_gain_table_mode7,
};
int idx = ar9003_hw_get_tx_gain_idx(ah);
@ -629,7 +695,10 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
ar9462_2p1_common_rx_gain);
else if (AR_SREV_9462_20(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9462_common_rx_gain_table_2p0);
ar9462_2p0_common_rx_gain);
else if (AR_SREV_9565_11(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9565_1p1_Common_rx_gain_table);
else if (AR_SREV_9565(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9565_1p0_Common_rx_gain_table);
@ -657,7 +726,7 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
ar9462_2p1_common_wo_xlna_rx_gain);
else if (AR_SREV_9462_20(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9462_common_wo_xlna_rx_gain_table_2p0);
ar9462_2p0_common_wo_xlna_rx_gain);
else if (AR_SREV_9550(ah)) {
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar955x_1p0_common_wo_xlna_rx_gain_table);
@ -666,6 +735,9 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
} else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9580_1p0_wo_xlna_rx_gain_table);
else if (AR_SREV_9565_11(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9565_1p1_common_wo_xlna_rx_gain_table);
else if (AR_SREV_9565(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9565_1p0_common_wo_xlna_rx_gain_table);
@ -687,7 +759,7 @@ static void ar9003_rx_gain_table_mode2(struct ath_hw *ah)
ar9462_2p1_baseband_postamble_5g_xlna);
} else if (AR_SREV_9462_20(ah)) {
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9462_common_mixed_rx_gain_table_2p0);
ar9462_2p0_common_mixed_rx_gain);
INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_core,
ar9462_2p0_baseband_core_mix_rxgain);
INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_postamble,
@ -701,12 +773,12 @@ static void ar9003_rx_gain_table_mode3(struct ath_hw *ah)
{
if (AR_SREV_9462_21(ah)) {
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9462_2p1_common_5g_xlna_only_rx_gain);
ar9462_2p1_common_5g_xlna_only_rxgain);
INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
ar9462_2p1_baseband_postamble_5g_xlna);
} else if (AR_SREV_9462_20(ah)) {
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9462_2p0_5g_xlna_only_rxgain);
ar9462_2p0_common_5g_xlna_only_rxgain);
INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
ar9462_2p0_baseband_postamble_5g_xlna);
}
@ -750,6 +822,9 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah)
static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
bool power_off)
{
unsigned int i;
struct ar5416IniArray *array;
/*
* Increase L1 Entry Latency. Some WB222 boards don't have
* this change in eeprom/OTP.
@ -775,18 +850,13 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
* Configire PCIE after Ini init. SERDES values now come from ini file
* This enables PCIe low power mode.
*/
if (ah->config.pcieSerDesWrite) {
unsigned int i;
struct ar5416IniArray *array;
array = power_off ? &ah->iniPcieSerdes :
&ah->iniPcieSerdesLowPower;
array = power_off ? &ah->iniPcieSerdes :
&ah->iniPcieSerdesLowPower;
for (i = 0; i < array->ia_rows; i++) {
REG_WRITE(ah,
INI_RA(array, i, 0),
INI_RA(array, i, 1));
}
for (i = 0; i < array->ia_rows; i++) {
REG_WRITE(ah,
INI_RA(array, i, 0),
INI_RA(array, i, 1));
}
}

View file

@ -641,11 +641,12 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
else
ah->enabled_cals &= ~TX_IQ_CAL;
if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
ah->enabled_cals |= TX_CL_CAL;
else
ah->enabled_cals &= ~TX_CL_CAL;
}
if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
ah->enabled_cals |= TX_CL_CAL;
else
ah->enabled_cals &= ~TX_CL_CAL;
}
static void ar9003_hw_prog_ini(struct ath_hw *ah,

View file

@ -0,0 +1,422 @@
/*
* 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 <linux/export.h>
#include "ath9k.h"
#include "reg.h"
#include "hw-ops.h"
const char *ath9k_hw_wow_event_to_string(u32 wow_event)
{
if (wow_event & AH_WOW_MAGIC_PATTERN_EN)
return "Magic pattern";
if (wow_event & AH_WOW_USER_PATTERN_EN)
return "User pattern";
if (wow_event & AH_WOW_LINK_CHANGE)
return "Link change";
if (wow_event & AH_WOW_BEACON_MISS)
return "Beacon miss";
return "unknown reason";
}
EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);
static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
/* set rx disable bit */
REG_WRITE(ah, AR_CR, AR_CR_RXD);
if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) {
ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
return;
}
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);
}
static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN];
u32 ctl[13] = {0};
u32 data_word[KAL_NUM_DATA_WORDS];
u8 i;
u32 wow_ka_data_word0;
memcpy(sta_mac_addr, common->macaddr, ETH_ALEN);
memcpy(ap_mac_addr, common->curbssid, ETH_ALEN);
/* set the transmit buffer */
ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));
ctl[1] = 0;
ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */
ctl[4] = 0;
ctl[7] = (ah->txchainmask) << 2;
ctl[2] = 0xf << 16; /* tx_tries 0 */
for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |
(KAL_TO_DS << 8) | (KAL_DURATION_ID << 16);
data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |
(ap_mac_addr[1] << 8) | (ap_mac_addr[0]);
data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) |
(ap_mac_addr[5] << 8) | (ap_mac_addr[4]);
data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) |
(sta_mac_addr[3] << 8) | (sta_mac_addr[2]);
data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |
(ap_mac_addr[1] << 8) | (ap_mac_addr[0]);
data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);
if (AR_SREV_9462_20(ah)) {
/* AR9462 2.0 has an extra descriptor word (time based
* discard) compared to other chips */
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0);
wow_ka_data_word0 = AR_WOW_TXBUF(13);
} else {
wow_ka_data_word0 = AR_WOW_TXBUF(12);
}
for (i = 0; i < KAL_NUM_DATA_WORDS; i++)
REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]);
}
void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
u8 *user_mask, int pattern_count,
int pattern_len)
{
int i;
u32 pattern_val, mask_val;
u32 set, clr;
/* FIXME: should check count by querying the hardware capability */
if (pattern_count >= MAX_NUM_PATTERN)
return;
REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));
/* set the registers for pattern */
for (i = 0; i < MAX_PATTERN_SIZE; i += 4) {
memcpy(&pattern_val, user_pattern, 4);
REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i),
pattern_val);
user_pattern += 4;
}
/* set the registers for mask */
for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) {
memcpy(&mask_val, user_mask, 4);
REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val);
user_mask += 4;
}
/* set the pattern length to be matched
*
* AR_WOW_LENGTH1_REG1
* bit 31:24 pattern 0 length
* bit 23:16 pattern 1 length
* bit 15:8 pattern 2 length
* bit 7:0 pattern 3 length
*
* AR_WOW_LENGTH1_REG2
* bit 31:24 pattern 4 length
* bit 23:16 pattern 5 length
* bit 15:8 pattern 6 length
* bit 7:0 pattern 7 length
*
* the below logic writes out the new
* pattern length for the corresponding
* pattern_count, while masking out the
* other fields
*/
ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
if (pattern_count < 4) {
/* Pattern 0-3 uses AR_WOW_LENGTH1 register */
set = (pattern_len & AR_WOW_LENGTH_MAX) <<
AR_WOW_LEN1_SHIFT(pattern_count);
clr = AR_WOW_LENGTH1_MASK(pattern_count);
REG_RMW(ah, AR_WOW_LENGTH1, set, clr);
} else {
/* Pattern 4-7 uses AR_WOW_LENGTH2 register */
set = (pattern_len & AR_WOW_LENGTH_MAX) <<
AR_WOW_LEN2_SHIFT(pattern_count);
clr = AR_WOW_LENGTH2_MASK(pattern_count);
REG_RMW(ah, AR_WOW_LENGTH2, set, clr);
}
}
EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern);
u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
{
u32 wow_status = 0;
u32 val = 0, rval;
/*
* read the WoW status register to know
* the wakeup reason
*/
rval = REG_READ(ah, AR_WOW_PATTERN);
val = AR_WOW_STATUS(rval);
/*
* mask only the WoW events that we have enabled. Sometimes
* we have spurious WoW events from the AR_WOW_PATTERN
* register. This mask will clean it up.
*/
val &= ah->wow_event_mask;
if (val) {
if (val & AR_WOW_MAGIC_PAT_FOUND)
wow_status |= AH_WOW_MAGIC_PATTERN_EN;
if (AR_WOW_PATTERN_FOUND(val))
wow_status |= AH_WOW_USER_PATTERN_EN;
if (val & AR_WOW_KEEP_ALIVE_FAIL)
wow_status |= AH_WOW_LINK_CHANGE;
if (val & AR_WOW_BEACON_FAIL)
wow_status |= AH_WOW_BEACON_MISS;
}
/*
* set and clear WOW_PME_CLEAR registers for the chip to
* generate next wow signal.
* disable D3 before accessing other registers ?
*/
/* do we need to check the bit value 0x01000000 (7-10) ?? */
REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR,
AR_PMCTRL_PWR_STATE_D1D3);
/*
* clear all events
*/
REG_WRITE(ah, AR_WOW_PATTERN,
AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN)));
/*
* restore the beacon threshold to init value
*/
REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
/*
* Restore the way the PCI-E reset, Power-On-Reset, external
* PCIE_POR_SHORT pins are tied to its original value.
* Previously just before WoW sleep, we untie the PCI-E
* reset to our Chip's Power On Reset so that any PCI-E
* reset from the bus will not reset our chip
*/
if (ah->is_pciexpress)
ath9k_hw_configpcipowersave(ah, false);
ah->wow_event_mask = 0;
return wow_status;
}
EXPORT_SYMBOL(ath9k_hw_wow_wakeup);
void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
{
u32 wow_event_mask;
u32 set, clr;
/*
* wow_event_mask is a mask to the AR_WOW_PATTERN register to
* indicate which WoW events we have enabled. The WoW events
* are from the 'pattern_enable' in this function and
* 'pattern_count' of ath9k_hw_wow_apply_pattern()
*/
wow_event_mask = ah->wow_event_mask;
/*
* Untie Power-on-Reset from the PCI-E-Reset. When we are in
* WOW sleep, we do want the Reset from the PCI-E to disturb
* our hw state
*/
if (ah->is_pciexpress) {
/*
* we need to untie the internal POR (power-on-reset)
* to the external PCI-E reset. We also need to tie
* the PCI-E Phy reset to the PCI-E reset.
*/
set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
REG_RMW(ah, AR_WA, set, clr);
}
/*
* set the power states appropriately and enable PME
*/
set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA |
AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR;
/*
* set and clear WOW_PME_CLEAR registers for the chip
* to generate next wow signal.
*/
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
clr = AR_PMCTRL_WOW_PME_CLR;
REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
/*
* Setup for:
* - beacon misses
* - magic pattern
* - keep alive timeout
* - pattern matching
*/
/*
* Program default values for pattern backoff, aifs/slot/KAL count,
* beacon miss timeout, KAL timeout, etc.
*/
set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
REG_SET_BIT(ah, AR_WOW_PATTERN, set);
set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |
AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);
REG_SET_BIT(ah, AR_WOW_COUNT, set);
if (pattern_enable & AH_WOW_BEACON_MISS)
set = AR_WOW_BEACON_TIMO;
/* We are not using beacon miss, program a large value */
else
set = AR_WOW_BEACON_TIMO_MAX;
REG_WRITE(ah, AR_WOW_BCN_TIMO, set);
/*
* Keep alive timo in ms except AR9280
*/
if (!pattern_enable)
set = AR_WOW_KEEP_ALIVE_NEVER;
else
set = KAL_TIMEOUT * 32;
REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set);
/*
* Keep alive delay in us. based on 'power on clock',
* therefore in usec
*/
set = KAL_DELAY * 1000;
REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set);
/*
* Create keep alive pattern to respond to beacons
*/
ath9k_wow_create_keep_alive_pattern(ah);
/*
* Configure MAC WoW Registers
*/
set = 0;
/* Send keep alive timeouts anyway */
clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
if (pattern_enable & AH_WOW_LINK_CHANGE)
wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;
else
set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
/*
* we are relying on a bmiss failure. ensure we have
* enough threshold to prevent false positives
*/
REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,
AR_WOW_BMISSTHRESHOLD);
set = 0;
clr = 0;
if (pattern_enable & AH_WOW_BEACON_MISS) {
set = AR_WOW_BEACON_FAIL_EN;
wow_event_mask |= AR_WOW_BEACON_FAIL;
} else {
clr = AR_WOW_BEACON_FAIL_EN;
}
REG_RMW(ah, AR_WOW_BCN_EN, set, clr);
set = 0;
clr = 0;
/*
* Enable the magic packet registers
*/
if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) {
set = AR_WOW_MAGIC_EN;
wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;
} else {
clr = AR_WOW_MAGIC_EN;
}
set |= AR_WOW_MAC_INTR_EN;
REG_RMW(ah, AR_WOW_PATTERN, set, clr);
REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
AR_WOW_PATTERN_SUPPORTED);
/*
* Set the power states appropriately and enable PME
*/
clr = 0;
set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
AR_PMCTRL_PWR_PM_CTRL_ENA;
clr = AR_PCIE_PM_CTRL_ENA;
REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
/*
* this is needed to prevent the chip waking up
* the host within 3-4 seconds with certain
* platform/BIOS. The fix is to enable
* D1 & D3 to match original definition and
* also match the OTP value. Anyway this
* is more related to SW WOW.
*/
clr = AR_PMCTRL_PWR_STATE_D1D3;
REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
/* to bring down WOW power low margin */
set = BIT(13);
REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
/* HW WoW */
clr = BIT(5);
REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
ath9k_hw_set_powermode_wow_sleep(ah);
ah->wow_event_mask = wow_event_mask;
}
EXPORT_SYMBOL(ath9k_hw_wow_enable);

View file

@ -18,6 +18,18 @@
#ifndef INITVALS_9340_H
#define INITVALS_9340_H
#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble
#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble
#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2
#define ar9340Common_rx_gain_table_1p0 ar9300Common_rx_gain_table_2p2
#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2
#define ar9340_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484
static const u32 ar9340_1p0_radio_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800},
@ -100,8 +112,6 @@ static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = {
{0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
};
#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2
static const u32 ar9340_1p0_radio_core[][2] = {
/* Addr allmodes */
{0x00016000, 0x36db6db6},
@ -215,16 +225,12 @@ static const u32 ar9340_1p0_radio_core_40M[][2] = {
{0x0000824c, 0x0001e800},
};
#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble
#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble
static const u32 ar9340_1p0_baseband_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
{0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e},
{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
{0x00009828, 0x06903081, 0x06903081, 0x09103881, 0x09103881},
{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
@ -340,9 +346,9 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
{0x0000a370, 0x00000000},
{0x0000a390, 0x00000001},
{0x0000a394, 0x00000444},
{0x0000a398, 0x001f0e0f},
{0x0000a39c, 0x0075393f},
{0x0000a3a0, 0xb79f6427},
{0x0000a398, 0x00000000},
{0x0000a39c, 0x210d0401},
{0x0000a3a0, 0xab9a7144},
{0x0000a3a4, 0x00000000},
{0x0000a3a8, 0xaaaaaaaa},
{0x0000a3ac, 0x3c466478},
@ -714,266 +720,6 @@ static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = {
{0x0000b2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000},
};
static const u32 ar9340Common_rx_gain_table_1p0[][2] = {
/* Addr allmodes */
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},
{0x0000a008, 0x00050004},
{0x0000a00c, 0x00810080},
{0x0000a010, 0x00830082},
{0x0000a014, 0x01810180},
{0x0000a018, 0x01830182},
{0x0000a01c, 0x01850184},
{0x0000a020, 0x01890188},
{0x0000a024, 0x018b018a},
{0x0000a028, 0x018d018c},
{0x0000a02c, 0x01910190},
{0x0000a030, 0x01930192},
{0x0000a034, 0x01950194},
{0x0000a038, 0x038a0196},
{0x0000a03c, 0x038c038b},
{0x0000a040, 0x0390038d},
{0x0000a044, 0x03920391},
{0x0000a048, 0x03940393},
{0x0000a04c, 0x03960395},
{0x0000a050, 0x00000000},
{0x0000a054, 0x00000000},
{0x0000a058, 0x00000000},
{0x0000a05c, 0x00000000},
{0x0000a060, 0x00000000},
{0x0000a064, 0x00000000},
{0x0000a068, 0x00000000},
{0x0000a06c, 0x00000000},
{0x0000a070, 0x00000000},
{0x0000a074, 0x00000000},
{0x0000a078, 0x00000000},
{0x0000a07c, 0x00000000},
{0x0000a080, 0x22222229},
{0x0000a084, 0x1d1d1d1d},
{0x0000a088, 0x1d1d1d1d},
{0x0000a08c, 0x1d1d1d1d},
{0x0000a090, 0x171d1d1d},
{0x0000a094, 0x11111717},
{0x0000a098, 0x00030311},
{0x0000a09c, 0x00000000},
{0x0000a0a0, 0x00000000},
{0x0000a0a4, 0x00000000},
{0x0000a0a8, 0x00000000},
{0x0000a0ac, 0x00000000},
{0x0000a0b0, 0x00000000},
{0x0000a0b4, 0x00000000},
{0x0000a0b8, 0x00000000},
{0x0000a0bc, 0x00000000},
{0x0000a0c0, 0x001f0000},
{0x0000a0c4, 0x01000101},
{0x0000a0c8, 0x011e011f},
{0x0000a0cc, 0x011c011d},
{0x0000a0d0, 0x02030204},
{0x0000a0d4, 0x02010202},
{0x0000a0d8, 0x021f0200},
{0x0000a0dc, 0x0302021e},
{0x0000a0e0, 0x03000301},
{0x0000a0e4, 0x031e031f},
{0x0000a0e8, 0x0402031d},
{0x0000a0ec, 0x04000401},
{0x0000a0f0, 0x041e041f},
{0x0000a0f4, 0x0502041d},
{0x0000a0f8, 0x05000501},
{0x0000a0fc, 0x051e051f},
{0x0000a100, 0x06010602},
{0x0000a104, 0x061f0600},
{0x0000a108, 0x061d061e},
{0x0000a10c, 0x07020703},
{0x0000a110, 0x07000701},
{0x0000a114, 0x00000000},
{0x0000a118, 0x00000000},
{0x0000a11c, 0x00000000},
{0x0000a120, 0x00000000},
{0x0000a124, 0x00000000},
{0x0000a128, 0x00000000},
{0x0000a12c, 0x00000000},
{0x0000a130, 0x00000000},
{0x0000a134, 0x00000000},
{0x0000a138, 0x00000000},
{0x0000a13c, 0x00000000},
{0x0000a140, 0x001f0000},
{0x0000a144, 0x01000101},
{0x0000a148, 0x011e011f},
{0x0000a14c, 0x011c011d},
{0x0000a150, 0x02030204},
{0x0000a154, 0x02010202},
{0x0000a158, 0x021f0200},
{0x0000a15c, 0x0302021e},
{0x0000a160, 0x03000301},
{0x0000a164, 0x031e031f},
{0x0000a168, 0x0402031d},
{0x0000a16c, 0x04000401},
{0x0000a170, 0x041e041f},
{0x0000a174, 0x0502041d},
{0x0000a178, 0x05000501},
{0x0000a17c, 0x051e051f},
{0x0000a180, 0x06010602},
{0x0000a184, 0x061f0600},
{0x0000a188, 0x061d061e},
{0x0000a18c, 0x07020703},
{0x0000a190, 0x07000701},
{0x0000a194, 0x00000000},
{0x0000a198, 0x00000000},
{0x0000a19c, 0x00000000},
{0x0000a1a0, 0x00000000},
{0x0000a1a4, 0x00000000},
{0x0000a1a8, 0x00000000},
{0x0000a1ac, 0x00000000},
{0x0000a1b0, 0x00000000},
{0x0000a1b4, 0x00000000},
{0x0000a1b8, 0x00000000},
{0x0000a1bc, 0x00000000},
{0x0000a1c0, 0x00000000},
{0x0000a1c4, 0x00000000},
{0x0000a1c8, 0x00000000},
{0x0000a1cc, 0x00000000},
{0x0000a1d0, 0x00000000},
{0x0000a1d4, 0x00000000},
{0x0000a1d8, 0x00000000},
{0x0000a1dc, 0x00000000},
{0x0000a1e0, 0x00000000},
{0x0000a1e4, 0x00000000},
{0x0000a1e8, 0x00000000},
{0x0000a1ec, 0x00000000},
{0x0000a1f0, 0x00000396},
{0x0000a1f4, 0x00000396},
{0x0000a1f8, 0x00000396},
{0x0000a1fc, 0x00000196},
{0x0000b000, 0x00010000},
{0x0000b004, 0x00030002},
{0x0000b008, 0x00050004},
{0x0000b00c, 0x00810080},
{0x0000b010, 0x00830082},
{0x0000b014, 0x01810180},
{0x0000b018, 0x01830182},
{0x0000b01c, 0x01850184},
{0x0000b020, 0x02810280},
{0x0000b024, 0x02830282},
{0x0000b028, 0x02850284},
{0x0000b02c, 0x02890288},
{0x0000b030, 0x028b028a},
{0x0000b034, 0x0388028c},
{0x0000b038, 0x038a0389},
{0x0000b03c, 0x038c038b},
{0x0000b040, 0x0390038d},
{0x0000b044, 0x03920391},
{0x0000b048, 0x03940393},
{0x0000b04c, 0x03960395},
{0x0000b050, 0x00000000},
{0x0000b054, 0x00000000},
{0x0000b058, 0x00000000},
{0x0000b05c, 0x00000000},
{0x0000b060, 0x00000000},
{0x0000b064, 0x00000000},
{0x0000b068, 0x00000000},
{0x0000b06c, 0x00000000},
{0x0000b070, 0x00000000},
{0x0000b074, 0x00000000},
{0x0000b078, 0x00000000},
{0x0000b07c, 0x00000000},
{0x0000b080, 0x23232323},
{0x0000b084, 0x21232323},
{0x0000b088, 0x19191c1e},
{0x0000b08c, 0x12141417},
{0x0000b090, 0x07070e0e},
{0x0000b094, 0x03030305},
{0x0000b098, 0x00000003},
{0x0000b09c, 0x00000000},
{0x0000b0a0, 0x00000000},
{0x0000b0a4, 0x00000000},
{0x0000b0a8, 0x00000000},
{0x0000b0ac, 0x00000000},
{0x0000b0b0, 0x00000000},
{0x0000b0b4, 0x00000000},
{0x0000b0b8, 0x00000000},
{0x0000b0bc, 0x00000000},
{0x0000b0c0, 0x003f0020},
{0x0000b0c4, 0x00400041},
{0x0000b0c8, 0x0140005f},
{0x0000b0cc, 0x0160015f},
{0x0000b0d0, 0x017e017f},
{0x0000b0d4, 0x02410242},
{0x0000b0d8, 0x025f0240},
{0x0000b0dc, 0x027f0260},
{0x0000b0e0, 0x0341027e},
{0x0000b0e4, 0x035f0340},
{0x0000b0e8, 0x037f0360},
{0x0000b0ec, 0x04400441},
{0x0000b0f0, 0x0460045f},
{0x0000b0f4, 0x0541047f},
{0x0000b0f8, 0x055f0540},
{0x0000b0fc, 0x057f0560},
{0x0000b100, 0x06400641},
{0x0000b104, 0x0660065f},
{0x0000b108, 0x067e067f},
{0x0000b10c, 0x07410742},
{0x0000b110, 0x075f0740},
{0x0000b114, 0x077f0760},
{0x0000b118, 0x07800781},
{0x0000b11c, 0x07a0079f},
{0x0000b120, 0x07c107bf},
{0x0000b124, 0x000007c0},
{0x0000b128, 0x00000000},
{0x0000b12c, 0x00000000},
{0x0000b130, 0x00000000},
{0x0000b134, 0x00000000},
{0x0000b138, 0x00000000},
{0x0000b13c, 0x00000000},
{0x0000b140, 0x003f0020},
{0x0000b144, 0x00400041},
{0x0000b148, 0x0140005f},
{0x0000b14c, 0x0160015f},
{0x0000b150, 0x017e017f},
{0x0000b154, 0x02410242},
{0x0000b158, 0x025f0240},
{0x0000b15c, 0x027f0260},
{0x0000b160, 0x0341027e},
{0x0000b164, 0x035f0340},
{0x0000b168, 0x037f0360},
{0x0000b16c, 0x04400441},
{0x0000b170, 0x0460045f},
{0x0000b174, 0x0541047f},
{0x0000b178, 0x055f0540},
{0x0000b17c, 0x057f0560},
{0x0000b180, 0x06400641},
{0x0000b184, 0x0660065f},
{0x0000b188, 0x067e067f},
{0x0000b18c, 0x07410742},
{0x0000b190, 0x075f0740},
{0x0000b194, 0x077f0760},
{0x0000b198, 0x07800781},
{0x0000b19c, 0x07a0079f},
{0x0000b1a0, 0x07c107bf},
{0x0000b1a4, 0x000007c0},
{0x0000b1a8, 0x00000000},
{0x0000b1ac, 0x00000000},
{0x0000b1b0, 0x00000000},
{0x0000b1b4, 0x00000000},
{0x0000b1b8, 0x00000000},
{0x0000b1bc, 0x00000000},
{0x0000b1c0, 0x00000000},
{0x0000b1c4, 0x00000000},
{0x0000b1c8, 0x00000000},
{0x0000b1cc, 0x00000000},
{0x0000b1d0, 0x00000000},
{0x0000b1d4, 0x00000000},
{0x0000b1d8, 0x00000000},
{0x0000b1dc, 0x00000000},
{0x0000b1e0, 0x00000000},
{0x0000b1e4, 0x00000000},
{0x0000b1e8, 0x00000000},
{0x0000b1ec, 0x00000000},
{0x0000b1f0, 0x00000396},
{0x0000b1f4, 0x00000396},
{0x0000b1f8, 0x00000396},
{0x0000b1fc, 0x00000196},
};
static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
@ -1437,8 +1183,6 @@ static const u32 ar9340_1p0_mac_core[][2] = {
{0x000083d0, 0x000101ff},
};
#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2
static const u32 ar9340_1p0_soc_preamble[][2] = {
/* Addr allmodes */
{0x00007008, 0x00000000},
@ -1447,4 +1191,106 @@ static const u32 ar9340_1p0_soc_preamble[][2] = {
{0x00007038, 0x000004c2},
};
static const u32 ar9340_cus227_tx_gain_table_1p0[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
{0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400},
{0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402},
{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
{0x0000a520, 0x2c022220, 0x2c022220, 0x1b000603, 0x1b000603},
{0x0000a524, 0x30022222, 0x30022222, 0x1f000a02, 0x1f000a02},
{0x0000a528, 0x35022225, 0x35022225, 0x23000a04, 0x23000a04},
{0x0000a52c, 0x3b02222a, 0x3b02222a, 0x26000a20, 0x26000a20},
{0x0000a530, 0x3f02222c, 0x3f02222c, 0x2a000e20, 0x2a000e20},
{0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22},
{0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24},
{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640},
{0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
{0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861},
{0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81},
{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42001a83, 0x42001a83},
{0x0000a550, 0x61024a6c, 0x61024a6c, 0x44001c84, 0x44001c84},
{0x0000a554, 0x66026a6c, 0x66026a6c, 0x48001ce3, 0x48001ce3},
{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c001ce5, 0x4c001ce5},
{0x0000a55c, 0x7002708c, 0x7002708c, 0x50001ce9, 0x50001ce9},
{0x0000a560, 0x7302b08a, 0x7302b08a, 0x54001ceb, 0x54001ceb},
{0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
{0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
{0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
{0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
{0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
{0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400},
{0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402},
{0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603},
{0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02},
{0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04},
{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20},
{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20},
{0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22},
{0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24},
{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640},
{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660},
{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861},
{0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81},
{0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83},
{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84},
{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3},
{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5},
{0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9},
{0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb},
{0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
{0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
{0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
{0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
{0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
{0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
{0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
{0x00016048, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
{0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015},
{0x00016288, 0x30318000, 0x30318000, 0x00318000, 0x00318000},
{0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
{0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
{0x0000a3a4, 0x00000011, 0x00000011, 0x00000011, 0x00000011},
{0x0000a3a8, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c},
{0x0000a3ac, 0x30303030, 0x30303030, 0x30303030, 0x30303030},
};
#endif /* INITVALS_9340_H */

View file

@ -20,7 +20,7 @@
/* AR9462 2.0 */
static const u32 ar9462_modes_fast_clock_2p0[][3] = {
static const u32 ar9462_2p0_modes_fast_clock[][3] = {
/* Addr 5G_HT20 5G_HT40 */
{0x00001030, 0x00000268, 0x000004d0},
{0x00001070, 0x0000018c, 0x00000318},
@ -33,13 +33,6 @@ static const u32 ar9462_modes_fast_clock_2p0[][3] = {
{0x0000a254, 0x00000898, 0x00001130},
};
static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18253ede},
{0x00018c04, 0x000801d8},
{0x00018c08, 0x0003780c},
};
static const u32 ar9462_2p0_baseband_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d},
@ -99,7 +92,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
};
static const u32 ar9462_common_rx_gain_table_2p0[][2] = {
static const u32 ar9462_2p0_common_rx_gain[][2] = {
/* Addr allmodes */
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},
@ -359,20 +352,13 @@ static const u32 ar9462_common_rx_gain_table_2p0[][2] = {
{0x0000b1fc, 0x00000196},
};
static const u32 ar9462_pciephy_clkreq_disable_L1_2p0[][2] = {
static const u32 ar9462_2p0_pciephy_clkreq_disable_L1[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18213ede},
{0x00018c04, 0x000801d8},
{0x00018c08, 0x0003780c},
};
static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18212ede},
{0x00018c04, 0x000801d8},
{0x00018c08, 0x0003780c},
};
static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
@ -380,7 +366,7 @@ static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
};
static const u32 ar9462_common_wo_xlna_rx_gain_table_2p0[][2] = {
static const u32 ar9462_2p0_common_wo_xlna_rx_gain[][2] = {
/* Addr allmodes */
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},
@ -647,7 +633,7 @@ static const u32 ar9462_2p0_baseband_core_txfir_coeff_japan_2484[][2] = {
{0x0000a3a0, 0xca9228ee},
};
static const u32 ar9462_modes_low_ob_db_tx_gain_table_2p0[][5] = {
static const u32 ar9462_2p0_modes_low_ob_db_tx_gain[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
@ -879,7 +865,7 @@ static const u32 ar9462_2p0_radio_postamble[][5] = {
{0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
};
static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = {
static const u32 ar9462_2p0_modes_mix_ob_db_tx_gain[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
@ -942,7 +928,7 @@ static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = {
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
};
static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
static const u32 ar9462_2p0_modes_high_ob_db_tx_gain[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
@ -1252,7 +1238,7 @@ static const u32 ar9462_2p0_mac_postamble[][5] = {
{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
};
static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = {
static const u32 ar9462_2p0_common_mixed_rx_gain[][2] = {
/* Addr allmodes */
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},
@ -1517,7 +1503,7 @@ static const u32 ar9462_2p0_baseband_postamble_5g_xlna[][5] = {
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
};
static const u32 ar9462_2p0_5g_xlna_only_rxgain[][2] = {
static const u32 ar9462_2p0_common_5g_xlna_only_rxgain[][2] = {
/* Addr allmodes */
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2010-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* 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.
*/
#ifndef INITVALS_9565_1P1_H
#define INITVALS_9565_1P1_H
/* AR9565 1.1 */
#define ar9565_1p1_mac_core ar9565_1p0_mac_core
#define ar9565_1p1_mac_postamble ar9565_1p0_mac_postamble
#define ar9565_1p1_baseband_core ar9565_1p0_baseband_core
#define ar9565_1p1_baseband_postamble ar9565_1p0_baseband_postamble
#define ar9565_1p1_radio_core ar9565_1p0_radio_core
#define ar9565_1p1_soc_preamble ar9565_1p0_soc_preamble
#define ar9565_1p1_soc_postamble ar9565_1p0_soc_postamble
#define ar9565_1p1_Common_rx_gain_table ar9565_1p0_Common_rx_gain_table
#define ar9565_1p1_Modes_lowest_ob_db_tx_gain_table ar9565_1p0_Modes_lowest_ob_db_tx_gain_table
#define ar9565_1p1_pciephy_clkreq_disable_L1 ar9565_1p0_pciephy_clkreq_disable_L1
#define ar9565_1p1_modes_fast_clock ar9565_1p0_modes_fast_clock
#define ar9565_1p1_common_wo_xlna_rx_gain_table ar9565_1p0_common_wo_xlna_rx_gain_table
#define ar9565_1p1_modes_low_ob_db_tx_gain_table ar9565_1p0_modes_low_ob_db_tx_gain_table
#define ar9565_1p1_modes_high_ob_db_tx_gain_table ar9565_1p0_modes_high_ob_db_tx_gain_table
#define ar9565_1p1_modes_high_power_tx_gain_table ar9565_1p0_modes_high_power_tx_gain_table
#define ar9565_1p1_baseband_core_txfir_coeff_japan_2484 ar9565_1p0_baseband_core_txfir_coeff_japan_2484
static const u32 ar9565_1p1_radio_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524},
{0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
{0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70},
{0x0001610c, 0x40000000, 0x40000000, 0x40000000, 0x40000000},
{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
};
#endif /* INITVALS_9565_1P1_H */

View file

@ -20,18 +20,34 @@
/* AR9580 1.0 */
#define ar9580_1p0_soc_preamble ar9300_2p2_soc_preamble
#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble
#define ar9580_1p0_radio_core ar9300_2p2_radio_core
#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble
#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2
#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2
#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2
#define ar9580_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2
#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484
static const u32 ar9580_1p0_radio_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
{0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
{0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
{0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
{0x0001610c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
{0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
{0x0001650c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
{0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
{0x0001690c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
};
@ -44,9 +60,9 @@ static const u32 ar9580_1p0_baseband_core[][2] = {
{0x00009814, 0x3280c00a},
{0x00009818, 0x00000000},
{0x0000981c, 0x00020028},
{0x00009834, 0x6400a290},
{0x00009834, 0x6400a190},
{0x00009838, 0x0108ecff},
{0x0000983c, 0x0d000600},
{0x0000983c, 0x14000600},
{0x00009880, 0x201fff00},
{0x00009884, 0x00001042},
{0x000098a4, 0x00200400},
@ -67,7 +83,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = {
{0x00009d04, 0x40206c10},
{0x00009d08, 0x009c4060},
{0x00009d0c, 0x9883800a},
{0x00009d10, 0x01834061},
{0x00009d10, 0x01884061},
{0x00009d14, 0x00c0040b},
{0x00009d18, 0x00000000},
{0x00009e08, 0x0038230c},
@ -198,8 +214,6 @@ static const u32 ar9580_1p0_baseband_core[][2] = {
{0x0000c420, 0x00000000},
};
#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble
static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
@ -306,7 +320,112 @@ static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = {
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
#define ar9580_1p0_high_power_tx_gain_table ar9580_1p0_low_ob_db_tx_gain_table
static const u32 ar9580_1p0_high_power_tx_gain_table[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
{0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
{0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
{0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
{0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
{0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
{0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
{0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
{0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
{0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
{0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
{0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
{0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
{0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
{0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
{0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
{0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
{0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
{0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
{0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
{0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
{0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
{0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
{0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202},
{0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400},
{0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402},
{0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404},
{0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603},
{0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02},
{0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04},
{0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20},
{0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20},
{0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22},
{0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24},
{0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640},
{0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660},
{0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861},
{0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81},
{0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83},
{0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84},
{0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3},
{0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5},
{0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9},
{0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb},
{0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
{0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
{0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
{0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
{0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
{0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
{0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
{0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
{0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
{0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
{0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
{0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
{0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
{0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
{0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
{0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
{0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016288, 0x05a2040a, 0x05a2040a, 0x05a20408, 0x05a20408},
{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
@ -414,8 +533,6 @@ static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = {
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484
static const u32 ar9580_1p0_mac_core[][2] = {
/* Addr allmodes */
{0x00000008, 0x00000000},
@ -679,14 +796,6 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = {
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2
#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble
#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2
#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2
static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
@ -761,160 +870,264 @@ static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
static const u32 ar9580_1p0_soc_preamble[][2] = {
static const u32 ar9580_1p0_rx_gain_table[][2] = {
/* Addr allmodes */
{0x000040a4, 0x00a0c1c9},
{0x00007008, 0x00000000},
{0x00007020, 0x00000000},
{0x00007034, 0x00000002},
{0x00007038, 0x000004c2},
{0x00007048, 0x00000008},
};
#define ar9580_1p0_rx_gain_table ar9462_common_rx_gain_table_2p0
static const u32 ar9580_1p0_radio_core[][2] = {
/* Addr allmodes */
{0x00016000, 0x36db6db6},
{0x00016004, 0x6db6db40},
{0x00016008, 0x73f00000},
{0x0001600c, 0x00000000},
{0x00016040, 0x7f80fff8},
{0x0001604c, 0x76d005b5},
{0x00016050, 0x556cf031},
{0x00016054, 0x13449440},
{0x00016058, 0x0c51c92c},
{0x0001605c, 0x3db7fffc},
{0x00016060, 0xfffffffc},
{0x00016064, 0x000f0278},
{0x0001606c, 0x6db60000},
{0x00016080, 0x00000000},
{0x00016084, 0x0e48048c},
{0x00016088, 0x54214514},
{0x0001608c, 0x119f481e},
{0x00016090, 0x24926490},
{0x00016098, 0xd2888888},
{0x000160a0, 0x0a108ffe},
{0x000160a4, 0x812fc370},
{0x000160a8, 0x423c8000},
{0x000160b4, 0x92480080},
{0x000160c0, 0x00adb6d0},
{0x000160c4, 0x6db6db60},
{0x000160c8, 0x6db6db6c},
{0x000160cc, 0x01e6c000},
{0x00016100, 0x3fffbe01},
{0x00016104, 0xfff80000},
{0x00016108, 0x00080010},
{0x00016144, 0x02084080},
{0x00016148, 0x00000000},
{0x00016280, 0x058a0001},
{0x00016284, 0x3d840208},
{0x00016288, 0x05a20408},
{0x0001628c, 0x00038c07},
{0x00016290, 0x00000004},
{0x00016294, 0x458aa14f},
{0x00016380, 0x00000000},
{0x00016384, 0x00000000},
{0x00016388, 0x00800700},
{0x0001638c, 0x00800700},
{0x00016390, 0x00800700},
{0x00016394, 0x00000000},
{0x00016398, 0x00000000},
{0x0001639c, 0x00000000},
{0x000163a0, 0x00000001},
{0x000163a4, 0x00000001},
{0x000163a8, 0x00000000},
{0x000163ac, 0x00000000},
{0x000163b0, 0x00000000},
{0x000163b4, 0x00000000},
{0x000163b8, 0x00000000},
{0x000163bc, 0x00000000},
{0x000163c0, 0x000000a0},
{0x000163c4, 0x000c0000},
{0x000163c8, 0x14021402},
{0x000163cc, 0x00001402},
{0x000163d0, 0x00000000},
{0x000163d4, 0x00000000},
{0x00016400, 0x36db6db6},
{0x00016404, 0x6db6db40},
{0x00016408, 0x73f00000},
{0x0001640c, 0x00000000},
{0x00016440, 0x7f80fff8},
{0x0001644c, 0x76d005b5},
{0x00016450, 0x556cf031},
{0x00016454, 0x13449440},
{0x00016458, 0x0c51c92c},
{0x0001645c, 0x3db7fffc},
{0x00016460, 0xfffffffc},
{0x00016464, 0x000f0278},
{0x0001646c, 0x6db60000},
{0x00016500, 0x3fffbe01},
{0x00016504, 0xfff80000},
{0x00016508, 0x00080010},
{0x00016544, 0x02084080},
{0x00016548, 0x00000000},
{0x00016780, 0x00000000},
{0x00016784, 0x00000000},
{0x00016788, 0x00800700},
{0x0001678c, 0x00800700},
{0x00016790, 0x00800700},
{0x00016794, 0x00000000},
{0x00016798, 0x00000000},
{0x0001679c, 0x00000000},
{0x000167a0, 0x00000001},
{0x000167a4, 0x00000001},
{0x000167a8, 0x00000000},
{0x000167ac, 0x00000000},
{0x000167b0, 0x00000000},
{0x000167b4, 0x00000000},
{0x000167b8, 0x00000000},
{0x000167bc, 0x00000000},
{0x000167c0, 0x000000a0},
{0x000167c4, 0x000c0000},
{0x000167c8, 0x14021402},
{0x000167cc, 0x00001402},
{0x000167d0, 0x00000000},
{0x000167d4, 0x00000000},
{0x00016800, 0x36db6db6},
{0x00016804, 0x6db6db40},
{0x00016808, 0x73f00000},
{0x0001680c, 0x00000000},
{0x00016840, 0x7f80fff8},
{0x0001684c, 0x76d005b5},
{0x00016850, 0x556cf031},
{0x00016854, 0x13449440},
{0x00016858, 0x0c51c92c},
{0x0001685c, 0x3db7fffc},
{0x00016860, 0xfffffffc},
{0x00016864, 0x000f0278},
{0x0001686c, 0x6db60000},
{0x00016900, 0x3fffbe01},
{0x00016904, 0xfff80000},
{0x00016908, 0x00080010},
{0x00016944, 0x02084080},
{0x00016948, 0x00000000},
{0x00016b80, 0x00000000},
{0x00016b84, 0x00000000},
{0x00016b88, 0x00800700},
{0x00016b8c, 0x00800700},
{0x00016b90, 0x00800700},
{0x00016b94, 0x00000000},
{0x00016b98, 0x00000000},
{0x00016b9c, 0x00000000},
{0x00016ba0, 0x00000001},
{0x00016ba4, 0x00000001},
{0x00016ba8, 0x00000000},
{0x00016bac, 0x00000000},
{0x00016bb0, 0x00000000},
{0x00016bb4, 0x00000000},
{0x00016bb8, 0x00000000},
{0x00016bbc, 0x00000000},
{0x00016bc0, 0x000000a0},
{0x00016bc4, 0x000c0000},
{0x00016bc8, 0x14021402},
{0x00016bcc, 0x00001402},
{0x00016bd0, 0x00000000},
{0x00016bd4, 0x00000000},
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},
{0x0000a008, 0x00050004},
{0x0000a00c, 0x00810080},
{0x0000a010, 0x00830082},
{0x0000a014, 0x01810180},
{0x0000a018, 0x01830182},
{0x0000a01c, 0x01850184},
{0x0000a020, 0x01890188},
{0x0000a024, 0x018b018a},
{0x0000a028, 0x018d018c},
{0x0000a02c, 0x01910190},
{0x0000a030, 0x01930192},
{0x0000a034, 0x01950194},
{0x0000a038, 0x038a0196},
{0x0000a03c, 0x038c038b},
{0x0000a040, 0x0390038d},
{0x0000a044, 0x03920391},
{0x0000a048, 0x03940393},
{0x0000a04c, 0x03960395},
{0x0000a050, 0x00000000},
{0x0000a054, 0x00000000},
{0x0000a058, 0x00000000},
{0x0000a05c, 0x00000000},
{0x0000a060, 0x00000000},
{0x0000a064, 0x00000000},
{0x0000a068, 0x00000000},
{0x0000a06c, 0x00000000},
{0x0000a070, 0x00000000},
{0x0000a074, 0x00000000},
{0x0000a078, 0x00000000},
{0x0000a07c, 0x00000000},
{0x0000a080, 0x22222229},
{0x0000a084, 0x1d1d1d1d},
{0x0000a088, 0x1d1d1d1d},
{0x0000a08c, 0x1d1d1d1d},
{0x0000a090, 0x171d1d1d},
{0x0000a094, 0x11111717},
{0x0000a098, 0x00030311},
{0x0000a09c, 0x00000000},
{0x0000a0a0, 0x00000000},
{0x0000a0a4, 0x00000000},
{0x0000a0a8, 0x00000000},
{0x0000a0ac, 0x00000000},
{0x0000a0b0, 0x00000000},
{0x0000a0b4, 0x00000000},
{0x0000a0b8, 0x00000000},
{0x0000a0bc, 0x00000000},
{0x0000a0c0, 0x001f0000},
{0x0000a0c4, 0x01000101},
{0x0000a0c8, 0x011e011f},
{0x0000a0cc, 0x011c011d},
{0x0000a0d0, 0x02030204},
{0x0000a0d4, 0x02010202},
{0x0000a0d8, 0x021f0200},
{0x0000a0dc, 0x0302021e},
{0x0000a0e0, 0x03000301},
{0x0000a0e4, 0x031e031f},
{0x0000a0e8, 0x0402031d},
{0x0000a0ec, 0x04000401},
{0x0000a0f0, 0x041e041f},
{0x0000a0f4, 0x0502041d},
{0x0000a0f8, 0x05000501},
{0x0000a0fc, 0x051e051f},
{0x0000a100, 0x06010602},
{0x0000a104, 0x061f0600},
{0x0000a108, 0x061d061e},
{0x0000a10c, 0x07020703},
{0x0000a110, 0x07000701},
{0x0000a114, 0x00000000},
{0x0000a118, 0x00000000},
{0x0000a11c, 0x00000000},
{0x0000a120, 0x00000000},
{0x0000a124, 0x00000000},
{0x0000a128, 0x00000000},
{0x0000a12c, 0x00000000},
{0x0000a130, 0x00000000},
{0x0000a134, 0x00000000},
{0x0000a138, 0x00000000},
{0x0000a13c, 0x00000000},
{0x0000a140, 0x001f0000},
{0x0000a144, 0x01000101},
{0x0000a148, 0x011e011f},
{0x0000a14c, 0x011c011d},
{0x0000a150, 0x02030204},
{0x0000a154, 0x02010202},
{0x0000a158, 0x021f0200},
{0x0000a15c, 0x0302021e},
{0x0000a160, 0x03000301},
{0x0000a164, 0x031e031f},
{0x0000a168, 0x0402031d},
{0x0000a16c, 0x04000401},
{0x0000a170, 0x041e041f},
{0x0000a174, 0x0502041d},
{0x0000a178, 0x05000501},
{0x0000a17c, 0x051e051f},
{0x0000a180, 0x06010602},
{0x0000a184, 0x061f0600},
{0x0000a188, 0x061d061e},
{0x0000a18c, 0x07020703},
{0x0000a190, 0x07000701},
{0x0000a194, 0x00000000},
{0x0000a198, 0x00000000},
{0x0000a19c, 0x00000000},
{0x0000a1a0, 0x00000000},
{0x0000a1a4, 0x00000000},
{0x0000a1a8, 0x00000000},
{0x0000a1ac, 0x00000000},
{0x0000a1b0, 0x00000000},
{0x0000a1b4, 0x00000000},
{0x0000a1b8, 0x00000000},
{0x0000a1bc, 0x00000000},
{0x0000a1c0, 0x00000000},
{0x0000a1c4, 0x00000000},
{0x0000a1c8, 0x00000000},
{0x0000a1cc, 0x00000000},
{0x0000a1d0, 0x00000000},
{0x0000a1d4, 0x00000000},
{0x0000a1d8, 0x00000000},
{0x0000a1dc, 0x00000000},
{0x0000a1e0, 0x00000000},
{0x0000a1e4, 0x00000000},
{0x0000a1e8, 0x00000000},
{0x0000a1ec, 0x00000000},
{0x0000a1f0, 0x00000396},
{0x0000a1f4, 0x00000396},
{0x0000a1f8, 0x00000396},
{0x0000a1fc, 0x00000196},
{0x0000b000, 0x00010000},
{0x0000b004, 0x00030002},
{0x0000b008, 0x00050004},
{0x0000b00c, 0x00810080},
{0x0000b010, 0x00830082},
{0x0000b014, 0x01810180},
{0x0000b018, 0x01830182},
{0x0000b01c, 0x01850184},
{0x0000b020, 0x02810280},
{0x0000b024, 0x02830282},
{0x0000b028, 0x02850284},
{0x0000b02c, 0x02890288},
{0x0000b030, 0x028b028a},
{0x0000b034, 0x0388028c},
{0x0000b038, 0x038a0389},
{0x0000b03c, 0x038c038b},
{0x0000b040, 0x0390038d},
{0x0000b044, 0x03920391},
{0x0000b048, 0x03940393},
{0x0000b04c, 0x03960395},
{0x0000b050, 0x00000000},
{0x0000b054, 0x00000000},
{0x0000b058, 0x00000000},
{0x0000b05c, 0x00000000},
{0x0000b060, 0x00000000},
{0x0000b064, 0x00000000},
{0x0000b068, 0x00000000},
{0x0000b06c, 0x00000000},
{0x0000b070, 0x00000000},
{0x0000b074, 0x00000000},
{0x0000b078, 0x00000000},
{0x0000b07c, 0x00000000},
{0x0000b080, 0x23232323},
{0x0000b084, 0x21232323},
{0x0000b088, 0x19191c1e},
{0x0000b08c, 0x12141417},
{0x0000b090, 0x07070e0e},
{0x0000b094, 0x03030305},
{0x0000b098, 0x00000003},
{0x0000b09c, 0x00000000},
{0x0000b0a0, 0x00000000},
{0x0000b0a4, 0x00000000},
{0x0000b0a8, 0x00000000},
{0x0000b0ac, 0x00000000},
{0x0000b0b0, 0x00000000},
{0x0000b0b4, 0x00000000},
{0x0000b0b8, 0x00000000},
{0x0000b0bc, 0x00000000},
{0x0000b0c0, 0x003f0020},
{0x0000b0c4, 0x00400041},
{0x0000b0c8, 0x0140005f},
{0x0000b0cc, 0x0160015f},
{0x0000b0d0, 0x017e017f},
{0x0000b0d4, 0x02410242},
{0x0000b0d8, 0x025f0240},
{0x0000b0dc, 0x027f0260},
{0x0000b0e0, 0x0341027e},
{0x0000b0e4, 0x035f0340},
{0x0000b0e8, 0x037f0360},
{0x0000b0ec, 0x04400441},
{0x0000b0f0, 0x0460045f},
{0x0000b0f4, 0x0541047f},
{0x0000b0f8, 0x055f0540},
{0x0000b0fc, 0x057f0560},
{0x0000b100, 0x06400641},
{0x0000b104, 0x0660065f},
{0x0000b108, 0x067e067f},
{0x0000b10c, 0x07410742},
{0x0000b110, 0x075f0740},
{0x0000b114, 0x077f0760},
{0x0000b118, 0x07800781},
{0x0000b11c, 0x07a0079f},
{0x0000b120, 0x07c107bf},
{0x0000b124, 0x000007c0},
{0x0000b128, 0x00000000},
{0x0000b12c, 0x00000000},
{0x0000b130, 0x00000000},
{0x0000b134, 0x00000000},
{0x0000b138, 0x00000000},
{0x0000b13c, 0x00000000},
{0x0000b140, 0x003f0020},
{0x0000b144, 0x00400041},
{0x0000b148, 0x0140005f},
{0x0000b14c, 0x0160015f},
{0x0000b150, 0x017e017f},
{0x0000b154, 0x02410242},
{0x0000b158, 0x025f0240},
{0x0000b15c, 0x027f0260},
{0x0000b160, 0x0341027e},
{0x0000b164, 0x035f0340},
{0x0000b168, 0x037f0360},
{0x0000b16c, 0x04400441},
{0x0000b170, 0x0460045f},
{0x0000b174, 0x0541047f},
{0x0000b178, 0x055f0540},
{0x0000b17c, 0x057f0560},
{0x0000b180, 0x06400641},
{0x0000b184, 0x0660065f},
{0x0000b188, 0x067e067f},
{0x0000b18c, 0x07410742},
{0x0000b190, 0x075f0740},
{0x0000b194, 0x077f0760},
{0x0000b198, 0x07800781},
{0x0000b19c, 0x07a0079f},
{0x0000b1a0, 0x07c107bf},
{0x0000b1a4, 0x000007c0},
{0x0000b1a8, 0x00000000},
{0x0000b1ac, 0x00000000},
{0x0000b1b0, 0x00000000},
{0x0000b1b4, 0x00000000},
{0x0000b1b8, 0x00000000},
{0x0000b1bc, 0x00000000},
{0x0000b1c0, 0x00000000},
{0x0000b1c4, 0x00000000},
{0x0000b1c8, 0x00000000},
{0x0000b1cc, 0x00000000},
{0x0000b1d0, 0x00000000},
{0x0000b1d4, 0x00000000},
{0x0000b1d8, 0x00000000},
{0x0000b1dc, 0x00000000},
{0x0000b1e0, 0x00000000},
{0x0000b1e4, 0x00000000},
{0x0000b1e8, 0x00000000},
{0x0000b1ec, 0x00000000},
{0x0000b1f0, 0x00000396},
{0x0000b1f4, 0x00000396},
{0x0000b1f8, 0x00000396},
{0x0000b1fc, 0x00000196},
};
static const u32 ar9580_1p0_baseband_postamble[][5] = {
@ -956,7 +1169,7 @@ static const u32 ar9580_1p0_baseband_postamble[][5] = {
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
{0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982},
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},

View file

@ -459,6 +459,7 @@ void ath_check_ani(struct ath_softc *sc);
int ath_update_survey_stats(struct ath_softc *sc);
void ath_update_survey_nf(struct ath_softc *sc, int channel);
void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
void ath_ps_full_sleep(unsigned long data);
/**********/
/* BTCOEX */
@ -570,6 +571,34 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)
}
#endif
/************************/
/* Wake on Wireless LAN */
/************************/
#ifdef CONFIG_ATH9K_WOW
void ath9k_init_wow(struct ieee80211_hw *hw);
int ath9k_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan);
int ath9k_resume(struct ieee80211_hw *hw);
void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled);
#else
static inline void ath9k_init_wow(struct ieee80211_hw *hw)
{
}
static inline int ath9k_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan)
{
return 0;
}
static inline int ath9k_resume(struct ieee80211_hw *hw)
{
return 0;
}
static inline void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
{
}
#endif /* CONFIG_ATH9K_WOW */
/*******************************/
/* Antenna diversity/combining */
/*******************************/
@ -642,6 +671,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
#define ATH9K_PCI_AR9565_1ANT 0x0080
#define ATH9K_PCI_AR9565_2ANT 0x0100
#define ATH9K_PCI_NO_PLL_PWRSAVE 0x0200
#define ATH9K_PCI_KILLER 0x0400
/*
* Default cache line size, in bytes.
@ -724,6 +754,7 @@ struct ath_softc {
struct work_struct hw_check_work;
struct work_struct hw_reset_work;
struct completion paprd_complete;
wait_queue_head_t tx_wait;
unsigned int hw_busy_count;
unsigned long sc_flags;
@ -760,6 +791,7 @@ struct ath_softc {
struct delayed_work tx_complete_work;
struct delayed_work hw_pll_work;
struct timer_list rx_poll_timer;
struct timer_list sleep_timer;
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
struct ath_btcoex btcoex;
@ -784,7 +816,7 @@ struct ath_softc {
bool tx99_state;
s16 tx99_power;
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_ATH9K_WOW
atomic_t wow_got_bmiss_intr;
atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */
u32 wow_intr_before_sleep;
@ -947,10 +979,25 @@ struct fft_sample_ht20_40 {
u8 data[SPECTRAL_HT20_40_NUM_BINS];
} __packed;
int ath9k_tx99_init(struct ath_softc *sc);
void ath9k_tx99_deinit(struct ath_softc *sc);
/********/
/* TX99 */
/********/
#ifdef CONFIG_ATH9K_TX99
void ath9k_tx99_init_debug(struct ath_softc *sc);
int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
struct ath_tx_control *txctl);
#else
static inline void ath9k_tx99_init_debug(struct ath_softc *sc)
{
}
static inline int ath9k_tx99_send(struct ath_softc *sc,
struct sk_buff *skb,
struct ath_tx_control *txctl)
{
return 0;
}
#endif /* CONFIG_ATH9K_TX99 */
void ath9k_tasklet(unsigned long data);
int ath_cabq_update(struct ath_softc *);
@ -967,6 +1014,9 @@ extern bool is_ath9k_unloaded;
u8 ath9k_parse_mpdudensity(u8 mpdudensity);
irqreturn_t ath_isr(int irq, void *dev);
int ath_reset(struct ath_softc *sc);
void ath_cancel_work(struct ath_softc *sc);
void ath_restart_work(struct ath_softc *sc);
int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops);
void ath9k_deinit_device(struct ath_softc *sc);

View file

@ -1778,111 +1778,6 @@ void ath9k_deinit_debug(struct ath_softc *sc)
}
}
static ssize_t read_file_tx99(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[3];
unsigned int len;
len = sprintf(buf, "%d\n", sc->tx99_state);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32];
bool start;
ssize_t len;
int r;
if (sc->nvifs > 1)
return -EOPNOTSUPP;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
if (strtobool(buf, &start))
return -EINVAL;
if (start == sc->tx99_state) {
if (!start)
return count;
ath_dbg(common, XMIT, "Resetting TX99\n");
ath9k_tx99_deinit(sc);
}
if (!start) {
ath9k_tx99_deinit(sc);
return count;
}
r = ath9k_tx99_init(sc);
if (r)
return r;
return count;
}
static const struct file_operations fops_tx99 = {
.read = read_file_tx99,
.write = write_file_tx99,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_tx99_power(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d (%d dBm)\n",
sc->tx99_power,
sc->tx99_power / 2);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_tx99_power(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
int r;
u8 tx_power;
r = kstrtou8_from_user(user_buf, count, 0, &tx_power);
if (r)
return r;
if (tx_power > MAX_RATE_POWER)
return -EINVAL;
sc->tx99_power = tx_power;
ath9k_ps_wakeup(sc);
ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power);
ath9k_ps_restore(sc);
return count;
}
static const struct file_operations fops_tx99_power = {
.read = read_file_tx99_power,
.write = write_file_tx99_power,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
@ -1899,6 +1794,7 @@ int ath9k_init_debug(struct ath_hw *ah)
#endif
ath9k_dfs_init_debug(sc);
ath9k_tx99_init_debug(sc);
debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_dma);
@ -1974,15 +1870,6 @@ int ath9k_init_debug(struct ath_hw *ah)
debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_btcoex);
#endif
if (config_enabled(CONFIG_ATH9K_TX99) &&
AR_SREV_9300_20_OR_LATER(ah)) {
debugfs_create_file("tx99", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_tx99);
debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_tx99_power);
}
return 0;
}

View file

@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/time.h>
#include <asm/unaligned.h>
#include "hw.h"
@ -453,7 +454,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
}
ah->config.rx_intr_mitigation = true;
ah->config.pcieSerDesWrite = true;
/*
* We need this for PCI devices only (Cardbus, PCI, miniPCI)
@ -1501,8 +1501,9 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
int r;
if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) {
band_switch = IS_CHAN_5GHZ(ah->curchan) != IS_CHAN_5GHZ(chan);
mode_diff = (chan->channelFlags != ah->curchan->channelFlags);
u32 flags_diff = chan->channelFlags ^ ah->curchan->channelFlags;
band_switch = !!(flags_diff & CHANNEL_5GHZ);
mode_diff = !!(flags_diff & ~CHANNEL_HT);
}
for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
@ -1814,7 +1815,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
* If cross-band fcc is not supoprted, bail out if channelFlags differ.
*/
if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) &&
chan->channelFlags != ah->curchan->channelFlags)
((chan->channelFlags ^ ah->curchan->channelFlags) & ~CHANNEL_HT))
goto fail;
if (!ath9k_hw_check_alive(ah))
@ -1855,10 +1856,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool fastcc)
{
struct ath_common *common = ath9k_hw_common(ah);
struct timespec ts;
u32 saveLedState;
u32 saveDefAntenna;
u32 macStaId1;
u64 tsf = 0;
s64 usec = 0;
int r;
bool start_mci_reset = false;
bool save_fullsleep = ah->chip_fullsleep;
@ -1901,10 +1904,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
/* For chips on which RTC reset is done, save TSF before it gets cleared */
if (AR_SREV_9100(ah) ||
(AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)))
tsf = ath9k_hw_gettsf64(ah);
/* Save TSF before chip reset, a cold reset clears it */
tsf = ath9k_hw_gettsf64(ah);
getrawmonotonic(&ts);
usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000;
saveLedState = REG_READ(ah, AR_CFG_LED) &
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@ -1937,8 +1940,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
}
/* Restore TSF */
if (tsf)
ath9k_hw_settsf64(ah, tsf);
getrawmonotonic(&ts);
usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000 - usec;
ath9k_hw_settsf64(ah, tsf + usec);
if (AR_SREV_9280_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);

View file

@ -283,7 +283,6 @@ struct ath9k_ops_config {
int additional_swba_backoff;
int ack_6mb;
u32 cwm_ignore_extcca;
bool pcieSerDesWrite;
u8 pcie_clock_req;
u32 pcie_waen;
u8 analog_shiftreg;
@ -921,7 +920,7 @@ struct ath_hw {
/* Enterprise mode cap */
u32 ent_mode;
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_ATH9K_WOW
u32 wow_event_mask;
#endif
bool is_clk_25mhz;
@ -1127,7 +1126,7 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_ATH9K_WOW
const char *ath9k_hw_wow_event_to_string(u32 wow_event);
void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
u8 *user_mask, int pattern_count,

View file

@ -589,6 +589,9 @@ static void ath9k_init_platform(struct ath_softc *sc)
if (sc->driver_data & ATH9K_PCI_AR9565_2ANT)
ath_info(common, "WB335 2-ANT card detected\n");
if (sc->driver_data & ATH9K_PCI_KILLER)
ath_info(common, "Killer Wireless card detected\n");
/*
* Some WB335 cards do not support antenna diversity. Since
* we use a hardcoded value for AR9565 instead of using the
@ -688,6 +691,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
common = ath9k_hw_common(ah);
sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
sc->tx99_power = MAX_RATE_POWER + 1;
init_waitqueue_head(&sc->tx_wait);
if (!pdata) {
ah->ah_flags |= AH_USE_EEPROM;
@ -735,6 +739,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
(unsigned long)sc);
setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (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);
@ -873,15 +878,6 @@ static const struct ieee80211_iface_combination if_comb[] = {
}
};
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support ath9k_wowlan_support = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
.n_patterns = MAX_NUM_USER_PATTERN,
.pattern_min_len = 1,
.pattern_max_len = MAX_PATTERN_SIZE,
};
#endif
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
@ -931,16 +927,6 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
#ifdef CONFIG_PM_SLEEP
if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
(sc->driver_data & ATH9K_PCI_WOW) &&
device_can_wakeup(sc->dev))
hw->wiphy->wowlan = &ath9k_wowlan_support;
atomic_set(&sc->wow_sleep_proc_intr, -1);
atomic_set(&sc->wow_got_bmiss_intr, -1);
#endif
hw->queues = 4;
hw->max_rates = 4;
hw->channel_change_time = 5000;
@ -966,6 +952,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&sc->sbands[IEEE80211_BAND_5GHZ];
ath9k_init_wow(hw);
ath9k_reload_chainmask_settings(sc);
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
@ -1064,6 +1051,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
del_timer_sync(&sc->sleep_timer);
ath9k_hw_deinit(sc->sc_ah);
if (sc->dfs_detector != NULL)
sc->dfs_detector->exit(sc->dfs_detector);

View file

@ -82,6 +82,22 @@ static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
return ret;
}
void ath_ps_full_sleep(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *) data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
bool reset;
spin_lock(&common->cc_lock);
ath_hw_cycle_counters_update(common);
spin_unlock(&common->cc_lock);
ath9k_hw_setrxabort(sc->sc_ah, 1);
ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
}
void ath9k_ps_wakeup(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@ -92,6 +108,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
if (++sc->ps_usecount != 1)
goto unlock;
del_timer_sync(&sc->sleep_timer);
power_mode = sc->sc_ah->power_mode;
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
@ -117,17 +134,17 @@ void ath9k_ps_restore(struct ath_softc *sc)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
enum ath9k_power_mode mode;
unsigned long flags;
bool reset;
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (--sc->ps_usecount != 0)
goto unlock;
if (sc->ps_idle) {
ath9k_hw_setrxabort(sc->sc_ah, 1);
ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
mode = ATH9K_PM_FULL_SLEEP;
} else if (sc->ps_enabled &&
mod_timer(&sc->sleep_timer, jiffies + HZ / 10);
goto unlock;
}
if (sc->ps_enabled &&
!(sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA |
@ -163,13 +180,13 @@ static void __ath_cancel_work(struct ath_softc *sc)
#endif
}
static void ath_cancel_work(struct ath_softc *sc)
void ath_cancel_work(struct ath_softc *sc)
{
__ath_cancel_work(sc);
cancel_work_sync(&sc->hw_reset_work);
}
static void ath_restart_work(struct ath_softc *sc)
void ath_restart_work(struct ath_softc *sc)
{
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
@ -487,6 +504,8 @@ void ath9k_tasklet(unsigned long data)
ath_tx_edma_tasklet(sc);
else
ath_tx_tasklet(sc);
wake_up(&sc->tx_wait);
}
ath9k_btcoex_handle_interrupt(sc, status);
@ -579,7 +598,8 @@ irqreturn_t ath_isr(int irq, void *dev)
goto chip_reset;
}
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_ATH9K_WOW
if (status & ATH9K_INT_BMISS) {
if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
ath_dbg(common, ANY, "during WoW we got a BMISS\n");
@ -588,6 +608,8 @@ irqreturn_t ath_isr(int irq, void *dev)
}
}
#endif
if (status & ATH9K_INT_SWBA)
tasklet_schedule(&sc->bcon_tasklet);
@ -627,7 +649,7 @@ chip_reset:
#undef SCHED_INTR
}
static int ath_reset(struct ath_softc *sc)
int ath_reset(struct ath_softc *sc)
{
int r;
@ -1817,13 +1839,31 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
mutex_unlock(&sc->mutex);
}
static bool ath9k_has_tx_pending(struct ath_softc *sc)
{
int i, npend;
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (!ATH_TXQ_SETUP(sc, i))
continue;
if (!sc->tx.txq[i].axq_depth)
continue;
npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
if (npend)
break;
}
return !!npend;
}
static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
int timeout = 200; /* ms */
int i, j;
int timeout = HZ / 5; /* 200 ms */
bool drain_txq;
mutex_lock(&sc->mutex);
@ -1841,25 +1881,9 @@ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
return;
}
for (j = 0; j < timeout; j++) {
bool npend = false;
if (j)
usleep_range(1000, 2000);
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (!ATH_TXQ_SETUP(sc, i))
continue;
npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
if (npend)
break;
}
if (!npend)
break;
}
if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc),
timeout) > 0)
drop = false;
if (drop) {
ath9k_ps_wakeup(sc);
@ -2021,333 +2045,6 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static void ath9k_wow_map_triggers(struct ath_softc *sc,
struct cfg80211_wowlan *wowlan,
u32 *wow_triggers)
{
if (wowlan->disconnect)
*wow_triggers |= AH_WOW_LINK_CHANGE |
AH_WOW_BEACON_MISS;
if (wowlan->magic_pkt)
*wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
if (wowlan->n_patterns)
*wow_triggers |= AH_WOW_USER_PATTERN_EN;
sc->wow_enabled = *wow_triggers;
}
static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
int pattern_count = 0;
int i, byte_cnt;
u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
u8 dis_deauth_mask[MAX_PATTERN_SIZE];
memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);
memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);
/*
* Create Dissassociate / Deauthenticate packet filter
*
* 2 bytes 2 byte 6 bytes 6 bytes 6 bytes
* +--------------+----------+---------+--------+--------+----
* + Frame Control+ Duration + DA + SA + BSSID +
* +--------------+----------+---------+--------+--------+----
*
* The above is the management frame format for disassociate/
* deauthenticate pattern, from this we need to match the first byte
* of 'Frame Control' and DA, SA, and BSSID fields
* (skipping 2nd byte of FC and Duration feild.
*
* Disassociate pattern
* --------------------
* Frame control = 00 00 1010
* DA, SA, BSSID = x:x:x:x:x:x
* Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x
* | x:x:x:x:x:x -- 22 bytes
*
* Deauthenticate pattern
* ----------------------
* Frame control = 00 00 1100
* DA, SA, BSSID = x:x:x:x:x:x
* Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x
* | x:x:x:x:x:x -- 22 bytes
*/
/* Create Disassociate Pattern first */
byte_cnt = 0;
/* Fill out the mask with all FF's */
for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
dis_deauth_mask[i] = 0xff;
/* copy the first byte of frame control field */
dis_deauth_pattern[byte_cnt] = 0xa0;
byte_cnt++;
/* skip 2nd byte of frame control and Duration field */
byte_cnt += 3;
/*
* need not match the destination mac address, it can be a broadcast
* mac address or an unicast to this station
*/
byte_cnt += 6;
/* copy the source mac address */
memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
byte_cnt += 6;
/* copy the bssid, its same as the source mac address */
memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
/* Create Disassociate pattern mask */
dis_deauth_mask[0] = 0xfe;
dis_deauth_mask[1] = 0x03;
dis_deauth_mask[2] = 0xc0;
ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
pattern_count, byte_cnt);
pattern_count++;
/*
* for de-authenticate pattern, only the first byte of the frame
* control field gets changed from 0xA0 to 0xC0
*/
dis_deauth_pattern[0] = 0xC0;
ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
pattern_count, byte_cnt);
}
static void ath9k_wow_add_pattern(struct ath_softc *sc,
struct cfg80211_wowlan *wowlan)
{
struct ath_hw *ah = sc->sc_ah;
struct ath9k_wow_pattern *wow_pattern = NULL;
struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
int mask_len;
s8 i = 0;
if (!wowlan->n_patterns)
return;
/*
* Add the new user configured patterns
*/
for (i = 0; i < wowlan->n_patterns; i++) {
wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL);
if (!wow_pattern)
return;
/*
* TODO: convert the generic user space pattern to
* appropriate chip specific/802.11 pattern.
*/
mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE);
memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE);
memcpy(wow_pattern->pattern_bytes, patterns[i].pattern,
patterns[i].pattern_len);
memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len);
wow_pattern->pattern_len = patterns[i].pattern_len;
/*
* just need to take care of deauth and disssoc pattern,
* make sure we don't overwrite them.
*/
ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes,
wow_pattern->mask_bytes,
i + 2,
wow_pattern->pattern_len);
kfree(wow_pattern);
}
}
static int ath9k_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
u32 wow_triggers_enabled = 0;
int ret = 0;
mutex_lock(&sc->mutex);
ath_cancel_work(sc);
ath_stop_ani(sc);
del_timer_sync(&sc->rx_poll_timer);
if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
ath_dbg(common, ANY, "Device not present\n");
ret = -EINVAL;
goto fail_wow;
}
if (WARN_ON(!wowlan)) {
ath_dbg(common, WOW, "None of the WoW triggers enabled\n");
ret = -EINVAL;
goto fail_wow;
}
if (!device_can_wakeup(sc->dev)) {
ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n");
ret = 1;
goto fail_wow;
}
/*
* none of the sta vifs are associated
* and we are not currently handling multivif
* cases, for instance we have to seperately
* configure 'keep alive frame' for each
* STA.
*/
if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
ath_dbg(common, WOW, "None of the STA vifs are associated\n");
ret = 1;
goto fail_wow;
}
if (sc->nvifs > 1) {
ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
ret = 1;
goto fail_wow;
}
ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);
ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",
wow_triggers_enabled);
ath9k_ps_wakeup(sc);
ath9k_stop_btcoex(sc);
/*
* Enable wake up on recieving disassoc/deauth
* frame by default.
*/
ath9k_wow_add_disassoc_deauth_pattern(sc);
if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN)
ath9k_wow_add_pattern(sc, wowlan);
spin_lock_bh(&sc->sc_pcu_lock);
/*
* To avoid false wake, we enable beacon miss interrupt only
* when we go to sleep. We save the current interrupt mask
* so we can restore it after the system wakes up
*/
sc->wow_intr_before_sleep = ah->imask;
ah->imask &= ~ATH9K_INT_GLOBAL;
ath9k_hw_disable_interrupts(ah);
ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
spin_unlock_bh(&sc->sc_pcu_lock);
/*
* we can now sync irq and kill any running tasklets, since we already
* disabled interrupts and not holding a spin lock
*/
synchronize_irq(sc->irq);
tasklet_kill(&sc->intr_tq);
ath9k_hw_wow_enable(ah, wow_triggers_enabled);
ath9k_ps_restore(sc);
ath_dbg(common, ANY, "WoW enabled in ath9k\n");
atomic_inc(&sc->wow_sleep_proc_intr);
fail_wow:
mutex_unlock(&sc->mutex);
return ret;
}
static int ath9k_resume(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
u32 wow_status;
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
spin_lock_bh(&sc->sc_pcu_lock);
ath9k_hw_disable_interrupts(ah);
ah->imask = sc->wow_intr_before_sleep;
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
spin_unlock_bh(&sc->sc_pcu_lock);
wow_status = ath9k_hw_wow_wakeup(ah);
if (atomic_read(&sc->wow_got_bmiss_intr) == 0) {
/*
* some devices may not pick beacon miss
* as the reason they woke up so we add
* that here for that shortcoming.
*/
wow_status |= AH_WOW_BEACON_MISS;
atomic_dec(&sc->wow_got_bmiss_intr);
ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");
}
atomic_dec(&sc->wow_sleep_proc_intr);
if (wow_status) {
ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n",
ath9k_hw_wow_event_to_string(wow_status), wow_status);
}
ath_restart_work(sc);
ath9k_start_btcoex(sc);
ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);
return 0;
}
static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
{
struct ath_softc *sc = hw->priv;
mutex_lock(&sc->mutex);
device_init_wakeup(sc->dev, 1);
device_set_wakeup_enable(sc->dev, enabled);
mutex_unlock(&sc->mutex);
}
#endif
static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
@ -2373,134 +2070,6 @@ static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
sc->csa_vif = vif;
}
static void ath9k_tx99_stop(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
ath_drain_all_txq(sc);
ath_startrecv(sc);
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
ieee80211_wake_queues(sc->hw);
kfree_skb(sc->tx99_skb);
sc->tx99_skb = NULL;
sc->tx99_state = false;
ath9k_hw_tx99_stop(sc->sc_ah);
ath_dbg(common, XMIT, "TX99 stopped\n");
}
static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
{
static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
u32 len = 1200;
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info;
struct sk_buff *skb;
skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
return NULL;
skb_put(skb, len);
memset(skb->data, 0, len);
hdr = (struct ieee80211_hdr *)skb->data;
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
hdr->duration_id = 0;
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);
hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
tx_info = IEEE80211_SKB_CB(skb);
memset(tx_info, 0, sizeof(*tx_info));
tx_info->band = hw->conf.chandef.chan->band;
tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
tx_info->control.vif = sc->tx99_vif;
memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
return skb;
}
void ath9k_tx99_deinit(struct ath_softc *sc)
{
ath_reset(sc);
ath9k_ps_wakeup(sc);
ath9k_tx99_stop(sc);
ath9k_ps_restore(sc);
}
int ath9k_tx99_init(struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_tx_control txctl;
int r;
if (sc->sc_flags & SC_OP_INVALID) {
ath_err(common,
"driver is in invalid state unable to use TX99");
return -EINVAL;
}
sc->tx99_skb = ath9k_build_tx99_skb(sc);
if (!sc->tx99_skb)
return -ENOMEM;
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
ath_reset(sc);
ath9k_ps_wakeup(sc);
ath9k_hw_disable_interrupts(ah);
atomic_set(&ah->intr_ref_cnt, -1);
ath_drain_all_txq(sc);
ath_stoprecv(sc);
sc->tx99_state = true;
ieee80211_stop_queues(hw);
if (sc->tx99_power == MAX_RATE_POWER + 1)
sc->tx99_power = MAX_RATE_POWER;
ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
if (r) {
ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
return r;
}
ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
sc->tx99_power,
sc->tx99_power / 2);
/* We leave the harware awake as it will be chugging on */
return 0;
}
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
@ -2531,7 +2100,7 @@ struct ieee80211_ops ath9k_ops = {
.set_antenna = ath9k_set_antenna,
.get_antenna = ath9k_get_antenna,
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_ATH9K_WOW
.suspend = ath9k_suspend,
.resume = ath9k_resume,
.set_wakeup = ath9k_set_wakeup,

View file

@ -87,6 +87,19 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
{ PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
/* Killer Wireless (3x3) */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0030,
0x1A56,
0x2000),
.driver_data = ATH9K_PCI_KILLER },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0030,
0x1A56,
0x2001),
.driver_data = ATH9K_PCI_KILLER },
{ PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */
/* PCI-E CUS198 */
@ -354,6 +367,13 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
0x1783),
.driver_data = ATH9K_PCI_WOW },
/* Killer Wireless (2x2) */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0030,
0x1A56,
0x2003),
.driver_data = ATH9K_PCI_KILLER },
{ PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E AR9462 */
{ PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E AR1111/AR9485 */
@ -446,6 +466,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
0x11AD, /* LITEON */
0x0662),
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
0x11AD, /* LITEON */
0x0682),
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
PCI_VENDOR_ID_AZWAVE,
@ -456,6 +481,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
PCI_VENDOR_ID_LENOVO,
0x3026),
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
PCI_VENDOR_ID_LENOVO,
0x4026),
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
PCI_VENDOR_ID_HP,
@ -466,6 +496,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
PCI_VENDOR_ID_HP,
0x217F),
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
PCI_VENDOR_ID_HP,
0x2005),
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
PCI_VENDOR_ID_DELL,
@ -545,6 +580,16 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
0x185F, /* WNC */
0x3027),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
0x185F, /* WNC */
0xA120),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
PCI_VENDOR_ID_FOXCONN,
0xE07F),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
/* PCI-E AR9565 (WB335) */
{ PCI_VDEVICE(ATHEROS, 0x0036),

View file

@ -809,6 +809,8 @@
#define AR_SREV_REVISION_9462_21 3
#define AR_SREV_VERSION_9565 0x2C0
#define AR_SREV_REVISION_9565_10 0
#define AR_SREV_REVISION_9565_101 1
#define AR_SREV_REVISION_9565_11 2
#define AR_SREV_VERSION_9550 0x400
#define AR_SREV_5416(_ah) \
@ -927,10 +929,18 @@
#define AR_SREV_9565(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
#define AR_SREV_9565_10(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_10))
#define AR_SREV_9565_101(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_101))
#define AR_SREV_9565_11(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_11))
#define AR_SREV_9565_11_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9565_11))
#define AR_SREV_9550(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9550))

View file

@ -0,0 +1,264 @@
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "ath9k.h"
static void ath9k_tx99_stop(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
ath_drain_all_txq(sc);
ath_startrecv(sc);
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
ieee80211_wake_queues(sc->hw);
kfree_skb(sc->tx99_skb);
sc->tx99_skb = NULL;
sc->tx99_state = false;
ath9k_hw_tx99_stop(sc->sc_ah);
ath_dbg(common, XMIT, "TX99 stopped\n");
}
static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
{
static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
u32 len = 1200;
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info;
struct sk_buff *skb;
skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
return NULL;
skb_put(skb, len);
memset(skb->data, 0, len);
hdr = (struct ieee80211_hdr *)skb->data;
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
hdr->duration_id = 0;
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);
hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
tx_info = IEEE80211_SKB_CB(skb);
memset(tx_info, 0, sizeof(*tx_info));
tx_info->band = hw->conf.chandef.chan->band;
tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
tx_info->control.vif = sc->tx99_vif;
tx_info->control.rates[0].count = 1;
memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
return skb;
}
static void ath9k_tx99_deinit(struct ath_softc *sc)
{
ath_reset(sc);
ath9k_ps_wakeup(sc);
ath9k_tx99_stop(sc);
ath9k_ps_restore(sc);
}
static int ath9k_tx99_init(struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_tx_control txctl;
int r;
if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
ath_err(common,
"driver is in invalid state unable to use TX99");
return -EINVAL;
}
sc->tx99_skb = ath9k_build_tx99_skb(sc);
if (!sc->tx99_skb)
return -ENOMEM;
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
ath_reset(sc);
ath9k_ps_wakeup(sc);
ath9k_hw_disable_interrupts(ah);
atomic_set(&ah->intr_ref_cnt, -1);
ath_drain_all_txq(sc);
ath_stoprecv(sc);
sc->tx99_state = true;
ieee80211_stop_queues(hw);
if (sc->tx99_power == MAX_RATE_POWER + 1)
sc->tx99_power = MAX_RATE_POWER;
ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
if (r) {
ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
return r;
}
ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
sc->tx99_power,
sc->tx99_power / 2);
/* We leave the harware awake as it will be chugging on */
return 0;
}
static ssize_t read_file_tx99(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[3];
unsigned int len;
len = sprintf(buf, "%d\n", sc->tx99_state);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32];
bool start;
ssize_t len;
int r;
if (sc->nvifs > 1)
return -EOPNOTSUPP;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
if (strtobool(buf, &start))
return -EINVAL;
if (start == sc->tx99_state) {
if (!start)
return count;
ath_dbg(common, XMIT, "Resetting TX99\n");
ath9k_tx99_deinit(sc);
}
if (!start) {
ath9k_tx99_deinit(sc);
return count;
}
r = ath9k_tx99_init(sc);
if (r)
return r;
return count;
}
static const struct file_operations fops_tx99 = {
.read = read_file_tx99,
.write = write_file_tx99,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_tx99_power(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d (%d dBm)\n",
sc->tx99_power,
sc->tx99_power / 2);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_tx99_power(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
int r;
u8 tx_power;
r = kstrtou8_from_user(user_buf, count, 0, &tx_power);
if (r)
return r;
if (tx_power > MAX_RATE_POWER)
return -EINVAL;
sc->tx99_power = tx_power;
ath9k_ps_wakeup(sc);
ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power);
ath9k_ps_restore(sc);
return count;
}
static const struct file_operations fops_tx99_power = {
.read = read_file_tx99_power,
.write = write_file_tx99_power,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
void ath9k_tx99_init_debug(struct ath_softc *sc)
{
if (!AR_SREV_9300_20_OR_LATER(sc->sc_ah))
return;
debugfs_create_file("tx99", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_tx99);
debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_tx99_power);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 Qualcomm Atheros, Inc.
* Copyright (c) 2013 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
@ -14,409 +14,348 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/export.h>
#include "ath9k.h"
#include "reg.h"
#include "hw-ops.h"
const char *ath9k_hw_wow_event_to_string(u32 wow_event)
static const struct wiphy_wowlan_support ath9k_wowlan_support = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
.n_patterns = MAX_NUM_USER_PATTERN,
.pattern_min_len = 1,
.pattern_max_len = MAX_PATTERN_SIZE,
};
static void ath9k_wow_map_triggers(struct ath_softc *sc,
struct cfg80211_wowlan *wowlan,
u32 *wow_triggers)
{
if (wow_event & AH_WOW_MAGIC_PATTERN_EN)
return "Magic pattern";
if (wow_event & AH_WOW_USER_PATTERN_EN)
return "User pattern";
if (wow_event & AH_WOW_LINK_CHANGE)
return "Link change";
if (wow_event & AH_WOW_BEACON_MISS)
return "Beacon miss";
if (wowlan->disconnect)
*wow_triggers |= AH_WOW_LINK_CHANGE |
AH_WOW_BEACON_MISS;
if (wowlan->magic_pkt)
*wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
if (wowlan->n_patterns)
*wow_triggers |= AH_WOW_USER_PATTERN_EN;
sc->wow_enabled = *wow_triggers;
return "unknown reason";
}
EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);
static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
int pattern_count = 0;
int i, byte_cnt;
u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
u8 dis_deauth_mask[MAX_PATTERN_SIZE];
REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);
memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);
/* set rx disable bit */
REG_WRITE(ah, AR_CR, AR_CR_RXD);
/*
* Create Dissassociate / Deauthenticate packet filter
*
* 2 bytes 2 byte 6 bytes 6 bytes 6 bytes
* +--------------+----------+---------+--------+--------+----
* + Frame Control+ Duration + DA + SA + BSSID +
* +--------------+----------+---------+--------+--------+----
*
* The above is the management frame format for disassociate/
* deauthenticate pattern, from this we need to match the first byte
* of 'Frame Control' and DA, SA, and BSSID fields
* (skipping 2nd byte of FC and Duration feild.
*
* Disassociate pattern
* --------------------
* Frame control = 00 00 1010
* DA, SA, BSSID = x:x:x:x:x:x
* Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x
* | x:x:x:x:x:x -- 22 bytes
*
* Deauthenticate pattern
* ----------------------
* Frame control = 00 00 1100
* DA, SA, BSSID = x:x:x:x:x:x
* Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x
* | x:x:x:x:x:x -- 22 bytes
*/
if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) {
ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
return;
}
/* Create Disassociate Pattern first */
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);
}
byte_cnt = 0;
static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN];
u32 ctl[13] = {0};
u32 data_word[KAL_NUM_DATA_WORDS];
u8 i;
u32 wow_ka_data_word0;
/* Fill out the mask with all FF's */
memcpy(sta_mac_addr, common->macaddr, ETH_ALEN);
memcpy(ap_mac_addr, common->curbssid, ETH_ALEN);
for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
dis_deauth_mask[i] = 0xff;
/* set the transmit buffer */
ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));
ctl[1] = 0;
ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */
ctl[4] = 0;
ctl[7] = (ah->txchainmask) << 2;
ctl[2] = 0xf << 16; /* tx_tries 0 */
/* copy the first byte of frame control field */
dis_deauth_pattern[byte_cnt] = 0xa0;
byte_cnt++;
for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
/* skip 2nd byte of frame control and Duration field */
byte_cnt += 3;
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
/*
* need not match the destination mac address, it can be a broadcast
* mac address or an unicast to this station
*/
byte_cnt += 6;
data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |
(KAL_TO_DS << 8) | (KAL_DURATION_ID << 16);
data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |
(ap_mac_addr[1] << 8) | (ap_mac_addr[0]);
data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) |
(ap_mac_addr[5] << 8) | (ap_mac_addr[4]);
data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) |
(sta_mac_addr[3] << 8) | (sta_mac_addr[2]);
data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |
(ap_mac_addr[1] << 8) | (ap_mac_addr[0]);
data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);
/* copy the source mac address */
memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
if (AR_SREV_9462_20(ah)) {
/* AR9462 2.0 has an extra descriptor word (time based
* discard) compared to other chips */
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0);
wow_ka_data_word0 = AR_WOW_TXBUF(13);
} else {
wow_ka_data_word0 = AR_WOW_TXBUF(12);
}
byte_cnt += 6;
for (i = 0; i < KAL_NUM_DATA_WORDS; i++)
REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]);
/* copy the bssid, its same as the source mac address */
memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
/* Create Disassociate pattern mask */
dis_deauth_mask[0] = 0xfe;
dis_deauth_mask[1] = 0x03;
dis_deauth_mask[2] = 0xc0;
ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
pattern_count, byte_cnt);
pattern_count++;
/*
* for de-authenticate pattern, only the first byte of the frame
* control field gets changed from 0xA0 to 0xC0
*/
dis_deauth_pattern[0] = 0xC0;
ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
pattern_count, byte_cnt);
}
void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
u8 *user_mask, int pattern_count,
int pattern_len)
static void ath9k_wow_add_pattern(struct ath_softc *sc,
struct cfg80211_wowlan *wowlan)
{
int i;
u32 pattern_val, mask_val;
u32 set, clr;
struct ath_hw *ah = sc->sc_ah;
struct ath9k_wow_pattern *wow_pattern = NULL;
struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
int mask_len;
s8 i = 0;
/* FIXME: should check count by querying the hardware capability */
if (pattern_count >= MAX_NUM_PATTERN)
if (!wowlan->n_patterns)
return;
REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));
/* set the registers for pattern */
for (i = 0; i < MAX_PATTERN_SIZE; i += 4) {
memcpy(&pattern_val, user_pattern, 4);
REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i),
pattern_val);
user_pattern += 4;
}
/* set the registers for mask */
for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) {
memcpy(&mask_val, user_mask, 4);
REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val);
user_mask += 4;
}
/* set the pattern length to be matched
*
* AR_WOW_LENGTH1_REG1
* bit 31:24 pattern 0 length
* bit 23:16 pattern 1 length
* bit 15:8 pattern 2 length
* bit 7:0 pattern 3 length
*
* AR_WOW_LENGTH1_REG2
* bit 31:24 pattern 4 length
* bit 23:16 pattern 5 length
* bit 15:8 pattern 6 length
* bit 7:0 pattern 7 length
*
* the below logic writes out the new
* pattern length for the corresponding
* pattern_count, while masking out the
* other fields
*/
ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
if (pattern_count < 4) {
/* Pattern 0-3 uses AR_WOW_LENGTH1 register */
set = (pattern_len & AR_WOW_LENGTH_MAX) <<
AR_WOW_LEN1_SHIFT(pattern_count);
clr = AR_WOW_LENGTH1_MASK(pattern_count);
REG_RMW(ah, AR_WOW_LENGTH1, set, clr);
} else {
/* Pattern 4-7 uses AR_WOW_LENGTH2 register */
set = (pattern_len & AR_WOW_LENGTH_MAX) <<
AR_WOW_LEN2_SHIFT(pattern_count);
clr = AR_WOW_LENGTH2_MASK(pattern_count);
REG_RMW(ah, AR_WOW_LENGTH2, set, clr);
}
}
EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern);
u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
{
u32 wow_status = 0;
u32 val = 0, rval;
/*
* read the WoW status register to know
* the wakeup reason
* Add the new user configured patterns
*/
rval = REG_READ(ah, AR_WOW_PATTERN);
val = AR_WOW_STATUS(rval);
for (i = 0; i < wowlan->n_patterns; i++) {
/*
* mask only the WoW events that we have enabled. Sometimes
* we have spurious WoW events from the AR_WOW_PATTERN
* register. This mask will clean it up.
*/
wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL);
val &= ah->wow_event_mask;
if (!wow_pattern)
return;
if (val) {
if (val & AR_WOW_MAGIC_PAT_FOUND)
wow_status |= AH_WOW_MAGIC_PATTERN_EN;
if (AR_WOW_PATTERN_FOUND(val))
wow_status |= AH_WOW_USER_PATTERN_EN;
if (val & AR_WOW_KEEP_ALIVE_FAIL)
wow_status |= AH_WOW_LINK_CHANGE;
if (val & AR_WOW_BEACON_FAIL)
wow_status |= AH_WOW_BEACON_MISS;
}
/*
* set and clear WOW_PME_CLEAR registers for the chip to
* generate next wow signal.
* disable D3 before accessing other registers ?
*/
/* do we need to check the bit value 0x01000000 (7-10) ?? */
REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR,
AR_PMCTRL_PWR_STATE_D1D3);
/*
* clear all events
*/
REG_WRITE(ah, AR_WOW_PATTERN,
AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN)));
/*
* restore the beacon threshold to init value
*/
REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
/*
* Restore the way the PCI-E reset, Power-On-Reset, external
* PCIE_POR_SHORT pins are tied to its original value.
* Previously just before WoW sleep, we untie the PCI-E
* reset to our Chip's Power On Reset so that any PCI-E
* reset from the bus will not reset our chip
*/
if (ah->is_pciexpress)
ath9k_hw_configpcipowersave(ah, false);
ah->wow_event_mask = 0;
return wow_status;
}
EXPORT_SYMBOL(ath9k_hw_wow_wakeup);
void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
{
u32 wow_event_mask;
u32 set, clr;
/*
* wow_event_mask is a mask to the AR_WOW_PATTERN register to
* indicate which WoW events we have enabled. The WoW events
* are from the 'pattern_enable' in this function and
* 'pattern_count' of ath9k_hw_wow_apply_pattern()
*/
wow_event_mask = ah->wow_event_mask;
/*
* Untie Power-on-Reset from the PCI-E-Reset. When we are in
* WOW sleep, we do want the Reset from the PCI-E to disturb
* our hw state
*/
if (ah->is_pciexpress) {
/*
* we need to untie the internal POR (power-on-reset)
* to the external PCI-E reset. We also need to tie
* the PCI-E Phy reset to the PCI-E reset.
* TODO: convert the generic user space pattern to
* appropriate chip specific/802.11 pattern.
*/
set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
REG_RMW(ah, AR_WA, set, clr);
mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE);
memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE);
memcpy(wow_pattern->pattern_bytes, patterns[i].pattern,
patterns[i].pattern_len);
memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len);
wow_pattern->pattern_len = patterns[i].pattern_len;
/*
* just need to take care of deauth and disssoc pattern,
* make sure we don't overwrite them.
*/
ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes,
wow_pattern->mask_bytes,
i + 2,
wow_pattern->pattern_len);
kfree(wow_pattern);
}
/*
* set the power states appropriately and enable PME
*/
set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA |
AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR;
/*
* set and clear WOW_PME_CLEAR registers for the chip
* to generate next wow signal.
*/
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
clr = AR_PMCTRL_WOW_PME_CLR;
REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
/*
* Setup for:
* - beacon misses
* - magic pattern
* - keep alive timeout
* - pattern matching
*/
/*
* Program default values for pattern backoff, aifs/slot/KAL count,
* beacon miss timeout, KAL timeout, etc.
*/
set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
REG_SET_BIT(ah, AR_WOW_PATTERN, set);
set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |
AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);
REG_SET_BIT(ah, AR_WOW_COUNT, set);
if (pattern_enable & AH_WOW_BEACON_MISS)
set = AR_WOW_BEACON_TIMO;
/* We are not using beacon miss, program a large value */
else
set = AR_WOW_BEACON_TIMO_MAX;
REG_WRITE(ah, AR_WOW_BCN_TIMO, set);
/*
* Keep alive timo in ms except AR9280
*/
if (!pattern_enable)
set = AR_WOW_KEEP_ALIVE_NEVER;
else
set = KAL_TIMEOUT * 32;
REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set);
/*
* Keep alive delay in us. based on 'power on clock',
* therefore in usec
*/
set = KAL_DELAY * 1000;
REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set);
/*
* Create keep alive pattern to respond to beacons
*/
ath9k_wow_create_keep_alive_pattern(ah);
/*
* Configure MAC WoW Registers
*/
set = 0;
/* Send keep alive timeouts anyway */
clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
if (pattern_enable & AH_WOW_LINK_CHANGE)
wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;
else
set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
/*
* we are relying on a bmiss failure. ensure we have
* enough threshold to prevent false positives
*/
REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,
AR_WOW_BMISSTHRESHOLD);
set = 0;
clr = 0;
if (pattern_enable & AH_WOW_BEACON_MISS) {
set = AR_WOW_BEACON_FAIL_EN;
wow_event_mask |= AR_WOW_BEACON_FAIL;
} else {
clr = AR_WOW_BEACON_FAIL_EN;
}
REG_RMW(ah, AR_WOW_BCN_EN, set, clr);
set = 0;
clr = 0;
/*
* Enable the magic packet registers
*/
if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) {
set = AR_WOW_MAGIC_EN;
wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;
} else {
clr = AR_WOW_MAGIC_EN;
}
set |= AR_WOW_MAC_INTR_EN;
REG_RMW(ah, AR_WOW_PATTERN, set, clr);
REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
AR_WOW_PATTERN_SUPPORTED);
/*
* Set the power states appropriately and enable PME
*/
clr = 0;
set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
AR_PMCTRL_PWR_PM_CTRL_ENA;
clr = AR_PCIE_PM_CTRL_ENA;
REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
/*
* this is needed to prevent the chip waking up
* the host within 3-4 seconds with certain
* platform/BIOS. The fix is to enable
* D1 & D3 to match original definition and
* also match the OTP value. Anyway this
* is more related to SW WOW.
*/
clr = AR_PMCTRL_PWR_STATE_D1D3;
REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
/* to bring down WOW power low margin */
set = BIT(13);
REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
/* HW WoW */
clr = BIT(5);
REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
ath9k_hw_set_powermode_wow_sleep(ah);
ah->wow_event_mask = wow_event_mask;
}
EXPORT_SYMBOL(ath9k_hw_wow_enable);
int ath9k_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
u32 wow_triggers_enabled = 0;
int ret = 0;
mutex_lock(&sc->mutex);
ath_cancel_work(sc);
ath_stop_ani(sc);
del_timer_sync(&sc->rx_poll_timer);
if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
ath_dbg(common, ANY, "Device not present\n");
ret = -EINVAL;
goto fail_wow;
}
if (WARN_ON(!wowlan)) {
ath_dbg(common, WOW, "None of the WoW triggers enabled\n");
ret = -EINVAL;
goto fail_wow;
}
if (!device_can_wakeup(sc->dev)) {
ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n");
ret = 1;
goto fail_wow;
}
/*
* none of the sta vifs are associated
* and we are not currently handling multivif
* cases, for instance we have to seperately
* configure 'keep alive frame' for each
* STA.
*/
if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
ath_dbg(common, WOW, "None of the STA vifs are associated\n");
ret = 1;
goto fail_wow;
}
if (sc->nvifs > 1) {
ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
ret = 1;
goto fail_wow;
}
ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);
ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",
wow_triggers_enabled);
ath9k_ps_wakeup(sc);
ath9k_stop_btcoex(sc);
/*
* Enable wake up on recieving disassoc/deauth
* frame by default.
*/
ath9k_wow_add_disassoc_deauth_pattern(sc);
if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN)
ath9k_wow_add_pattern(sc, wowlan);
spin_lock_bh(&sc->sc_pcu_lock);
/*
* To avoid false wake, we enable beacon miss interrupt only
* when we go to sleep. We save the current interrupt mask
* so we can restore it after the system wakes up
*/
sc->wow_intr_before_sleep = ah->imask;
ah->imask &= ~ATH9K_INT_GLOBAL;
ath9k_hw_disable_interrupts(ah);
ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
spin_unlock_bh(&sc->sc_pcu_lock);
/*
* we can now sync irq and kill any running tasklets, since we already
* disabled interrupts and not holding a spin lock
*/
synchronize_irq(sc->irq);
tasklet_kill(&sc->intr_tq);
ath9k_hw_wow_enable(ah, wow_triggers_enabled);
ath9k_ps_restore(sc);
ath_dbg(common, ANY, "WoW enabled in ath9k\n");
atomic_inc(&sc->wow_sleep_proc_intr);
fail_wow:
mutex_unlock(&sc->mutex);
return ret;
}
int ath9k_resume(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
u32 wow_status;
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
spin_lock_bh(&sc->sc_pcu_lock);
ath9k_hw_disable_interrupts(ah);
ah->imask = sc->wow_intr_before_sleep;
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
spin_unlock_bh(&sc->sc_pcu_lock);
wow_status = ath9k_hw_wow_wakeup(ah);
if (atomic_read(&sc->wow_got_bmiss_intr) == 0) {
/*
* some devices may not pick beacon miss
* as the reason they woke up so we add
* that here for that shortcoming.
*/
wow_status |= AH_WOW_BEACON_MISS;
atomic_dec(&sc->wow_got_bmiss_intr);
ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");
}
atomic_dec(&sc->wow_sleep_proc_intr);
if (wow_status) {
ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n",
ath9k_hw_wow_event_to_string(wow_status), wow_status);
}
ath_restart_work(sc);
ath9k_start_btcoex(sc);
ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);
return 0;
}
void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
{
struct ath_softc *sc = hw->priv;
mutex_lock(&sc->mutex);
device_init_wakeup(sc->dev, 1);
device_set_wakeup_enable(sc->dev, enabled);
mutex_unlock(&sc->mutex);
}
void ath9k_init_wow(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
(sc->driver_data & ATH9K_PCI_WOW) &&
device_can_wakeup(sc->dev))
hw->wiphy->wowlan = &ath9k_wowlan_support;
atomic_set(&sc->wow_sleep_proc_intr, -1);
atomic_set(&sc->wow_got_bmiss_intr, -1);
}

View file

@ -1786,6 +1786,9 @@ bool ath_drain_all_txq(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
if (!sc->tx.txq[i].axq_depth)
continue;
if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum))
npend |= BIT(i);
}
@ -2749,6 +2752,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
}
}
#ifdef CONFIG_ATH9K_TX99
int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
struct ath_tx_control *txctl)
{
@ -2791,3 +2796,5 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
return 0;
}
#endif /* CONFIG_ATH9K_TX99 */

View file

@ -37,17 +37,18 @@ static int __ath_regd_init(struct ath_regulatory *reg);
/* We enable active scan on these a case by case basis by regulatory domain */
#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\
NL80211_RRF_PASSIVE_SCAN)
NL80211_RRF_NO_IR)
#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
NL80211_RRF_NO_IR | \
NL80211_RRF_NO_OFDM)
/* We allow IBSS on these on a case by case basis by regulatory domain */
#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \
ATH9K_2GHZ_CH12_13, \
@ -113,286 +114,6 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
}
};
static inline bool is_wwr_sku(u16 regd)
{
return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
(((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
(regd == WORLD));
}
static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
{
return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
}
bool ath_is_world_regd(struct ath_regulatory *reg)
{
return is_wwr_sku(ath_regd_get_eepromRD(reg));
}
EXPORT_SYMBOL(ath_is_world_regd);
static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
{
/* this is the most restrictive */
return &ath_world_regdom_64;
}
static const struct
ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
{
switch (reg->regpair->regDmnEnum) {
case 0x60:
case 0x61:
case 0x62:
return &ath_world_regdom_60_61_62;
case 0x63:
case 0x65:
return &ath_world_regdom_63_65;
case 0x64:
return &ath_world_regdom_64;
case 0x66:
case 0x69:
return &ath_world_regdom_66_69;
case 0x67:
case 0x68:
case 0x6A:
case 0x6C:
return &ath_world_regdom_67_68_6A_6C;
default:
WARN_ON(1);
return ath_default_world_regdomain();
}
}
bool ath_is_49ghz_allowed(u16 regdomain)
{
/* possibly more */
return regdomain == MKK9_MKKC;
}
EXPORT_SYMBOL(ath_is_49ghz_allowed);
/* Frequency is one where radar detection is required */
static bool ath_is_radar_freq(u16 center_freq)
{
return (center_freq >= 5260 && center_freq <= 5700);
}
/*
* N.B: These exception rules do not apply radar freqs.
*
* - We enable adhoc (or beaconing) if allowed by 11d
* - We enable active scan if the channel is allowed by 11d
* - If no country IE has been processed and a we determine we have
* received a beacon on a channel we can enable active scan and
* adhoc (or beaconing).
*/
static void
ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator)
{
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
const struct ieee80211_reg_rule *reg_rule;
struct ieee80211_channel *ch;
unsigned int i;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!wiphy->bands[band])
continue;
sband = wiphy->bands[band];
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
if (ath_is_radar_freq(ch->center_freq) ||
(ch->flags & IEEE80211_CHAN_RADAR))
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (IS_ERR(reg_rule))
continue;
/*
* If 11d had a rule for this channel ensure
* we enable adhoc/beaconing if it allows us to
* use it. Note that we would have disabled it
* by applying our static world regdomain by
* default during init, prior to calling our
* regulatory_hint().
*/
if (!(reg_rule->flags &
NL80211_RRF_NO_IBSS))
ch->flags &=
~IEEE80211_CHAN_NO_IBSS;
if (!(reg_rule->flags &
NL80211_RRF_PASSIVE_SCAN))
ch->flags &=
~IEEE80211_CHAN_PASSIVE_SCAN;
} else {
if (ch->beacon_found)
ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN);
}
}
}
}
/* Allows active scan scan on Ch 12 and 13 */
static void
ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator)
{
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
const struct ieee80211_reg_rule *reg_rule;
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
if (!sband)
return;
/*
* If no country IE has been received always enable active scan
* on these channels. This is only done for specific regulatory SKUs
*/
if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
ch = &sband->channels[11]; /* CH 12 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
ch = &sband->channels[12]; /* CH 13 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
return;
}
/*
* If a country IE has been received check its rule for this
* channel first before enabling active scan. The passive scan
* would have been enforced by the initial processing of our
* custom regulatory domain.
*/
ch = &sband->channels[11]; /* CH 12 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
}
ch = &sband->channels[12]; /* CH 13 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
}
}
/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
{
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
unsigned int i;
if (!wiphy->bands[IEEE80211_BAND_5GHZ])
return;
sband = wiphy->bands[IEEE80211_BAND_5GHZ];
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
if (!ath_is_radar_freq(ch->center_freq))
continue;
/* We always enable radar detection/DFS on this
* frequency range. Additionally we also apply on
* this frequency range:
* - If STA mode does not yet have DFS supports disable
* active scanning
* - If adhoc mode does not support DFS yet then
* disable adhoc in the frequency.
* - If AP mode does not yet support radar detection/DFS
* do not allow AP mode
*/
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
ch->flags |= IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN;
}
}
static void ath_reg_apply_world_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
struct ath_regulatory *reg)
{
switch (reg->regpair->regDmnEnum) {
case 0x60:
case 0x63:
case 0x66:
case 0x67:
case 0x6C:
ath_reg_apply_beaconing_flags(wiphy, initiator);
break;
case 0x68:
ath_reg_apply_beaconing_flags(wiphy, initiator);
ath_reg_apply_active_scan_flags(wiphy, initiator);
break;
}
}
static u16 ath_regd_find_country_by_name(char *alpha2)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
if (!memcmp(allCountries[i].isoName, alpha2, 2))
return allCountries[i].countryCode;
}
return -1;
}
static int __ath_reg_dyn_country(struct wiphy *wiphy,
struct ath_regulatory *reg,
struct regulatory_request *request)
{
u16 country_code;
if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
!ath_is_world_regd(reg))
return -EINVAL;
country_code = ath_regd_find_country_by_name(request->alpha2);
if (country_code == (u16) -1)
return -EINVAL;
reg->current_rd = COUNTRY_ERD_FLAG;
reg->current_rd |= country_code;
__ath_regd_init(reg);
ath_reg_apply_world_flags(wiphy, request->initiator, reg);
return 0;
}
static void ath_reg_dyn_country(struct wiphy *wiphy,
struct ath_regulatory *reg,
struct regulatory_request *request)
{
if (__ath_reg_dyn_country(wiphy, reg, request))
return;
printk(KERN_DEBUG "ath: regdomain 0x%0x "
"dynamically updated by %s\n",
reg->current_rd,
reg_initiator_name(request->initiator));
}
static bool dynamic_country_user_possible(struct ath_regulatory *reg)
{
if (config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
@ -465,15 +186,316 @@ static bool dynamic_country_user_possible(struct ath_regulatory *reg)
return true;
}
static void ath_reg_dyn_country_user(struct wiphy *wiphy,
struct ath_regulatory *reg,
struct regulatory_request *request)
static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg)
{
if (!config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS))
return;
return false;
if (!dynamic_country_user_possible(reg))
return false;
return true;
}
static inline bool is_wwr_sku(u16 regd)
{
return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
(((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
(regd == WORLD));
}
static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
{
return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
}
bool ath_is_world_regd(struct ath_regulatory *reg)
{
return is_wwr_sku(ath_regd_get_eepromRD(reg));
}
EXPORT_SYMBOL(ath_is_world_regd);
static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
{
/* this is the most restrictive */
return &ath_world_regdom_64;
}
static const struct
ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
{
switch (reg->regpair->regDmnEnum) {
case 0x60:
case 0x61:
case 0x62:
return &ath_world_regdom_60_61_62;
case 0x63:
case 0x65:
return &ath_world_regdom_63_65;
case 0x64:
return &ath_world_regdom_64;
case 0x66:
case 0x69:
return &ath_world_regdom_66_69;
case 0x67:
case 0x68:
case 0x6A:
case 0x6C:
return &ath_world_regdom_67_68_6A_6C;
default:
WARN_ON(1);
return ath_default_world_regdomain();
}
}
bool ath_is_49ghz_allowed(u16 regdomain)
{
/* possibly more */
return regdomain == MKK9_MKKC;
}
EXPORT_SYMBOL(ath_is_49ghz_allowed);
/* Frequency is one where radar detection is required */
static bool ath_is_radar_freq(u16 center_freq)
{
return (center_freq >= 5260 && center_freq <= 5700);
}
static void ath_force_clear_no_ir_chan(struct wiphy *wiphy,
struct ieee80211_channel *ch)
{
const struct ieee80211_reg_rule *reg_rule;
reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
if (IS_ERR(reg_rule))
return;
ath_reg_dyn_country(wiphy, reg, request);
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
static void ath_force_clear_no_ir_freq(struct wiphy *wiphy, u16 center_freq)
{
struct ieee80211_channel *ch;
ch = ieee80211_get_channel(wiphy, center_freq);
if (!ch)
return;
ath_force_clear_no_ir_chan(wiphy, ch);
}
static void ath_force_no_ir_chan(struct ieee80211_channel *ch)
{
ch->flags |= IEEE80211_CHAN_NO_IR;
}
static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq)
{
struct ieee80211_channel *ch;
ch = ieee80211_get_channel(wiphy, center_freq);
if (!ch)
return;
ath_force_no_ir_chan(ch);
}
static void
__ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
struct ath_regulatory *reg,
enum nl80211_reg_initiator initiator,
struct ieee80211_channel *ch)
{
if (ath_is_radar_freq(ch->center_freq) ||
(ch->flags & IEEE80211_CHAN_RADAR))
return;
switch (initiator) {
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
ath_force_clear_no_ir_chan(wiphy, ch);
break;
case NL80211_REGDOM_SET_BY_USER:
if (ath_reg_dyn_country_user_allow(reg))
ath_force_clear_no_ir_chan(wiphy, ch);
break;
default:
if (ch->beacon_found)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
}
/*
* These exception rules do not apply radar frequencies.
*
* - We enable initiating radiation if the country IE says its fine:
* - If no country IE has been processed and a we determine we have
* received a beacon on a channel we can enable initiating radiation.
*/
static void
ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
struct ath_regulatory *reg,
enum nl80211_reg_initiator initiator)
{
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
unsigned int i;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!wiphy->bands[band])
continue;
sband = wiphy->bands[band];
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
__ath_reg_apply_beaconing_flags(wiphy, reg,
initiator, ch);
}
}
}
/**
* ath_reg_apply_ir_flags()
* @wiphy: the wiphy to use
* @initiator: the regulatory hint initiator
*
* If no country IE has been received always enable passive scan
* and no-ibss on these channels. This is only done for specific
* regulatory SKUs.
*
* If a country IE has been received check its rule for this
* channel first before enabling active scan. The passive scan
* would have been enforced by the initial processing of our
* custom regulatory domain.
*/
static void
ath_reg_apply_ir_flags(struct wiphy *wiphy,
struct ath_regulatory *reg,
enum nl80211_reg_initiator initiator)
{
struct ieee80211_supported_band *sband;
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
if (!sband)
return;
switch(initiator) {
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
ath_force_clear_no_ir_freq(wiphy, 2467);
ath_force_clear_no_ir_freq(wiphy, 2472);
break;
case NL80211_REGDOM_SET_BY_USER:
if (!ath_reg_dyn_country_user_allow(reg))
break;
ath_force_clear_no_ir_freq(wiphy, 2467);
ath_force_clear_no_ir_freq(wiphy, 2472);
break;
default:
ath_force_no_ir_freq(wiphy, 2467);
ath_force_no_ir_freq(wiphy, 2472);
}
}
/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
{
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
unsigned int i;
if (!wiphy->bands[IEEE80211_BAND_5GHZ])
return;
sband = wiphy->bands[IEEE80211_BAND_5GHZ];
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
if (!ath_is_radar_freq(ch->center_freq))
continue;
/* We always enable radar detection/DFS on this
* frequency range. Additionally we also apply on
* this frequency range:
* - If STA mode does not yet have DFS supports disable
* active scanning
* - If adhoc mode does not support DFS yet then
* disable adhoc in the frequency.
* - If AP mode does not yet support radar detection/DFS
* do not allow AP mode
*/
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
ch->flags |= IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR;
}
}
static void ath_reg_apply_world_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
struct ath_regulatory *reg)
{
switch (reg->regpair->regDmnEnum) {
case 0x60:
case 0x63:
case 0x66:
case 0x67:
case 0x6C:
ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
break;
case 0x68:
ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
ath_reg_apply_ir_flags(wiphy, reg, initiator);
break;
default:
if (ath_reg_dyn_country_user_allow(reg))
ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
}
}
static u16 ath_regd_find_country_by_name(char *alpha2)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
if (!memcmp(allCountries[i].isoName, alpha2, 2))
return allCountries[i].countryCode;
}
return -1;
}
static int __ath_reg_dyn_country(struct wiphy *wiphy,
struct ath_regulatory *reg,
struct regulatory_request *request)
{
u16 country_code;
if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
!ath_is_world_regd(reg))
return -EINVAL;
country_code = ath_regd_find_country_by_name(request->alpha2);
if (country_code == (u16) -1)
return -EINVAL;
reg->current_rd = COUNTRY_ERD_FLAG;
reg->current_rd |= country_code;
__ath_regd_init(reg);
ath_reg_apply_world_flags(wiphy, request->initiator, reg);
return 0;
}
static void ath_reg_dyn_country(struct wiphy *wiphy,
struct ath_regulatory *reg,
struct regulatory_request *request)
{
if (__ath_reg_dyn_country(wiphy, reg, request))
return;
printk(KERN_DEBUG "ath: regdomain 0x%0x "
"dynamically updated by %s\n",
reg->current_rd,
reg_initiator_name(request->initiator));
}
void ath_reg_notifier_apply(struct wiphy *wiphy,
@ -508,7 +530,8 @@ void ath_reg_notifier_apply(struct wiphy *wiphy,
case NL80211_REGDOM_SET_BY_DRIVER:
break;
case NL80211_REGDOM_SET_BY_USER:
ath_reg_dyn_country_user(wiphy, reg, request);
if (ath_reg_dyn_country_user_allow(reg))
ath_reg_dyn_country(wiphy, reg, request);
break;
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
ath_reg_dyn_country(wiphy, reg, request);
@ -609,7 +632,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
const struct ieee80211_regdomain *regd;
wiphy->reg_notifier = reg_notifier;
wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
if (ath_is_world_regd(reg)) {
/*
@ -617,7 +640,8 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
* saved on the wiphy orig_* parameters
*/
regd = ath_world_regdomain(reg);
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_COUNTRY_IE_FOLLOW_POWER;
} else {
/*
* This gets applied in the case of the absence of CRDA,

View file

@ -2644,7 +2644,7 @@ struct wcn36xx_hal_trigger_ba_rsp_candidate {
struct add_ba_info ba_info[STACFG_MAX_TC];
} __packed;
struct wcn36xx_hal_trigget_ba_req_candidate {
struct wcn36xx_hal_trigger_ba_req_candidate {
u8 sta_index;
u8 tid_bitmap;
} __packed;

View file

@ -641,7 +641,8 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
dev_kfree_skb(skb);
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
if (changed & BSS_CHANGED_BEACON_ENABLED ||
changed & BSS_CHANGED_BEACON) {
wcn36xx_dbg(WCN36XX_DBG_MAC,
"mac bss changed beacon enabled %d\n",
bss_conf->enable_beacon);

View file

@ -115,6 +115,22 @@ static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta,
}
}
static void wcn36xx_smd_set_sta_default_ht_params(
struct wcn36xx_hal_config_sta_params *sta_params)
{
sta_params->ht_capable = 1;
sta_params->tx_channel_width_set = 1;
sta_params->lsig_txop_protection = 1;
sta_params->max_ampdu_size = 3;
sta_params->max_ampdu_density = 5;
sta_params->max_amsdu_size = 0;
sta_params->sgi_20Mhz = 1;
sta_params->sgi_40mhz = 1;
sta_params->green_field_capable = 1;
sta_params->delayed_ba_support = 0;
sta_params->dsss_cck_mode_40mhz = 1;
}
static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@ -172,6 +188,7 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
sizeof(priv_sta->supported_rates));
} else {
wcn36xx_set_default_rates(&sta_params->supported_rates);
wcn36xx_smd_set_sta_default_ht_params(sta_params);
}
}
@ -1838,7 +1855,7 @@ out:
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
{
struct wcn36xx_hal_trigger_ba_req_msg msg_body;
struct wcn36xx_hal_trigget_ba_req_candidate *candidate;
struct wcn36xx_hal_trigger_ba_req_candidate *candidate;
int ret = 0;
mutex_lock(&wcn->hal_mutex);
@ -1849,7 +1866,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
msg_body.header.len += sizeof(*candidate);
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
candidate = (struct wcn36xx_hal_trigget_ba_req_candidate *)
candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *)
(wcn->hal_buf + sizeof(msg_body));
candidate->sta_index = sta_index;
candidate->tid_bitmap = 1;

View file

@ -54,7 +54,7 @@ enum wcn36xx_debug_mask {
};
#define wcn36xx_err(fmt, arg...) \
printk(KERN_ERR pr_fmt("ERROR " fmt), ##arg);
printk(KERN_ERR pr_fmt("ERROR " fmt), ##arg)
#define wcn36xx_warn(fmt, arg...) \
printk(KERN_WARNING pr_fmt("WARNING " fmt), ##arg)

View file

@ -4,13 +4,12 @@ config BRCMUTIL
config BRCMSMAC
tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver"
depends on MAC80211
depends on BCMA
depends on BCMA_POSSIBLE
select BCMA
select NEW_LEDS if BCMA_DRIVER_GPIO
select LEDS_CLASS if BCMA_DRIVER_GPIO
select BRCMUTIL
select FW_LOADER
select CRC_CCITT
select CRC8
select CORDIC
---help---
This module adds support for PCIe wireless adapters based on Broadcom

View file

@ -28,7 +28,8 @@ brcmfmac-objs += \
fweh.o \
fwsignal.o \
p2p.o \
dhd_cdc.o \
proto.o \
bcdc.o \
dhd_common.o \
dhd_linux.o \
btcoex.o

View file

@ -0,0 +1,384 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* 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.
*/
/*******************************************************************************
* Communicates with the dongle by using dcmd codes.
* For certain dcmd codes, the dongle interprets string data from the host.
******************************************************************************/
#include <linux/types.h>
#include <linux/netdevice.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "fwsignal.h"
#include "dhd_dbg.h"
#include "tracepoint.h"
#include "proto.h"
#include "bcdc.h"
struct brcmf_proto_bcdc_dcmd {
__le32 cmd; /* dongle command value */
__le32 len; /* lower 16: output buflen;
* upper 16: input buflen (excludes header) */
__le32 flags; /* flag defns given below */
__le32 status; /* status code returned from the device */
};
/* Max valid buffer size that can be sent to the dongle */
#define BCDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN)
/* BCDC flag definitions */
#define BCDC_DCMD_ERROR 0x01 /* 1=cmd failed */
#define BCDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */
#define BCDC_DCMD_IF_MASK 0xF000 /* I/F index */
#define BCDC_DCMD_IF_SHIFT 12
#define BCDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */
#define BCDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */
#define BCDC_DCMD_ID(flags) \
(((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT)
/*
* BCDC header - Broadcom specific extension of CDC.
* Used on data packets to convey priority across USB.
*/
#define BCDC_HEADER_LEN 4
#define BCDC_PROTO_VER 2 /* Protocol version */
#define BCDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */
#define BCDC_FLAG_VER_SHIFT 4 /* Protocol version shift */
#define BCDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */
#define BCDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */
#define BCDC_PRIORITY_MASK 0x7
#define BCDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */
#define BCDC_FLAG2_IF_SHIFT 0
#define BCDC_GET_IF_IDX(hdr) \
((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT))
#define BCDC_SET_IF_IDX(hdr, idx) \
((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \
((idx) << BCDC_FLAG2_IF_SHIFT)))
/**
* struct brcmf_proto_bcdc_header - BCDC header format
*
* @flags: flags contain protocol and checksum info.
* @priority: 802.1d priority and USB flow control info (bit 4:7).
* @flags2: additional flags containing dongle interface index.
* @data_offset: start of packet data. header is following by firmware signals.
*/
struct brcmf_proto_bcdc_header {
u8 flags;
u8 priority;
u8 flags2;
u8 data_offset;
};
/*
* maximum length of firmware signal data between
* the BCDC header and packet data in the tx path.
*/
#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 12
#define RETRIES 2 /* # of retries to retrieve matching dcmd response */
#define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE
* (amount of header tha might be added)
* plus any space that might be needed
* for bus alignment padding.
*/
#define ROUND_UP_MARGIN 2048 /* Biggest bus block size possible for
* round off at the end of buffer
* Currently is SDIO
*/
struct brcmf_bcdc {
u16 reqid;
u8 bus_header[BUS_HEADER_LEN];
struct brcmf_proto_bcdc_dcmd msg;
unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
};
static int brcmf_proto_bcdc_msg(struct brcmf_pub *drvr)
{
struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
int len = le32_to_cpu(bcdc->msg.len) +
sizeof(struct brcmf_proto_bcdc_dcmd);
brcmf_dbg(BCDC, "Enter\n");
/* NOTE : bcdc->msg.len holds the desired length of the buffer to be
* returned. Only up to BCDC_MAX_MSG_SIZE of this buffer area
* is actually sent to the dongle
*/
if (len > BCDC_MAX_MSG_SIZE)
len = BCDC_MAX_MSG_SIZE;
/* Send request */
return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len);
}
static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
{
int ret;
struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
brcmf_dbg(BCDC, "Enter\n");
len += sizeof(struct brcmf_proto_bcdc_dcmd);
do {
ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg,
len);
if (ret < 0)
break;
} while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id);
return ret;
}
static int
brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len)
{
struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
void *info;
int ret = 0, retries = 0;
u32 id, flags;
brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT);
flags = (flags & ~BCDC_DCMD_IF_MASK) |
(ifidx << BCDC_DCMD_IF_SHIFT);
msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(bcdc->buf, buf, len);
ret = brcmf_proto_bcdc_msg(drvr);
if (ret < 0) {
brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n",
ret);
goto done;
}
retry:
/* wait for interrupt and get first fragment */
ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);
if (ret < 0)
goto done;
flags = le32_to_cpu(msg->flags);
id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;
if ((id < bcdc->reqid) && (++retries < RETRIES))
goto retry;
if (id != bcdc->reqid) {
brcmf_err("%s: unexpected request id %d (expected %d)\n",
brcmf_ifname(drvr, ifidx), id, bcdc->reqid);
ret = -EINVAL;
goto done;
}
/* Check info buffer */
info = (void *)&msg[1];
/* Copy info buffer */
if (buf) {
if (ret < (int)len)
len = ret;
memcpy(buf, info, len);
}
/* Check the ERROR flag */
if (flags & BCDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status);
done:
return ret;
}
static int
brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len)
{
struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
int ret = 0;
u32 flags, id;
brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT) | BCDC_DCMD_SET;
flags = (flags & ~BCDC_DCMD_IF_MASK) |
(ifidx << BCDC_DCMD_IF_SHIFT);
msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(bcdc->buf, buf, len);
ret = brcmf_proto_bcdc_msg(drvr);
if (ret < 0)
goto done;
ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);
if (ret < 0)
goto done;
flags = le32_to_cpu(msg->flags);
id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;
if (id != bcdc->reqid) {
brcmf_err("%s: unexpected request id %d (expected %d)\n",
brcmf_ifname(drvr, ifidx), id, bcdc->reqid);
ret = -EINVAL;
goto done;
}
/* Check the ERROR flag */
if (flags & BCDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status);
done:
return ret;
}
static void
brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
struct sk_buff *pktbuf)
{
struct brcmf_proto_bcdc_header *h;
brcmf_dbg(BCDC, "Enter\n");
/* Push BDC header used to convey priority for buses that don't */
skb_push(pktbuf, BCDC_HEADER_LEN);
h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT);
if (pktbuf->ip_summed == CHECKSUM_PARTIAL)
h->flags |= BCDC_FLAG_SUM_NEEDED;
h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK);
h->flags2 = 0;
h->data_offset = offset;
BCDC_SET_IF_IDX(h, ifidx);
trace_brcmf_bcdchdr(pktbuf->data);
}
static int
brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
struct sk_buff *pktbuf)
{
struct brcmf_proto_bcdc_header *h;
brcmf_dbg(BCDC, "Enter\n");
/* Pop BCDC header used to convey priority for buses that don't */
if (pktbuf->len <= BCDC_HEADER_LEN) {
brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",
pktbuf->len, BCDC_HEADER_LEN);
return -EBADE;
}
trace_brcmf_bcdchdr(pktbuf->data);
h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
*ifidx = BCDC_GET_IF_IDX(h);
if (*ifidx >= BRCMF_MAX_IFS) {
brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
return -EBADE;
}
/* The ifidx is the idx to map to matching netdev/ifp. When receiving
* events this is easy because it contains the bssidx which maps
* 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
* bssidx 1 is used for p2p0 and no data can be received or
* transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
*/
if (*ifidx)
(*ifidx)++;
if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=
BCDC_PROTO_VER) {
brcmf_err("%s: non-BCDC packet received, flags 0x%x\n",
brcmf_ifname(drvr, *ifidx), h->flags);
return -EBADE;
}
if (h->flags & BCDC_FLAG_SUM_GOOD) {
brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
brcmf_ifname(drvr, *ifidx), h->flags);
pktbuf->ip_summed = CHECKSUM_UNNECESSARY;
}
pktbuf->priority = h->priority & BCDC_PRIORITY_MASK;
skb_pull(pktbuf, BCDC_HEADER_LEN);
if (do_fws)
brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
else
skb_pull(pktbuf, h->data_offset << 2);
if (pktbuf->len == 0)
return -ENODATA;
return 0;
}
int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
{
struct brcmf_bcdc *bcdc;
bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC);
if (!bcdc)
goto fail;
/* ensure that the msg buf directly follows the cdc msg struct */
if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) {
brcmf_err("struct brcmf_proto_bcdc is not correctly defined\n");
goto fail;
}
drvr->proto->hdrpush = brcmf_proto_bcdc_hdrpush;
drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull;
drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd;
drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd;
drvr->proto->pd = bcdc;
drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
sizeof(struct brcmf_proto_bcdc_dcmd) + ROUND_UP_MARGIN;
return 0;
fail:
kfree(bcdc);
return -ENOMEM;
}
void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr)
{
kfree(drvr->proto->pd);
drvr->proto->pd = NULL;
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2013 Broadcom Corporation
*
* 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.
*/
#ifndef BRCMFMAC_BCDC_H
#define BRCMFMAC_BCDC_H
int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr);
void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr);
#endif /* BRCMFMAC_BCDC_H */

View file

@ -17,7 +17,6 @@
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/sched.h>
@ -774,7 +773,6 @@ out:
return ret;
}
EXPORT_SYMBOL(brcmf_sdio_probe);
int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
{
@ -791,7 +789,6 @@ int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
return 0;
}
EXPORT_SYMBOL(brcmf_sdio_remove);
void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
{

View file

@ -158,10 +158,21 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
}
}
if (err_ret)
brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
rw ? "write" : "read", func, regaddr, *byte, err_ret);
if (err_ret) {
/*
* SleepCSR register access can fail when
* waking up the device so reduce this noise
* in the logs.
*/
if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
rw ? "write" : "read", func, regaddr, *byte,
err_ret);
else
brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
rw ? "write" : "read", func, regaddr, *byte,
err_ret);
}
return err_ret;
}
@ -269,6 +280,9 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
{
int err_ret = 0;
struct mmc_host *host;
struct sdio_func *func;
uint max_blocks;
brcmf_dbg(SDIO, "\n");
@ -290,6 +304,20 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
brcmf_sdioh_enablefuncs(sdiodev);
/*
* determine host related variables after brcmf_sdio_probe()
* as func->cur_blksize is properly set and F2 init has been
* completed successfully.
*/
func = sdiodev->func[2];
host = func->card->host;
sdiodev->sg_support = host->max_segs > 1;
max_blocks = min_t(uint, host->max_blk_count, 511u);
sdiodev->max_request_size = min_t(uint, host->max_req_size,
max_blocks * func->cur_blksize);
sdiodev->max_segment_count = min_t(uint, host->max_segs,
SG_MAX_SINGLE_ALLOC);
sdiodev->max_segment_size = host->max_seg_size;
out:
sdio_release_host(sdiodev->func[1]);
brcmf_dbg(SDIO, "Done\n");
@ -318,8 +346,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
int err;
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
struct mmc_host *host;
uint max_blocks;
brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "Class=%x\n", func->class);
@ -367,19 +393,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
goto fail;
}
/*
* determine host related variables after brcmf_sdio_probe()
* as func->cur_blksize is properly set and F2 init has been
* completed successfully.
*/
host = func->card->host;
sdiodev->sg_support = host->max_segs > 1;
max_blocks = min_t(uint, host->max_blk_count, 511u);
sdiodev->max_request_size = min_t(uint, host->max_req_size,
max_blocks * func->cur_blksize);
sdiodev->max_segment_count = min_t(uint, host->max_segs,
SG_MAX_SINGLE_ALLOC);
sdiodev->max_segment_size = host->max_seg_size;
brcmf_dbg(SDIO, "F2 init completed...\n");
return 0;

View file

@ -25,184 +25,14 @@
#include "fweh.h"
/*******************************************************************************
* IO codes that are interpreted by dongle firmware
******************************************************************************/
#define BRCMF_C_GET_VERSION 1
#define BRCMF_C_UP 2
#define BRCMF_C_DOWN 3
#define BRCMF_C_SET_PROMISC 10
#define BRCMF_C_GET_RATE 12
#define BRCMF_C_GET_INFRA 19
#define BRCMF_C_SET_INFRA 20
#define BRCMF_C_GET_AUTH 21
#define BRCMF_C_SET_AUTH 22
#define BRCMF_C_GET_BSSID 23
#define BRCMF_C_GET_SSID 25
#define BRCMF_C_SET_SSID 26
#define BRCMF_C_TERMINATED 28
#define BRCMF_C_GET_CHANNEL 29
#define BRCMF_C_SET_CHANNEL 30
#define BRCMF_C_GET_SRL 31
#define BRCMF_C_SET_SRL 32
#define BRCMF_C_GET_LRL 33
#define BRCMF_C_SET_LRL 34
#define BRCMF_C_GET_RADIO 37
#define BRCMF_C_SET_RADIO 38
#define BRCMF_C_GET_PHYTYPE 39
#define BRCMF_C_SET_KEY 45
#define BRCMF_C_SET_PASSIVE_SCAN 49
#define BRCMF_C_SCAN 50
#define BRCMF_C_SCAN_RESULTS 51
#define BRCMF_C_DISASSOC 52
#define BRCMF_C_REASSOC 53
#define BRCMF_C_SET_ROAM_TRIGGER 55
#define BRCMF_C_SET_ROAM_DELTA 57
#define BRCMF_C_GET_BCNPRD 75
#define BRCMF_C_SET_BCNPRD 76
#define BRCMF_C_GET_DTIMPRD 77
#define BRCMF_C_SET_DTIMPRD 78
#define BRCMF_C_SET_COUNTRY 84
#define BRCMF_C_GET_PM 85
#define BRCMF_C_SET_PM 86
#define BRCMF_C_GET_CURR_RATESET 114
#define BRCMF_C_GET_AP 117
#define BRCMF_C_SET_AP 118
#define BRCMF_C_GET_RSSI 127
#define BRCMF_C_GET_WSEC 133
#define BRCMF_C_SET_WSEC 134
#define BRCMF_C_GET_PHY_NOISE 135
#define BRCMF_C_GET_BSS_INFO 136
#define BRCMF_C_GET_BANDLIST 140
#define BRCMF_C_SET_SCB_TIMEOUT 158
#define BRCMF_C_GET_PHYLIST 180
#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185
#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187
#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201
#define BRCMF_C_GET_VALID_CHANNELS 217
#define BRCMF_C_GET_KEY_PRIMARY 235
#define BRCMF_C_SET_KEY_PRIMARY 236
#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258
#define BRCMF_C_GET_VAR 262
#define BRCMF_C_SET_VAR 263
/* phy types (returned by WLC_GET_PHYTPE) */
#define WLC_PHY_TYPE_A 0
#define WLC_PHY_TYPE_B 1
#define WLC_PHY_TYPE_G 2
#define WLC_PHY_TYPE_N 4
#define WLC_PHY_TYPE_LP 5
#define WLC_PHY_TYPE_SSN 6
#define WLC_PHY_TYPE_HT 7
#define WLC_PHY_TYPE_LCN 8
#define WLC_PHY_TYPE_NULL 0xf
#define TOE_TX_CSUM_OL 0x00000001
#define TOE_RX_CSUM_OL 0x00000002
#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */
/* size of brcmf_scan_params not including variable length array */
#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
/* masks for channel and ssid count */
#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16
/* primary (ie tx) key */
#define BRCMF_PRIMARY_KEY (1 << 1)
/* For supporting multiple interfaces */
#define BRCMF_MAX_IFS 16
#define DOT11_BSSTYPE_ANY 2
#define DOT11_MAX_DEFAULT_KEYS 4
#define BRCMF_ESCAN_REQ_VERSION 1
#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
#define BRCMF_STA_ASSOC 0x10 /* Associated */
#define BRCMF_E_STATUS_SUCCESS 0
#define BRCMF_E_STATUS_FAIL 1
#define BRCMF_E_STATUS_TIMEOUT 2
#define BRCMF_E_STATUS_NO_NETWORKS 3
#define BRCMF_E_STATUS_ABORT 4
#define BRCMF_E_STATUS_NO_ACK 5
#define BRCMF_E_STATUS_UNSOLICITED 6
#define BRCMF_E_STATUS_ATTEMPT 7
#define BRCMF_E_STATUS_PARTIAL 8
#define BRCMF_E_STATUS_NEWSCAN 9
#define BRCMF_E_STATUS_NEWASSOC 10
#define BRCMF_E_STATUS_11HQUIET 11
#define BRCMF_E_STATUS_SUPPRESS 12
#define BRCMF_E_STATUS_NOCHANS 13
#define BRCMF_E_STATUS_CS_ABORT 15
#define BRCMF_E_STATUS_ERROR 16
#define BRCMF_E_REASON_INITIAL_ASSOC 0
#define BRCMF_E_REASON_LOW_RSSI 1
#define BRCMF_E_REASON_DEAUTH 2
#define BRCMF_E_REASON_DISASSOC 3
#define BRCMF_E_REASON_BCNS_LOST 4
#define BRCMF_E_REASON_MINTXRATE 9
#define BRCMF_E_REASON_TXFAIL 10
#define BRCMF_E_REASON_LINK_BSSCFG_DIS 4
#define BRCMF_E_REASON_FAST_ROAM_FAILED 5
#define BRCMF_E_REASON_DIRECTED_ROAM 6
#define BRCMF_E_REASON_TSPEC_REJECTED 7
#define BRCMF_E_REASON_BETTER_AP 8
#define BRCMF_E_PRUNE_ENCR_MISMATCH 1
#define BRCMF_E_PRUNE_BCAST_BSSID 2
#define BRCMF_E_PRUNE_MAC_DENY 3
#define BRCMF_E_PRUNE_MAC_NA 4
#define BRCMF_E_PRUNE_REG_PASSV 5
#define BRCMF_E_PRUNE_SPCT_MGMT 6
#define BRCMF_E_PRUNE_RADAR 7
#define BRCMF_E_RSN_MISMATCH 8
#define BRCMF_E_PRUNE_NO_COMMON_RATES 9
#define BRCMF_E_PRUNE_BASIC_RATES 10
#define BRCMF_E_PRUNE_CIPHER_NA 12
#define BRCMF_E_PRUNE_KNOWN_STA 13
#define BRCMF_E_PRUNE_WDS_PEER 15
#define BRCMF_E_PRUNE_QBSS_LOAD 16
#define BRCMF_E_PRUNE_HOME_AP 17
#define BRCMF_E_SUP_OTHER 0
#define BRCMF_E_SUP_DECRYPT_KEY_DATA 1
#define BRCMF_E_SUP_BAD_UCAST_WEP128 2
#define BRCMF_E_SUP_BAD_UCAST_WEP40 3
#define BRCMF_E_SUP_UNSUP_KEY_LEN 4
#define BRCMF_E_SUP_PW_KEY_CIPHER 5
#define BRCMF_E_SUP_MSG3_TOO_MANY_IE 6
#define BRCMF_E_SUP_MSG3_IE_MISMATCH 7
#define BRCMF_E_SUP_NO_INSTALL_FLAG 8
#define BRCMF_E_SUP_MSG3_NO_GTK 9
#define BRCMF_E_SUP_GRP_KEY_CIPHER 10
#define BRCMF_E_SUP_GRP_MSG1_NO_GTK 11
#define BRCMF_E_SUP_GTK_DECRYPT_FAIL 12
#define BRCMF_E_SUP_SEND_FAIL 13
#define BRCMF_E_SUP_DEAUTH 14
#define BRCMF_E_IF_ADD 1
#define BRCMF_E_IF_DEL 2
#define BRCMF_E_IF_CHANGE 3
#define BRCMF_E_IF_FLAG_NOIF 1
#define BRCMF_E_IF_ROLE_STA 0
#define BRCMF_E_IF_ROLE_AP 1
#define BRCMF_E_IF_ROLE_WDS 2
#define BRCMF_E_LINK_BCN_LOSS 1
#define BRCMF_E_LINK_DISASSOC 2
#define BRCMF_E_LINK_ASSOC_REC 3
#define BRCMF_E_LINK_BSSCFG_DIS 4
/* Small, medium and maximum buffer size for dcmd
*/
#define BRCMF_DCMD_SMLEN 256
@ -211,291 +41,10 @@
#define BRCMF_AMPDU_RX_REORDER_MAXFLOWS 256
/* Pattern matching filter. Specifies an offset within received packets to
* start matching, the pattern to match, the size of the pattern, and a bitmask
* that indicates which bits within the pattern should be matched.
/* Length of firmware version string stored for
* ethtool driver info which uses 32 bytes as well.
*/
struct brcmf_pkt_filter_pattern_le {
/*
* Offset within received packet to start pattern matching.
* Offset '0' is the first byte of the ethernet header.
*/
__le32 offset;
/* Size of the pattern. Bitmask must be the same size.*/
__le32 size_bytes;
/*
* Variable length mask and pattern data. mask starts at offset 0.
* Pattern immediately follows mask.
*/
u8 mask_and_pattern[1];
};
/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */
struct brcmf_pkt_filter_le {
__le32 id; /* Unique filter id, specified by app. */
__le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */
__le32 negate_match; /* Negate the result of filter matches */
union { /* Filter definitions */
struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */
} u;
};
/* IOVAR "pkt_filter_enable" parameter. */
struct brcmf_pkt_filter_enable_le {
__le32 id; /* Unique filter id */
__le32 enable; /* Enable/disable bool */
};
/* BSS info structure
* Applications MUST CHECK ie_offset field and length field to access IEs and
* next bss_info structure in a vector (in struct brcmf_scan_results)
*/
struct brcmf_bss_info_le {
__le32 version; /* version field */
__le32 length; /* byte length of data in this record,
* starting at version and including IEs
*/
u8 BSSID[ETH_ALEN];
__le16 beacon_period; /* units are Kusec */
__le16 capability; /* Capability information */
u8 SSID_len;
u8 SSID[32];
struct {
__le32 count; /* # rates in this set */
u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */
} rateset; /* supported rates */
__le16 chanspec; /* chanspec for bss */
__le16 atim_window; /* units are Kusec */
u8 dtim_period; /* DTIM period */
__le16 RSSI; /* receive signal strength (in dBm) */
s8 phy_noise; /* noise (in dBm) */
u8 n_cap; /* BSS is 802.11N Capable */
/* 802.11N BSS Capabilities (based on HT_CAP_*): */
__le32 nbss_cap;
u8 ctl_ch; /* 802.11N BSS control channel number */
__le32 reserved32[1]; /* Reserved for expansion of BSS properties */
u8 flags; /* flags */
u8 reserved[3]; /* Reserved for expansion of BSS properties */
u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */
__le16 ie_offset; /* offset at which IEs start, from beginning */
__le32 ie_length; /* byte length of Information Elements */
__le16 SNR; /* average SNR of during frame reception */
/* Add new fields here */
/* variable length Information Elements */
};
struct brcm_rateset_le {
/* # rates in this set */
__le32 count;
/* rates in 500kbps units w/hi bit set if basic */
u8 rates[BRCMF_MAXRATES_IN_SET];
};
struct brcmf_ssid {
u32 SSID_len;
unsigned char SSID[32];
};
struct brcmf_ssid_le {
__le32 SSID_len;
unsigned char SSID[32];
};
struct brcmf_scan_params_le {
struct brcmf_ssid_le ssid_le; /* default: {0, ""} */
u8 bssid[ETH_ALEN]; /* default: bcast */
s8 bss_type; /* default: any,
* DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
*/
u8 scan_type; /* flags, 0 use default */
__le32 nprobes; /* -1 use default, number of probes per channel */
__le32 active_time; /* -1 use default, dwell time per channel for
* active scanning
*/
__le32 passive_time; /* -1 use default, dwell time per channel
* for passive scanning
*/
__le32 home_time; /* -1 use default, dwell time for the
* home channel between channel scans
*/
__le32 channel_num; /* count of channels and ssids that follow
*
* low half is count of channels in
* channel_list, 0 means default (use all
* available channels)
*
* high half is entries in struct brcmf_ssid
* array that follows channel_list, aligned for
* s32 (4 bytes) meaning an odd channel count
* implies a 2-byte pad between end of
* channel_list and first ssid
*
* if ssid count is zero, single ssid in the
* fixed parameter portion is assumed, otherwise
* ssid in the fixed portion is ignored
*/
__le16 channel_list[1]; /* list of chanspecs */
};
struct brcmf_scan_results {
u32 buflen;
u32 version;
u32 count;
struct brcmf_bss_info_le bss_info_le[];
};
struct brcmf_escan_params_le {
__le32 version;
__le16 action;
__le16 sync_id;
struct brcmf_scan_params_le params_le;
};
struct brcmf_escan_result_le {
__le32 buflen;
__le32 version;
__le16 sync_id;
__le16 bss_count;
struct brcmf_bss_info_le bss_info_le;
};
#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \
sizeof(struct brcmf_bss_info_le))
/* used for association with a specific BSSID and chanspec list */
struct brcmf_assoc_params_le {
/* 00:00:00:00:00:00: broadcast scan */
u8 bssid[ETH_ALEN];
/* 0: all available channels, otherwise count of chanspecs in
* chanspec_list */
__le32 chanspec_num;
/* list of chanspecs */
__le16 chanspec_list[1];
};
/* used for join with or without a specific bssid and channel list */
struct brcmf_join_params {
struct brcmf_ssid_le ssid_le;
struct brcmf_assoc_params_le params_le;
};
/* scan params for extended join */
struct brcmf_join_scan_params_le {
u8 scan_type; /* 0 use default, active or passive scan */
__le32 nprobes; /* -1 use default, nr of probes per channel */
__le32 active_time; /* -1 use default, dwell time per channel for
* active scanning
*/
__le32 passive_time; /* -1 use default, dwell time per channel
* for passive scanning
*/
__le32 home_time; /* -1 use default, dwell time for the home
* channel between channel scans
*/
};
/* extended join params */
struct brcmf_ext_join_params_le {
struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */
struct brcmf_join_scan_params_le scan_le;
struct brcmf_assoc_params_le assoc_le;
};
struct brcmf_wsec_key {
u32 index; /* key index */
u32 len; /* key length */
u8 data[WLAN_MAX_KEY_LEN]; /* key data */
u32 pad_1[18];
u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
u32 flags; /* misc flags */
u32 pad_2[3];
u32 iv_initialized; /* has IV been initialized already? */
u32 pad_3;
/* Rx IV */
struct {
u32 hi; /* upper 32 bits of IV */
u16 lo; /* lower 16 bits of IV */
} rxiv;
u32 pad_4[2];
u8 ea[ETH_ALEN]; /* per station */
};
/*
* dongle requires same struct as above but with fields in little endian order
*/
struct brcmf_wsec_key_le {
__le32 index; /* key index */
__le32 len; /* key length */
u8 data[WLAN_MAX_KEY_LEN]; /* key data */
__le32 pad_1[18];
__le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
__le32 flags; /* misc flags */
__le32 pad_2[3];
__le32 iv_initialized; /* has IV been initialized already? */
__le32 pad_3;
/* Rx IV */
struct {
__le32 hi; /* upper 32 bits of IV */
__le16 lo; /* lower 16 bits of IV */
} rxiv;
__le32 pad_4[2];
u8 ea[ETH_ALEN]; /* per station */
};
/* Used to get specific STA parameters */
struct brcmf_scb_val_le {
__le32 val;
u8 ea[ETH_ALEN];
};
/* channel encoding */
struct brcmf_channel_info_le {
__le32 hw_channel;
__le32 target_channel;
__le32 scan_channel;
};
struct brcmf_sta_info_le {
__le16 ver; /* version of this struct */
__le16 len; /* length in bytes of this structure */
__le16 cap; /* sta's advertised capabilities */
__le32 flags; /* flags defined below */
__le32 idle; /* time since data pkt rx'd from sta */
u8 ea[ETH_ALEN]; /* Station address */
__le32 count; /* # rates in this set */
u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
/* w/hi bit set if basic */
__le32 in; /* seconds elapsed since associated */
__le32 listen_interval_inms; /* Min Listen interval in ms for STA */
__le32 tx_pkts; /* # of packets transmitted */
__le32 tx_failures; /* # of packets failed */
__le32 rx_ucast_pkts; /* # of unicast packets received */
__le32 rx_mcast_pkts; /* # of multicast packets received */
__le32 tx_rate; /* Rate of last successful tx frame */
__le32 rx_rate; /* Rate of last successful rx frame */
__le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
__le32 rx_decrypt_failures; /* # of packet decrypted failed */
};
struct brcmf_chanspec_list {
__le32 count; /* # of entries */
__le32 element[1]; /* variable length uint32 list */
};
/*
* WLC_E_PROBRESP_MSG
* WLC_E_P2P_PROBREQ_MSG
* WLC_E_ACTION_FRAME_RX
*/
struct brcmf_rx_mgmt_data {
__be16 version;
__be16 chanspec;
__be32 rssi;
__be32 mactime;
__be32 rate;
};
#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32
/* Bus independent dongle command */
struct brcmf_dcmd {
@ -535,7 +84,7 @@ struct brcmf_fws_info; /* firmware signalling info */
struct brcmf_pub {
/* Linkage ponters */
struct brcmf_bus *bus_if;
struct brcmf_proto *prot;
struct brcmf_proto *proto;
struct brcmf_cfg80211_info *config;
/* Internal brcmf items */
@ -544,7 +93,7 @@ struct brcmf_pub {
u8 wme_dp; /* wme discard priority */
/* Dongle media info */
unsigned long drv_version; /* Version of dongle-resident driver */
char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];
u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
/* Multicast data packets sent to dongle */
@ -566,14 +115,6 @@ struct brcmf_pub {
#endif
};
struct brcmf_if_event {
u8 ifidx;
u8 action;
u8 flags;
u8 bssidx;
u8 role;
};
/* forward declarations */
struct brcmf_cfg80211_vif;
struct brcmf_fws_mac_descriptor;
@ -635,16 +176,6 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
/* Return pointer to interface name */
char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
/* Query dongle */
int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len);
int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len);
/* Remove any protocol-specific data header. */
int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
struct sk_buff *rxp);
int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
char *name, u8 *mac_addr);
@ -655,4 +186,7 @@ u32 brcmf_get_chip_info(struct brcmf_if *ifp);
void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
bool success);
/* Sets dongle media info (drv_version, mac address). */
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
#endif /* _BRCMF_H_ */

View file

@ -34,6 +34,7 @@ struct brcmf_bus_dcmd {
/**
* struct brcmf_bus_ops - bus callback operations.
*
* @preinit: execute bus/device specific dongle init commands (optional).
* @init: prepare for communication with dongle.
* @stop: clear pending frames, disable data flow.
* @txdata: send a data frame to the dongle. When the data
@ -51,6 +52,7 @@ struct brcmf_bus_dcmd {
* indicated otherwise these callbacks are mandatory.
*/
struct brcmf_bus_ops {
int (*preinit)(struct device *dev);
int (*init)(struct device *dev);
void (*stop)(struct device *dev);
int (*txdata)(struct device *dev, struct sk_buff *skb);
@ -85,7 +87,6 @@ struct brcmf_bus {
unsigned long tx_realloc;
u32 chip;
u32 chiprev;
struct list_head dcmd_list;
struct brcmf_bus_ops *ops;
};
@ -93,6 +94,13 @@ struct brcmf_bus {
/*
* callback wrappers
*/
static inline int brcmf_bus_preinit(struct brcmf_bus *bus)
{
if (!bus->ops->preinit)
return 0;
return bus->ops->preinit(bus->dev);
}
static inline int brcmf_bus_init(struct brcmf_bus *bus)
{
return bus->ops->init(bus->dev);
@ -139,7 +147,7 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
/* Indication from bus module regarding presence/insertion of dongle. */
int brcmf_attach(uint bus_hdrlen, struct device *dev);
int brcmf_attach(struct device *dev);
/* Indication from bus module regarding removal/absence of dongle */
void brcmf_detach(struct device *dev);
/* Indication from bus module that dongle should be reset */
@ -151,6 +159,9 @@ void brcmf_txflowblock(struct device *dev, bool state);
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
int brcmf_bus_start(struct device *dev);
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data,
u32 len);
void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
#ifdef CONFIG_BRCMFMAC_SDIO
void brcmf_sdio_exit(void);

View file

@ -1,392 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* 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.
*/
/*******************************************************************************
* Communicates with the dongle by using dcmd codes.
* For certain dcmd codes, the dongle interprets string data from the host.
******************************************************************************/
#include <linux/types.h>
#include <linux/netdevice.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_proto.h"
#include "dhd_bus.h"
#include "fwsignal.h"
#include "dhd_dbg.h"
#include "tracepoint.h"
struct brcmf_proto_cdc_dcmd {
__le32 cmd; /* dongle command value */
__le32 len; /* lower 16: output buflen;
* upper 16: input buflen (excludes header) */
__le32 flags; /* flag defns given below */
__le32 status; /* status code returned from the device */
};
/* Max valid buffer size that can be sent to the dongle */
#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN)
/* CDC flag definitions */
#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */
#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */
#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */
#define CDC_DCMD_IF_SHIFT 12
#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */
#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */
#define CDC_DCMD_ID(flags) \
(((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT)
/*
* BDC header - Broadcom specific extension of CDC.
* Used on data packets to convey priority across USB.
*/
#define BDC_HEADER_LEN 4
#define BDC_PROTO_VER 2 /* Protocol version */
#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */
#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */
#define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */
#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */
#define BDC_PRIORITY_MASK 0x7
#define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */
#define BDC_FLAG2_IF_SHIFT 0
#define BDC_GET_IF_IDX(hdr) \
((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
#define BDC_SET_IF_IDX(hdr, idx) \
((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \
((idx) << BDC_FLAG2_IF_SHIFT)))
/**
* struct brcmf_proto_bdc_header - BDC header format
*
* @flags: flags contain protocol and checksum info.
* @priority: 802.1d priority and USB flow control info (bit 4:7).
* @flags2: additional flags containing dongle interface index.
* @data_offset: start of packet data. header is following by firmware signals.
*/
struct brcmf_proto_bdc_header {
u8 flags;
u8 priority;
u8 flags2;
u8 data_offset;
};
/*
* maximum length of firmware signal data between
* the BDC header and packet data in the tx path.
*/
#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 12
#define RETRIES 2 /* # of retries to retrieve matching dcmd response */
#define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE
* (amount of header tha might be added)
* plus any space that might be needed
* for bus alignment padding.
*/
#define ROUND_UP_MARGIN 2048 /* Biggest bus block size possible for
* round off at the end of buffer
* Currently is SDIO
*/
struct brcmf_proto {
u16 reqid;
u8 bus_header[BUS_HEADER_LEN];
struct brcmf_proto_cdc_dcmd msg;
unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
};
static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
{
struct brcmf_proto *prot = drvr->prot;
int len = le32_to_cpu(prot->msg.len) +
sizeof(struct brcmf_proto_cdc_dcmd);
brcmf_dbg(CDC, "Enter\n");
/* NOTE : cdc->msg.len holds the desired length of the buffer to be
* returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
* is actually sent to the dongle
*/
if (len > CDC_MAX_MSG_SIZE)
len = CDC_MAX_MSG_SIZE;
/* Send request */
return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&prot->msg, len);
}
static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
{
int ret;
struct brcmf_proto *prot = drvr->prot;
brcmf_dbg(CDC, "Enter\n");
len += sizeof(struct brcmf_proto_cdc_dcmd);
do {
ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg,
len);
if (ret < 0)
break;
} while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id);
return ret;
}
int
brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len)
{
struct brcmf_proto *prot = drvr->prot;
struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
void *info;
int ret = 0, retries = 0;
u32 id, flags;
brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
flags = (++prot->reqid << CDC_DCMD_ID_SHIFT);
flags = (flags & ~CDC_DCMD_IF_MASK) |
(ifidx << CDC_DCMD_IF_SHIFT);
msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(prot->buf, buf, len);
ret = brcmf_proto_cdc_msg(drvr);
if (ret < 0) {
brcmf_err("brcmf_proto_cdc_msg failed w/status %d\n",
ret);
goto done;
}
retry:
/* wait for interrupt and get first fragment */
ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);
if (ret < 0)
goto done;
flags = le32_to_cpu(msg->flags);
id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;
if ((id < prot->reqid) && (++retries < RETRIES))
goto retry;
if (id != prot->reqid) {
brcmf_err("%s: unexpected request id %d (expected %d)\n",
brcmf_ifname(drvr, ifidx), id, prot->reqid);
ret = -EINVAL;
goto done;
}
/* Check info buffer */
info = (void *)&msg[1];
/* Copy info buffer */
if (buf) {
if (ret < (int)len)
len = ret;
memcpy(buf, info, len);
}
/* Check the ERROR flag */
if (flags & CDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status);
done:
return ret;
}
int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len)
{
struct brcmf_proto *prot = drvr->prot;
struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
int ret = 0;
u32 flags, id;
brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET;
flags = (flags & ~CDC_DCMD_IF_MASK) |
(ifidx << CDC_DCMD_IF_SHIFT);
msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(prot->buf, buf, len);
ret = brcmf_proto_cdc_msg(drvr);
if (ret < 0)
goto done;
ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);
if (ret < 0)
goto done;
flags = le32_to_cpu(msg->flags);
id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;
if (id != prot->reqid) {
brcmf_err("%s: unexpected request id %d (expected %d)\n",
brcmf_ifname(drvr, ifidx), id, prot->reqid);
ret = -EINVAL;
goto done;
}
/* Check the ERROR flag */
if (flags & CDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status);
done:
return ret;
}
static bool pkt_sum_needed(struct sk_buff *skb)
{
return skb->ip_summed == CHECKSUM_PARTIAL;
}
static void pkt_set_sum_good(struct sk_buff *skb, bool x)
{
skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE);
}
void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
struct sk_buff *pktbuf)
{
struct brcmf_proto_bdc_header *h;
brcmf_dbg(CDC, "Enter\n");
/* Push BDC header used to convey priority for buses that don't */
skb_push(pktbuf, BDC_HEADER_LEN);
h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
if (pkt_sum_needed(pktbuf))
h->flags |= BDC_FLAG_SUM_NEEDED;
h->priority = (pktbuf->priority & BDC_PRIORITY_MASK);
h->flags2 = 0;
h->data_offset = offset;
BDC_SET_IF_IDX(h, ifidx);
trace_brcmf_bdchdr(pktbuf->data);
}
int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
struct sk_buff *pktbuf)
{
struct brcmf_proto_bdc_header *h;
brcmf_dbg(CDC, "Enter\n");
/* Pop BDC header used to convey priority for buses that don't */
if (pktbuf->len <= BDC_HEADER_LEN) {
brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",
pktbuf->len, BDC_HEADER_LEN);
return -EBADE;
}
trace_brcmf_bdchdr(pktbuf->data);
h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
*ifidx = BDC_GET_IF_IDX(h);
if (*ifidx >= BRCMF_MAX_IFS) {
brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
return -EBADE;
}
/* The ifidx is the idx to map to matching netdev/ifp. When receiving
* events this is easy because it contains the bssidx which maps
* 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
* bssidx 1 is used for p2p0 and no data can be received or
* transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
*/
if (*ifidx)
(*ifidx)++;
if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
BDC_PROTO_VER) {
brcmf_err("%s: non-BDC packet received, flags 0x%x\n",
brcmf_ifname(drvr, *ifidx), h->flags);
return -EBADE;
}
if (h->flags & BDC_FLAG_SUM_GOOD) {
brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
brcmf_ifname(drvr, *ifidx), h->flags);
pkt_set_sum_good(pktbuf, true);
}
pktbuf->priority = h->priority & BDC_PRIORITY_MASK;
skb_pull(pktbuf, BDC_HEADER_LEN);
if (do_fws)
brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
else
skb_pull(pktbuf, h->data_offset << 2);
if (pktbuf->len == 0)
return -ENODATA;
return 0;
}
int brcmf_proto_attach(struct brcmf_pub *drvr)
{
struct brcmf_proto *cdc;
cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC);
if (!cdc)
goto fail;
/* ensure that the msg buf directly follows the cdc msg struct */
if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) {
brcmf_err("struct brcmf_proto is not correctly defined\n");
goto fail;
}
drvr->prot = cdc;
drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN;
return 0;
fail:
kfree(cdc);
return -ENOMEM;
}
/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */
void brcmf_proto_detach(struct brcmf_pub *drvr)
{
kfree(drvr->prot);
drvr->prot = NULL;
}
void brcmf_proto_stop(struct brcmf_pub *drvr)
{
/* Nothing to do for CDC */
}

View file

@ -21,9 +21,9 @@
#include <brcmu_utils.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_proto.h"
#include "dhd_dbg.h"
#include "fwil.h"
#include "fwil_types.h"
#include "tracepoint.h"
#define PKTFILTER_BUF_SIZE 128
@ -257,8 +257,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
u8 buf[BRCMF_DCMD_SMLEN];
char *ptr;
s32 err;
struct brcmf_bus_dcmd *cmdlst;
struct list_head *cur, *q;
/* retreive mac address */
err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
@ -281,9 +279,14 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
}
ptr = (char *)buf;
strsep(&ptr, "\n");
/* Print fw version info */
brcmf_err("Firmware version = %s\n", buf);
/* locate firmware version number for ethtool */
ptr = strrchr(buf, ' ') + 1;
strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
/*
* Setup timeout if Beacons are lost and roam is off to report
* link down
@ -342,17 +345,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
0, true);
/* set bus specific command if there is any */
list_for_each_safe(cur, q, &ifp->drvr->bus_if->dcmd_list) {
cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list);
if (cmdlst->name && cmdlst->param && cmdlst->param_len) {
brcmf_fil_iovar_data_set(ifp, cmdlst->name,
cmdlst->param,
cmdlst->param_len);
}
list_del(cur);
kfree(cmdlst);
}
/* do bus specific preinit here */
err = brcmf_bus_preinit(ifp->drvr->bus_if);
done:
return err;
}

View file

@ -22,7 +22,6 @@
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "tracepoint.h"
static struct dentry *root_folder;
@ -42,6 +41,40 @@ void brcmf_debugfs_exit(void)
root_folder = NULL;
}
static
ssize_t brcmf_debugfs_chipinfo_read(struct file *f, char __user *data,
size_t count, loff_t *ppos)
{
struct brcmf_pub *drvr = f->private_data;
struct brcmf_bus *bus = drvr->bus_if;
char buf[40];
int res;
/* only allow read from start */
if (*ppos > 0)
return 0;
res = scnprintf(buf, sizeof(buf), "chip: %x(%u) rev %u\n",
bus->chip, bus->chip, bus->chiprev);
return simple_read_from_buffer(data, count, ppos, buf, res);
}
static const struct file_operations brcmf_debugfs_chipinfo_ops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = brcmf_debugfs_chipinfo_read
};
static int brcmf_debugfs_create_chipinfo(struct brcmf_pub *drvr)
{
struct dentry *dentry = drvr->dbgfs_dir;
if (!IS_ERR_OR_NULL(dentry))
debugfs_create_file("chipinfo", S_IRUGO, dentry, drvr,
&brcmf_debugfs_chipinfo_ops);
return 0;
}
int brcmf_debugfs_attach(struct brcmf_pub *drvr)
{
struct device *dev = drvr->bus_if->dev;
@ -50,6 +83,7 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr)
return -ENODEV;
drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
brcmf_debugfs_create_chipinfo(drvr);
return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
}

View file

@ -33,7 +33,7 @@
#define BRCMF_USB_VAL 0x00002000
#define BRCMF_SCAN_VAL 0x00004000
#define BRCMF_CONN_VAL 0x00008000
#define BRCMF_CDC_VAL 0x00010000
#define BRCMF_BCDC_VAL 0x00010000
#define BRCMF_SDIO_VAL 0x00020000
/* set default print format */

View file

@ -24,13 +24,13 @@
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_proto.h"
#include "dhd_dbg.h"
#include "fwil_types.h"
#include "p2p.h"
#include "wl_cfg80211.h"
#include "fwil.h"
#include "fwsignal.h"
#include "proto.h"
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
@ -592,28 +592,6 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
return &ifp->stats;
}
/*
* Set current toe component enables in toe_ol iovar,
* and set toe global enable iovar
*/
static int brcmf_toe_set(struct brcmf_if *ifp, u32 toe_ol)
{
s32 err;
err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol);
if (err < 0) {
brcmf_err("Setting toe_ol failed, %d\n", err);
return err;
}
err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0));
if (err < 0)
brcmf_err("Setting toe failed, %d\n", err);
return err;
}
static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info)
{
@ -621,8 +599,8 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
struct brcmf_pub *drvr = ifp->drvr;
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
snprintf(info->version, sizeof(info->version), "%lu",
drvr->drv_version);
snprintf(info->version, sizeof(info->version), "n/a");
strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));
strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
sizeof(info->bus_info));
}
@ -631,124 +609,6 @@ static const struct ethtool_ops brcmf_ethtool_ops = {
.get_drvinfo = brcmf_ethtool_get_drvinfo,
};
static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
{
struct brcmf_pub *drvr = ifp->drvr;
struct ethtool_drvinfo info;
char drvname[sizeof(info.driver)];
u32 cmd;
struct ethtool_value edata;
u32 toe_cmpnt, csum_dir;
int ret;
brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
/* all ethtool calls start with a cmd word */
if (copy_from_user(&cmd, uaddr, sizeof(u32)))
return -EFAULT;
switch (cmd) {
case ETHTOOL_GDRVINFO:
/* Copy out any request driver name */
if (copy_from_user(&info, uaddr, sizeof(info)))
return -EFAULT;
strncpy(drvname, info.driver, sizeof(info.driver));
drvname[sizeof(info.driver) - 1] = '\0';
/* clear struct for return */
memset(&info, 0, sizeof(info));
info.cmd = cmd;
/* if requested, identify ourselves */
if (strcmp(drvname, "?dhd") == 0) {
sprintf(info.driver, "dhd");
strcpy(info.version, BRCMF_VERSION_STR);
}
/* report dongle driver type */
else
sprintf(info.driver, "wl");
sprintf(info.version, "%lu", drvr->drv_version);
if (copy_to_user(uaddr, &info, sizeof(info)))
return -EFAULT;
brcmf_dbg(TRACE, "given %*s, returning %s\n",
(int)sizeof(drvname), drvname, info.driver);
break;
/* Get toe offload components from dongle */
case ETHTOOL_GRXCSUM:
case ETHTOOL_GTXCSUM:
ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
if (ret < 0)
return ret;
csum_dir =
(cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
edata.cmd = cmd;
edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
if (copy_to_user(uaddr, &edata, sizeof(edata)))
return -EFAULT;
break;
/* Set toe offload components in dongle */
case ETHTOOL_SRXCSUM:
case ETHTOOL_STXCSUM:
if (copy_from_user(&edata, uaddr, sizeof(edata)))
return -EFAULT;
/* Read the current settings, update and write back */
ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
if (ret < 0)
return ret;
csum_dir =
(cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
if (edata.data != 0)
toe_cmpnt |= csum_dir;
else
toe_cmpnt &= ~csum_dir;
ret = brcmf_toe_set(ifp, toe_cmpnt);
if (ret < 0)
return ret;
/* If setting TX checksum mode, tell Linux the new mode */
if (cmd == ETHTOOL_STXCSUM) {
if (edata.data)
ifp->ndev->features |= NETIF_F_IP_CSUM;
else
ifp->ndev->features &= ~NETIF_F_IP_CSUM;
}
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
int cmd)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd);
if (!drvr->iflist[ifp->bssidx])
return -1;
if (cmd == SIOCETHTOOL)
return brcmf_ethtool(ifp, ifr->ifr_data);
return -EOPNOTSUPP;
}
static int brcmf_netdev_stop(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
@ -769,7 +629,6 @@ static int brcmf_netdev_open(struct net_device *ndev)
struct brcmf_pub *drvr = ifp->drvr;
struct brcmf_bus *bus_if = drvr->bus_if;
u32 toe_ol;
s32 ret = 0;
brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
@ -788,21 +647,20 @@ static int brcmf_netdev_open(struct net_device *ndev)
else
ndev->features &= ~NETIF_F_IP_CSUM;
/* Allow transmit calls */
netif_start_queue(ndev);
if (brcmf_cfg80211_up(ndev)) {
brcmf_err("failed to bring up cfg80211\n");
return -1;
return -EIO;
}
return ret;
/* Allow transmit calls */
netif_start_queue(ndev);
return 0;
}
static const struct net_device_ops brcmf_netdev_ops_pri = {
.ndo_open = brcmf_netdev_open,
.ndo_stop = brcmf_netdev_stop,
.ndo_get_stats = brcmf_netdev_get_stats,
.ndo_do_ioctl = brcmf_netdev_ioctl_entry,
.ndo_start_xmit = brcmf_netdev_start_xmit,
.ndo_set_mac_address = brcmf_netdev_set_mac_address,
.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
@ -868,13 +726,6 @@ static int brcmf_net_p2p_stop(struct net_device *ndev)
return brcmf_cfg80211_down(ndev);
}
static int brcmf_net_p2p_do_ioctl(struct net_device *ndev,
struct ifreq *ifr, int cmd)
{
brcmf_dbg(TRACE, "Enter\n");
return 0;
}
static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
@ -887,7 +738,6 @@ static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
static const struct net_device_ops brcmf_netdev_ops_p2p = {
.ndo_open = brcmf_net_p2p_open,
.ndo_stop = brcmf_net_p2p_stop,
.ndo_do_ioctl = brcmf_net_p2p_do_ioctl,
.ndo_start_xmit = brcmf_net_p2p_start_xmit
};
@ -1016,7 +866,7 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
}
}
int brcmf_attach(uint bus_hdrlen, struct device *dev)
int brcmf_attach(struct device *dev)
{
struct brcmf_pub *drvr = NULL;
int ret = 0;
@ -1031,7 +881,7 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
mutex_init(&drvr->proto_block);
/* Link to bus module */
drvr->hdrlen = bus_hdrlen;
drvr->hdrlen = 0;
drvr->bus_if = dev_get_drvdata(dev);
drvr->bus_if->drvr = drvr;
@ -1048,8 +898,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
/* attach firmware event handler */
brcmf_fweh_attach(drvr);
INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
return ret;
fail:
@ -1138,14 +986,21 @@ fail:
return 0;
}
void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
if (drvr) {
drvr->hdrlen += len;
}
}
static void brcmf_bus_detach(struct brcmf_pub *drvr)
{
brcmf_dbg(TRACE, "Enter\n");
if (drvr) {
/* Stop the protocol module */
brcmf_proto_stop(drvr);
/* Stop the bus module */
brcmf_bus_stop(drvr->bus_if);
}
@ -1186,8 +1041,7 @@ void brcmf_detach(struct device *dev)
brcmf_bus_detach(drvr);
if (drvr->prot)
brcmf_proto_detach(drvr);
brcmf_proto_detach(drvr);
brcmf_fws_deinit(drvr);
@ -1196,6 +1050,14 @@ void brcmf_detach(struct device *dev)
kfree(drvr);
}
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_if *ifp = bus_if->drvr->iflist[0];
return brcmf_fil_iovar_data_set(ifp, name, data, len);
}
static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
{
return atomic_read(&ifp->pend_8021x_cnt);

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* 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.
*/
#ifndef _BRCMF_PROTO_H_
#define _BRCMF_PROTO_H_
/*
* Exported from the brcmf protocol module (brcmf_cdc)
*/
/* Linkage, sets prot link and updates hdrlen in pub */
int brcmf_proto_attach(struct brcmf_pub *drvr);
/* Unlink, frees allocated protocol memory (including brcmf_proto) */
void brcmf_proto_detach(struct brcmf_pub *drvr);
/* Stop protocol: sync w/dongle state. */
void brcmf_proto_stop(struct brcmf_pub *drvr);
/* Add any protocol-specific data header.
* Caller must reserve prot_hdrlen prepend space.
*/
void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, u8 offset,
struct sk_buff *txp);
/* Sets dongle media info (drv_version, mac address). */
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
#endif /* _BRCMF_PROTO_H_ */

View file

@ -32,6 +32,7 @@
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
#include <linux/platform_data/brcmfmac-sdio.h>
#include <linux/moduleparam.h>
#include <asm/unaligned.h>
#include <defs.h>
#include <brcmu_wifi.h>
@ -110,6 +111,8 @@ struct rte_console {
#define BRCMF_TXBOUND 20 /* Default for max tx frames in
one scheduling */
#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */
#define MEMBLOCK 2048 /* Block size used for downloading
@ -360,6 +363,8 @@ struct brcmf_sdio_hdrinfo {
u16 len_left;
u16 len_nxtfrm;
u8 dat_offset;
bool lastfrm;
u16 tail_pad;
};
/* misc chip info needed by some of the routines */
@ -384,7 +389,7 @@ struct brcmf_sdio {
u8 tx_seq; /* Transmit sequence number (next) */
u8 tx_max; /* Maximum transmit sequence allowed */
u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN];
u8 *hdrbuf; /* buffer for handling rx frame */
u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
u8 rx_seq; /* Receive sequence number (expected) */
struct brcmf_sdio_hdrinfo cur_read;
@ -455,6 +460,10 @@ struct brcmf_sdio {
bool sleeping; /* SDIO bus sleeping */
u8 tx_hdrlen; /* sdio bus header length for tx packet */
bool txglom; /* host tx glomming enable flag */
struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */
u16 head_align; /* buffer pointer alignment */
u16 sgentry_align; /* scatter-gather buffer alignment */
};
/* clkstate */
@ -479,6 +488,10 @@ static const uint max_roundup = 512;
#define ALIGNMENT 4
static int brcmf_sdio_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
module_param_named(txglomsz, brcmf_sdio_txglomsz, int, 0);
MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
enum brcmf_sdio_frmtype {
BRCMF_SDIO_FT_NORMAL,
BRCMF_SDIO_FT_SUPER,
@ -499,6 +512,8 @@ enum brcmf_sdio_frmtype {
#define BCM4334_NVRAM_NAME "brcm/brcmfmac4334-sdio.txt"
#define BCM4335_FIRMWARE_NAME "brcm/brcmfmac4335-sdio.bin"
#define BCM4335_NVRAM_NAME "brcm/brcmfmac4335-sdio.txt"
#define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin"
#define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt"
MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM43143_NVRAM_NAME);
@ -514,6 +529,8 @@ MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM4334_NVRAM_NAME);
MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM4335_NVRAM_NAME);
MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM4339_NVRAM_NAME);
struct brcmf_firmware_names {
u32 chipid;
@ -537,7 +554,8 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = {
{ BCM4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
{ BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
{ BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
{ BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }
{ BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
{ BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }
};
@ -1097,10 +1115,18 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
* host and WiFi dongle which contains information needed for SDIO core and
* firmware
*
* It consists of 2 parts: hw header and software header
* It consists of 3 parts: hardware header, hardware extension header and
* software header
* hardware header (frame tag) - 4 bytes
* Byte 0~1: Frame length
* Byte 2~3: Checksum, bit-wise inverse of frame length
* hardware extension header - 8 bytes
* Tx glom mode only, N/A for Rx or normal Tx
* Byte 0~1: Packet length excluding hw frame tag
* Byte 2: Reserved
* Byte 3: Frame flags, bit 0: last frame indication
* Byte 4~5: Reserved
* Byte 6~7: Tail padding length
* software header - 8 bytes
* Byte 0: Rx/Tx sequence number
* Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag
@ -1111,6 +1137,7 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
* Byte 6~7: Reserved
*/
#define SDPCM_HWHDR_LEN 4
#define SDPCM_HWEXT_LEN 8
#define SDPCM_SWHDR_LEN 8
#define SDPCM_HDRLEN (SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN)
/* software header */
@ -1147,7 +1174,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
u8 rx_seq, fc, tx_seq_max;
u32 swheader;
trace_brcmf_sdpcm_hdr(false, header);
trace_brcmf_sdpcm_hdr(SDPCM_RX, header);
/* hw header */
len = get_unaligned_le16(header);
@ -1260,25 +1287,34 @@ static inline void brcmf_sdio_update_hwhdr(u8 *header, u16 frm_length)
static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header,
struct brcmf_sdio_hdrinfo *hd_info)
{
u32 sw_header;
u32 hdrval;
u8 hdr_offset;
brcmf_sdio_update_hwhdr(header, hd_info->len);
hdr_offset = SDPCM_HWHDR_LEN;
sw_header = bus->tx_seq;
sw_header |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) &
SDPCM_CHANNEL_MASK;
sw_header |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) &
SDPCM_DOFFSET_MASK;
*(((__le32 *)header) + 1) = cpu_to_le32(sw_header);
*(((__le32 *)header) + 2) = 0;
trace_brcmf_sdpcm_hdr(true, header);
if (bus->txglom) {
hdrval = (hd_info->len - hdr_offset) | (hd_info->lastfrm << 24);
*((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval);
hdrval = (u16)hd_info->tail_pad << 16;
*(((__le32 *)(header + hdr_offset)) + 1) = cpu_to_le32(hdrval);
hdr_offset += SDPCM_HWEXT_LEN;
}
hdrval = hd_info->seq_num;
hdrval |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) &
SDPCM_CHANNEL_MASK;
hdrval |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) &
SDPCM_DOFFSET_MASK;
*((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval);
*(((__le32 *)(header + hdr_offset)) + 1) = 0;
trace_brcmf_sdpcm_hdr(SDPCM_TX + !!(bus->txglom), header);
}
static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
{
u16 dlen, totlen;
u8 *dptr, num = 0;
u32 align = 0;
u16 sublen;
struct sk_buff *pfirst, *pnext;
@ -1293,11 +1329,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
brcmf_dbg(SDIO, "start: glomd %p glom %p\n",
bus->glomd, skb_peek(&bus->glom));
if (bus->sdiodev->pdata)
align = bus->sdiodev->pdata->sd_sgentry_align;
if (align < 4)
align = 4;
/* If there's a descriptor, generate the packet chain */
if (bus->glomd) {
pfirst = pnext = NULL;
@ -1321,9 +1352,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
pnext = NULL;
break;
}
if (sublen % align) {
if (sublen % bus->sgentry_align) {
brcmf_err("sublen %d not multiple of %d\n",
sublen, align);
sublen, bus->sgentry_align);
}
totlen += sublen;
@ -1336,7 +1367,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
}
/* Allocate/chain packet for next subframe */
pnext = brcmu_pkt_buf_get_skb(sublen + align);
pnext = brcmu_pkt_buf_get_skb(sublen + bus->sgentry_align);
if (pnext == NULL) {
brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n",
num, sublen);
@ -1345,7 +1376,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
skb_queue_tail(&bus->glom, pnext);
/* Adhere to start alignment requirements */
pkt_align(pnext, sublen, align);
pkt_align(pnext, sublen, bus->sgentry_align);
}
/* If all allocations succeeded, save packet chain
@ -1549,9 +1580,9 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
goto done;
rbuf = bus->rxbuf;
pad = ((unsigned long)rbuf % BRCMF_SDALIGN);
pad = ((unsigned long)rbuf % bus->head_align);
if (pad)
rbuf += (BRCMF_SDALIGN - pad);
rbuf += (bus->head_align - pad);
/* Copy the already-read portion over */
memcpy(buf, hdr, BRCMF_FIRSTREAD);
@ -1565,14 +1596,10 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
((len + pad) < bus->sdiodev->bus_if->maxctl))
rdlen += pad;
} else if (rdlen % BRCMF_SDALIGN) {
rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
} else if (rdlen % bus->head_align) {
rdlen += bus->head_align - (rdlen % bus->head_align);
}
/* Satisfy length-alignment requirements */
if (rdlen & (ALIGNMENT - 1))
rdlen = roundup(rdlen, ALIGNMENT);
/* Drop if the read is too big or it exceeds our maximum */
if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
@ -1637,8 +1664,8 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
if (*pad <= bus->roundup && *pad < bus->blocksize &&
*rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ)
*rdlen += *pad;
} else if (*rdlen % BRCMF_SDALIGN) {
*rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN);
} else if (*rdlen % bus->head_align) {
*rdlen += bus->head_align - (*rdlen % bus->head_align);
}
}
@ -1726,7 +1753,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
brcmf_pad(bus, &pad, &rd->len_left);
pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read +
BRCMF_SDALIGN);
bus->head_align);
if (!pkt) {
/* Give up on data, request rtx of events */
brcmf_err("brcmu_pkt_buf_get_skb failed\n");
@ -1736,7 +1763,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
continue;
}
skb_pull(pkt, head_read);
pkt_align(pkt, rd->len_left, BRCMF_SDALIGN);
pkt_align(pkt, rd->len_left, bus->head_align);
ret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, pkt);
@ -1871,6 +1898,29 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
return;
}
static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
{
u16 head_pad;
u8 *dat_buf;
dat_buf = (u8 *)(pkt->data);
/* Check head padding */
head_pad = ((unsigned long)dat_buf % bus->head_align);
if (head_pad) {
if (skb_headroom(pkt) < head_pad) {
bus->sdiodev->bus_if->tx_realloc++;
head_pad = 0;
if (skb_cow(pkt, head_pad))
return -ENOMEM;
}
skb_push(pkt, head_pad);
dat_buf = (u8 *)(pkt->data);
memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
}
return head_pad;
}
/**
* struct brcmf_skbuff_cb reserves first two bytes in sk_buff::cb for
* bus layer usage.
@ -1880,32 +1930,40 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
/* bit mask of data length chopped from the previous packet */
#define ALIGN_SKB_CHOP_LEN_MASK 0x7fff
static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio_dev *sdiodev,
static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
struct sk_buff_head *pktq,
struct sk_buff *pkt, uint chan)
struct sk_buff *pkt, u16 total_len)
{
struct brcmf_sdio_dev *sdiodev;
struct sk_buff *pkt_pad;
u16 tail_pad, tail_chop, sg_align;
u16 tail_pad, tail_chop, chain_pad;
unsigned int blksize;
u8 *dat_buf;
int ntail;
bool lastfrm;
int ntail, ret;
sdiodev = bus->sdiodev;
blksize = sdiodev->func[SDIO_FUNC_2]->cur_blksize;
sg_align = 4;
if (sdiodev->pdata && sdiodev->pdata->sd_sgentry_align > 4)
sg_align = sdiodev->pdata->sd_sgentry_align;
/* sg entry alignment should be a divisor of block size */
WARN_ON(blksize % sg_align);
WARN_ON(blksize % bus->sgentry_align);
/* Check tail padding */
pkt_pad = NULL;
tail_chop = pkt->len % sg_align;
tail_pad = sg_align - tail_chop;
tail_pad += blksize - (pkt->len + tail_pad) % blksize;
lastfrm = skb_queue_is_last(pktq, pkt);
tail_pad = 0;
tail_chop = pkt->len % bus->sgentry_align;
if (tail_chop)
tail_pad = bus->sgentry_align - tail_chop;
chain_pad = (total_len + tail_pad) % blksize;
if (lastfrm && chain_pad)
tail_pad += blksize - chain_pad;
if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
pkt_pad = bus->txglom_sgpad;
if (pkt_pad == NULL)
brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
if (pkt_pad == NULL)
return -ENOMEM;
ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
if (unlikely(ret < 0))
return ret;
memcpy(pkt_pad->data,
pkt->data + pkt->len - tail_chop,
tail_chop);
@ -1920,14 +1978,10 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio_dev *sdiodev,
return -ENOMEM;
if (skb_linearize(pkt))
return -ENOMEM;
dat_buf = (u8 *)(pkt->data);
__skb_put(pkt, tail_pad);
}
if (pkt_pad)
return pkt->len + tail_chop;
else
return pkt->len - tail_pad;
return tail_pad;
}
/**
@ -1946,58 +2000,66 @@ static int
brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
uint chan)
{
u16 head_pad, head_align;
u16 head_pad, total_len;
struct sk_buff *pkt_next;
u8 *dat_buf;
int err;
u8 txseq;
int ret;
struct brcmf_sdio_hdrinfo hd_info = {0};
/* SDIO ADMA requires at least 32 bit alignment */
head_align = 4;
if (bus->sdiodev->pdata && bus->sdiodev->pdata->sd_head_align > 4)
head_align = bus->sdiodev->pdata->sd_head_align;
txseq = bus->tx_seq;
total_len = 0;
skb_queue_walk(pktq, pkt_next) {
/* alignment packet inserted in previous
* loop cycle can be skipped as it is
* already properly aligned and does not
* need an sdpcm header.
*/
if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
continue;
pkt_next = pktq->next;
dat_buf = (u8 *)(pkt_next->data);
/* align packet data pointer */
ret = brcmf_sdio_txpkt_hdalign(bus, pkt_next);
if (ret < 0)
return ret;
head_pad = (u16)ret;
if (head_pad)
memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen);
/* Check head padding */
head_pad = ((unsigned long)dat_buf % head_align);
if (head_pad) {
if (skb_headroom(pkt_next) < head_pad) {
bus->sdiodev->bus_if->tx_realloc++;
head_pad = 0;
if (skb_cow(pkt_next, head_pad))
return -ENOMEM;
}
skb_push(pkt_next, head_pad);
dat_buf = (u8 *)(pkt_next->data);
memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
}
total_len += pkt_next->len;
if (bus->sdiodev->sg_support && pktq->qlen > 1) {
err = brcmf_sdio_txpkt_prep_sg(bus->sdiodev, pktq,
pkt_next, chan);
if (err < 0)
return err;
hd_info.len = (u16)err;
} else {
hd_info.len = pkt_next->len;
hd_info.lastfrm = skb_queue_is_last(pktq, pkt_next);
if (bus->txglom && pktq->qlen > 1) {
ret = brcmf_sdio_txpkt_prep_sg(bus, pktq,
pkt_next, total_len);
if (ret < 0)
return ret;
hd_info.tail_pad = (u16)ret;
total_len += (u16)ret;
}
hd_info.channel = chan;
hd_info.dat_offset = head_pad + bus->tx_hdrlen;
hd_info.seq_num = txseq++;
/* Now fill the header */
brcmf_sdio_hdpack(bus, pkt_next->data, &hd_info);
if (BRCMF_BYTES_ON() &&
((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
(BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
brcmf_dbg_hex_dump(true, pkt_next, hd_info.len,
"Tx Frame:\n");
else if (BRCMF_HDRS_ON())
brcmf_dbg_hex_dump(true, pkt_next,
head_pad + bus->tx_hdrlen,
"Tx Header:\n");
}
hd_info.channel = chan;
hd_info.dat_offset = head_pad + bus->tx_hdrlen;
/* Now fill the header */
brcmf_sdio_hdpack(bus, dat_buf, &hd_info);
if (BRCMF_BYTES_ON() &&
((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
(BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, "Tx Frame:\n");
else if (BRCMF_HDRS_ON())
brcmf_dbg_hex_dump(true, pkt_next, head_pad + bus->tx_hdrlen,
"Tx Header:\n");
/* Hardware length tag of the first packet should be total
* length of the chain (including padding)
*/
if (bus->txglom)
brcmf_sdio_update_hwhdr(pktq->next->data, total_len);
return 0;
}
@ -2015,6 +2077,7 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
{
u8 *hdr;
u32 dat_offset;
u16 tail_pad;
u32 dummy_flags, chop_len;
struct sk_buff *pkt_next, *tmp, *pkt_prev;
@ -2024,42 +2087,42 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
if (chop_len) {
pkt_prev = pkt_next->prev;
memcpy(pkt_prev->data + pkt_prev->len,
pkt_next->data, chop_len);
skb_put(pkt_prev, chop_len);
}
__skb_unlink(pkt_next, pktq);
brcmu_pkt_buf_free_skb(pkt_next);
} else {
hdr = pkt_next->data + SDPCM_HWHDR_LEN;
hdr = pkt_next->data + bus->tx_hdrlen - SDPCM_SWHDR_LEN;
dat_offset = le32_to_cpu(*(__le32 *)hdr);
dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >>
SDPCM_DOFFSET_SHIFT;
skb_pull(pkt_next, dat_offset);
if (bus->txglom) {
tail_pad = le16_to_cpu(*(__le16 *)(hdr - 2));
skb_trim(pkt_next, pkt_next->len - tail_pad);
}
}
}
}
/* Writes a HW/SW header into the packet and sends it. */
/* Assumes: (a) header space already there, (b) caller holds lock */
static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
uint chan)
{
int ret;
int i;
struct sk_buff_head localq;
struct sk_buff *pkt_next, *tmp;
brcmf_dbg(TRACE, "Enter\n");
__skb_queue_head_init(&localq);
__skb_queue_tail(&localq, pkt);
ret = brcmf_sdio_txpkt_prep(bus, &localq, chan);
ret = brcmf_sdio_txpkt_prep(bus, pktq, chan);
if (ret)
goto done;
sdio_claim_host(bus->sdiodev->func[1]);
ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, &localq);
SDIO_FUNC_2, F2SYNC, pktq);
bus->sdcnt.f2txdata++;
if (ret < 0) {
@ -2083,42 +2146,56 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
if ((hi == 0) && (lo == 0))
break;
}
}
sdio_release_host(bus->sdiodev->func[1]);
if (ret == 0)
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
done:
brcmf_sdio_txpkt_postp(bus, &localq);
__skb_dequeue_tail(&localq);
brcmf_txcomplete(bus->sdiodev->dev, pkt, ret == 0);
brcmf_sdio_txpkt_postp(bus, pktq);
if (ret == 0)
bus->tx_seq = (bus->tx_seq + pktq->qlen) % SDPCM_SEQ_WRAP;
skb_queue_walk_safe(pktq, pkt_next, tmp) {
__skb_unlink(pkt_next, pktq);
brcmf_txcomplete(bus->sdiodev->dev, pkt_next, ret == 0);
}
return ret;
}
static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
{
struct sk_buff *pkt;
struct sk_buff_head pktq;
u32 intstatus = 0;
int ret = 0, prec_out;
int ret = 0, prec_out, i;
uint cnt = 0;
u8 tx_prec_map;
u8 tx_prec_map, pkt_num;
brcmf_dbg(TRACE, "Enter\n");
tx_prec_map = ~bus->flowcontrol;
/* Send frames until the limit or some other event */
for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) {
for (cnt = 0; (cnt < maxframes) && data_ok(bus);) {
pkt_num = 1;
__skb_queue_head_init(&pktq);
if (bus->txglom)
pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
brcmf_sdio_txglomsz);
pkt_num = min_t(u32, pkt_num,
brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol));
spin_lock_bh(&bus->txqlock);
pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
if (pkt == NULL) {
spin_unlock_bh(&bus->txqlock);
break;
for (i = 0; i < pkt_num; i++) {
pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map,
&prec_out);
if (pkt == NULL)
break;
__skb_queue_tail(&pktq, pkt);
}
spin_unlock_bh(&bus->txqlock);
if (i == 0)
break;
ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL);
ret = brcmf_sdbrcm_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL);
cnt += i;
/* In poll mode, need to check for other events */
if (!bus->intr && cnt) {
@ -2665,7 +2742,7 @@ static int
brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
{
u8 *frame;
u16 len;
u16 len, pad;
uint retries = 0;
u8 doff = 0;
int ret = -1;
@ -2681,28 +2758,26 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
len = (msglen += bus->tx_hdrlen);
/* Add alignment padding (optional for ctl frames) */
doff = ((unsigned long)frame % BRCMF_SDALIGN);
doff = ((unsigned long)frame % bus->head_align);
if (doff) {
frame -= doff;
len += doff;
msglen += doff;
memset(frame, 0, doff + bus->tx_hdrlen);
}
/* precondition: doff < BRCMF_SDALIGN */
/* precondition: doff < bus->head_align */
doff += bus->tx_hdrlen;
/* Round send length to next SDIO block */
pad = 0;
if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
u16 pad = bus->blocksize - (len % bus->blocksize);
if ((pad <= bus->roundup) && (pad < bus->blocksize))
len += pad;
} else if (len % BRCMF_SDALIGN) {
len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
pad = bus->blocksize - (len % bus->blocksize);
if ((pad > bus->roundup) || (pad >= bus->blocksize))
pad = 0;
} else if (len % bus->head_align) {
pad = bus->head_align - (len % bus->head_align);
}
/* Satisfy length-alignment requirements */
if (len & (ALIGNMENT - 1))
len = roundup(len, ALIGNMENT);
len += pad;
/* precondition: IS_ALIGNED((unsigned long)frame, 2) */
@ -2714,8 +2789,14 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
hd_info.len = (u16)msglen;
hd_info.channel = SDPCM_CONTROL_CHANNEL;
hd_info.dat_offset = doff;
hd_info.seq_num = bus->tx_seq;
hd_info.lastfrm = true;
hd_info.tail_pad = pad;
brcmf_sdio_hdpack(bus, frame, &hd_info);
if (bus->txglom)
brcmf_sdio_update_hwhdr(frame, len);
if (!data_ok(bus)) {
brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
bus->tx_max, bus->tx_seq);
@ -3425,6 +3506,65 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
return ret;
}
static int brcmf_sdbrcm_bus_preinit(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
uint pad_size;
u32 value;
u8 idx;
int err;
/* the commands below use the terms tx and rx from
* a device perspective, ie. bus:txglom affects the
* bus transfers from device to host.
*/
idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
if (bus->ci->c_inf[idx].rev < 12) {
/* for sdio core rev < 12, disable txgloming */
value = 0;
err = brcmf_iovar_data_set(dev, "bus:txglom", &value,
sizeof(u32));
} else {
/* otherwise, set txglomalign */
value = 4;
if (sdiodev->pdata)
value = sdiodev->pdata->sd_sgentry_align;
/* SDIO ADMA requires at least 32 bit alignment */
value = max_t(u32, value, 4);
err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value,
sizeof(u32));
}
if (err < 0)
goto done;
bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
if (sdiodev->sg_support) {
bus->txglom = false;
value = 1;
pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size);
if (!bus->txglom_sgpad)
brcmf_err("allocating txglom padding skb failed, reduced performance\n");
err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
&value, sizeof(u32));
if (err < 0) {
/* bus:rxglom is allowed to fail */
err = 0;
} else {
bus->txglom = true;
bus->tx_hdrlen += SDPCM_HWEXT_LEN;
}
}
brcmf_bus_add_txhdrlen(bus->sdiodev->dev, bus->tx_hdrlen);
done:
return err;
}
static int brcmf_sdbrcm_bus_init(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@ -3673,7 +3813,7 @@ static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus)
if (bus->sdiodev->bus_if->maxctl) {
bus->rxblen =
roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
ALIGNMENT) + BRCMF_SDALIGN;
ALIGNMENT) + bus->head_align;
bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
if (!(bus->rxbuf))
return false;
@ -3774,9 +3914,13 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
/* allocate header buffer */
bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL);
if (!bus->hdrbuf)
return false;
/* Locate an appropriately-aligned portion of hdrbuf */
bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
BRCMF_SDALIGN);
bus->head_align);
/* Set the poll and/or interrupt flags */
bus->intr = true;
@ -3895,8 +4039,9 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
brcmf_sdbrcm_release_dongle(bus);
}
brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
brcmf_sdbrcm_release_malloc(bus);
kfree(bus->hdrbuf);
kfree(bus);
}
@ -3905,6 +4050,7 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.stop = brcmf_sdbrcm_bus_stop,
.preinit = brcmf_sdbrcm_bus_preinit,
.init = brcmf_sdbrcm_bus_init,
.txdata = brcmf_sdbrcm_bus_txdata,
.txctl = brcmf_sdbrcm_bus_txctl,
@ -3916,10 +4062,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
{
int ret;
struct brcmf_sdio *bus;
struct brcmf_bus_dcmd *dlst;
u32 dngl_txglom;
u32 txglomalign = 0;
u8 idx;
brcmf_dbg(TRACE, "Enter\n");
@ -3939,6 +4081,18 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
bus->txminmax = BRCMF_TXMINMAX;
bus->tx_seq = SDPCM_SEQ_WRAP - 1;
/* platform specific configuration:
* alignments must be at least 4 bytes for ADMA
*/
bus->head_align = ALIGNMENT;
bus->sgentry_align = ALIGNMENT;
if (sdiodev->pdata) {
if (sdiodev->pdata->sd_head_align > ALIGNMENT)
bus->head_align = sdiodev->pdata->sd_head_align;
if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT)
bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
}
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
if (bus->brcmf_wq == NULL) {
@ -3983,7 +4137,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
/* Attach to the common layer, reserve hdr space */
ret = brcmf_attach(bus->tx_hdrlen, bus->sdiodev->dev);
ret = brcmf_attach(bus->sdiodev->dev);
if (ret != 0) {
brcmf_err("brcmf_attach failed\n");
goto fail;
@ -4003,30 +4157,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
brcmf_sdio_debugfs_create(bus);
brcmf_dbg(INFO, "completed!!\n");
/* sdio bus core specific dcmd */
idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
dlst = kzalloc(sizeof(struct brcmf_bus_dcmd), GFP_KERNEL);
if (dlst) {
if (bus->ci->c_inf[idx].rev < 12) {
/* for sdio core rev < 12, disable txgloming */
dngl_txglom = 0;
dlst->name = "bus:txglom";
dlst->param = (char *)&dngl_txglom;
dlst->param_len = sizeof(u32);
} else {
/* otherwise, set txglomalign */
if (sdiodev->pdata)
txglomalign = sdiodev->pdata->sd_sgentry_align;
/* SDIO ADMA requires at least 32 bit alignment */
if (txglomalign < 4)
txglomalign = 4;
dlst->name = "bus:txglomalign";
dlst->param = (char *)&txglomalign;
dlst->param_len = sizeof(u32);
}
list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list);
}
/* if firmware path present try to download and bring up bus */
ret = brcmf_bus_start(bus->sdiodev->dev);
if (ret != 0) {

View file

@ -122,6 +122,52 @@ enum brcmf_fweh_event_code {
#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
#define BRCMF_EVENT_MSG_GROUP 0x04
/* status field values in struct brcmf_event_msg */
#define BRCMF_E_STATUS_SUCCESS 0
#define BRCMF_E_STATUS_FAIL 1
#define BRCMF_E_STATUS_TIMEOUT 2
#define BRCMF_E_STATUS_NO_NETWORKS 3
#define BRCMF_E_STATUS_ABORT 4
#define BRCMF_E_STATUS_NO_ACK 5
#define BRCMF_E_STATUS_UNSOLICITED 6
#define BRCMF_E_STATUS_ATTEMPT 7
#define BRCMF_E_STATUS_PARTIAL 8
#define BRCMF_E_STATUS_NEWSCAN 9
#define BRCMF_E_STATUS_NEWASSOC 10
#define BRCMF_E_STATUS_11HQUIET 11
#define BRCMF_E_STATUS_SUPPRESS 12
#define BRCMF_E_STATUS_NOCHANS 13
#define BRCMF_E_STATUS_CS_ABORT 15
#define BRCMF_E_STATUS_ERROR 16
/* reason field values in struct brcmf_event_msg */
#define BRCMF_E_REASON_INITIAL_ASSOC 0
#define BRCMF_E_REASON_LOW_RSSI 1
#define BRCMF_E_REASON_DEAUTH 2
#define BRCMF_E_REASON_DISASSOC 3
#define BRCMF_E_REASON_BCNS_LOST 4
#define BRCMF_E_REASON_MINTXRATE 9
#define BRCMF_E_REASON_TXFAIL 10
#define BRCMF_E_REASON_LINK_BSSCFG_DIS 4
#define BRCMF_E_REASON_FAST_ROAM_FAILED 5
#define BRCMF_E_REASON_DIRECTED_ROAM 6
#define BRCMF_E_REASON_TSPEC_REJECTED 7
#define BRCMF_E_REASON_BETTER_AP 8
/* action field values for brcmf_ifevent */
#define BRCMF_E_IF_ADD 1
#define BRCMF_E_IF_DEL 2
#define BRCMF_E_IF_CHANGE 3
/* flag field values for brcmf_ifevent */
#define BRCMF_E_IF_FLAG_NOIF 1
/* role field values for brcmf_ifevent */
#define BRCMF_E_IF_ROLE_STA 0
#define BRCMF_E_IF_ROLE_AP 1
#define BRCMF_E_IF_ROLE_WDS 2
/**
* definitions for event packet validation.
*/
@ -160,6 +206,14 @@ struct brcmf_event_msg {
u8 bsscfgidx;
};
struct brcmf_if_event {
u8 ifidx;
u8 action;
u8 flags;
u8 bssidx;
u8 role;
};
typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
const struct brcmf_event_msg *evtmsg,
void *data);

View file

@ -27,6 +27,7 @@
#include "dhd_dbg.h"
#include "tracepoint.h"
#include "fwil.h"
#include "proto.h"
#define MAX_HEX_DUMP_LEN 64
@ -46,11 +47,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
if (data != NULL)
len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
if (set)
err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data,
len);
err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd, data, len);
else
err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data,
len);
err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
if (err >= 0)
err = 0;

View file

@ -17,6 +17,67 @@
#ifndef _fwil_h_
#define _fwil_h_
/*******************************************************************************
* Dongle command codes that are interpreted by firmware
******************************************************************************/
#define BRCMF_C_GET_VERSION 1
#define BRCMF_C_UP 2
#define BRCMF_C_DOWN 3
#define BRCMF_C_SET_PROMISC 10
#define BRCMF_C_GET_RATE 12
#define BRCMF_C_GET_INFRA 19
#define BRCMF_C_SET_INFRA 20
#define BRCMF_C_GET_AUTH 21
#define BRCMF_C_SET_AUTH 22
#define BRCMF_C_GET_BSSID 23
#define BRCMF_C_GET_SSID 25
#define BRCMF_C_SET_SSID 26
#define BRCMF_C_TERMINATED 28
#define BRCMF_C_GET_CHANNEL 29
#define BRCMF_C_SET_CHANNEL 30
#define BRCMF_C_GET_SRL 31
#define BRCMF_C_SET_SRL 32
#define BRCMF_C_GET_LRL 33
#define BRCMF_C_SET_LRL 34
#define BRCMF_C_GET_RADIO 37
#define BRCMF_C_SET_RADIO 38
#define BRCMF_C_GET_PHYTYPE 39
#define BRCMF_C_SET_KEY 45
#define BRCMF_C_SET_PASSIVE_SCAN 49
#define BRCMF_C_SCAN 50
#define BRCMF_C_SCAN_RESULTS 51
#define BRCMF_C_DISASSOC 52
#define BRCMF_C_REASSOC 53
#define BRCMF_C_SET_ROAM_TRIGGER 55
#define BRCMF_C_SET_ROAM_DELTA 57
#define BRCMF_C_GET_BCNPRD 75
#define BRCMF_C_SET_BCNPRD 76
#define BRCMF_C_GET_DTIMPRD 77
#define BRCMF_C_SET_DTIMPRD 78
#define BRCMF_C_SET_COUNTRY 84
#define BRCMF_C_GET_PM 85
#define BRCMF_C_SET_PM 86
#define BRCMF_C_GET_CURR_RATESET 114
#define BRCMF_C_GET_AP 117
#define BRCMF_C_SET_AP 118
#define BRCMF_C_GET_RSSI 127
#define BRCMF_C_GET_WSEC 133
#define BRCMF_C_SET_WSEC 134
#define BRCMF_C_GET_PHY_NOISE 135
#define BRCMF_C_GET_BSS_INFO 136
#define BRCMF_C_GET_BANDLIST 140
#define BRCMF_C_SET_SCB_TIMEOUT 158
#define BRCMF_C_GET_PHYLIST 180
#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185
#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187
#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201
#define BRCMF_C_GET_VALID_CHANNELS 217
#define BRCMF_C_GET_KEY_PRIMARY 235
#define BRCMF_C_SET_KEY_PRIMARY 236
#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258
#define BRCMF_C_GET_VAR 262
#define BRCMF_C_SET_VAR 263
s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data);

View file

@ -29,6 +29,24 @@
#define BRCMF_ARP_OL_HOST_AUTO_REPLY 0x00000004
#define BRCMF_ARP_OL_PEER_AUTO_REPLY 0x00000008
#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */
#define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002
#define BRCMF_STA_ASSOC 0x10 /* Associated */
/* size of brcmf_scan_params not including variable length array */
#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
/* masks for channel and ssid count */
#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16
/* primary (ie tx) key */
#define BRCMF_PRIMARY_KEY (1 << 1)
#define DOT11_BSSTYPE_ANY 2
#define BRCMF_ESCAN_REQ_VERSION 1
#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
enum brcmf_fil_p2p_if_types {
BRCMF_FIL_P2P_IF_CLIENT,
@ -90,4 +108,290 @@ enum brcmf_tdls_manual_ep_ops {
BRCMF_TDLS_MANUAL_EP_DISCOVERY = 6
};
/* Pattern matching filter. Specifies an offset within received packets to
* start matching, the pattern to match, the size of the pattern, and a bitmask
* that indicates which bits within the pattern should be matched.
*/
struct brcmf_pkt_filter_pattern_le {
/*
* Offset within received packet to start pattern matching.
* Offset '0' is the first byte of the ethernet header.
*/
__le32 offset;
/* Size of the pattern. Bitmask must be the same size.*/
__le32 size_bytes;
/*
* Variable length mask and pattern data. mask starts at offset 0.
* Pattern immediately follows mask.
*/
u8 mask_and_pattern[1];
};
/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */
struct brcmf_pkt_filter_le {
__le32 id; /* Unique filter id, specified by app. */
__le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */
__le32 negate_match; /* Negate the result of filter matches */
union { /* Filter definitions */
struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */
} u;
};
/* IOVAR "pkt_filter_enable" parameter. */
struct brcmf_pkt_filter_enable_le {
__le32 id; /* Unique filter id */
__le32 enable; /* Enable/disable bool */
};
/* BSS info structure
* Applications MUST CHECK ie_offset field and length field to access IEs and
* next bss_info structure in a vector (in struct brcmf_scan_results)
*/
struct brcmf_bss_info_le {
__le32 version; /* version field */
__le32 length; /* byte length of data in this record,
* starting at version and including IEs
*/
u8 BSSID[ETH_ALEN];
__le16 beacon_period; /* units are Kusec */
__le16 capability; /* Capability information */
u8 SSID_len;
u8 SSID[32];
struct {
__le32 count; /* # rates in this set */
u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */
} rateset; /* supported rates */
__le16 chanspec; /* chanspec for bss */
__le16 atim_window; /* units are Kusec */
u8 dtim_period; /* DTIM period */
__le16 RSSI; /* receive signal strength (in dBm) */
s8 phy_noise; /* noise (in dBm) */
u8 n_cap; /* BSS is 802.11N Capable */
/* 802.11N BSS Capabilities (based on HT_CAP_*): */
__le32 nbss_cap;
u8 ctl_ch; /* 802.11N BSS control channel number */
__le32 reserved32[1]; /* Reserved for expansion of BSS properties */
u8 flags; /* flags */
u8 reserved[3]; /* Reserved for expansion of BSS properties */
u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */
__le16 ie_offset; /* offset at which IEs start, from beginning */
__le32 ie_length; /* byte length of Information Elements */
__le16 SNR; /* average SNR of during frame reception */
/* Add new fields here */
/* variable length Information Elements */
};
struct brcm_rateset_le {
/* # rates in this set */
__le32 count;
/* rates in 500kbps units w/hi bit set if basic */
u8 rates[BRCMF_MAXRATES_IN_SET];
};
struct brcmf_ssid {
u32 SSID_len;
unsigned char SSID[32];
};
struct brcmf_ssid_le {
__le32 SSID_len;
unsigned char SSID[32];
};
struct brcmf_scan_params_le {
struct brcmf_ssid_le ssid_le; /* default: {0, ""} */
u8 bssid[ETH_ALEN]; /* default: bcast */
s8 bss_type; /* default: any,
* DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
*/
u8 scan_type; /* flags, 0 use default */
__le32 nprobes; /* -1 use default, number of probes per channel */
__le32 active_time; /* -1 use default, dwell time per channel for
* active scanning
*/
__le32 passive_time; /* -1 use default, dwell time per channel
* for passive scanning
*/
__le32 home_time; /* -1 use default, dwell time for the
* home channel between channel scans
*/
__le32 channel_num; /* count of channels and ssids that follow
*
* low half is count of channels in
* channel_list, 0 means default (use all
* available channels)
*
* high half is entries in struct brcmf_ssid
* array that follows channel_list, aligned for
* s32 (4 bytes) meaning an odd channel count
* implies a 2-byte pad between end of
* channel_list and first ssid
*
* if ssid count is zero, single ssid in the
* fixed parameter portion is assumed, otherwise
* ssid in the fixed portion is ignored
*/
__le16 channel_list[1]; /* list of chanspecs */
};
struct brcmf_scan_results {
u32 buflen;
u32 version;
u32 count;
struct brcmf_bss_info_le bss_info_le[];
};
struct brcmf_escan_params_le {
__le32 version;
__le16 action;
__le16 sync_id;
struct brcmf_scan_params_le params_le;
};
struct brcmf_escan_result_le {
__le32 buflen;
__le32 version;
__le16 sync_id;
__le16 bss_count;
struct brcmf_bss_info_le bss_info_le;
};
#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \
sizeof(struct brcmf_bss_info_le))
/* used for association with a specific BSSID and chanspec list */
struct brcmf_assoc_params_le {
/* 00:00:00:00:00:00: broadcast scan */
u8 bssid[ETH_ALEN];
/* 0: all available channels, otherwise count of chanspecs in
* chanspec_list */
__le32 chanspec_num;
/* list of chanspecs */
__le16 chanspec_list[1];
};
/* used for join with or without a specific bssid and channel list */
struct brcmf_join_params {
struct brcmf_ssid_le ssid_le;
struct brcmf_assoc_params_le params_le;
};
/* scan params for extended join */
struct brcmf_join_scan_params_le {
u8 scan_type; /* 0 use default, active or passive scan */
__le32 nprobes; /* -1 use default, nr of probes per channel */
__le32 active_time; /* -1 use default, dwell time per channel for
* active scanning
*/
__le32 passive_time; /* -1 use default, dwell time per channel
* for passive scanning
*/
__le32 home_time; /* -1 use default, dwell time for the home
* channel between channel scans
*/
};
/* extended join params */
struct brcmf_ext_join_params_le {
struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */
struct brcmf_join_scan_params_le scan_le;
struct brcmf_assoc_params_le assoc_le;
};
struct brcmf_wsec_key {
u32 index; /* key index */
u32 len; /* key length */
u8 data[WLAN_MAX_KEY_LEN]; /* key data */
u32 pad_1[18];
u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
u32 flags; /* misc flags */
u32 pad_2[3];
u32 iv_initialized; /* has IV been initialized already? */
u32 pad_3;
/* Rx IV */
struct {
u32 hi; /* upper 32 bits of IV */
u16 lo; /* lower 16 bits of IV */
} rxiv;
u32 pad_4[2];
u8 ea[ETH_ALEN]; /* per station */
};
/*
* dongle requires same struct as above but with fields in little endian order
*/
struct brcmf_wsec_key_le {
__le32 index; /* key index */
__le32 len; /* key length */
u8 data[WLAN_MAX_KEY_LEN]; /* key data */
__le32 pad_1[18];
__le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
__le32 flags; /* misc flags */
__le32 pad_2[3];
__le32 iv_initialized; /* has IV been initialized already? */
__le32 pad_3;
/* Rx IV */
struct {
__le32 hi; /* upper 32 bits of IV */
__le16 lo; /* lower 16 bits of IV */
} rxiv;
__le32 pad_4[2];
u8 ea[ETH_ALEN]; /* per station */
};
/* Used to get specific STA parameters */
struct brcmf_scb_val_le {
__le32 val;
u8 ea[ETH_ALEN];
};
/* channel encoding */
struct brcmf_channel_info_le {
__le32 hw_channel;
__le32 target_channel;
__le32 scan_channel;
};
struct brcmf_sta_info_le {
__le16 ver; /* version of this struct */
__le16 len; /* length in bytes of this structure */
__le16 cap; /* sta's advertised capabilities */
__le32 flags; /* flags defined below */
__le32 idle; /* time since data pkt rx'd from sta */
u8 ea[ETH_ALEN]; /* Station address */
__le32 count; /* # rates in this set */
u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
/* w/hi bit set if basic */
__le32 in; /* seconds elapsed since associated */
__le32 listen_interval_inms; /* Min Listen interval in ms for STA */
__le32 tx_pkts; /* # of packets transmitted */
__le32 tx_failures; /* # of packets failed */
__le32 rx_ucast_pkts; /* # of unicast packets received */
__le32 rx_mcast_pkts; /* # of multicast packets received */
__le32 tx_rate; /* Rate of last successful tx frame */
__le32 rx_rate; /* Rate of last successful rx frame */
__le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
__le32 rx_decrypt_failures; /* # of packet decrypted failed */
};
struct brcmf_chanspec_list {
__le32 count; /* # of entries */
__le32 element[1]; /* variable length uint32 list */
};
/*
* WLC_E_PROBRESP_MSG
* WLC_E_P2P_PROBREQ_MSG
* WLC_E_ACTION_FRAME_RX
*/
struct brcmf_rx_mgmt_data {
__be16 version;
__be16 chanspec;
__be32 rssi;
__be32 mactime;
__be32 rate;
};
#endif /* FWIL_TYPES_H_ */

View file

@ -27,7 +27,6 @@
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_proto.h"
#include "dhd_dbg.h"
#include "dhd_bus.h"
#include "fwil.h"
@ -36,6 +35,7 @@
#include "fwsignal.h"
#include "p2p.h"
#include "wl_cfg80211.h"
#include "proto.h"
/**
* DOC: Firmware Signalling
@ -105,6 +105,7 @@ static struct {
};
#undef BRCMF_FWS_TLV_DEF
static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
{
int i;
@ -122,6 +123,12 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
}
#endif /* DEBUG */
/*
* The PKTTAG tlv has additional bytes when firmware-signalling
* mode has REUSESEQ flag set.
*/
#define BRCMF_FWS_TYPE_SEQ_LEN 2
/*
* flags used to enable tlv signalling from firmware.
*/
@ -147,8 +154,15 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
#define BRCMF_FWS_HTOD_FLAG_PKTFROMHOST 0x01
#define BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED 0x02
#define BRCMF_FWS_RET_OK_NOSCHEDULE 0
#define BRCMF_FWS_RET_OK_SCHEDULE 1
#define BRCMF_FWS_RET_OK_NOSCHEDULE 0
#define BRCMF_FWS_RET_OK_SCHEDULE 1
#define BRCMF_FWS_MODE_REUSESEQ_SHIFT 3 /* seq reuse */
#define BRCMF_FWS_MODE_SET_REUSESEQ(x, val) ((x) = \
((x) & ~(1 << BRCMF_FWS_MODE_REUSESEQ_SHIFT)) | \
(((val) & 1) << BRCMF_FWS_MODE_REUSESEQ_SHIFT))
#define BRCMF_FWS_MODE_GET_REUSESEQ(x) \
(((x) >> BRCMF_FWS_MODE_REUSESEQ_SHIFT) & 1)
/**
* enum brcmf_fws_skb_state - indicates processing state of skb.
@ -171,6 +185,7 @@ enum brcmf_fws_skb_state {
* @bus_flags: 2 bytes reserved for bus specific parameters
* @if_flags: holds interface index and packet related flags.
* @htod: host to device packet identifier (used in PKTTAG tlv).
* @htod_seq: this 16-bit is original seq number for every suppress packet.
* @state: transmit state of the packet.
* @mac: descriptor related to destination for this packet.
*
@ -181,6 +196,7 @@ struct brcmf_skbuff_cb {
u16 bus_flags;
u16 if_flags;
u32 htod;
u16 htod_seq;
enum brcmf_fws_skb_state state;
struct brcmf_fws_mac_descriptor *mac;
};
@ -257,6 +273,22 @@ struct brcmf_skbuff_cb {
BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT)
#define BRCMF_SKB_HTOD_SEQ_FROMFW_MASK 0x2000
#define BRCMF_SKB_HTOD_SEQ_FROMFW_SHIFT 13
#define BRCMF_SKB_HTOD_SEQ_FROMDRV_MASK 0x1000
#define BRCMF_SKB_HTOD_SEQ_FROMDRV_SHIFT 12
#define BRCMF_SKB_HTOD_SEQ_NR_MASK 0x0fff
#define BRCMF_SKB_HTOD_SEQ_NR_SHIFT 0
#define brcmf_skb_htod_seq_set_field(skb, field, value) \
brcmu_maskset16(&(brcmf_skbcb(skb)->htod_seq), \
BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \
BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT, (value))
#define brcmf_skb_htod_seq_get_field(skb, field) \
brcmu_maskget16(brcmf_skbcb(skb)->htod_seq, \
BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \
BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT)
#define BRCMF_FWS_TXSTAT_GENERATION_MASK 0x80000000
#define BRCMF_FWS_TXSTAT_GENERATION_SHIFT 31
#define BRCMF_FWS_TXSTAT_FLAGS_MASK 0x78000000
@ -265,8 +297,8 @@ struct brcmf_skbuff_cb {
#define BRCMF_FWS_TXSTAT_FIFO_SHIFT 24
#define BRCMF_FWS_TXSTAT_HSLOT_MASK 0x00FFFF00
#define BRCMF_FWS_TXSTAT_HSLOT_SHIFT 8
#define BRCMF_FWS_TXSTAT_PKTID_MASK 0x00FFFFFF
#define BRCMF_FWS_TXSTAT_PKTID_SHIFT 0
#define BRCMF_FWS_TXSTAT_FREERUN_MASK 0x000000FF
#define BRCMF_FWS_TXSTAT_FREERUN_SHIFT 0
#define brcmf_txstatus_get_field(txs, field) \
brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \
@ -443,6 +475,7 @@ struct brcmf_fws_info {
unsigned long borrow_defer_timestamp;
bool bus_flow_blocked;
bool creditmap_received;
u8 mode;
};
/*
@ -812,13 +845,16 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
u16 data_offset = 0;
u8 fillers;
__le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
__le16 pktseq = cpu_to_le16(brcmf_skbcb(skb)->htod_seq);
brcmf_dbg(TRACE, "enter: %s, idx=%d pkttag=0x%08X, hslot=%d\n",
brcmf_dbg(TRACE, "enter: %s, idx=%d hslot=%d htod %X seq %X\n",
entry->name, brcmf_skb_if_flags_get_field(skb, INDEX),
le32_to_cpu(pkttag), (le32_to_cpu(pkttag) >> 8) & 0xffff);
(le32_to_cpu(pkttag) >> 8) & 0xffff,
brcmf_skbcb(skb)->htod, brcmf_skbcb(skb)->htod_seq);
if (entry->send_tim_signal)
data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode))
data_offset += BRCMF_FWS_TYPE_SEQ_LEN;
/* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
fillers = round_up(data_offset, 4) - data_offset;
@ -830,7 +866,12 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
memcpy(&wlh[2], &pkttag, sizeof(pkttag));
wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2;
if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
wlh[1] += BRCMF_FWS_TYPE_SEQ_LEN;
memcpy(&wlh[2 + BRCMF_FWS_TYPE_PKTTAG_LEN], &pktseq,
sizeof(pktseq));
}
wlh += wlh[1] + 2;
if (entry->send_tim_signal) {
entry->send_tim_signal = 0;
@ -875,6 +916,7 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
/* create a dummy packet and sent that. The traffic */
/* bitmap info will automatically be attached to that packet */
len = BRCMF_FWS_TYPE_PKTTAG_LEN + 2 +
BRCMF_FWS_TYPE_SEQ_LEN +
BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2 +
4 + fws->drvr->hdrlen;
skb = brcmu_pkt_buf_get_skb(len);
@ -884,6 +926,8 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
skcb = brcmf_skbcb(skb);
skcb->mac = entry;
skcb->state = BRCMF_FWS_SKBSTATE_TIM;
skcb->htod = 0;
skcb->htod_seq = 0;
bus = fws->drvr->bus_if;
err = brcmf_fws_hdrpush(fws, skb);
if (err == 0) {
@ -1172,8 +1216,13 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws,
{
int prec = 2 * fifo;
u32 *qfull_stat = &fws->stats.delayq_full_error;
struct brcmf_fws_mac_descriptor *entry;
struct pktq *pq;
struct sk_buff_head *queue;
struct sk_buff *p_head;
struct sk_buff *p_tail;
u32 fr_new;
u32 fr_compare;
entry = brcmf_skbcb(p)->mac;
if (entry == NULL) {
@ -1185,9 +1234,55 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws,
if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
prec += 1;
qfull_stat = &fws->stats.supprq_full_error;
}
if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
/* Fix out of order delivery of frames. Dont assume frame */
/* can be inserted at the end, but look for correct position */
pq = &entry->psq;
if (pktq_full(pq) || pktq_pfull(pq, prec)) {
*qfull_stat += 1;
return -ENFILE;
}
queue = &pq->q[prec].skblist;
p_head = skb_peek(queue);
p_tail = skb_peek_tail(queue);
fr_new = brcmf_skb_htod_tag_get_field(p, FREERUN);
while (p_head != p_tail) {
fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
FREERUN);
/* be sure to handle wrap of 256 */
if (((fr_new > fr_compare) &&
((fr_new - fr_compare) < 128)) ||
((fr_new < fr_compare) &&
((fr_compare - fr_new) > 128)))
break;
p_tail = skb_queue_prev(queue, p_tail);
}
/* Position found. Determine what to do */
if (p_tail == NULL) {
/* empty list */
__skb_queue_tail(queue, p);
} else {
fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
FREERUN);
if (((fr_new > fr_compare) &&
((fr_new - fr_compare) < 128)) ||
((fr_new < fr_compare) &&
((fr_compare - fr_new) > 128))) {
/* After tail */
__skb_queue_after(queue, p_tail, p);
} else {
/* Before tail */
__skb_insert(p, p_tail->prev, p_tail, queue);
}
}
/* Complete the counters and statistics */
pq->len++;
if (pq->hi_prec < prec)
pq->hi_prec = (u8) prec;
} else if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
*qfull_stat += 1;
return -ENFILE;
}
@ -1277,7 +1372,8 @@ done:
}
static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
struct sk_buff *skb, u32 genbit)
struct sk_buff *skb, u32 genbit,
u16 seq)
{
struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
u32 hslot;
@ -1298,6 +1394,14 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
if (ret == 0)
brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit);
brcmf_skbcb(skb)->htod_seq = seq;
if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) {
brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1);
brcmf_skb_htod_seq_set_field(skb, FROMFW, 0);
} else {
brcmf_skb_htod_seq_set_field(skb, FROMDRV, 0);
}
ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo,
skb);
if (ret != 0) {
@ -1317,7 +1421,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
static int
brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
u32 genbit)
u32 genbit, u16 seq)
{
u32 fifo;
int ret;
@ -1360,8 +1464,8 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
if (entry->suppressed && entry->suppr_transit_count)
entry->suppr_transit_count--;
brcmf_dbg(DATA, "%s flags %X htod %X\n", entry->name, skcb->if_flags,
skcb->htod);
brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name, flags,
skcb->htod, seq);
/* pick up the implicit credit from this packet */
fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
@ -1374,7 +1478,8 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
brcmf_fws_macdesc_return_req_credit(skb);
if (!remove_from_hanger)
ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit);
ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit,
seq);
if (remove_from_hanger || ret)
brcmf_txfinalize(fws->drvr, skb, true);
@ -1406,10 +1511,12 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
{
__le32 status_le;
__le16 seq_le;
u32 status;
u32 hslot;
u32 genbit;
u8 flags;
u16 seq;
fws->stats.txs_indicate++;
memcpy(&status_le, data, sizeof(status_le));
@ -1417,9 +1524,16 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
flags = brcmf_txstatus_get_field(status, FLAGS);
hslot = brcmf_txstatus_get_field(status, HSLOT);
genbit = brcmf_txstatus_get_field(status, GENERATION);
if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
memcpy(&seq_le, &data[BRCMF_FWS_TYPE_PKTTAG_LEN],
sizeof(seq_le));
seq = le16_to_cpu(seq_le);
} else {
seq = 0;
}
brcmf_fws_lock(fws);
brcmf_fws_txs_process(fws, flags, hslot, genbit);
brcmf_fws_txs_process(fws, flags, hslot, genbit, seq);
brcmf_fws_unlock(fws);
return BRCMF_FWS_RET_OK_NOSCHEDULE;
}
@ -1610,8 +1724,8 @@ static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
struct brcmf_fws_mac_descriptor *entry = skcb->mac;
u8 flags;
brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
if (skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED)
brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
if (brcmf_skb_if_flags_get_field(p, REQUESTED)) {
/*
@ -1652,7 +1766,7 @@ static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
fws->stats.rollback_failed++;
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
hslot, 0);
hslot, 0, 0);
} else {
fws->stats.rollback_success++;
brcmf_fws_return_credits(fws, fifo, 1);
@ -1732,6 +1846,8 @@ static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p,
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
int rc, hslot;
skcb->htod = 0;
skcb->htod_seq = 0;
hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
brcmf_skb_htod_tag_set_field(p, FREERUN, skcb->mac->seq[fifo]);
@ -1908,6 +2024,7 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
struct brcmf_fws_info *fws;
u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
int rc;
u32 mode;
drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
if (!drvr->fws) {
@ -1966,6 +2083,18 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1))
brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
/* Enable seq number reuse, if supported */
if (brcmf_fil_iovar_int_get(drvr->iflist[0], "wlfc_mode", &mode) == 0) {
if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) {
mode = 0;
BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1);
if (brcmf_fil_iovar_int_set(drvr->iflist[0],
"wlfc_mode", mode) == 0) {
BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1);
}
}
}
brcmf_fws_hanger_init(&fws->hanger);
brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);
brcmf_fws_macdesc_set_name(fws, &fws->desc.other);
@ -2022,7 +2151,7 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
}
brcmf_fws_lock(fws);
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0);
brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0);
brcmf_fws_unlock(fws);
}

View file

@ -812,7 +812,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
struct ieee80211_channel *chan = request->channels[i];
if (chan->flags & (IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_PASSIVE_SCAN))
IEEE80211_CHAN_NO_IR))
continue;
chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf,

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2013 Broadcom Corporation
*
* 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 <linux/types.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_dbg.h"
#include "proto.h"
#include "bcdc.h"
int brcmf_proto_attach(struct brcmf_pub *drvr)
{
struct brcmf_proto *proto;
proto = kzalloc(sizeof(*proto), GFP_ATOMIC);
if (!proto)
goto fail;
drvr->proto = proto;
/* BCDC protocol is only protocol supported for the moment */
if (brcmf_proto_bcdc_attach(drvr))
goto fail;
if ((proto->hdrpush == NULL) || (proto->hdrpull == NULL) ||
(proto->query_dcmd == NULL) || (proto->set_dcmd == NULL)) {
brcmf_err("Not all proto handlers have been installed\n");
goto fail;
}
return 0;
fail:
kfree(proto);
drvr->proto = NULL;
return -ENOMEM;
}
void brcmf_proto_detach(struct brcmf_pub *drvr)
{
if (drvr->proto) {
brcmf_proto_bcdc_detach(drvr);
kfree(drvr->proto);
drvr->proto = NULL;
}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2013 Broadcom Corporation
*
* 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.
*/
#ifndef BRCMFMAC_PROTO_H
#define BRCMFMAC_PROTO_H
struct brcmf_proto {
void (*hdrpush)(struct brcmf_pub *drvr, int ifidx, u8 offset,
struct sk_buff *skb);
int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
struct sk_buff *skb);
int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len);
int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
uint len);
void *pd;
};
int brcmf_proto_attach(struct brcmf_pub *drvr);
void brcmf_proto_detach(struct brcmf_pub *drvr);
static inline void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
u8 offset, struct sk_buff *skb)
{
drvr->proto->hdrpush(drvr, ifidx, offset, skb);
}
static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
u8 *ifidx, struct sk_buff *skb)
{
return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb);
}
static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx,
uint cmd, void *buf, uint len)
{
return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len);
}
static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx,
uint cmd, void *buf, uint len)
{
return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len);
}
#endif /* BRCMFMAC_PROTO_H */

View file

@ -89,7 +89,7 @@ TRACE_EVENT(brcmf_hexdump,
TP_printk("hexdump [addr=%lx, length=%lu]", __entry->addr, __entry->len)
);
TRACE_EVENT(brcmf_bdchdr,
TRACE_EVENT(brcmf_bcdchdr,
TP_PROTO(void *data),
TP_ARGS(data),
TP_STRUCT__entry(
@ -107,24 +107,35 @@ TRACE_EVENT(brcmf_bdchdr,
memcpy(__get_dynamic_array(signal),
(u8 *)data + 4, __entry->siglen);
),
TP_printk("bdc: prio=%d siglen=%d", __entry->prio, __entry->siglen)
TP_printk("bcdc: prio=%d siglen=%d", __entry->prio, __entry->siglen)
);
#ifndef SDPCM_RX
#define SDPCM_RX 0
#endif
#ifndef SDPCM_TX
#define SDPCM_TX 1
#endif
#ifndef SDPCM_GLOM
#define SDPCM_GLOM 2
#endif
TRACE_EVENT(brcmf_sdpcm_hdr,
TP_PROTO(bool tx, void *data),
TP_ARGS(tx, data),
TP_PROTO(u8 dir, void *data),
TP_ARGS(dir, data),
TP_STRUCT__entry(
__field(u8, tx)
__field(u8, dir)
__field(u16, len)
__array(u8, hdr, 12)
__dynamic_array(u8, hdr, dir == SDPCM_GLOM ? 20 : 12)
),
TP_fast_assign(
memcpy(__entry->hdr, data, 12);
__entry->len = __entry->hdr[0] | (__entry->hdr[1] << 8);
__entry->tx = tx ? 1 : 0;
memcpy(__get_dynamic_array(hdr), data, dir == SDPCM_GLOM ? 20 : 12);
__entry->len = *(u8 *)data | (*((u8 *)data + 1) << 8);
__entry->dir = dir;
),
TP_printk("sdpcm: %s len %u, seq %d", __entry->tx ? "TX" : "RX",
__entry->len, __entry->hdr[4])
TP_printk("sdpcm: %s len %u, seq %d",
__entry->dir == SDPCM_RX ? "RX" : "TX",
__entry->len, ((u8 *)__get_dynamic_array(hdr))[4])
);
#ifdef CONFIG_BRCM_TRACING

View file

@ -1255,7 +1255,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
bus->chiprev = bus_pub->chiprev;
/* Attach to the common driver interface */
ret = brcmf_attach(0, dev);
ret = brcmf_attach(dev);
if (ret) {
brcmf_err("brcmf_attach failed\n");
goto fail;
@ -1454,7 +1454,7 @@ static int brcmf_usb_resume(struct usb_interface *intf)
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
brcmf_dbg(USB, "Enter\n");
if (!brcmf_attach(0, devinfo->dev))
if (!brcmf_attach(devinfo->dev))
return brcmf_bus_start(&usb->dev);
return 0;

View file

@ -202,9 +202,9 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {
/* This is to override regulatory domains defined in cfg80211 module (reg.c)
* By default world regulatory domain defined in reg.c puts the flags
* NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for
* 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't
* start p2p operations on 5GHz channels. All the changes in world regulatory
* NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
* With respect to these flags, wpa_supplicant doesn't * start p2p
* operations on 5GHz channels. All the changes in world regulatory
* domain are to be done here.
*/
static const struct ieee80211_regdomain brcmf_regdom = {
@ -2556,8 +2556,8 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
ch_bss.band == ch_bss_info_le.band &&
bss_info_le->SSID_len == bss->SSID_len &&
!memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
(bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
(bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
s16 bss_rssi = le16_to_cpu(bss->RSSI);
s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
@ -2566,13 +2566,13 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
*/
if (bss_info_rssi > bss_rssi)
bss->RSSI = bss_info_le->RSSI;
} else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
(bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
} else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
(bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
/* preserve the on-channel rssi measurement
* if the new measurement is off channel
*/
bss->RSSI = bss_info_le->RSSI;
bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
}
return 1;
}
@ -3973,11 +3973,12 @@ brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
static int
brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct ieee80211_channel *chan = params->chan;
const u8 *buf = params->buf;
size_t len = params->len;
const struct ieee80211_mgmt *mgmt;
struct brcmf_cfg80211_vif *vif;
s32 err = 0;
@ -4341,7 +4342,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
wiphy->max_remain_on_channel_duration = 5000;
brcmf_wiphy_pno_params(wiphy);
brcmf_dbg(INFO, "Registering custom regulatory\n");
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
err = wiphy_register(wiphy);
if (err < 0) {
@ -5197,10 +5198,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
if (channel & WL_CHAN_RADAR)
band_chan_arr[index].flags |=
(IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IBSS);
IEEE80211_CHAN_NO_IR);
if (channel & WL_CHAN_PASSIVE)
band_chan_arr[index].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
}
}
if (!update)

View file

@ -59,23 +59,18 @@
#define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_DFS | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_DFS | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
static const struct ieee80211_regdomain brcms_regdom_x2 = {
.n_reg_rules = 6,
@ -395,7 +390,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
brcms_b_set_chanspec(wlc->hw, chanspec,
!!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN),
!!(ch->flags & IEEE80211_CHAN_NO_IR),
&txpwr);
}
@ -657,8 +652,8 @@ static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
*/
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
ch->flags |= IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_IR;
}
}
@ -684,18 +679,15 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
rule = freq_reg_info(wiphy, ch->center_freq);
rule = freq_reg_info(wiphy,
MHZ_TO_KHZ(ch->center_freq));
if (IS_ERR(rule))
continue;
if (!(rule->flags & NL80211_RRF_NO_IBSS))
ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN))
ch->flags &=
~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(rule->flags & NL80211_RRF_NO_IR))
ch->flags &= ~IEEE80211_CHAN_NO_IR;
} else if (ch->beacon_found) {
ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN);
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
}
}
@ -775,8 +767,8 @@ void brcms_c_regd_init(struct brcms_c_info *wlc)
}
wlc->wiphy->reg_notifier = brcms_reg_notifier;
wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_STRICT_REGULATORY;
wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_STRICT_REG;
wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);
}

View file

@ -125,13 +125,13 @@ static struct ieee80211_channel brcms_2ghz_chantable[] = {
CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
CHAN2GHZ(12, 2467,
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_HT40PLUS),
CHAN2GHZ(13, 2472,
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_HT40PLUS),
CHAN2GHZ(14, 2484,
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS |
IEEE80211_CHAN_NO_OFDM)
};
@ -144,51 +144,51 @@ static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
/* UNII-2 */
CHAN5GHZ(52,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(56,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(60,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(64,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
/* MID */
CHAN5GHZ(100,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(104,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(108,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(112,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(116,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(120,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(124,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(128,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(132,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(136,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(140,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS |
IEEE80211_CHAN_NO_HT40MINUS),
/* UNII-3 */
CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),

View file

@ -108,9 +108,9 @@ static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
struct hwbus_priv *self = dev_id;
if (self->core) {
sdio_claim_host(self->func);
cw1200_sdio_lock(self);
cw1200_irq_handler(self->core);
sdio_release_host(self->func);
cw1200_sdio_unlock(self);
return IRQ_HANDLED;
} else {
return IRQ_NONE;

View file

@ -173,8 +173,9 @@ void cw1200_scan_work(struct work_struct *work)
cw1200_set_pm(priv, &priv->powersave_mode);
if (priv->scan.status < 0)
wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan failed (%d).\n",
priv->scan.status);
wiphy_warn(priv->hw->wiphy,
"[SCAN] Scan failed (%d).\n",
priv->scan.status);
else if (priv->scan.req)
wiphy_dbg(priv->hw->wiphy,
"[SCAN] Scan completed.\n");
@ -197,9 +198,9 @@ void cw1200_scan_work(struct work_struct *work)
if ((*it)->band != first->band)
break;
if (((*it)->flags ^ first->flags) &
IEEE80211_CHAN_PASSIVE_SCAN)
IEEE80211_CHAN_NO_IR)
break;
if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
(*it)->max_power != first->max_power)
break;
}
@ -210,7 +211,7 @@ void cw1200_scan_work(struct work_struct *work)
else
scan.max_tx_rate = WSM_TRANSMIT_RATE_1;
scan.num_probes =
(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 2;
(first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2;
scan.num_ssids = priv->scan.n_ssids;
scan.ssids = &priv->scan.ssids[0];
scan.num_channels = it - priv->scan.curr;
@ -233,7 +234,7 @@ void cw1200_scan_work(struct work_struct *work)
}
for (i = 0; i < scan.num_channels; ++i) {
scan.ch[i].number = priv->scan.curr[i]->hw_value;
if (priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) {
scan.ch[i].min_chan_time = 50;
scan.ch[i].max_chan_time = 100;
} else {
@ -241,7 +242,7 @@ void cw1200_scan_work(struct work_struct *work)
scan.ch[i].max_chan_time = 25;
}
}
if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
priv->scan.output_power != first->max_power) {
priv->scan.output_power = first->max_power;
wsm_set_output_power(priv,

View file

@ -1930,10 +1930,10 @@ static int ipw2100_wdev_init(struct net_device *dev)
bg_band->channels[i].max_power = geo->bg[i].max_power;
if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
bg_band->channels[i].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
bg_band->channels[i].flags |=
IEEE80211_CHAN_NO_IBSS;
IEEE80211_CHAN_NO_IR;
if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
bg_band->channels[i].flags |=
IEEE80211_CHAN_RADAR;
@ -6362,7 +6362,6 @@ out:
&ipw2100_attribute_group);
free_libipw(dev, 0);
pci_set_drvdata(pci_dev, NULL);
}
pci_iounmap(pci_dev, ioaddr);

View file

@ -11472,10 +11472,10 @@ static int ipw_wdev_init(struct net_device *dev)
bg_band->channels[i].max_power = geo->bg[i].max_power;
if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
bg_band->channels[i].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
bg_band->channels[i].flags |=
IEEE80211_CHAN_NO_IBSS;
IEEE80211_CHAN_NO_IR;
if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
bg_band->channels[i].flags |=
IEEE80211_CHAN_RADAR;
@ -11511,10 +11511,10 @@ static int ipw_wdev_init(struct net_device *dev)
a_band->channels[i].max_power = geo->a[i].max_power;
if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
a_band->channels[i].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
a_band->channels[i].flags |=
IEEE80211_CHAN_NO_IBSS;
IEEE80211_CHAN_NO_IR;
if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
a_band->channels[i].flags |=
IEEE80211_CHAN_RADAR;

View file

@ -1595,7 +1595,7 @@ il3945_get_channels_for_scan(struct il_priv *il, enum ieee80211_band band,
* and use long active_dwell time.
*/
if (!is_active || il_is_channel_passive(ch_info) ||
(chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
(chan->flags & IEEE80211_CHAN_NO_IR)) {
scan_ch->type = 0; /* passive */
if (IL_UCODE_API(il->ucode_ver) == 1)
scan_ch->active_dwell =
@ -2396,8 +2396,7 @@ __il3945_up(struct il_priv *il)
clear_bit(S_RFKILL, &il->status);
else {
set_bit(S_RFKILL, &il->status);
IL_WARN("Radio disabled by HW RF Kill switch\n");
return -ENODEV;
return -ERFKILL;
}
_il_wr(il, CSR_INT, 0xFFFFFFFF);
@ -3575,9 +3574,9 @@ il3945_setup_mac(struct il_priv *il)
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->flags |=
WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;

View file

@ -805,7 +805,7 @@ il4965_get_channels_for_scan(struct il_priv *il, struct ieee80211_vif *vif,
}
if (!is_active || il_is_channel_passive(ch_info) ||
(chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
(chan->flags & IEEE80211_CHAN_NO_IR))
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
@ -5778,9 +5778,9 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->flags |=
WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
/*
* For now, disable PS by default because it affects

View file

@ -3445,10 +3445,10 @@ il_init_geos(struct il_priv *il)
if (il_is_channel_valid(ch)) {
if (!(ch->flags & EEPROM_CHANNEL_IBSS))
geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
geo_ch->flags |= IEEE80211_CHAN_NO_IR;
if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
geo_ch->flags |= IEEE80211_CHAN_NO_IR;
if (ch->flags & EEPROM_CHANNEL_RADAR)
geo_ch->flags |= IEEE80211_CHAN_RADAR;

View file

@ -567,12 +567,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].
flags & IEEE80211_CHAN_NO_IBSS) ||
flags & IEEE80211_CHAN_NO_IR) ||
(channels[i].
flags & IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].
flags & IEEE80211_CHAN_PASSIVE_SCAN ?
flags & IEEE80211_CHAN_NO_IR ?
"passive only" : "active/passive");
}
supp_band = il_get_hw_mode(il, IEEE80211_BAND_5GHZ);
@ -594,12 +594,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].
flags & IEEE80211_CHAN_NO_IBSS) ||
flags & IEEE80211_CHAN_NO_IR) ||
(channels[i].
flags & IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].
flags & IEEE80211_CHAN_PASSIVE_SCAN ?
flags & IEEE80211_CHAN_NO_IR ?
"passive only" : "active/passive");
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);

View file

@ -352,12 +352,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
((channels[i].flags & IEEE80211_CHAN_NO_IR)
|| (channels[i].flags &
IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].flags &
IEEE80211_CHAN_PASSIVE_SCAN ?
IEEE80211_CHAN_NO_IR ?
"passive only" : "active/passive");
}
supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
@ -375,12 +375,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
((channels[i].flags & IEEE80211_CHAN_NO_IR)
|| (channels[i].flags &
IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].flags &
IEEE80211_CHAN_PASSIVE_SCAN ?
IEEE80211_CHAN_NO_IR ?
"passive only" : "active/passive");
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);

View file

@ -155,9 +155,9 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
}
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
#ifdef CONFIG_PM_SLEEP
if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&

View file

@ -544,7 +544,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
channel = chan->hw_value;
scan_ch->channel = cpu_to_le16(channel);
if (!is_active || (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
if (!is_active || (chan->flags & IEEE80211_CHAN_NO_IR))
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;

View file

@ -614,10 +614,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
channel->flags = IEEE80211_CHAN_NO_HT40;
if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS))
channel->flags |= IEEE80211_CHAN_NO_IBSS;
channel->flags |= IEEE80211_CHAN_NO_IR;
if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE))
channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
channel->flags |= IEEE80211_CHAN_NO_IR;
if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR)
channel->flags |= IEEE80211_CHAN_RADAR;

View file

@ -223,10 +223,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
channel->flags |= IEEE80211_CHAN_NO_160MHZ;
if (!(ch_flags & NVM_CHANNEL_IBSS))
channel->flags |= IEEE80211_CHAN_NO_IBSS;
channel->flags |= IEEE80211_CHAN_NO_IR;
if (!(ch_flags & NVM_CHANNEL_ACTIVE))
channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
channel->flags |= IEEE80211_CHAN_NO_IR;
if (ch_flags & NVM_CHANNEL_RADAR)
channel->flags |= IEEE80211_CHAN_RADAR;

View file

@ -199,9 +199,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
hw->wiphy->n_iface_combinations =

View file

@ -192,7 +192,7 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
for (i = 0; i < cmd->channel_count; i++) {
chan->channel = cpu_to_le16(req->channels[i]->hw_value);
chan->type = cpu_to_le32(type);
if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
chan->active_dwell = cpu_to_le16(active_dwell);
chan->passive_dwell = cpu_to_le16(passive_dwell);
@ -642,7 +642,7 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
channels->iter_count[index] = cpu_to_le16(1);
channels->iter_interval[index] = 0;
if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
if (!(s_band->channels[i].flags & IEEE80211_CHAN_NO_IR))
channels->type[index] |=
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);

View file

@ -849,7 +849,7 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card)
card->started = true;
/* Tell PM core that we don't need the card to be
* powered now */
pm_runtime_put_noidle(&func->dev);
pm_runtime_put(&func->dev);
}
}
@ -907,8 +907,8 @@ static int if_sdio_power_on(struct if_sdio_card *card)
sdio_release_host(func);
ret = if_sdio_prog_firmware(card);
if (ret) {
sdio_disable_func(func);
return ret;
sdio_claim_host(func);
goto disable;
}
return 0;

View file

@ -93,7 +93,6 @@ static void free_if_spi_card(struct if_spi_card *card)
list_del(&packet->list);
kfree(packet);
}
spi_set_drvdata(card->spi, NULL);
kfree(card);
}

View file

@ -159,7 +159,7 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = {
.reg_rules = {
REG_RULE(2412-10, 2462+10, 40, 0, 20, 0),
REG_RULE(5725-10, 5850+10, 40, 0, 30,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
NL80211_RRF_NO_IR),
}
};
@ -353,7 +353,6 @@ struct mac80211_hwsim_data {
} ps;
bool ps_poll_pending;
struct dentry *debugfs;
struct dentry *debugfs_ps;
struct sk_buff_head pending; /* packets pending */
/*
@ -362,7 +361,6 @@ struct mac80211_hwsim_data {
* radio can be in more then one group.
*/
u64 group;
struct dentry *debugfs_group;
int power_level;
@ -1493,7 +1491,7 @@ static void hw_scan_work(struct work_struct *work)
req->channels[hwsim->scan_chan_idx]->center_freq);
hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx];
if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
if (hwsim->tmp_chan->flags & IEEE80211_CHAN_NO_IR ||
!req->n_ssids) {
dwell = 120;
} else {
@ -1742,9 +1740,7 @@ static void mac80211_hwsim_free(void)
spin_unlock_bh(&hwsim_radio_lock);
list_for_each_entry_safe(data, tmpdata, &tmplist, list) {
debugfs_remove(data->debugfs_group);
debugfs_remove(data->debugfs_ps);
debugfs_remove(data->debugfs);
debugfs_remove_recursive(data->debugfs);
ieee80211_unregister_hw(data->hw);
device_release_driver(data->dev);
device_unregister(data->dev);
@ -1901,6 +1897,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val)
DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
"%llu\n");
static int hwsim_write_simulate_radar(void *dat, u64 val)
{
struct mac80211_hwsim_data *data = dat;
ieee80211_radar_detected(data->hw);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL,
hwsim_write_simulate_radar, "%llu\n");
static int hwsim_fops_group_read(void *dat, u64 *val)
{
@ -2201,11 +2208,28 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
};
static struct ieee80211_iface_combination hwsim_if_comb = {
.limits = hwsim_if_limits,
.n_limits = ARRAY_SIZE(hwsim_if_limits),
.max_interfaces = 2048,
.num_different_channels = 1,
static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
{ .max = 8, .types = BIT(NL80211_IFTYPE_AP) },
};
static struct ieee80211_iface_combination hwsim_if_comb[] = {
{
.limits = hwsim_if_limits,
.n_limits = ARRAY_SIZE(hwsim_if_limits),
.max_interfaces = 2048,
.num_different_channels = 1,
},
{
.limits = hwsim_if_dfs_limits,
.n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
.max_interfaces = 8,
.num_different_channels = 1,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160),
}
};
static int __init init_mac80211_hwsim(void)
@ -2223,7 +2247,7 @@ static int __init init_mac80211_hwsim(void)
return -EINVAL;
if (channels > 1) {
hwsim_if_comb.num_different_channels = channels;
hwsim_if_comb[0].num_different_channels = channels;
mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
mac80211_hwsim_ops.cancel_hw_scan =
mac80211_hwsim_cancel_hw_scan;
@ -2303,13 +2327,15 @@ static int __init init_mac80211_hwsim(void)
hw->wiphy->n_addresses = 2;
hw->wiphy->addresses = data->addresses;
hw->wiphy->iface_combinations = &hwsim_if_comb;
hw->wiphy->n_iface_combinations = 1;
hw->wiphy->iface_combinations = hwsim_if_comb;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
if (channels > 1) {
hw->wiphy->max_scan_ssids = 255;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
hw->wiphy->max_remain_on_channel_duration = 1000;
/* For channels > 1 DFS is not allowed */
hw->wiphy->n_iface_combinations = 1;
}
INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
@ -2333,7 +2359,8 @@ static int __init init_mac80211_hwsim(void)
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_WANT_MONITOR_VIF |
IEEE80211_HW_QUEUE_CONTROL;
IEEE80211_HW_QUEUE_CONTROL |
IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
if (rctbl)
hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
@ -2393,6 +2420,7 @@ static int __init init_mac80211_hwsim(void)
sband->vht_cap.cap =
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
IEEE80211_VHT_CAP_RXLDPC |
IEEE80211_VHT_CAP_SHORT_GI_80 |
IEEE80211_VHT_CAP_SHORT_GI_160 |
@ -2435,46 +2463,53 @@ static int __init init_mac80211_hwsim(void)
break;
case HWSIM_REGTEST_WORLD_ROAM:
if (i == 0) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_01);
}
break;
case HWSIM_REGTEST_CUSTOM_WORLD:
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_01);
break;
case HWSIM_REGTEST_CUSTOM_WORLD_2:
if (i == 0) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_01);
} else if (i == 1) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_02);
}
break;
case HWSIM_REGTEST_STRICT_ALL:
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
break;
case HWSIM_REGTEST_STRICT_FOLLOW:
case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
if (i == 0)
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_STRICT_REG;
break;
case HWSIM_REGTEST_ALL:
if (i == 0) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_01);
} else if (i == 1) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_02);
} else if (i == 4)
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_STRICT_REG;
break;
default:
break;
@ -2541,16 +2576,18 @@ static int __init init_mac80211_hwsim(void)
data->debugfs = debugfs_create_dir("hwsim",
hw->wiphy->debugfsdir);
data->debugfs_ps = debugfs_create_file("ps", 0666,
data->debugfs, data,
&hwsim_fops_ps);
data->debugfs_group = debugfs_create_file("group", 0666,
data->debugfs, data,
&hwsim_fops_group);
debugfs_create_file("ps", 0666, data->debugfs, data,
&hwsim_fops_ps);
debugfs_create_file("group", 0666, data->debugfs, data,
&hwsim_fops_group);
if (channels == 1)
debugfs_create_file("dfs_simulate_radar", 0222,
data->debugfs,
data, &hwsim_simulate_radar);
tasklet_hrtimer_init(&data->beacon_timer,
mac80211_hwsim_beacon,
CLOCK_REALTIME, HRTIMER_MODE_ABS);
CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS);
list_add_tail(&data->list, &hwsim_radios);
}

View file

@ -50,24 +50,24 @@ static const struct ieee80211_regdomain mwifiex_world_regdom_custom = {
REG_RULE(2412-10, 2462+10, 40, 3, 20, 0),
/* Channel 12 - 13 */
REG_RULE(2467-10, 2472+10, 20, 3, 20,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
NL80211_RRF_NO_IR),
/* Channel 14 */
REG_RULE(2484-10, 2484+10, 20, 3, 20,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
NL80211_RRF_NO_IR |
NL80211_RRF_NO_OFDM),
/* Channel 36 - 48 */
REG_RULE(5180-10, 5240+10, 40, 3, 20,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
NL80211_RRF_NO_IR),
/* Channel 149 - 165 */
REG_RULE(5745-10, 5825+10, 40, 3, 20,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
NL80211_RRF_NO_IR),
/* Channel 52 - 64 */
REG_RULE(5260-10, 5320+10, 40, 3, 30,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
NL80211_RRF_NO_IR |
NL80211_RRF_DFS),
/* Channel 100 - 140 */
REG_RULE(5500-10, 5700+10, 40, 3, 30,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
NL80211_RRF_NO_IR |
NL80211_RRF_DFS),
}
};
@ -184,10 +184,10 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
*/
static int
mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
{
const u8 *buf = params->buf;
size_t len = params->len;
struct sk_buff *skb;
u16 pkt_len;
const struct ieee80211_mgmt *mgmt;
@ -1968,7 +1968,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
user_scan_cfg->chan_list[i].radio_type = chan->band;
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
if (chan->flags & IEEE80211_CHAN_NO_IR)
user_scan_cfg->chan_list[i].scan_type =
MWIFIEX_SCAN_TYPE_PASSIVE;
else
@ -2702,9 +2702,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_STRICT_REGULATORY |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG |
REGULATORY_STRICT_REG;
wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);

View file

@ -515,14 +515,14 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
scan_chan_list[chan_idx].max_scan_time =
cpu_to_le16((u16) user_scan_in->
chan_list[0].scan_time);
else if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
else if (ch->flags & IEEE80211_CHAN_NO_IR)
scan_chan_list[chan_idx].max_scan_time =
cpu_to_le16(adapter->passive_scan_time);
else
scan_chan_list[chan_idx].max_scan_time =
cpu_to_le16(adapter->active_scan_time);
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
if (ch->flags & IEEE80211_CHAN_NO_IR)
scan_chan_list[chan_idx].chan_scan_mode_bitmap
|= MWIFIEX_PASSIVE_SCAN;
else

View file

@ -338,8 +338,7 @@ static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
if (!data_buf)
return -1;
pg_tlv_hdr = (struct mwifiex_types_power_group *)
((u8 *) data_buf + sizeof(struct host_cmd_ds_txpwr_cfg));
pg_tlv_hdr = (struct mwifiex_types_power_group *)((u8 *)data_buf);
pg = (struct mwifiex_power_group *)
((u8 *) pg_tlv_hdr + sizeof(struct mwifiex_types_power_group));
length = le16_to_cpu(pg_tlv_hdr->length);
@ -383,19 +382,25 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
struct mwifiex_types_power_group *pg_tlv_hdr;
struct mwifiex_power_group *pg;
u16 action = le16_to_cpu(txp_cfg->action);
u16 tlv_buf_left;
pg_tlv_hdr = (struct mwifiex_types_power_group *)
((u8 *)txp_cfg +
sizeof(struct host_cmd_ds_txpwr_cfg));
pg = (struct mwifiex_power_group *)
((u8 *)pg_tlv_hdr +
sizeof(struct mwifiex_types_power_group));
tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*txp_cfg);
if (tlv_buf_left <
le16_to_cpu(pg_tlv_hdr->length) + sizeof(*pg_tlv_hdr))
return 0;
switch (action) {
case HostCmd_ACT_GEN_GET:
pg_tlv_hdr = (struct mwifiex_types_power_group *)
((u8 *) txp_cfg +
sizeof(struct host_cmd_ds_txpwr_cfg));
pg = (struct mwifiex_power_group *)
((u8 *) pg_tlv_hdr +
sizeof(struct mwifiex_types_power_group));
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
mwifiex_get_power_level(priv, txp_cfg);
mwifiex_get_power_level(priv, pg_tlv_hdr);
priv->tx_power_level = (u16) pg->power_min;
break;
@ -404,14 +409,6 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
if (!le32_to_cpu(txp_cfg->mode))
break;
pg_tlv_hdr = (struct mwifiex_types_power_group *)
((u8 *) txp_cfg +
sizeof(struct host_cmd_ds_txpwr_cfg));
pg = (struct mwifiex_power_group *)
((u8 *) pg_tlv_hdr +
sizeof(struct mwifiex_types_power_group));
if (pg->power_max == pg->power_min)
priv->tx_power_level = (u16) pg->power_min;
break;

View file

@ -914,7 +914,6 @@ islpci_setup(struct pci_dev *pdev)
do_islpci_free_memory:
islpci_free_memory(priv);
do_free_netdev:
pci_set_drvdata(pdev, NULL);
free_netdev(ndev);
priv = NULL;
return NULL;

View file

@ -199,7 +199,6 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
do_unregister_netdev:
unregister_netdev(ndev);
islpci_free_memory(priv);
pci_set_drvdata(pdev, NULL);
free_netdev(ndev);
priv = NULL;
do_pci_clear_mwi:
@ -247,7 +246,6 @@ prism54_remove(struct pci_dev *pdev)
/* free the PCI memory and unmap the remapped page */
islpci_free_memory(priv);
pci_set_drvdata(pdev, NULL);
free_netdev(ndev);
priv = NULL;

View file

@ -5462,15 +5462,14 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
rt2800_bbp_write(rt2x00dev, 68, 0x0b);
rt2800_bbp_write(rt2x00dev, 69, 0x12);
rt2800_bbp_write(rt2x00dev, 69, 0x0d);
rt2800_bbp_write(rt2x00dev, 70, 0x06);
rt2800_bbp_write(rt2x00dev, 73, 0x13);
rt2800_bbp_write(rt2x00dev, 75, 0x46);
rt2800_bbp_write(rt2x00dev, 76, 0x28);
rt2800_bbp_write(rt2x00dev, 77, 0x59);
rt2800_bbp_write(rt2x00dev, 70, 0x0a);
rt2800_bbp_write(rt2x00dev, 79, 0x13);
rt2800_bbp_write(rt2x00dev, 80, 0x05);
rt2800_bbp_write(rt2x00dev, 81, 0x33);
@ -5513,6 +5512,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt(rt2x00dev, RT5392)) {
rt2800_bbp_write(rt2x00dev, 134, 0xd0);
rt2800_bbp_write(rt2x00dev, 135, 0xf6);
rt2800_bbp_write(rt2x00dev, 148, 0x84);
}
rt2800_disable_unused_dac_adc(rt2x00dev);
@ -6453,7 +6453,7 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
rt2800_rfcsr_write(rt2x00dev, 12, 0xc6);
rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
@ -6466,7 +6466,8 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
if (rt2x00_is_usb(rt2x00dev) &&
rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
else
rt2800_rfcsr_write(rt2x00dev, 25, 0xc0);
@ -6486,10 +6487,7 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
else
rt2800_rfcsr_write(rt2x00dev, 40, 0x4b);
rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
rt2800_rfcsr_write(rt2x00dev, 42, 0xd2);
rt2800_rfcsr_write(rt2x00dev, 43, 0x9a);
@ -6510,16 +6508,26 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 53, 0x84);
rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
rt2800_rfcsr_write(rt2x00dev, 55, 0x44);
rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
rt2800_rfcsr_write(rt2x00dev, 56, 0x42);
else
rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
rt2800_rfcsr_write(rt2x00dev, 59, 0x8f);
rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
else
rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
if (rt2x00_is_usb(rt2x00dev))
rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
else
rt2800_rfcsr_write(rt2x00dev, 61, 0xd5);
} else {
if (rt2x00_is_usb(rt2x00dev))
rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
else
rt2800_rfcsr_write(rt2x00dev, 61, 0xb5);
}
rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
@ -6602,7 +6610,6 @@ static void rt2800_init_rfcsr_5592(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 1, 0x3F);
rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
rt2800_rfcsr_write(rt2x00dev, 6, 0xE4);
rt2800_rfcsr_write(rt2x00dev, 7, 0x00);

View file

@ -156,8 +156,6 @@ exit_release_regions:
exit_disable_device:
pci_disable_device(pci_dev);
pci_set_drvdata(pci_dev, NULL);
return retval;
}
EXPORT_SYMBOL_GPL(rt2x00pci_probe);
@ -177,7 +175,6 @@ void rt2x00pci_remove(struct pci_dev *pci_dev)
/*
* Free the PCI device data.
*/
pci_set_drvdata(pci_dev, NULL);
pci_disable_device(pci_dev);
pci_release_regions(pci_dev);
}

View file

@ -416,7 +416,7 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
struct rtl8187_rx_info *info;
int ret = 0;
while (skb_queue_len(&priv->rx_queue) < 16) {
while (skb_queue_len(&priv->rx_queue) < 32) {
skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
if (!skb) {
ret = -ENOMEM;

View file

@ -1437,7 +1437,8 @@ void rtl_watchdog_wq_callback(void *data)
/* if we can't recv beacon for 6s, we should
* reconnect this AP
*/
if (rtlpriv->link_info.roam_times >= 3) {
if ((rtlpriv->link_info.roam_times >= 3) &&
!is_zero_ether_addr(rtlpriv->mac80211.bssid)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"AP off, try to reconnect now\n");
rtlpriv->link_info.roam_times = 0;

View file

@ -46,10 +46,20 @@ void rtl_fw_cb(const struct firmware *firmware, void *context)
"Firmware callback routine entered!\n");
complete(&rtlpriv->firmware_loading_complete);
if (!firmware) {
if (rtlpriv->cfg->alt_fw_name) {
err = request_firmware(&firmware,
rtlpriv->cfg->alt_fw_name,
rtlpriv->io.dev);
pr_info("Loading alternative firmware %s\n",
rtlpriv->cfg->alt_fw_name);
if (!err)
goto found_alt;
}
pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
rtlpriv->max_fw_size = 0;
return;
}
found_alt:
if (firmware->size > rtlpriv->max_fw_size) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Firmware is too big!\n");
@ -184,6 +194,7 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
rtlpriv->cfg->maps
[RTL_IBSS_INT_MASKS]);
}
mac->link_state = MAC80211_LINKED;
break;
case NL80211_IFTYPE_ADHOC:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,

View file

@ -688,8 +688,6 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
rtlpriv->stats.rxbytesunicast += skb->len;
}
rtl_is_special_data(hw, skb, false);
if (ieee80211_is_data(fc)) {
rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX);

View file

@ -59,30 +59,26 @@ static struct country_code_to_enum_rd allCountries[] = {
*/
#define RTL819x_2GHZ_CH12_13 \
REG_RULE(2467-10, 2472+10, 40, 0, 20,\
NL80211_RRF_PASSIVE_SCAN)
NL80211_RRF_NO_IR)
#define RTL819x_2GHZ_CH14 \
REG_RULE(2484-10, 2484+10, 40, 0, 20, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_OFDM)
NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM)
/* 5G chan 36 - chan 64*/
#define RTL819x_5GHZ_5150_5350 \
REG_RULE(5150-10, 5350+10, 40, 0, 30, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
/* 5G chan 100 - chan 165*/
#define RTL819x_5GHZ_5470_5850 \
REG_RULE(5470-10, 5850+10, 40, 0, 30, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
/* 5G chan 149 - chan 165*/
#define RTL819x_5GHZ_5725_5850 \
REG_RULE(5725-10, 5850+10, 40, 0, 30, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define RTL819x_5GHZ_ALL \
(RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
@ -172,7 +168,8 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
(ch->flags & IEEE80211_CHAN_RADAR))
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
reg_rule = freq_reg_info(wiphy, ch->center_freq);
reg_rule = freq_reg_info(wiphy,
MHZ_TO_KHZ(ch->center_freq));
if (IS_ERR(reg_rule))
continue;
@ -185,16 +182,11 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
*regulatory_hint().
*/
if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
if (!(reg_rule->
flags & NL80211_RRF_PASSIVE_SCAN))
ch->flags &=
~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
ch->flags &= ~IEEE80211_CHAN_NO_IR;
} else {
if (ch->beacon_found)
ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN);
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
}
}
@ -219,11 +211,11 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
ch = &sband->channels[11]; /* CH 12 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
ch = &sband->channels[12]; /* CH 13 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
return;
}
@ -235,19 +227,19 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
ch = &sband->channels[11]; /* CH 12 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
ch = &sband->channels[12]; /* CH 13 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
}
@ -284,8 +276,7 @@ static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy)
*/
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
ch->flags |= IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
}
}
@ -354,9 +345,9 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
wiphy->reg_notifier = reg_notifier;
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
regd = _rtl_regdomain_select(reg);
wiphy_apply_custom_regulatory(wiphy, regd);

View file

@ -1078,7 +1078,7 @@ static void rtl88e_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
rtldm->swing_flag_ofdm = true;
}
if (rtldm->swing_idx_cck != rtldm->swing_idx_cck) {
if (rtldm->swing_idx_cck_cur != rtldm->swing_idx_cck) {
rtldm->swing_idx_cck_cur = rtldm->swing_idx_cck;
rtldm->swing_flag_cck = true;
}

View file

@ -158,6 +158,42 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}
};
static u32 power_index_reg[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a};
void dm_restorepowerindex(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 index;
for (index = 0; index < 6; index++)
rtl_write_byte(rtlpriv, power_index_reg[index],
rtlpriv->dm.powerindex_backup[index]);
}
EXPORT_SYMBOL_GPL(dm_restorepowerindex);
void dm_writepowerindex(struct ieee80211_hw *hw, u8 value)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 index;
for (index = 0; index < 6; index++)
rtl_write_byte(rtlpriv, power_index_reg[index], value);
}
EXPORT_SYMBOL_GPL(dm_writepowerindex);
void dm_savepowerindex(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 index;
u8 tmp;
for (index = 0; index < 6; index++) {
tmp = rtl_read_byte(rtlpriv, power_index_reg[index]);
rtlpriv->dm.powerindex_backup[index] = tmp;
}
}
EXPORT_SYMBOL_GPL(dm_savepowerindex);
static void rtl92c_dm_diginit(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@ -180,7 +216,12 @@ static void rtl92c_dm_diginit(struct ieee80211_hw *hw)
dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX;
dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LowRssi;
dm_digtable->forbidden_igi = DM_DIG_MIN;
dm_digtable->large_fa_hit = 0;
dm_digtable->recover_cnt = 0;
dm_digtable->dig_dynamic_min = 0x25;
}
static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
@ -206,7 +247,9 @@ static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
}
return (u8) rssi_val_min;
if (rssi_val_min > 100)
rssi_val_min = 100;
return (u8)rssi_val_min;
}
static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
@ -224,9 +267,17 @@ static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD);
falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff);
falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16);
falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
falsealm_cnt->cnt_rate_illegal +
falsealm_cnt->cnt_crc8_fail + falsealm_cnt->cnt_mcs_fail;
falsealm_cnt->cnt_rate_illegal +
falsealm_cnt->cnt_crc8_fail +
falsealm_cnt->cnt_mcs_fail +
falsealm_cnt->cnt_fast_fsync_fail +
falsealm_cnt->cnt_sb_search_fail;
rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1);
ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0);
@ -271,12 +322,14 @@ static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw)
value_igi++;
else if (rtlpriv->falsealm_cnt.cnt_all >= DM_DIG_FA_TH2)
value_igi += 2;
if (value_igi > DM_DIG_FA_UPPER)
value_igi = DM_DIG_FA_UPPER;
else if (value_igi < DM_DIG_FA_LOWER)
value_igi = DM_DIG_FA_LOWER;
if (rtlpriv->falsealm_cnt.cnt_all > 10000)
value_igi = 0x32;
value_igi = DM_DIG_FA_UPPER;
dm_digtable->cur_igvalue = value_igi;
rtl92c_dm_write_dig(hw);
@ -286,32 +339,80 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct dig_t *digtable = &rtlpriv->dm_digtable;
u32 isbt;
if (rtlpriv->falsealm_cnt.cnt_all > digtable->fa_highthresh) {
if ((digtable->back_val - 2) < digtable->back_range_min)
digtable->back_val = digtable->back_range_min;
else
digtable->back_val -= 2;
} else if (rtlpriv->falsealm_cnt.cnt_all < digtable->fa_lowthresh) {
if ((digtable->back_val + 2) > digtable->back_range_max)
digtable->back_val = digtable->back_range_max;
else
digtable->back_val += 2;
/* modify DIG lower bound, deal with abnorally large false alarm */
if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
digtable->large_fa_hit++;
if (digtable->forbidden_igi < digtable->cur_igvalue) {
digtable->forbidden_igi = digtable->cur_igvalue;
digtable->large_fa_hit = 1;
}
if (digtable->large_fa_hit >= 3) {
if ((digtable->forbidden_igi + 1) >
digtable->rx_gain_max)
digtable->rx_gain_min = digtable->rx_gain_max;
else
digtable->rx_gain_min = (digtable->forbidden_igi + 1);
digtable->recover_cnt = 3600; /* 3600=2hr */
}
} else {
/* Recovery mechanism for IGI lower bound */
if (digtable->recover_cnt != 0) {
digtable->recover_cnt--;
} else {
if (digtable->large_fa_hit == 0) {
if ((digtable->forbidden_igi-1) < DM_DIG_MIN) {
digtable->forbidden_igi = DM_DIG_MIN;
digtable->rx_gain_min = DM_DIG_MIN;
} else {
digtable->forbidden_igi--;
digtable->rx_gain_min = digtable->forbidden_igi + 1;
}
} else if (digtable->large_fa_hit == 3) {
digtable->large_fa_hit = 0;
}
}
}
if (rtlpriv->falsealm_cnt.cnt_all < 250) {
isbt = rtl_read_byte(rtlpriv, 0x4fd) & 0x01;
if (!isbt) {
if (rtlpriv->falsealm_cnt.cnt_all >
digtable->fa_lowthresh) {
if ((digtable->back_val - 2) <
digtable->back_range_min)
digtable->back_val = digtable->back_range_min;
else
digtable->back_val -= 2;
} else if (rtlpriv->falsealm_cnt.cnt_all <
digtable->fa_lowthresh) {
if ((digtable->back_val + 2) >
digtable->back_range_max)
digtable->back_val = digtable->back_range_max;
else
digtable->back_val += 2;
}
} else {
digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
}
} else {
/* Adjust initial gain by false alarm */
if (rtlpriv->falsealm_cnt.cnt_all > 1000)
digtable->cur_igvalue = digtable->pre_igvalue + 2;
else if (rtlpriv->falsealm_cnt.cnt_all > 750)
digtable->cur_igvalue = digtable->pre_igvalue + 1;
else if (rtlpriv->falsealm_cnt.cnt_all < 500)
digtable->cur_igvalue = digtable->pre_igvalue - 1;
}
if ((digtable->rssi_val_min + 10 - digtable->back_val) >
digtable->rx_gain_max)
/* Check initial gain by upper/lower bound */
if (digtable->cur_igvalue > digtable->rx_gain_max)
digtable->cur_igvalue = digtable->rx_gain_max;
else if ((digtable->rssi_val_min + 10 -
digtable->back_val) < digtable->rx_gain_min)
digtable->cur_igvalue = digtable->rx_gain_min;
else
digtable->cur_igvalue = digtable->rssi_val_min + 10 -
digtable->back_val;
RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
"rssi_val_min = %x back_val %x\n",
digtable->rssi_val_min, digtable->back_val);
if (digtable->cur_igvalue < digtable->rx_gain_min)
digtable->cur_igvalue = digtable->rx_gain_min;
rtl92c_dm_write_dig(hw);
}
@ -329,7 +430,7 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
multi_sta = true;
if (!multi_sta ||
dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {
dm_digtable->cursta_cstate == DIG_STA_DISCONNECT) {
initialized = false;
dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
return;
@ -375,7 +476,6 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
"presta_cstate = %x, cursta_cstate = %x\n",
dm_digtable->presta_cstate, dm_digtable->cursta_cstate);
if (dm_digtable->presta_cstate == dm_digtable->cursta_cstate ||
dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT ||
dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
@ -383,6 +483,8 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)
if (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {
dm_digtable->rssi_val_min =
rtl92c_dm_initial_gain_min_pwdb(hw);
if (dm_digtable->rssi_val_min > 100)
dm_digtable->rssi_val_min = 100;
rtl92c_dm_ctrl_initgain_by_rssi(hw);
}
} else {
@ -398,11 +500,12 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)
static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw);
if (dm_digtable->rssi_val_min > 100)
dm_digtable->rssi_val_min = 100;
if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) {
if (dm_digtable->rssi_val_min <= 25)
@ -424,48 +527,14 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
}
if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) {
if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) {
if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800)
dm_digtable->cur_cck_fa_state =
CCK_FA_STAGE_High;
else
dm_digtable->cur_cck_fa_state = CCK_FA_STAGE_Low;
if (dm_digtable->pre_cck_fa_state !=
dm_digtable->cur_cck_fa_state) {
if (dm_digtable->cur_cck_fa_state ==
CCK_FA_STAGE_Low)
rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2,
0x83);
else
rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2,
0xcd);
dm_digtable->pre_cck_fa_state =
dm_digtable->cur_cck_fa_state;
}
rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40);
if (IS_92C_SERIAL(rtlhal->version))
rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT,
MASKBYTE2, 0xd7);
} else {
if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) ||
(dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_MAX))
rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83);
else
rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x47);
if (IS_92C_SERIAL(rtlhal->version))
rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT,
MASKBYTE2, 0xd3);
}
dm_digtable->pre_cck_pd_state = dm_digtable->cur_cck_pd_state;
}
RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "CCKPDStage=%x\n",
dm_digtable->cur_cck_pd_state);
RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "is92C=%x\n",
IS_92C_SERIAL(rtlhal->version));
}
static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
@ -482,6 +551,8 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
else
dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;
dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
rtl92c_dm_initial_gain_sta(hw);
rtl92c_dm_initial_gain_multi_sta(hw);
rtl92c_dm_cck_packet_detection_thresh(hw);
@ -493,23 +564,26 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
static void rtl92c_dm_dig(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
if (rtlpriv->dm.dm_initialgain_enable == false)
return;
if (dm_digtable->dig_enable_flag == false)
if (!rtlpriv->dm.dm_flag & DYNAMIC_FUNC_DIG)
return;
rtl92c_dm_ctrl_initgain_by_twoport(hw);
}
static void rtl92c_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->dm.dynamic_txpower_enable = false;
if (rtlpriv->rtlhal.interface == INTF_USB &&
rtlpriv->rtlhal.board_type & 0x1) {
dm_savepowerindex(hw);
rtlpriv->dm.dynamic_txpower_enable = true;
} else {
rtlpriv->dm.dynamic_txpower_enable = false;
}
rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
}
@ -524,9 +598,14 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw)
dm_digtable->cur_igvalue, dm_digtable->pre_igvalue,
dm_digtable->back_val);
dm_digtable->cur_igvalue += 2;
if (dm_digtable->cur_igvalue > 0x3f)
dm_digtable->cur_igvalue = 0x3f;
if (rtlpriv->rtlhal.interface == INTF_USB &&
!dm_digtable->dig_enable_flag) {
dm_digtable->pre_igvalue = 0x17;
return;
}
dm_digtable->cur_igvalue -= 1;
if (dm_digtable->cur_igvalue < DM_DIG_MIN)
dm_digtable->cur_igvalue = DM_DIG_MIN;
if (dm_digtable->pre_igvalue != dm_digtable->cur_igvalue) {
rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f,
@ -536,11 +615,47 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw)
dm_digtable->pre_igvalue = dm_digtable->cur_igvalue;
}
RT_TRACE(rtlpriv, COMP_DIG, DBG_WARNING,
"dig values 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
dm_digtable->cur_igvalue, dm_digtable->pre_igvalue,
dm_digtable->rssi_val_min, dm_digtable->back_val,
dm_digtable->rx_gain_max, dm_digtable->rx_gain_min,
dm_digtable->large_fa_hit, dm_digtable->forbidden_igi);
}
EXPORT_SYMBOL(rtl92c_dm_write_dig);
static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
long tmpentry_max_pwdb = 0, tmpentry_min_pwdb = 0xff;
if (mac->link_state != MAC80211_LINKED)
return;
if (mac->opmode == NL80211_IFTYPE_ADHOC ||
mac->opmode == NL80211_IFTYPE_AP) {
/* TODO: Handle ADHOC and AP Mode */
}
if (tmpentry_max_pwdb != 0)
rtlpriv->dm.entry_max_undec_sm_pwdb = tmpentry_max_pwdb;
else
rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
if (tmpentry_min_pwdb != 0xff)
rtlpriv->dm.entry_min_undec_sm_pwdb = tmpentry_min_pwdb;
else
rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
/* TODO:
* if (mac->opmode == NL80211_IFTYPE_STATION) {
* if (rtlpriv->rtlhal.fw_ready) {
* u32 param = (u32)(rtlpriv->dm.undec_sm_pwdb << 16);
* rtl8192c_set_rssi_cmd(hw, param);
* }
* }
*/
}
void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw)
@ -750,6 +865,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i];
rtlpriv->dm.cck_index = cck_index_old;
}
/* Handle USB High PA boards */
delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
(thermalvalue - rtlpriv->dm.thermalvalue) :
@ -1140,22 +1256,22 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ps_t *dm_pstable = &rtlpriv->dm_pstable;
static u8 initialize;
static u32 reg_874, reg_c70, reg_85c, reg_a74;
if (initialize == 0) {
reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
MASKDWORD) & 0x1CC000) >> 14;
if (!rtlpriv->reg_init) {
rtlpriv->reg_874 = (rtl_get_bbreg(hw,
RFPGA0_XCD_RFINTERFACESW,
MASKDWORD) & 0x1CC000) >> 14;
reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1,
MASKDWORD) & BIT(3)) >> 3;
rtlpriv->reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1,
MASKDWORD) & BIT(3)) >> 3;
reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
MASKDWORD) & 0xFF000000) >> 24;
rtlpriv->reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
MASKDWORD) & 0xFF000000) >> 24;
reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & 0xF000) >> 12;
rtlpriv->reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) &
0xF000) >> 12;
initialize = 1;
rtlpriv->reg_init = true;
}
if (!bforce_in_normal) {
@ -1192,12 +1308,12 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal)
rtl_set_bbreg(hw, 0x818, BIT(28), 0x1);
} else {
rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
0x1CC000, reg_874);
0x1CC000, rtlpriv->reg_874);
rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3),
reg_c70);
rtlpriv->reg_c70);
rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000,
reg_85c);
rtl_set_bbreg(hw, 0xa74, 0xF000, reg_a74);
rtlpriv->reg_85c);
rtl_set_bbreg(hw, 0xa74, 0xF000, rtlpriv->reg_a74);
rtl_set_bbreg(hw, 0x818, BIT(28), 0x0);
}
@ -1213,6 +1329,7 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
/* Determine the minimum RSSI */
if (((mac->link_state == MAC80211_NOLINK)) &&
(rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
dm_pstable->rssi_val_min = 0;
@ -1241,6 +1358,7 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
dm_pstable->rssi_val_min);
}
/* Power Saving for 92C */
if (IS_92C_SERIAL(rtlhal->version))
;/* rtl92c_dm_1r_cca(hw); */
else
@ -1252,12 +1370,23 @@ void rtl92c_dm_init(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
rtlpriv->dm.dm_flag = DYNAMIC_FUNC_DISABLE | DYNAMIC_FUNC_DIG;
rtlpriv->dm.undec_sm_pwdb = -1;
rtlpriv->dm.undec_sm_cck = -1;
rtlpriv->dm.dm_initialgain_enable = true;
rtl92c_dm_diginit(hw);
rtlpriv->dm.dm_flag |= HAL_DM_HIPWR_DISABLE;
rtl92c_dm_init_dynamic_txpower(hw);
rtl92c_dm_init_edca_turbo(hw);
rtl92c_dm_init_rate_adaptive_mask(hw);
rtlpriv->dm.dm_flag |= DYNAMIC_FUNC_SS;
rtl92c_dm_initialize_txpower_tracking(hw);
rtl92c_dm_init_dynamic_bb_powersaving(hw);
rtlpriv->dm.ofdm_pkt_cnt = 0;
rtlpriv->dm.dm_rssi_sel = RSSI_DEFAULT;
}
EXPORT_SYMBOL(rtl92c_dm_init);
@ -1308,7 +1437,7 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
}
if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL2;
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
"TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n");
} else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
@ -1328,8 +1457,16 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
"PHY_SetTxPowerLevel8192S() Channel = %d\n",
rtlphy->current_channel);
rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
if (rtlpriv->dm.dynamic_txhighpower_lvl ==
TXHIGHPWRLEVEL_NORMAL)
dm_restorepowerindex(hw);
else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
TXHIGHPWRLEVEL_LEVEL1)
dm_writepowerindex(hw, 0x14);
else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
TXHIGHPWRLEVEL_LEVEL2)
dm_writepowerindex(hw, 0x10);
}
rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
}
@ -1400,12 +1537,6 @@ u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw)
else
curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW);
/* Set Tx Power according to BT status. */
if (undec_sm_pwdb >= 30)
curr_bt_rssi_state |= BT_RSSI_STATE_TXPOWER_LOW;
else if (undec_sm_pwdb < 25)
curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW);
/* Check BT state related to BT_Idle in B/G mode. */
if (undec_sm_pwdb < 15)
curr_bt_rssi_state |= BT_RSSI_STATE_BG_EDCA_LOW;

View file

@ -91,6 +91,17 @@
#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74
#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67
#define DYNAMIC_FUNC_DISABLE 0x0
#define DYNAMIC_FUNC_DIG BIT(0)
#define DYNAMIC_FUNC_HP BIT(1)
#define DYNAMIC_FUNC_SS BIT(2) /*Tx Power Tracking*/
#define DYNAMIC_FUNC_BT BIT(3)
#define DYNAMIC_FUNC_ANT_DIV BIT(4)
#define RSSI_CCK 0
#define RSSI_OFDM 1
#define RSSI_DEFAULT 2
struct swat_t {
u8 failure_cnt;
u8 try_flag;
@ -167,5 +178,8 @@ void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw);
void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery);
void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw);
void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw);
void dm_savepowerindex(struct ieee80211_hw *hw);
void dm_writepowerindex(struct ieee80211_hw *hw, u8 value);
void dm_restorepowerindex(struct ieee80211_hw *hw);
#endif

View file

@ -1147,6 +1147,12 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
0x522, 0x550, 0x551, 0x040
};
u32 iqk_bb_reg_92C[9] = {
0xc04, 0xc08, 0x874, 0xb68,
0xb6c, 0x870, 0x860, 0x864,
0x800
};
const u32 retrycount = 2;
if (t == 0) {
@ -1157,6 +1163,8 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
rtlphy->adda_backup, 16);
_rtl92c_phy_save_mac_registers(hw, iqk_mac_reg,
rtlphy->iqk_mac_backup);
_rtl92c_phy_save_adda_registers(hw, iqk_bb_reg_92C,
rtlphy->iqk_bb_backup, 9);
}
_rtl92c_phy_path_adda_on(hw, adda_reg, true, is2t);
if (t == 0) {
@ -1167,14 +1175,18 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
if (!rtlphy->rfpi_enable)
_rtl92c_phy_pi_mode_switch(hw, true);
if (t == 0) {
rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD);
rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD);
rtlphy->reg_874 = rtl_get_bbreg(hw, 0x874, MASKDWORD);
}
rtl_set_bbreg(hw, 0x800, BIT(24), 0x0);
rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
rtl_set_bbreg(hw, 0x870, BIT(10), 0x1);
rtl_set_bbreg(hw, 0x870, BIT(26), 0x1);
rtl_set_bbreg(hw, 0x860, BIT(10), 0x0);
rtl_set_bbreg(hw, 0x864, BIT(10), 0x0);
if (is2t) {
rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000);
@ -1239,13 +1251,9 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
0x3FF0000) >> 16;
}
}
rtl_set_bbreg(hw, 0xc04, MASKDWORD, rtlphy->reg_c04);
rtl_set_bbreg(hw, 0x874, MASKDWORD, rtlphy->reg_874);
rtl_set_bbreg(hw, 0xc08, MASKDWORD, rtlphy->reg_c08);
rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
if (is2t)
rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
if (t != 0) {
if (!rtlphy->rfpi_enable)
_rtl92c_phy_pi_mode_switch(hw, false);
@ -1253,6 +1261,15 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
rtlphy->adda_backup, 16);
_rtl92c_phy_reload_mac_registers(hw, iqk_mac_reg,
rtlphy->iqk_mac_backup);
_rtl92c_phy_reload_adda_registers(hw, iqk_bb_reg_92C,
rtlphy->iqk_bb_backup, 9);
rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
if (is2t)
rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00);
rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00);
}
}

View file

@ -101,6 +101,15 @@ void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw)
"PHY_SetTxPowerLevel8192S() Channel = %d\n",
rtlphy->current_channel);
rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
if (rtlpriv->dm.dynamic_txhighpower_lvl ==
TXHIGHPWRLEVEL_NORMAL)
dm_restorepowerindex(hw);
else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
TXHIGHPWRLEVEL_LEVEL1)
dm_writepowerindex(hw, 0x14);
else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
TXHIGHPWRLEVEL_LEVEL2)
dm_writepowerindex(hw, 0x10);
}
rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;

View file

@ -30,3 +30,6 @@
#include "../rtl8192ce/dm.h"
void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw);
void dm_savepowerindex(struct ieee80211_hw *hw);
void dm_writepowerindex(struct ieee80211_hw *hw, u8 value);
void dm_restorepowerindex(struct ieee80211_hw *hw);

View file

@ -1022,7 +1022,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
if (ppsc->rfpwr_state == ERFON) {
rtl92c_phy_set_rfpath_switch(hw, 1);
if (iqk_initialized) {
rtl92c_phy_iq_calibrate(hw, false);
rtl92c_phy_iq_calibrate(hw, true);
} else {
rtl92c_phy_iq_calibrate(hw, false);
iqk_initialized = true;

View file

@ -120,6 +120,7 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u16 regval;
u32 regval32;
u8 b_reg_hwparafile = 1;
_rtl92c_phy_init_bb_rf_register_definition(hw);
@ -135,8 +136,11 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw)
} else if (IS_HARDWARE_TYPE_8192CU(rtlhal)) {
rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD |
FEN_BB_GLB_RSTn | FEN_BBRSTB);
rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f);
}
regval32 = rtl_read_dword(rtlpriv, 0x87c);
rtl_write_dword(rtlpriv, 0x87c, regval32 & (~BIT(31)));
if (IS_HARDWARE_TYPE_8192CU(rtlhal))
rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f);
rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
if (b_reg_hwparafile == 1)
rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw);

View file

@ -85,17 +85,15 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
if (mac->act_scanning) {
tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
if (turbo_scanoff) {
for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
tx_agc[idx1] = ppowerlevel[idx1] |
(ppowerlevel[idx1] << 8) |
(ppowerlevel[idx1] << 16) |
(ppowerlevel[idx1] << 24);
if (rtlhal->interface == INTF_USB) {
if (tx_agc[idx1] > 0x20 &&
rtlefuse->external_pa)
tx_agc[idx1] = 0x20;
}
for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
tx_agc[idx1] = ppowerlevel[idx1] |
(ppowerlevel[idx1] << 8) |
(ppowerlevel[idx1] << 16) |
(ppowerlevel[idx1] << 24);
if (rtlhal->interface == INTF_USB) {
if (tx_agc[idx1] > 0x20 &&
rtlefuse->external_pa)
tx_agc[idx1] = 0x20;
}
}
} else {
@ -107,7 +105,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
TXHIGHPWRLEVEL_LEVEL2) {
tx_agc[RF90_PATH_A] = 0x00000000;
tx_agc[RF90_PATH_B] = 0x00000000;
} else{
} else {
for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
tx_agc[idx1] = ppowerlevel[idx1] |
(ppowerlevel[idx1] << 8) |
@ -373,7 +371,12 @@ static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw,
regoffset == RTXAGC_B_MCS07_MCS04)
regoffset = 0xc98;
for (i = 0; i < 3; i++) {
writeVal = (writeVal > 6) ? (writeVal - 6) : 0;
if (i != 2)
writeVal = (writeVal > 8) ?
(writeVal - 8) : 0;
else
writeVal = (writeVal > 6) ?
(writeVal - 6) : 0;
rtl_write_byte(rtlpriv, (u32)(regoffset + i),
(u8)writeVal);
}

Some files were not shown because too many files have changed in this diff Show more