mirror of https://gitee.com/openkylin/linux.git
Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next
This commit is contained in:
commit
6e55eed8f1
10
MAINTAINERS
10
MAINTAINERS
|
@ -5629,16 +5629,6 @@ F: Documentation/networking/mac80211-injection.txt
|
|||
F: include/net/mac80211.h
|
||||
F: net/mac80211/
|
||||
|
||||
MAC80211 PID RATE CONTROL
|
||||
M: Stefano Brivio <stefano.brivio@polimi.it>
|
||||
M: Mattias Nissler <mattias.nissler@gmx.de>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
|
||||
S: Maintained
|
||||
F: net/mac80211/rc80211_pid*
|
||||
|
||||
MACVLAN DRIVER
|
||||
M: Patrick McHardy <kaber@trash.net>
|
||||
L: netdev@vger.kernel.org
|
||||
|
|
|
@ -220,6 +220,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
|
|||
#endif
|
||||
switch (cc->core->bus->chipinfo.id) {
|
||||
case BCMA_CHIP_ID_BCM5357:
|
||||
case BCMA_CHIP_ID_BCM53572:
|
||||
chip->ngpio = 32;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -1955,8 +1955,9 @@ static void at76_dwork_hw_scan(struct work_struct *work)
|
|||
|
||||
static int at76_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
struct ieee80211_scan_request *hw_req)
|
||||
{
|
||||
struct cfg80211_scan_request *req = &hw_req->req;
|
||||
struct at76_priv *priv = hw->priv;
|
||||
struct at76_req_scan scan;
|
||||
u8 *ssid = NULL;
|
||||
|
|
|
@ -63,6 +63,7 @@ enum ath_op_flags {
|
|||
ATH_OP_PRIM_STA_VIF,
|
||||
ATH_OP_HW_RESET,
|
||||
ATH_OP_SCANNING,
|
||||
ATH_OP_MULTI_CHANNEL,
|
||||
};
|
||||
|
||||
enum ath_bus_type {
|
||||
|
|
|
@ -3137,10 +3137,11 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
|
||||
static int ath10k_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
struct ieee80211_scan_request *hw_req)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct cfg80211_scan_request *req = &hw_req->req;
|
||||
struct wmi_start_scan_arg arg;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
|
|
@ -1285,6 +1285,7 @@ struct ath5k_hw {
|
|||
#define ATH_STAT_STARTED 3 /* opened & irqs enabled */
|
||||
|
||||
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
|
||||
unsigned int fif_filter_flags; /* Current FIF_* filter flags */
|
||||
struct ieee80211_channel *curchan; /* current h/w channel */
|
||||
|
||||
u16 nvifs;
|
||||
|
|
|
@ -1382,6 +1382,9 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
|
|||
rxs->flag = 0;
|
||||
if (unlikely(rs->rs_status & AR5K_RXERR_MIC))
|
||||
rxs->flag |= RX_FLAG_MMIC_ERROR;
|
||||
if (unlikely(rs->rs_status & AR5K_RXERR_CRC))
|
||||
rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
|
||||
|
||||
/*
|
||||
* always extend the mac timestamp, since this information is
|
||||
|
@ -1449,6 +1452,8 @@ ath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs)
|
|||
ah->stats.rx_bytes_count += rs->rs_datalen;
|
||||
|
||||
if (unlikely(rs->rs_status)) {
|
||||
unsigned int filters;
|
||||
|
||||
if (rs->rs_status & AR5K_RXERR_CRC)
|
||||
ah->stats.rxerr_crc++;
|
||||
if (rs->rs_status & AR5K_RXERR_FIFO)
|
||||
|
@ -1457,7 +1462,20 @@ ath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs)
|
|||
ah->stats.rxerr_phy++;
|
||||
if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32)
|
||||
ah->stats.rxerr_phy_code[rs->rs_phyerr]++;
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Treat packets that underwent a CCK or OFDM reset as having a bad CRC.
|
||||
* These restarts happen when the radio resynchronizes to a stronger frame
|
||||
* while receiving a weaker frame. Here we receive the prefix of the weak
|
||||
* frame. Since these are incomplete packets, mark their CRC as invalid.
|
||||
*/
|
||||
if (rs->rs_phyerr == AR5K_RX_PHY_ERROR_OFDM_RESTART ||
|
||||
rs->rs_phyerr == AR5K_RX_PHY_ERROR_CCK_RESTART) {
|
||||
rs->rs_status |= AR5K_RXERR_CRC;
|
||||
rs->rs_status &= ~AR5K_RXERR_PHY;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (rs->rs_status & AR5K_RXERR_DECRYPT) {
|
||||
/*
|
||||
|
@ -1480,8 +1498,15 @@ ath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* reject any frames with non-crypto errors */
|
||||
if (rs->rs_status & ~(AR5K_RXERR_DECRYPT))
|
||||
/*
|
||||
* Reject any frames with non-crypto errors, and take into account the
|
||||
* current FIF_* filters.
|
||||
*/
|
||||
filters = AR5K_RXERR_DECRYPT;
|
||||
if (ah->fif_filter_flags & FIF_FCSFAIL)
|
||||
filters |= AR5K_RXERR_CRC;
|
||||
|
||||
if (rs->rs_status & ~filters)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -473,6 +473,8 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
|||
/* Set the cached hw filter flags, this will later actually
|
||||
* be set in HW */
|
||||
ah->filter_flags = rfilt;
|
||||
/* Store current FIF filter flags */
|
||||
ah->fif_filter_flags = *new_flags;
|
||||
|
||||
mutex_unlock(&ah->lock);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@ ath9k-y += beacon.o \
|
|||
recv.o \
|
||||
xmit.o \
|
||||
link.o \
|
||||
antenna.o
|
||||
antenna.o \
|
||||
channel.o
|
||||
|
||||
ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
|
||||
ath9k-$(CONFIG_ATH9K_PCI) += pci.o
|
||||
|
|
|
@ -3535,7 +3535,8 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
|
|||
{
|
||||
int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl;
|
||||
|
||||
if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah))
|
||||
if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
|
||||
AR_SREV_9531(ah))
|
||||
REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
|
||||
else if (AR_SREV_9462(ah) || AR_SREV_9550(ah) || AR_SREV_9565(ah))
|
||||
REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
|
||||
|
|
|
@ -314,10 +314,17 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
|
|||
qca953x_1p0_mac_core);
|
||||
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
|
||||
qca953x_1p0_mac_postamble);
|
||||
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
|
||||
qca953x_1p0_baseband_core);
|
||||
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
|
||||
qca953x_1p0_baseband_postamble);
|
||||
if (AR_SREV_9531_20(ah)) {
|
||||
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
|
||||
qca953x_2p0_baseband_core);
|
||||
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
|
||||
qca953x_2p0_baseband_postamble);
|
||||
} else {
|
||||
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
|
||||
qca953x_1p0_baseband_core);
|
||||
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
|
||||
qca953x_1p0_baseband_postamble);
|
||||
}
|
||||
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
|
||||
qca953x_1p0_radio_core);
|
||||
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
|
||||
|
|
|
@ -1552,13 +1552,15 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
|
|||
u8 *ini_reloaded)
|
||||
{
|
||||
unsigned int regWrites = 0;
|
||||
u32 modesIndex;
|
||||
u32 modesIndex, txgain_index;
|
||||
|
||||
if (IS_CHAN_5GHZ(chan))
|
||||
modesIndex = IS_CHAN_HT40(chan) ? 2 : 1;
|
||||
else
|
||||
modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;
|
||||
|
||||
txgain_index = AR_SREV_9531(ah) ? 1 : modesIndex;
|
||||
|
||||
if (modesIndex == ah->modes_index) {
|
||||
*ini_reloaded = false;
|
||||
goto set_rfmode;
|
||||
|
@ -1573,7 +1575,7 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
|
|||
ar9003_hw_prog_ini(ah, &ah->ini_radio_post_sys2ant,
|
||||
modesIndex);
|
||||
|
||||
REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
|
||||
REG_WRITE_ARRAY(&ah->iniModesTxGain, txgain_index, regWrites);
|
||||
|
||||
if (AR_SREV_9462_20_OR_LATER(ah)) {
|
||||
/*
|
||||
|
|
|
@ -219,7 +219,7 @@ static const u32 qca953x_1p0_baseband_core[][2] = {
|
|||
{0x00009d04, 0x40206c10},
|
||||
{0x00009d08, 0x009c4060},
|
||||
{0x00009d0c, 0x9883800a},
|
||||
{0x00009d10, 0x01884061},
|
||||
{0x00009d10, 0x018848c6},
|
||||
{0x00009d14, 0x00c0040b},
|
||||
{0x00009d18, 0x00000000},
|
||||
{0x00009e08, 0x0038230c},
|
||||
|
@ -715,4 +715,203 @@ static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = {
|
|||
{0x00016448, 0x6c927a70},
|
||||
};
|
||||
|
||||
static const u32 qca953x_2p0_baseband_core[][2] = {
|
||||
/* Addr allmodes */
|
||||
{0x00009800, 0xafe68e30},
|
||||
{0x00009804, 0xfd14e000},
|
||||
{0x00009808, 0x9c0a9f6b},
|
||||
{0x0000980c, 0x04900000},
|
||||
{0x00009814, 0x0280c00a},
|
||||
{0x00009818, 0x00000000},
|
||||
{0x0000981c, 0x00020028},
|
||||
{0x00009834, 0x6400a190},
|
||||
{0x00009838, 0x0108ecff},
|
||||
{0x0000983c, 0x14000600},
|
||||
{0x00009880, 0x201fff00},
|
||||
{0x00009884, 0x00001042},
|
||||
{0x000098a4, 0x00200400},
|
||||
{0x000098b0, 0x32840bbe},
|
||||
{0x000098bc, 0x00000002},
|
||||
{0x000098d0, 0x004b6a8e},
|
||||
{0x000098d4, 0x00000820},
|
||||
{0x000098dc, 0x00000000},
|
||||
{0x000098f0, 0x00000000},
|
||||
{0x000098f4, 0x00000000},
|
||||
{0x00009c04, 0xff55ff55},
|
||||
{0x00009c08, 0x0320ff55},
|
||||
{0x00009c0c, 0x00000000},
|
||||
{0x00009c10, 0x00000000},
|
||||
{0x00009c14, 0x00046384},
|
||||
{0x00009c18, 0x05b6b440},
|
||||
{0x00009c1c, 0x00b6b440},
|
||||
{0x00009d00, 0xc080a333},
|
||||
{0x00009d04, 0x40206c10},
|
||||
{0x00009d08, 0x009c4060},
|
||||
{0x00009d0c, 0x9883800a},
|
||||
{0x00009d10, 0x018848c6},
|
||||
{0x00009d14, 0x00c0040b},
|
||||
{0x00009d18, 0x00000000},
|
||||
{0x00009e08, 0x0038230c},
|
||||
{0x00009e24, 0x990bb515},
|
||||
{0x00009e28, 0x0c6f0000},
|
||||
{0x00009e30, 0x06336f77},
|
||||
{0x00009e34, 0x6af6532f},
|
||||
{0x00009e38, 0x0cc80c00},
|
||||
{0x00009e40, 0x0d261820},
|
||||
{0x00009e4c, 0x00001004},
|
||||
{0x00009e50, 0x00ff03f1},
|
||||
{0x00009fc0, 0x813e4788},
|
||||
{0x00009fc4, 0x0001efb5},
|
||||
{0x00009fcc, 0x40000014},
|
||||
{0x00009fd0, 0x02993b93},
|
||||
{0x0000a20c, 0x00000000},
|
||||
{0x0000a220, 0x00000000},
|
||||
{0x0000a224, 0x00000000},
|
||||
{0x0000a228, 0x10002310},
|
||||
{0x0000a23c, 0x00000000},
|
||||
{0x0000a244, 0x0c000000},
|
||||
{0x0000a248, 0x00000140},
|
||||
{0x0000a2a0, 0x00000007},
|
||||
{0x0000a2c0, 0x00000007},
|
||||
{0x0000a2c8, 0x00000000},
|
||||
{0x0000a2d4, 0x00000000},
|
||||
{0x0000a2ec, 0x00000000},
|
||||
{0x0000a2f0, 0x00000000},
|
||||
{0x0000a2f4, 0x00000000},
|
||||
{0x0000a2f8, 0x00000000},
|
||||
{0x0000a344, 0x00000000},
|
||||
{0x0000a34c, 0x00000000},
|
||||
{0x0000a350, 0x0000a000},
|
||||
{0x0000a364, 0x00000000},
|
||||
{0x0000a370, 0x00000000},
|
||||
{0x0000a390, 0x00000001},
|
||||
{0x0000a394, 0x00000444},
|
||||
{0x0000a398, 0x001f0e0f},
|
||||
{0x0000a39c, 0x0075393f},
|
||||
{0x0000a3a0, 0xb79f6427},
|
||||
{0x0000a3a4, 0x000400ff},
|
||||
{0x0000a3a8, 0x6a6a6a6a},
|
||||
{0x0000a3ac, 0x6a6a6a6a},
|
||||
{0x0000a3b0, 0x00c8641a},
|
||||
{0x0000a3b4, 0x0000001a},
|
||||
{0x0000a3b8, 0x0088642a},
|
||||
{0x0000a3bc, 0x000001fa},
|
||||
{0x0000a3c0, 0x20202020},
|
||||
{0x0000a3c4, 0x22222220},
|
||||
{0x0000a3c8, 0x20200020},
|
||||
{0x0000a3cc, 0x20202020},
|
||||
{0x0000a3d0, 0x20202020},
|
||||
{0x0000a3d4, 0x20202020},
|
||||
{0x0000a3d8, 0x20202020},
|
||||
{0x0000a3dc, 0x20202020},
|
||||
{0x0000a3e0, 0x20202020},
|
||||
{0x0000a3e4, 0x20202020},
|
||||
{0x0000a3e8, 0x20202020},
|
||||
{0x0000a3ec, 0x20202020},
|
||||
{0x0000a3f0, 0x00000000},
|
||||
{0x0000a3f4, 0x00000000},
|
||||
{0x0000a3f8, 0x0c9bd380},
|
||||
{0x0000a3fc, 0x000f0f01},
|
||||
{0x0000a400, 0x8fa91f01},
|
||||
{0x0000a404, 0x00000000},
|
||||
{0x0000a408, 0x0e79e5c6},
|
||||
{0x0000a40c, 0x00820820},
|
||||
{0x0000a414, 0x1ce42108},
|
||||
{0x0000a418, 0x2d001dce},
|
||||
{0x0000a41c, 0x1ce73908},
|
||||
{0x0000a420, 0x000001ce},
|
||||
{0x0000a424, 0x1ce738e7},
|
||||
{0x0000a428, 0x000001ce},
|
||||
{0x0000a42c, 0x1ce739ce},
|
||||
{0x0000a430, 0x1ce739ce},
|
||||
{0x0000a434, 0x00000000},
|
||||
{0x0000a438, 0x00001801},
|
||||
{0x0000a43c, 0x00100000},
|
||||
{0x0000a444, 0x00000000},
|
||||
{0x0000a448, 0x05000080},
|
||||
{0x0000a44c, 0x00000001},
|
||||
{0x0000a450, 0x00010000},
|
||||
{0x0000a458, 0x00000000},
|
||||
{0x0000a644, 0xbfad9d74},
|
||||
{0x0000a648, 0x0048060a},
|
||||
{0x0000a64c, 0x00003c37},
|
||||
{0x0000a670, 0x03020100},
|
||||
{0x0000a674, 0x09080504},
|
||||
{0x0000a678, 0x0d0c0b0a},
|
||||
{0x0000a67c, 0x13121110},
|
||||
{0x0000a680, 0x31301514},
|
||||
{0x0000a684, 0x35343332},
|
||||
{0x0000a688, 0x00000036},
|
||||
{0x0000a690, 0x08000838},
|
||||
{0x0000a7cc, 0x00000000},
|
||||
{0x0000a7d0, 0x00000000},
|
||||
{0x0000a7d4, 0x00000004},
|
||||
{0x0000a7dc, 0x00000000},
|
||||
{0x0000a8d0, 0x004b6a8e},
|
||||
{0x0000a8d4, 0x00000820},
|
||||
{0x0000a8dc, 0x00000000},
|
||||
{0x0000a8f0, 0x00000000},
|
||||
{0x0000a8f4, 0x00000000},
|
||||
{0x0000b2d0, 0x00000080},
|
||||
{0x0000b2d4, 0x00000000},
|
||||
{0x0000b2ec, 0x00000000},
|
||||
{0x0000b2f0, 0x00000000},
|
||||
{0x0000b2f4, 0x00000000},
|
||||
{0x0000b2f8, 0x00000000},
|
||||
{0x0000b408, 0x0e79e5c0},
|
||||
{0x0000b40c, 0x00820820},
|
||||
{0x0000b420, 0x00000000},
|
||||
};
|
||||
|
||||
static const u32 qca953x_2p0_baseband_postamble[][5] = {
|
||||
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
|
||||
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
|
||||
{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
|
||||
{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
|
||||
{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
|
||||
{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
|
||||
{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
|
||||
{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
|
||||
{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
|
||||
{0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
|
||||
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
|
||||
{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
|
||||
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
|
||||
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946222, 0xcf946222},
|
||||
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
{0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0},
|
||||
{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
|
||||
{0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
|
||||
{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
|
||||
{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
|
||||
{0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
|
||||
{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
|
||||
{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
|
||||
{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
|
||||
{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e},
|
||||
{0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
|
||||
{0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e},
|
||||
{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
|
||||
{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
|
||||
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
|
||||
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
|
||||
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
|
||||
{0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
|
||||
{0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
|
||||
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
|
||||
{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
|
||||
{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
|
||||
{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
|
||||
{0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
|
||||
};
|
||||
|
||||
#endif /* INITVALS_953X_H */
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
|
@ -35,10 +36,7 @@ extern struct ieee80211_ops ath9k_ops;
|
|||
extern int ath9k_modparam_nohwcrypt;
|
||||
extern int led_blink;
|
||||
extern bool is_ath9k_unloaded;
|
||||
|
||||
struct ath_config {
|
||||
u16 txpowlimit;
|
||||
};
|
||||
extern int ath9k_use_chanctx;
|
||||
|
||||
/*************************/
|
||||
/* Descriptor Management */
|
||||
|
@ -167,7 +165,6 @@ struct ath_txq {
|
|||
u32 axq_ampdu_depth;
|
||||
bool stopped;
|
||||
bool axq_tx_inprogress;
|
||||
struct list_head axq_acq;
|
||||
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
|
||||
u8 txq_headidx;
|
||||
u8 txq_tailidx;
|
||||
|
@ -280,8 +277,9 @@ struct ath_node {
|
|||
struct ath_tx_control {
|
||||
struct ath_txq *txq;
|
||||
struct ath_node *an;
|
||||
u8 paprd;
|
||||
struct ieee80211_sta *sta;
|
||||
u8 paprd;
|
||||
bool force_channel;
|
||||
};
|
||||
|
||||
|
||||
|
@ -325,6 +323,116 @@ struct ath_rx {
|
|||
u32 ampdu_ref;
|
||||
};
|
||||
|
||||
struct ath_chanctx {
|
||||
struct cfg80211_chan_def chandef;
|
||||
struct list_head vifs;
|
||||
struct list_head acq[IEEE80211_NUM_ACS];
|
||||
int hw_queue_base;
|
||||
|
||||
/* do not dereference, use for comparison only */
|
||||
struct ieee80211_vif *primary_sta;
|
||||
|
||||
struct ath_beacon_config beacon;
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
struct timespec tsf_ts;
|
||||
u64 tsf_val;
|
||||
u32 last_beacon;
|
||||
|
||||
u16 txpower;
|
||||
bool offchannel;
|
||||
bool stopped;
|
||||
bool active;
|
||||
bool assigned;
|
||||
bool switch_after_beacon;
|
||||
};
|
||||
|
||||
enum ath_chanctx_event {
|
||||
ATH_CHANCTX_EVENT_BEACON_PREPARE,
|
||||
ATH_CHANCTX_EVENT_BEACON_SENT,
|
||||
ATH_CHANCTX_EVENT_TSF_TIMER,
|
||||
ATH_CHANCTX_EVENT_BEACON_RECEIVED,
|
||||
ATH_CHANCTX_EVENT_ASSOC,
|
||||
ATH_CHANCTX_EVENT_SWITCH,
|
||||
ATH_CHANCTX_EVENT_UNASSIGN,
|
||||
ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL,
|
||||
};
|
||||
|
||||
enum ath_chanctx_state {
|
||||
ATH_CHANCTX_STATE_IDLE,
|
||||
ATH_CHANCTX_STATE_WAIT_FOR_BEACON,
|
||||
ATH_CHANCTX_STATE_WAIT_FOR_TIMER,
|
||||
ATH_CHANCTX_STATE_SWITCH,
|
||||
ATH_CHANCTX_STATE_FORCE_ACTIVE,
|
||||
};
|
||||
|
||||
struct ath_chanctx_sched {
|
||||
bool beacon_pending;
|
||||
bool offchannel_pending;
|
||||
enum ath_chanctx_state state;
|
||||
u8 beacon_miss;
|
||||
|
||||
u32 next_tbtt;
|
||||
u32 switch_start_time;
|
||||
unsigned int offchannel_duration;
|
||||
unsigned int channel_switch_time;
|
||||
|
||||
/* backup, in case the hardware timer fails */
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
enum ath_offchannel_state {
|
||||
ATH_OFFCHANNEL_IDLE,
|
||||
ATH_OFFCHANNEL_PROBE_SEND,
|
||||
ATH_OFFCHANNEL_PROBE_WAIT,
|
||||
ATH_OFFCHANNEL_SUSPEND,
|
||||
ATH_OFFCHANNEL_ROC_START,
|
||||
ATH_OFFCHANNEL_ROC_WAIT,
|
||||
ATH_OFFCHANNEL_ROC_DONE,
|
||||
};
|
||||
|
||||
struct ath_offchannel {
|
||||
struct ath_chanctx chan;
|
||||
struct timer_list timer;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
struct ieee80211_vif *scan_vif;
|
||||
int scan_idx;
|
||||
enum ath_offchannel_state state;
|
||||
struct ieee80211_channel *roc_chan;
|
||||
struct ieee80211_vif *roc_vif;
|
||||
int roc_duration;
|
||||
int duration;
|
||||
};
|
||||
#define ath_for_each_chanctx(_sc, _ctx) \
|
||||
for (ctx = &sc->chanctx[0]; \
|
||||
ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \
|
||||
ctx++)
|
||||
|
||||
void ath9k_fill_chanctx_ops(void);
|
||||
void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
static inline struct ath_chanctx *
|
||||
ath_chanctx_get(struct ieee80211_chanctx_conf *ctx)
|
||||
{
|
||||
struct ath_chanctx **ptr = (void *) ctx->drv_priv;
|
||||
return *ptr;
|
||||
}
|
||||
void ath_chanctx_init(struct ath_softc *sc);
|
||||
void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx);
|
||||
void ath_offchannel_timer(unsigned long data);
|
||||
void ath_offchannel_channel_change(struct ath_softc *sc);
|
||||
void ath_chanctx_offchan_switch(struct ath_softc *sc,
|
||||
struct ieee80211_channel *chan);
|
||||
struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
|
||||
bool active);
|
||||
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
|
||||
enum ath_chanctx_event ev);
|
||||
void ath_chanctx_timer(unsigned long data);
|
||||
|
||||
int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
|
||||
int ath_startrecv(struct ath_softc *sc);
|
||||
bool ath_stoprecv(struct ath_softc *sc);
|
||||
u32 ath_calcrxfilter(struct ath_softc *sc);
|
||||
|
@ -341,6 +449,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq);
|
|||
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
|
||||
void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
|
||||
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
|
||||
void ath_txq_schedule_all(struct ath_softc *sc);
|
||||
int ath_tx_init(struct ath_softc *sc, int nbufs);
|
||||
int ath_txq_update(struct ath_softc *sc, int qnum,
|
||||
struct ath9k_tx_queue_info *q);
|
||||
|
@ -370,32 +479,47 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
|
|||
/********/
|
||||
|
||||
struct ath_vif {
|
||||
struct list_head list;
|
||||
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath_node mcast_node;
|
||||
int av_bslot;
|
||||
bool primary_sta_vif;
|
||||
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
|
||||
struct ath_buf *av_bcbuf;
|
||||
struct ath_chanctx *chanctx;
|
||||
|
||||
/* P2P Client */
|
||||
struct ieee80211_noa_data noa;
|
||||
|
||||
/* P2P GO */
|
||||
u8 noa_index;
|
||||
u32 offchannel_start;
|
||||
u32 offchannel_duration;
|
||||
|
||||
u32 periodic_noa_start;
|
||||
u32 periodic_noa_duration;
|
||||
};
|
||||
|
||||
struct ath9k_vif_iter_data {
|
||||
u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */
|
||||
u8 mask[ETH_ALEN]; /* bssid mask */
|
||||
bool has_hw_macaddr;
|
||||
u8 slottime;
|
||||
bool beacons;
|
||||
|
||||
int naps; /* number of AP vifs */
|
||||
int nmeshes; /* number of mesh vifs */
|
||||
int nstations; /* number of station vifs */
|
||||
int nwds; /* number of WDS vifs */
|
||||
int nadhocs; /* number of adhoc vifs */
|
||||
struct ieee80211_vif *primary_sta;
|
||||
};
|
||||
|
||||
void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
void ath9k_calculate_iter_data(struct ath_softc *sc,
|
||||
struct ath_chanctx *ctx,
|
||||
struct ath9k_vif_iter_data *iter_data);
|
||||
void ath9k_calculate_summary_state(struct ath_softc *sc,
|
||||
struct ath_chanctx *ctx);
|
||||
|
||||
/*******************/
|
||||
/* Beacon Handling */
|
||||
|
@ -458,6 +582,7 @@ void ath9k_csa_update(struct ath_softc *sc);
|
|||
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
|
||||
#define ATH_PLL_WORK_INTERVAL 100
|
||||
|
||||
void ath_chanctx_work(struct work_struct *work);
|
||||
void ath_tx_complete_poll_work(struct work_struct *work);
|
||||
void ath_reset_work(struct work_struct *work);
|
||||
bool ath_hw_check(struct ath_softc *sc);
|
||||
|
@ -473,6 +598,7 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
|
|||
void ath_ps_full_sleep(unsigned long data);
|
||||
void ath9k_p2p_ps_timer(void *priv);
|
||||
void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
|
||||
|
||||
/**********/
|
||||
/* BTCOEX */
|
||||
|
@ -702,6 +828,8 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
|
|||
#define PS_BEACON_SYNC BIT(4)
|
||||
#define PS_WAIT_FOR_ANI BIT(5)
|
||||
|
||||
#define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */
|
||||
|
||||
struct ath_softc {
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
|
@ -720,6 +848,7 @@ struct ath_softc {
|
|||
struct mutex mutex;
|
||||
struct work_struct paprd_work;
|
||||
struct work_struct hw_reset_work;
|
||||
struct work_struct chanctx_work;
|
||||
struct completion paprd_complete;
|
||||
wait_queue_head_t tx_wait;
|
||||
|
||||
|
@ -738,23 +867,27 @@ struct ath_softc {
|
|||
short nvifs;
|
||||
unsigned long ps_usecount;
|
||||
|
||||
struct ath_config config;
|
||||
struct ath_rx rx;
|
||||
struct ath_tx tx;
|
||||
struct ath_beacon beacon;
|
||||
|
||||
struct cfg80211_chan_def cur_chandef;
|
||||
struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX];
|
||||
struct ath_chanctx *cur_chan;
|
||||
struct ath_chanctx *next_chan;
|
||||
spinlock_t chan_lock;
|
||||
struct ath_offchannel offchannel;
|
||||
struct ath_chanctx_sched sched;
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
bool led_registered;
|
||||
char led_name[32];
|
||||
struct led_classdev led_cdev;
|
||||
#endif
|
||||
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
struct ath9k_debug debug;
|
||||
#endif
|
||||
struct ath_beacon_config cur_beacon_conf;
|
||||
struct delayed_work tx_complete_work;
|
||||
struct delayed_work hw_pll_work;
|
||||
struct timer_list sleep_timer;
|
||||
|
|
|
@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|||
u8 chainmask = ah->txchainmask;
|
||||
u8 rate = 0;
|
||||
|
||||
sband = &common->sbands[common->hw->conf.chandef.chan->band];
|
||||
sband = &common->sbands[sc->cur_chandef.chan->band];
|
||||
rate = sband->bitrates[rateidx].hw_value;
|
||||
if (vif->bss_conf.use_short_preamble)
|
||||
rate |= sband->bitrates[rateidx].hw_value_short;
|
||||
|
@ -108,6 +108,55 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|||
ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
|
||||
}
|
||||
|
||||
static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
static const u8 noa_ie_hdr[] = {
|
||||
WLAN_EID_VENDOR_SPECIFIC, /* type */
|
||||
0, /* length */
|
||||
0x50, 0x6f, 0x9a, /* WFA OUI */
|
||||
0x09, /* P2P subtype */
|
||||
0x0c, /* Notice of Absence */
|
||||
0x00, /* LSB of little-endian len */
|
||||
0x00, /* MSB of little-endian len */
|
||||
};
|
||||
|
||||
struct ieee80211_p2p_noa_attr *noa;
|
||||
int noa_len, noa_desc, i = 0;
|
||||
u8 *hdr;
|
||||
|
||||
if (!avp->offchannel_duration && !avp->periodic_noa_duration)
|
||||
return;
|
||||
|
||||
noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration;
|
||||
noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
|
||||
|
||||
hdr = skb_put(skb, sizeof(noa_ie_hdr));
|
||||
memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
|
||||
hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
|
||||
hdr[7] = noa_len;
|
||||
|
||||
noa = (void *) skb_put(skb, noa_len);
|
||||
memset(noa, 0, noa_len);
|
||||
|
||||
noa->index = avp->noa_index;
|
||||
if (avp->periodic_noa_duration) {
|
||||
u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
|
||||
|
||||
noa->desc[i].count = 255;
|
||||
noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start);
|
||||
noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
|
||||
noa->desc[i].interval = cpu_to_le32(interval);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (avp->offchannel_duration) {
|
||||
noa->desc[i].count = 1;
|
||||
noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
|
||||
noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
|
@ -155,6 +204,9 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
|
|||
hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
|
||||
}
|
||||
|
||||
if (vif->p2p)
|
||||
ath9k_beacon_add_noa(sc, avp, skb);
|
||||
|
||||
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
|
||||
skb->len, DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
|
||||
|
@ -249,7 +301,7 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|||
static int ath9k_beacon_choose_slot(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
|
||||
u16 intval;
|
||||
u32 tsftu;
|
||||
u64 tsf;
|
||||
|
@ -277,8 +329,8 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
|
|||
static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
struct ath_beacon_config *cur_conf = &avp->chanctx->beacon;
|
||||
u32 tsfadjust;
|
||||
|
||||
if (avp->av_bslot == 0)
|
||||
|
@ -374,12 +426,19 @@ void ath9k_beacon_tasklet(unsigned long data)
|
|||
vif = sc->beacon.bslot[slot];
|
||||
|
||||
/* EDMA devices check that in the tx completion function. */
|
||||
if (!edma && ath9k_csa_is_finished(sc, vif))
|
||||
return;
|
||||
if (!edma) {
|
||||
if (sc->sched.beacon_pending)
|
||||
ath_chanctx_event(sc, NULL,
|
||||
ATH_CHANCTX_EVENT_BEACON_SENT);
|
||||
|
||||
if (ath9k_csa_is_finished(sc, vif))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vif || !vif->bss_conf.enable_beacon)
|
||||
return;
|
||||
|
||||
ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
|
||||
bf = ath9k_beacon_generate(sc->hw, vif);
|
||||
|
||||
if (sc->beacon.bmisscnt != 0) {
|
||||
|
@ -500,7 +559,6 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
|
|||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
if ((vif->type != NL80211_IFTYPE_AP) ||
|
||||
|
@ -514,7 +572,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
|
|||
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
||||
if ((vif->type == NL80211_IFTYPE_STATION) &&
|
||||
test_bit(ATH_OP_BEACONS, &common->op_flags) &&
|
||||
!avp->primary_sta_vif) {
|
||||
vif != sc->cur_chan->primary_sta) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"Beacon already configured for a station interface\n");
|
||||
return false;
|
||||
|
@ -525,10 +583,11 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
|
|||
}
|
||||
|
||||
static void ath9k_cache_beacon_config(struct ath_softc *sc,
|
||||
struct ath_chanctx *ctx,
|
||||
struct ieee80211_bss_conf *bss_conf)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
struct ath_beacon_config *cur_conf = &ctx->beacon;
|
||||
|
||||
ath_dbg(common, BEACON,
|
||||
"Caching beacon data for BSS: %pM\n", bss_conf->bssid);
|
||||
|
@ -564,20 +623,29 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|||
u32 changed)
|
||||
{
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
struct ath_chanctx *ctx = avp->chanctx;
|
||||
struct ath_beacon_config *cur_conf;
|
||||
unsigned long flags;
|
||||
bool skip_beacon = false;
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
cur_conf = &avp->chanctx->beacon;
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
ath9k_set_tsfadjust(sc, vif);
|
||||
|
||||
if (!ath9k_allow_beacon_config(sc, vif))
|
||||
return;
|
||||
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
||||
ath9k_cache_beacon_config(sc, bss_conf);
|
||||
if (vif->type == NL80211_IFTYPE_STATION) {
|
||||
ath9k_cache_beacon_config(sc, ctx, bss_conf);
|
||||
if (ctx != sc->cur_chan)
|
||||
return;
|
||||
|
||||
ath9k_set_beacon(sc);
|
||||
set_bit(ATH_OP_BEACONS, &common->op_flags);
|
||||
return;
|
||||
|
@ -593,10 +661,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|||
cur_conf->enable_beacon = false;
|
||||
} else if (bss_conf->enable_beacon) {
|
||||
cur_conf->enable_beacon = true;
|
||||
ath9k_cache_beacon_config(sc, bss_conf);
|
||||
ath9k_cache_beacon_config(sc, ctx, bss_conf);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx != sc->cur_chan)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Configure the HW beacon registers only when we have a valid
|
||||
* beacon interval.
|
||||
|
@ -631,7 +702,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|||
void ath9k_set_beacon(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
|
||||
|
||||
switch (sc->sc_ah->opmode) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
|
|
|
@ -0,0 +1,685 @@
|
|||
/*
|
||||
* Copyright (c) 2014 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"
|
||||
|
||||
/* Set/change channels. If the channel is really being changed, it's done
|
||||
* by reseting the chip. To accomplish this we must first cleanup any pending
|
||||
* DMA, then restart stuff.
|
||||
*/
|
||||
static int ath_set_channel(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ath9k_channel *hchan;
|
||||
struct cfg80211_chan_def *chandef = &sc->cur_chan->chandef;
|
||||
struct ieee80211_channel *chan = chandef->chan;
|
||||
int pos = chan->hw_value;
|
||||
int old_pos = -1;
|
||||
int r;
|
||||
|
||||
if (test_bit(ATH_OP_INVALID, &common->op_flags))
|
||||
return -EIO;
|
||||
|
||||
if (ah->curchan)
|
||||
old_pos = ah->curchan - &ah->channels[0];
|
||||
|
||||
ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
|
||||
chan->center_freq, chandef->width);
|
||||
|
||||
/* update survey stats for the old channel before switching */
|
||||
spin_lock_bh(&common->cc_lock);
|
||||
ath_update_survey_stats(sc);
|
||||
spin_unlock_bh(&common->cc_lock);
|
||||
|
||||
ath9k_cmn_get_channel(hw, ah, chandef);
|
||||
|
||||
/* If the operating channel changes, change the survey in-use flags
|
||||
* along with it.
|
||||
* Reset the survey data for the new channel, unless we're switching
|
||||
* back to the operating channel from an off-channel operation.
|
||||
*/
|
||||
if (!sc->cur_chan->offchannel && sc->cur_survey != &sc->survey[pos]) {
|
||||
if (sc->cur_survey)
|
||||
sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
|
||||
|
||||
sc->cur_survey = &sc->survey[pos];
|
||||
|
||||
memset(sc->cur_survey, 0, sizeof(struct survey_info));
|
||||
sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
|
||||
} else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
|
||||
memset(&sc->survey[pos], 0, sizeof(struct survey_info));
|
||||
}
|
||||
|
||||
hchan = &sc->sc_ah->channels[pos];
|
||||
r = ath_reset_internal(sc, hchan);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* The most recent snapshot of channel->noisefloor for the old
|
||||
* channel is only available after the hardware reset. Copy it to
|
||||
* the survey stats now.
|
||||
*/
|
||||
if (old_pos >= 0)
|
||||
ath_update_survey_nf(sc, old_pos);
|
||||
|
||||
/* Enable radar pulse detection if on a DFS channel. Spectral
|
||||
* scanning and radar detection can not be used concurrently.
|
||||
*/
|
||||
if (hw->conf.radar_enabled) {
|
||||
u32 rxfilter;
|
||||
|
||||
/* set HW specific DFS configuration */
|
||||
ath9k_hw_set_radar_params(ah);
|
||||
rxfilter = ath9k_hw_getrxfilter(ah);
|
||||
rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
|
||||
ATH9K_RX_FILTER_PHYERR;
|
||||
ath9k_hw_setrxfilter(ah, rxfilter);
|
||||
ath_dbg(common, DFS, "DFS enabled at freq %d\n",
|
||||
chan->center_freq);
|
||||
} else {
|
||||
/* perform spectral scan if requested. */
|
||||
if (test_bit(ATH_OP_SCANNING, &common->op_flags) &&
|
||||
sc->spectral_mode == SPECTRAL_CHANSCAN)
|
||||
ath9k_spectral_scan_trigger(hw);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
|
||||
bool powersave)
|
||||
{
|
||||
struct ieee80211_vif *vif = avp->vif;
|
||||
struct ieee80211_sta *sta = NULL;
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
struct ath_tx_control txctl;
|
||||
struct sk_buff *skb;
|
||||
int band = sc->cur_chan->chandef.chan->band;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!vif->bss_conf.assoc)
|
||||
return false;
|
||||
|
||||
skb = ieee80211_nullfunc_get(sc->hw, vif);
|
||||
if (!skb)
|
||||
return false;
|
||||
|
||||
nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
|
||||
if (powersave)
|
||||
nullfunc->frame_control |=
|
||||
cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
|
||||
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
|
||||
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&txctl, 0, sizeof(txctl));
|
||||
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
|
||||
txctl.sta = sta;
|
||||
txctl.force_channel = true;
|
||||
if (ath_tx_start(sc->hw, skb, &txctl)) {
|
||||
ieee80211_free_txskb(sc->hw, skb);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_vif *avp;
|
||||
bool active = false;
|
||||
u8 n_active = 0;
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
list_for_each_entry(avp, &ctx->vifs, list) {
|
||||
struct ieee80211_vif *vif = avp->vif;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (vif->bss_conf.assoc)
|
||||
active = true;
|
||||
break;
|
||||
default:
|
||||
active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx->active = active;
|
||||
|
||||
ath_for_each_chanctx(sc, ctx) {
|
||||
if (!ctx->assigned || list_empty(&ctx->vifs))
|
||||
continue;
|
||||
n_active++;
|
||||
}
|
||||
|
||||
if (n_active <= 1) {
|
||||
clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
|
||||
return;
|
||||
}
|
||||
if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
|
||||
return;
|
||||
ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
|
||||
}
|
||||
|
||||
static bool
|
||||
ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
|
||||
{
|
||||
struct ath_vif *avp;
|
||||
bool sent = false;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
|
||||
if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
|
||||
sent = true;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
static bool ath_chanctx_defer_switch(struct ath_softc *sc)
|
||||
{
|
||||
if (sc->cur_chan == &sc->offchannel.chan)
|
||||
return false;
|
||||
|
||||
switch (sc->sched.state) {
|
||||
case ATH_CHANCTX_STATE_SWITCH:
|
||||
return false;
|
||||
case ATH_CHANCTX_STATE_IDLE:
|
||||
if (!sc->cur_chan->switch_after_beacon)
|
||||
return false;
|
||||
|
||||
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ath_chanctx_set_next(struct ath_softc *sc, bool force)
|
||||
{
|
||||
struct timespec ts;
|
||||
bool measure_time = false;
|
||||
bool send_ps = false;
|
||||
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
if (!sc->next_chan) {
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force && ath_chanctx_defer_switch(sc)) {
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc->cur_chan != sc->next_chan) {
|
||||
sc->cur_chan->stopped = true;
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
|
||||
if (sc->next_chan == &sc->offchannel.chan) {
|
||||
getrawmonotonic(&ts);
|
||||
measure_time = true;
|
||||
}
|
||||
__ath9k_flush(sc->hw, ~0, true);
|
||||
|
||||
if (ath_chanctx_send_ps_frame(sc, true))
|
||||
__ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
|
||||
|
||||
send_ps = true;
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
|
||||
if (sc->cur_chan != &sc->offchannel.chan) {
|
||||
getrawmonotonic(&sc->cur_chan->tsf_ts);
|
||||
sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
|
||||
}
|
||||
}
|
||||
sc->cur_chan = sc->next_chan;
|
||||
sc->cur_chan->stopped = false;
|
||||
sc->next_chan = NULL;
|
||||
sc->sched.offchannel_duration = 0;
|
||||
if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
|
||||
sc->sched.state = ATH_CHANCTX_STATE_IDLE;
|
||||
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
|
||||
if (sc->sc_ah->chip_fullsleep ||
|
||||
memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
|
||||
sizeof(sc->cur_chandef))) {
|
||||
ath_set_channel(sc);
|
||||
if (measure_time)
|
||||
sc->sched.channel_switch_time =
|
||||
ath9k_hw_get_tsf_offset(&ts, NULL);
|
||||
}
|
||||
if (send_ps)
|
||||
ath_chanctx_send_ps_frame(sc, false);
|
||||
|
||||
ath_offchannel_channel_change(sc);
|
||||
ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
|
||||
}
|
||||
|
||||
void ath_chanctx_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
chanctx_work);
|
||||
mutex_lock(&sc->mutex);
|
||||
ath_chanctx_set_next(sc, false);
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
void ath_chanctx_init(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_chanctx *ctx;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *chan;
|
||||
int i, j;
|
||||
|
||||
sband = &common->sbands[IEEE80211_BAND_2GHZ];
|
||||
if (!sband->n_channels)
|
||||
sband = &common->sbands[IEEE80211_BAND_5GHZ];
|
||||
|
||||
chan = &sband->channels[0];
|
||||
for (i = 0; i < ATH9K_NUM_CHANCTX; i++) {
|
||||
ctx = &sc->chanctx[i];
|
||||
cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
|
||||
INIT_LIST_HEAD(&ctx->vifs);
|
||||
ctx->txpower = ATH_TXPOWER_MAX;
|
||||
for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
|
||||
INIT_LIST_HEAD(&ctx->acq[j]);
|
||||
}
|
||||
ctx = &sc->offchannel.chan;
|
||||
cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
|
||||
INIT_LIST_HEAD(&ctx->vifs);
|
||||
ctx->txpower = ATH_TXPOWER_MAX;
|
||||
for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
|
||||
INIT_LIST_HEAD(&ctx->acq[j]);
|
||||
sc->offchannel.chan.offchannel = true;
|
||||
|
||||
}
|
||||
|
||||
void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
|
||||
bool changed = false;
|
||||
|
||||
if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
|
||||
return;
|
||||
|
||||
if (!avp->chanctx)
|
||||
return;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
|
||||
sc->next_chan = avp->chanctx;
|
||||
changed = true;
|
||||
}
|
||||
sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
|
||||
if (changed)
|
||||
ath_chanctx_set_next(sc, true);
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
|
||||
if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
|
||||
(sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
|
||||
sc->sched.offchannel_pending = true;
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
sc->next_chan = ctx;
|
||||
if (chandef)
|
||||
ctx->chandef = *chandef;
|
||||
|
||||
if (sc->next_chan == &sc->offchannel.chan) {
|
||||
sc->sched.offchannel_duration =
|
||||
TU_TO_USEC(sc->offchannel.duration) +
|
||||
sc->sched.channel_switch_time;
|
||||
}
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
|
||||
}
|
||||
|
||||
void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
bool cur_chan;
|
||||
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
if (chandef)
|
||||
memcpy(&ctx->chandef, chandef, sizeof(*chandef));
|
||||
cur_chan = sc->cur_chan == ctx;
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
|
||||
if (!cur_chan)
|
||||
return;
|
||||
|
||||
ath_set_channel(sc);
|
||||
}
|
||||
|
||||
struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active)
|
||||
{
|
||||
struct ath_chanctx *ctx;
|
||||
|
||||
ath_for_each_chanctx(sc, ctx) {
|
||||
if (!ctx->assigned || list_empty(&ctx->vifs))
|
||||
continue;
|
||||
if (active && !ctx->active)
|
||||
continue;
|
||||
|
||||
if (ctx->switch_after_beacon)
|
||||
return ctx;
|
||||
}
|
||||
|
||||
return &sc->chanctx[0];
|
||||
}
|
||||
|
||||
void ath_chanctx_offchan_switch(struct ath_softc *sc,
|
||||
struct ieee80211_channel *chan)
|
||||
{
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
||||
cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
|
||||
|
||||
ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
|
||||
}
|
||||
|
||||
static struct ath_chanctx *
|
||||
ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx)
|
||||
{
|
||||
int idx = ctx - &sc->chanctx[0];
|
||||
|
||||
return &sc->chanctx[!idx];
|
||||
}
|
||||
|
||||
static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_chanctx *prev, *cur;
|
||||
struct timespec ts;
|
||||
u32 cur_tsf, prev_tsf, beacon_int;
|
||||
s32 offset;
|
||||
|
||||
beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
|
||||
|
||||
cur = sc->cur_chan;
|
||||
prev = ath_chanctx_get_next(sc, cur);
|
||||
|
||||
getrawmonotonic(&ts);
|
||||
cur_tsf = (u32) cur->tsf_val +
|
||||
ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts);
|
||||
|
||||
prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf;
|
||||
prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts);
|
||||
|
||||
/* Adjust the TSF time of the AP chanctx to keep its beacons
|
||||
* at half beacon interval offset relative to the STA chanctx.
|
||||
*/
|
||||
offset = cur_tsf - prev_tsf;
|
||||
|
||||
/* Ignore stale data or spurious timestamps */
|
||||
if (offset < 0 || offset > 3 * beacon_int)
|
||||
return;
|
||||
|
||||
offset = beacon_int / 2 - (offset % beacon_int);
|
||||
prev->tsf_val += offset;
|
||||
}
|
||||
|
||||
void ath_chanctx_timer(unsigned long data)
|
||||
{
|
||||
struct ath_softc *sc = (struct ath_softc *) data;
|
||||
|
||||
ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
|
||||
}
|
||||
|
||||
/* Configure the TSF based hardware timer for a channel switch.
|
||||
* Also set up backup software timer, in case the gen timer fails.
|
||||
* This could be caused by a hardware reset.
|
||||
*/
|
||||
static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
|
||||
tsf_time -= ath9k_hw_gettsf32(ah);
|
||||
tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
|
||||
mod_timer(&sc->sched.timer, tsf_time);
|
||||
}
|
||||
|
||||
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
|
||||
enum ath_chanctx_event ev)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_beacon_config *cur_conf;
|
||||
struct ath_vif *avp = NULL;
|
||||
struct ath_chanctx *ctx;
|
||||
u32 tsf_time;
|
||||
u32 beacon_int;
|
||||
bool noa_changed = false;
|
||||
|
||||
if (vif)
|
||||
avp = (struct ath_vif *) vif->drv_priv;
|
||||
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
|
||||
switch (ev) {
|
||||
case ATH_CHANCTX_EVENT_BEACON_PREPARE:
|
||||
if (avp->offchannel_duration)
|
||||
avp->offchannel_duration = 0;
|
||||
|
||||
if (avp->chanctx != sc->cur_chan)
|
||||
break;
|
||||
|
||||
if (sc->sched.offchannel_pending) {
|
||||
sc->sched.offchannel_pending = false;
|
||||
sc->next_chan = &sc->offchannel.chan;
|
||||
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
|
||||
}
|
||||
|
||||
ctx = ath_chanctx_get_next(sc, sc->cur_chan);
|
||||
if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) {
|
||||
sc->next_chan = ctx;
|
||||
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
|
||||
}
|
||||
|
||||
/* if the timer missed its window, use the next interval */
|
||||
if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
|
||||
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
|
||||
|
||||
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
|
||||
break;
|
||||
|
||||
sc->sched.beacon_pending = true;
|
||||
sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER);
|
||||
|
||||
cur_conf = &sc->cur_chan->beacon;
|
||||
beacon_int = TU_TO_USEC(cur_conf->beacon_interval);
|
||||
|
||||
/* defer channel switch by a quarter beacon interval */
|
||||
tsf_time = sc->sched.next_tbtt + beacon_int / 4;
|
||||
sc->sched.switch_start_time = tsf_time;
|
||||
sc->cur_chan->last_beacon = sc->sched.next_tbtt;
|
||||
|
||||
/* Prevent wrap-around issues */
|
||||
if (avp->periodic_noa_duration &&
|
||||
tsf_time - avp->periodic_noa_start > BIT(30))
|
||||
avp->periodic_noa_duration = 0;
|
||||
|
||||
if (ctx->active && !avp->periodic_noa_duration) {
|
||||
avp->periodic_noa_start = tsf_time;
|
||||
avp->periodic_noa_duration =
|
||||
TU_TO_USEC(cur_conf->beacon_interval) / 2 -
|
||||
sc->sched.channel_switch_time;
|
||||
noa_changed = true;
|
||||
} else if (!ctx->active && avp->periodic_noa_duration) {
|
||||
avp->periodic_noa_duration = 0;
|
||||
noa_changed = true;
|
||||
}
|
||||
|
||||
/* If at least two consecutive beacons were missed on the STA
|
||||
* chanctx, stay on the STA channel for one extra beacon period,
|
||||
* to resync the timer properly.
|
||||
*/
|
||||
if (ctx->active && sc->sched.beacon_miss >= 2)
|
||||
sc->sched.offchannel_duration = 3 * beacon_int / 2;
|
||||
|
||||
if (sc->sched.offchannel_duration) {
|
||||
noa_changed = true;
|
||||
avp->offchannel_start = tsf_time;
|
||||
avp->offchannel_duration =
|
||||
sc->sched.offchannel_duration;
|
||||
}
|
||||
|
||||
if (noa_changed)
|
||||
avp->noa_index++;
|
||||
break;
|
||||
case ATH_CHANCTX_EVENT_BEACON_SENT:
|
||||
if (!sc->sched.beacon_pending)
|
||||
break;
|
||||
|
||||
sc->sched.beacon_pending = false;
|
||||
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
|
||||
break;
|
||||
|
||||
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
|
||||
ath_chanctx_setup_timer(sc, sc->sched.switch_start_time);
|
||||
break;
|
||||
case ATH_CHANCTX_EVENT_TSF_TIMER:
|
||||
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
|
||||
break;
|
||||
|
||||
if (!sc->cur_chan->switch_after_beacon &&
|
||||
sc->sched.beacon_pending)
|
||||
sc->sched.beacon_miss++;
|
||||
|
||||
sc->sched.state = ATH_CHANCTX_STATE_SWITCH;
|
||||
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
|
||||
break;
|
||||
case ATH_CHANCTX_EVENT_BEACON_RECEIVED:
|
||||
if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) ||
|
||||
sc->cur_chan == &sc->offchannel.chan)
|
||||
break;
|
||||
|
||||
ath_chanctx_adjust_tbtt_delta(sc);
|
||||
sc->sched.beacon_pending = false;
|
||||
sc->sched.beacon_miss = 0;
|
||||
|
||||
/* TSF time might have been updated by the incoming beacon,
|
||||
* need update the channel switch timer to reflect the change.
|
||||
*/
|
||||
tsf_time = sc->sched.switch_start_time;
|
||||
tsf_time -= (u32) sc->cur_chan->tsf_val +
|
||||
ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL);
|
||||
tsf_time += ath9k_hw_gettsf32(ah);
|
||||
|
||||
|
||||
ath_chanctx_setup_timer(sc, tsf_time);
|
||||
break;
|
||||
case ATH_CHANCTX_EVENT_ASSOC:
|
||||
if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE ||
|
||||
avp->chanctx != sc->cur_chan)
|
||||
break;
|
||||
|
||||
sc->sched.state = ATH_CHANCTX_STATE_IDLE;
|
||||
/* fall through */
|
||||
case ATH_CHANCTX_EVENT_SWITCH:
|
||||
if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) ||
|
||||
sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE ||
|
||||
sc->cur_chan->switch_after_beacon ||
|
||||
sc->cur_chan == &sc->offchannel.chan)
|
||||
break;
|
||||
|
||||
/* If this is a station chanctx, stay active for a half
|
||||
* beacon period (minus channel switch time)
|
||||
*/
|
||||
sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
|
||||
cur_conf = &sc->cur_chan->beacon;
|
||||
|
||||
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
|
||||
|
||||
tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2;
|
||||
if (sc->sched.beacon_miss >= 2) {
|
||||
sc->sched.beacon_miss = 0;
|
||||
tsf_time *= 3;
|
||||
}
|
||||
|
||||
tsf_time -= sc->sched.channel_switch_time;
|
||||
tsf_time += ath9k_hw_gettsf32(sc->sc_ah);
|
||||
sc->sched.switch_start_time = tsf_time;
|
||||
|
||||
ath_chanctx_setup_timer(sc, tsf_time);
|
||||
sc->sched.beacon_pending = true;
|
||||
break;
|
||||
case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL:
|
||||
if (sc->cur_chan == &sc->offchannel.chan ||
|
||||
sc->cur_chan->switch_after_beacon)
|
||||
break;
|
||||
|
||||
sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
|
||||
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
|
||||
break;
|
||||
case ATH_CHANCTX_EVENT_UNASSIGN:
|
||||
if (sc->cur_chan->assigned) {
|
||||
if (sc->next_chan && !sc->next_chan->assigned &&
|
||||
sc->next_chan != &sc->offchannel.chan)
|
||||
sc->sched.state = ATH_CHANCTX_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
ctx = ath_chanctx_get_next(sc, sc->cur_chan);
|
||||
sc->sched.state = ATH_CHANCTX_STATE_IDLE;
|
||||
if (!ctx->assigned)
|
||||
break;
|
||||
|
||||
sc->next_chan = ctx;
|
||||
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
}
|
|
@ -57,7 +57,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
|
|||
struct ath9k_beacon_state *bs)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int dtim_intval;
|
||||
int dtim_intval, sleepduration;
|
||||
u64 tsf;
|
||||
|
||||
/* No need to configure beacon if we are not associated */
|
||||
|
@ -75,6 +75,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
|
|||
* last beacon we received (which may be none).
|
||||
*/
|
||||
dtim_intval = conf->intval * conf->dtim_period;
|
||||
sleepduration = ah->hw->conf.listen_interval * conf->intval;
|
||||
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current
|
||||
|
@ -112,7 +113,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
|
|||
*/
|
||||
|
||||
bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
|
||||
conf->intval));
|
||||
sleepduration));
|
||||
if (bs->bs_sleepduration > bs->bs_dtimperiod)
|
||||
bs->bs_sleepduration = bs->bs_dtimperiod;
|
||||
|
||||
|
|
|
@ -750,13 +750,13 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
|
|||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ath9k_vif_iter_data iter_data;
|
||||
struct ath_chanctx *ctx;
|
||||
char buf[512];
|
||||
unsigned int len = 0;
|
||||
ssize_t retval = 0;
|
||||
unsigned int reg;
|
||||
u32 rxfilter;
|
||||
u32 rxfilter, i;
|
||||
|
||||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
"BSSID: %pM\n", common->curbssid);
|
||||
|
@ -826,14 +826,20 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
|
|||
|
||||
len += scnprintf(buf + len, sizeof(buf) - len, "\n");
|
||||
|
||||
ath9k_calculate_iter_data(hw, NULL, &iter_data);
|
||||
i = 0;
|
||||
ath_for_each_chanctx(sc, ctx) {
|
||||
if (!ctx->assigned || list_empty(&ctx->vifs))
|
||||
continue;
|
||||
ath9k_calculate_iter_data(sc, ctx, &iter_data);
|
||||
|
||||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
"VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i"
|
||||
" ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
|
||||
iter_data.naps, iter_data.nstations, iter_data.nmeshes,
|
||||
iter_data.nwds, iter_data.nadhocs,
|
||||
sc->nvifs, sc->nbcnvifs);
|
||||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
"VIF-COUNTS: CTX %i AP: %i STA: %i MESH: %i WDS: %i",
|
||||
i++, iter_data.naps, iter_data.nstations,
|
||||
iter_data.nmeshes, iter_data.nwds);
|
||||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
" ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
|
||||
iter_data.nadhocs, sc->nvifs, sc->nbcnvifs);
|
||||
}
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
@ -1080,7 +1086,7 @@ static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf,
|
|||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath9k_nfcal_hist *h = sc->caldata.nfCalHist;
|
||||
struct ath9k_nfcal_hist *h = sc->cur_chan->caldata.nfCalHist;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_conf *conf = &common->hw->conf;
|
||||
u32 len = 0, size = 1500;
|
||||
|
|
|
@ -791,7 +791,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
|
|||
refdiv = 5;
|
||||
} else {
|
||||
pll2_divint = 0x11;
|
||||
pll2_divfrac = 0x26666;
|
||||
pll2_divfrac =
|
||||
AR_SREV_9531(ah) ? 0x26665 : 0x26666;
|
||||
refdiv = 1;
|
||||
}
|
||||
}
|
||||
|
@ -1730,6 +1731,23 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
u32 ath9k_hw_get_tsf_offset(struct timespec *last, struct timespec *cur)
|
||||
{
|
||||
struct timespec ts;
|
||||
s64 usec;
|
||||
|
||||
if (!cur) {
|
||||
getrawmonotonic(&ts);
|
||||
cur = &ts;
|
||||
}
|
||||
|
||||
usec = cur->tv_sec * 1000000ULL + cur->tv_nsec / 1000;
|
||||
usec -= last->tv_sec * 1000000ULL + last->tv_nsec / 1000;
|
||||
|
||||
return (u32) usec;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_get_tsf_offset);
|
||||
|
||||
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
struct ath9k_hw_cal_data *caldata, bool fastcc)
|
||||
{
|
||||
|
@ -1739,7 +1757,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
u32 saveDefAntenna;
|
||||
u32 macStaId1;
|
||||
u64 tsf = 0;
|
||||
s64 usec = 0;
|
||||
int r;
|
||||
bool start_mci_reset = false;
|
||||
bool save_fullsleep = ah->chip_fullsleep;
|
||||
|
@ -1785,7 +1802,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
/* Save TSF before chip reset, a cold reset clears it */
|
||||
tsf = ath9k_hw_gettsf64(ah);
|
||||
getrawmonotonic(&ts);
|
||||
usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;
|
||||
|
||||
saveLedState = REG_READ(ah, AR_CFG_LED) &
|
||||
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
|
||||
|
@ -1818,9 +1834,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
}
|
||||
|
||||
/* Restore TSF */
|
||||
getrawmonotonic(&ts);
|
||||
usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec;
|
||||
ath9k_hw_settsf64(ah, tsf + usec);
|
||||
ath9k_hw_settsf64(ah, tsf + ath9k_hw_get_tsf_offset(&ts, NULL));
|
||||
|
||||
if (AR_SREV_9280_20_OR_LATER(ah))
|
||||
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
|
||||
|
|
|
@ -1000,6 +1000,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah);
|
|||
u64 ath9k_hw_gettsf64(struct ath_hw *ah);
|
||||
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
|
||||
void ath9k_hw_reset_tsf(struct ath_hw *ah);
|
||||
u32 ath9k_hw_get_tsf_offset(struct timespec *last, struct timespec *cur);
|
||||
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set);
|
||||
void ath9k_hw_init_global_settings(struct ath_hw *ah);
|
||||
u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
|
||||
|
|
|
@ -61,7 +61,7 @@ static int ath9k_ps_enable;
|
|||
module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
|
||||
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
|
||||
|
||||
static int ath9k_use_chanctx;
|
||||
int ath9k_use_chanctx;
|
||||
module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444);
|
||||
MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency");
|
||||
|
||||
|
@ -169,9 +169,9 @@ static void ath9k_reg_notifier(struct wiphy *wiphy,
|
|||
|
||||
/* Set tx power */
|
||||
if (ah->curchan) {
|
||||
sc->config.txpowlimit = 2 * ah->curchan->chan->max_power;
|
||||
sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power;
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
|
||||
ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false);
|
||||
sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
|
||||
/* synchronize DFS detector if regulatory domain changed */
|
||||
if (sc->dfs_detector != NULL)
|
||||
|
@ -335,7 +335,6 @@ static void ath9k_init_misc(struct ath_softc *sc)
|
|||
setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
|
||||
|
||||
common->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
sc->config.txpowlimit = ATH_TXPOWER_MAX;
|
||||
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
||||
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
|
||||
|
||||
|
@ -511,6 +510,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
|||
sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
|
||||
sc->tx99_power = MAX_RATE_POWER + 1;
|
||||
init_waitqueue_head(&sc->tx_wait);
|
||||
sc->cur_chan = &sc->chanctx[0];
|
||||
if (!ath9k_use_chanctx)
|
||||
sc->cur_chan->hw_queue_base = 0;
|
||||
|
||||
if (!pdata || pdata->use_eeprom) {
|
||||
ah->ah_flags |= AH_USE_EEPROM;
|
||||
|
@ -556,6 +558,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
|||
spin_lock_init(&common->cc_lock);
|
||||
spin_lock_init(&sc->sc_serial_rw);
|
||||
spin_lock_init(&sc->sc_pm_lock);
|
||||
spin_lock_init(&sc->chan_lock);
|
||||
mutex_init(&sc->mutex);
|
||||
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
|
||||
tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
|
||||
|
@ -564,7 +567,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *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->paprd_work, ath_paprd_calibrate);
|
||||
INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
|
||||
INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
|
||||
setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
|
||||
(unsigned long)sc);
|
||||
setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc);
|
||||
|
||||
/*
|
||||
* Cache line size is used to size and align various
|
||||
|
@ -599,6 +606,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
|||
ath9k_cmn_init_crypto(sc->sc_ah);
|
||||
ath9k_init_misc(sc);
|
||||
ath_fill_led_pin(sc);
|
||||
ath_chanctx_init(sc);
|
||||
|
||||
if (common->bus_ops->aspm_init)
|
||||
common->bus_ops->aspm_init(common);
|
||||
|
@ -664,6 +672,12 @@ static const struct ieee80211_iface_limit wds_limits[] = {
|
|||
{ .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) },
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_limit if_limits_multi[] = {
|
||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_STATION) },
|
||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) },
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_limit if_dfs_limits[] = {
|
||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
|
@ -672,6 +686,16 @@ static const struct ieee80211_iface_limit if_dfs_limits[] = {
|
|||
BIT(NL80211_IFTYPE_ADHOC) },
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination if_comb_multi[] = {
|
||||
{
|
||||
.limits = if_limits_multi,
|
||||
.n_limits = ARRAY_SIZE(if_limits_multi),
|
||||
.max_interfaces = 2,
|
||||
.num_different_channels = 2,
|
||||
.beacon_int_infra_match = true,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination if_comb[] = {
|
||||
{
|
||||
.limits = if_limits,
|
||||
|
@ -712,6 +736,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
IEEE80211_HW_SPECTRUM_MGMT |
|
||||
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
|
||||
IEEE80211_HW_SUPPORTS_RC_TABLE |
|
||||
IEEE80211_HW_QUEUE_CONTROL |
|
||||
IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
|
||||
|
||||
if (ath9k_ps_enable)
|
||||
|
@ -739,12 +764,21 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
hw->wiphy->iface_combinations = if_comb;
|
||||
if (!ath9k_use_chanctx) {
|
||||
hw->wiphy->iface_combinations = if_comb;
|
||||
hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
|
||||
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS);
|
||||
} else
|
||||
hw->wiphy->n_iface_combinations = 1;
|
||||
} else {
|
||||
hw->wiphy->iface_combinations = if_comb_multi;
|
||||
hw->wiphy->n_iface_combinations =
|
||||
ARRAY_SIZE(if_comb_multi);
|
||||
hw->wiphy->max_scan_ssids = 255;
|
||||
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
|
||||
hw->wiphy->max_remain_on_channel_duration = 10000;
|
||||
hw->chanctx_data_size = sizeof(void *);
|
||||
hw->extra_beacon_tailroom =
|
||||
sizeof(struct ieee80211_p2p_noa_attr) + 9;
|
||||
}
|
||||
}
|
||||
|
||||
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
|
@ -756,9 +790,14 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||
|
||||
hw->queues = 4;
|
||||
/* allow 4 queues per channel context +
|
||||
* 1 cab queue + 1 offchannel tx queue
|
||||
*/
|
||||
hw->queues = 10;
|
||||
/* last queue for offchannel */
|
||||
hw->offchannel_tx_hw_queue = hw->queues - 1;
|
||||
hw->max_rates = 4;
|
||||
hw->max_listen_interval = 1;
|
||||
hw->max_listen_interval = 10;
|
||||
hw->max_rate_tries = 10;
|
||||
hw->sta_data_size = sizeof(struct ath_node);
|
||||
hw->vif_data_size = sizeof(struct ath_vif);
|
||||
|
|
|
@ -178,7 +178,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
|
|||
txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE];
|
||||
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->band = hw->conf.chandef.chan->band;
|
||||
tx_info->band = sc->cur_chandef.chan->band;
|
||||
tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
tx_info->control.rates[0].idx = 0;
|
||||
tx_info->control.rates[0].count = 1;
|
||||
|
@ -416,7 +416,7 @@ void ath_start_ani(struct ath_softc *sc)
|
|||
|
||||
if (common->disable_ani ||
|
||||
!test_bit(ATH_OP_ANI_RUN, &common->op_flags) ||
|
||||
(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
|
||||
sc->cur_chan->offchannel)
|
||||
return;
|
||||
|
||||
common->ani.longcal_timer = timestamp;
|
||||
|
@ -440,7 +440,7 @@ void ath_check_ani(struct ath_softc *sc)
|
|||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
|
||||
|
||||
/*
|
||||
* Check for the various conditions in which ANI has to
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -706,7 +706,7 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
|
|||
return;
|
||||
|
||||
if (setchannel) {
|
||||
struct ath9k_hw_cal_data *caldata = &sc->caldata;
|
||||
struct ath9k_hw_cal_data *caldata = &sc->cur_chan->caldata;
|
||||
if (IS_CHAN_HT40PLUS(ah->curchan) &&
|
||||
(ah->curchan->channel > caldata->channel) &&
|
||||
(ah->curchan->channel <= caldata->channel + 20))
|
||||
|
@ -720,7 +720,7 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
|
|||
mci_hw->concur_tx = concur_tx;
|
||||
|
||||
if (old_concur_tx != mci_hw->concur_tx)
|
||||
ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
|
||||
ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false);
|
||||
}
|
||||
|
||||
static void ath9k_mci_stomp_audio(struct ath_softc *sc)
|
||||
|
|
|
@ -843,6 +843,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
ath9k_fill_chanctx_ops();
|
||||
hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
|
||||
if (!hw) {
|
||||
dev_err(&pdev->dev, "No memory for ieee80211_hw\n");
|
||||
|
|
|
@ -259,7 +259,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
|
|||
ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP);
|
||||
ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP);
|
||||
ath_opmode_init(sc);
|
||||
ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
|
||||
ath9k_hw_startpcureceive(sc->sc_ah, sc->cur_chan->offchannel);
|
||||
}
|
||||
|
||||
static void ath_edma_stop_recv(struct ath_softc *sc)
|
||||
|
@ -374,6 +374,7 @@ void ath_rx_cleanup(struct ath_softc *sc)
|
|||
|
||||
u32 ath_calcrxfilter(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
u32 rfilt;
|
||||
|
||||
if (config_enabled(CONFIG_ATH9K_TX99))
|
||||
|
@ -424,6 +425,10 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
|||
if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
|
||||
rfilt |= ATH9K_RX_FILTER_4ADDRESS;
|
||||
|
||||
if (ath9k_use_chanctx &&
|
||||
test_bit(ATH_OP_SCANNING, &common->op_flags))
|
||||
rfilt |= ATH9K_RX_FILTER_BEACON;
|
||||
|
||||
return rfilt;
|
||||
|
||||
}
|
||||
|
@ -457,7 +462,7 @@ int ath_startrecv(struct ath_softc *sc)
|
|||
|
||||
start_recv:
|
||||
ath_opmode_init(sc);
|
||||
ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
|
||||
ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -540,7 +545,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
|
|||
sc->ps_flags &= ~PS_BEACON_SYNC;
|
||||
ath_dbg(common, PS,
|
||||
"Reconfigure beacon timers based on synchronized timestamp\n");
|
||||
if (!(WARN_ON_ONCE(sc->cur_beacon_conf.beacon_interval == 0)))
|
||||
if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0)))
|
||||
ath9k_set_beacon(sc);
|
||||
if (sc->p2p_ps_vif)
|
||||
ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
|
||||
|
@ -887,6 +892,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rx_stats->is_mybeacon) {
|
||||
sc->sched.next_tbtt = rx_stats->rs_tstamp;
|
||||
ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED);
|
||||
}
|
||||
|
||||
ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
|
||||
|
||||
rx_status->band = ah->curchan->chan->band;
|
||||
|
|
|
@ -813,6 +813,7 @@
|
|||
#define AR_SREV_VERSION_9531 0x500
|
||||
#define AR_SREV_REVISION_9531_10 0
|
||||
#define AR_SREV_REVISION_9531_11 1
|
||||
#define AR_SREV_REVISION_9531_20 2
|
||||
|
||||
#define AR_SREV_5416(_ah) \
|
||||
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
|
||||
|
@ -958,6 +959,9 @@
|
|||
#define AR_SREV_9531_11(_ah) \
|
||||
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \
|
||||
((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11))
|
||||
#define AR_SREV_9531_20(_ah) \
|
||||
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \
|
||||
((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_20))
|
||||
|
||||
/* NOTE: When adding chips newer than Peacock, add chip check here */
|
||||
#define AR_SREV_9580_10_OR_LATER(_ah) \
|
||||
|
|
|
@ -76,7 +76,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
|
|||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
rate = &tx_info->control.rates[0];
|
||||
tx_info->band = hw->conf.chandef.chan->band;
|
||||
tx_info->band = sc->cur_chan->chandef.chan->band;
|
||||
tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
|
||||
tx_info->control.vif = sc->tx99_vif;
|
||||
rate->count = 1;
|
||||
|
|
|
@ -193,6 +193,7 @@ int ath9k_suspend(struct ieee80211_hw *hw,
|
|||
u32 wow_triggers_enabled = 0;
|
||||
int ret = 0;
|
||||
|
||||
cancel_work_sync(&sc->chanctx_work);
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
ath_cancel_work(sc);
|
||||
|
|
|
@ -103,9 +103,16 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
|
|||
ieee80211_tx_status(sc->hw, skb);
|
||||
}
|
||||
|
||||
static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
|
||||
static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct ath_atx_tid *tid)
|
||||
{
|
||||
struct ath_atx_ac *ac = tid->ac;
|
||||
struct list_head *list;
|
||||
struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
|
||||
struct ath_chanctx *ctx = avp->chanctx;
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
if (tid->sched)
|
||||
return;
|
||||
|
@ -117,7 +124,9 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
|
|||
return;
|
||||
|
||||
ac->sched = true;
|
||||
list_add_tail(&ac->list, &txq->axq_acq);
|
||||
|
||||
list = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
|
||||
list_add_tail(&ac->list, list);
|
||||
}
|
||||
|
||||
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
|
||||
|
@ -147,7 +156,8 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
|||
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
int q;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
int q, hw_queue;
|
||||
|
||||
q = skb_get_queue_mapping(skb);
|
||||
if (txq == sc->tx.uapsdq)
|
||||
|
@ -159,9 +169,10 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
|
|||
if (WARN_ON(--txq->pending_frames < 0))
|
||||
txq->pending_frames = 0;
|
||||
|
||||
hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue;
|
||||
if (txq->stopped &&
|
||||
txq->pending_frames < sc->tx.txq_max_pending[q]) {
|
||||
ieee80211_wake_queue(sc->hw, q);
|
||||
ieee80211_wake_queue(sc->hw, hw_queue);
|
||||
txq->stopped = false;
|
||||
}
|
||||
}
|
||||
|
@ -626,7 +637,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
|
||||
skb_queue_splice_tail(&bf_pending, &tid->retry_q);
|
||||
if (!an->sleeping) {
|
||||
ath_tx_queue_tid(txq, tid);
|
||||
ath_tx_queue_tid(sc, txq, tid);
|
||||
|
||||
if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
|
||||
tid->ac->clear_ps_filter = true;
|
||||
|
@ -1483,7 +1494,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
|
|||
ac->clear_ps_filter = true;
|
||||
|
||||
if (ath_tid_has_buffered(tid)) {
|
||||
ath_tx_queue_tid(txq, tid);
|
||||
ath_tx_queue_tid(sc, txq, tid);
|
||||
ath_txq_schedule(sc, txq);
|
||||
}
|
||||
|
||||
|
@ -1507,7 +1518,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
|
|||
tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
|
||||
|
||||
if (ath_tid_has_buffered(tid)) {
|
||||
ath_tx_queue_tid(txq, tid);
|
||||
ath_tx_queue_tid(sc, txq, tid);
|
||||
ath_txq_schedule(sc, txq);
|
||||
}
|
||||
|
||||
|
@ -1642,7 +1653,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
|
|||
txq->axq_link = NULL;
|
||||
__skb_queue_head_init(&txq->complete_q);
|
||||
INIT_LIST_HEAD(&txq->axq_q);
|
||||
INIT_LIST_HEAD(&txq->axq_acq);
|
||||
spin_lock_init(&txq->axq_lock);
|
||||
txq->axq_depth = 0;
|
||||
txq->axq_ampdu_depth = 0;
|
||||
|
@ -1686,7 +1696,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
|
|||
int ath_cabq_update(struct ath_softc *sc)
|
||||
{
|
||||
struct ath9k_tx_queue_info qi;
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
|
||||
int qnum = sc->beacon.cabq->axq_qnum;
|
||||
|
||||
ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
|
||||
|
@ -1804,7 +1814,7 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
|
||||
}
|
||||
|
||||
/* For each axq_acq entry, for each tid, try to schedule packets
|
||||
/* For each acq entry, for each tid, try to schedule packets
|
||||
* for transmit until ampdu_depth has reached min Q depth.
|
||||
*/
|
||||
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
||||
|
@ -1812,19 +1822,31 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
|||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_atx_ac *ac, *last_ac;
|
||||
struct ath_atx_tid *tid, *last_tid;
|
||||
struct list_head *ac_list;
|
||||
bool sent = false;
|
||||
|
||||
if (test_bit(ATH_OP_HW_RESET, &common->op_flags) ||
|
||||
list_empty(&txq->axq_acq))
|
||||
if (txq->mac80211_qnum < 0)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
ac_list = &sc->cur_chan->acq[txq->mac80211_qnum];
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
|
||||
if (test_bit(ATH_OP_HW_RESET, &common->op_flags) ||
|
||||
list_empty(ac_list))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
rcu_read_lock();
|
||||
|
||||
last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);
|
||||
while (!list_empty(&txq->axq_acq)) {
|
||||
last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list);
|
||||
while (!list_empty(ac_list)) {
|
||||
bool stop = false;
|
||||
|
||||
ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
|
||||
if (sc->cur_chan->stopped)
|
||||
break;
|
||||
|
||||
ac = list_first_entry(ac_list, struct ath_atx_ac, list);
|
||||
last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
|
||||
list_del(&ac->list);
|
||||
ac->sched = false;
|
||||
|
@ -1844,7 +1866,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
|||
* are pending for the tid
|
||||
*/
|
||||
if (ath_tid_has_buffered(tid))
|
||||
ath_tx_queue_tid(txq, tid);
|
||||
ath_tx_queue_tid(sc, txq, tid);
|
||||
|
||||
if (stop || tid == last_tid)
|
||||
break;
|
||||
|
@ -1852,7 +1874,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
|||
|
||||
if (!list_empty(&ac->tid_q) && !ac->sched) {
|
||||
ac->sched = true;
|
||||
list_add_tail(&ac->list, &txq->axq_acq);
|
||||
list_add_tail(&ac->list, ac_list);
|
||||
}
|
||||
|
||||
if (stop)
|
||||
|
@ -1863,12 +1885,27 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
|||
break;
|
||||
|
||||
sent = false;
|
||||
last_ac = list_entry(txq->axq_acq.prev,
|
||||
last_ac = list_entry(ac_list->prev,
|
||||
struct ath_atx_ac, list);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
}
|
||||
|
||||
void ath_txq_schedule_all(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_txq *txq;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
txq = sc->tx.txq_map[i];
|
||||
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
ath_txq_schedule(sc, txq);
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/***********/
|
||||
|
@ -2150,13 +2187,21 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_sta *sta = txctl->sta;
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct ath_vif *avp = NULL;
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_txq *txq = txctl->txq;
|
||||
struct ath_atx_tid *tid = NULL;
|
||||
struct ath_buf *bf;
|
||||
int q;
|
||||
bool queue;
|
||||
int q, hw_queue;
|
||||
int ret;
|
||||
|
||||
if (vif)
|
||||
avp = (void *)vif->drv_priv;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
|
||||
txctl->force_channel = true;
|
||||
|
||||
ret = ath_tx_prepare(hw, skb, txctl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -2168,24 +2213,39 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|||
*/
|
||||
|
||||
q = skb_get_queue_mapping(skb);
|
||||
hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue;
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
if (txq == sc->tx.txq_map[q] &&
|
||||
++txq->pending_frames > sc->tx.txq_max_pending[q] &&
|
||||
!txq->stopped) {
|
||||
ieee80211_stop_queue(sc->hw, q);
|
||||
ieee80211_stop_queue(sc->hw, hw_queue);
|
||||
txq->stopped = true;
|
||||
}
|
||||
|
||||
if (txctl->an && ieee80211_is_data_present(hdr->frame_control))
|
||||
queue = ieee80211_is_data_present(hdr->frame_control);
|
||||
|
||||
/* Force queueing of all frames that belong to a virtual interface on
|
||||
* a different channel context, to ensure that they are sent on the
|
||||
* correct channel.
|
||||
*/
|
||||
if (((avp && avp->chanctx != sc->cur_chan) ||
|
||||
sc->cur_chan->stopped) && !txctl->force_channel) {
|
||||
if (!txctl->an)
|
||||
txctl->an = &avp->mcast_node;
|
||||
info->flags &= ~IEEE80211_TX_CTL_PS_RESPONSE;
|
||||
queue = true;
|
||||
}
|
||||
|
||||
if (txctl->an && queue)
|
||||
tid = ath_get_skb_tid(sc, txctl->an, skb);
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
|
||||
if (info->flags & (IEEE80211_TX_CTL_PS_RESPONSE |
|
||||
IEEE80211_TX_CTL_TX_OFFCHAN)) {
|
||||
ath_txq_unlock(sc, txq);
|
||||
txq = sc->tx.uapsdq;
|
||||
ath_txq_lock(sc, txq);
|
||||
} else if (txctl->an &&
|
||||
ieee80211_is_data_present(hdr->frame_control)) {
|
||||
} else if (txctl->an && queue) {
|
||||
WARN_ON(tid->ac->txq != txctl->txq);
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
|
||||
|
@ -2198,7 +2258,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|||
TX_STAT_INC(txq->axq_qnum, a_queued_sw);
|
||||
__skb_queue_tail(&tid->buf_q, skb);
|
||||
if (!txctl->an->sleeping)
|
||||
ath_tx_queue_tid(txq, tid);
|
||||
ath_tx_queue_tid(sc, txq, tid);
|
||||
|
||||
ath_txq_schedule(sc, txq);
|
||||
goto out;
|
||||
|
@ -2244,8 +2304,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
int max_duration;
|
||||
|
||||
max_duration =
|
||||
sc->cur_beacon_conf.beacon_interval * 1000 *
|
||||
sc->cur_beacon_conf.dtim_period / ATH_BCBUF;
|
||||
sc->cur_chan->beacon.beacon_interval * 1000 *
|
||||
sc->cur_chan->beacon.dtim_period / ATH_BCBUF;
|
||||
|
||||
do {
|
||||
struct ath_frame_info *fi = get_frame_info(skb);
|
||||
|
@ -2560,6 +2620,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
|
|||
sc->beacon.tx_processed = true;
|
||||
sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
|
||||
|
||||
ath_chanctx_event(sc, NULL,
|
||||
ATH_CHANCTX_EVENT_BEACON_SENT);
|
||||
ath9k_csa_update(sc);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -104,8 +104,8 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
|
||||
struct station_info *sinfo)
|
||||
int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
|
||||
struct station_info *sinfo)
|
||||
{
|
||||
struct wmi_notify_req_cmd cmd = {
|
||||
.cid = cid,
|
||||
|
@ -287,6 +287,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
|
||||
wil->scan_request = request;
|
||||
mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);
|
||||
|
||||
|
@ -443,15 +444,15 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params,
|
||||
u64 *cookie)
|
||||
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params,
|
||||
u64 *cookie)
|
||||
{
|
||||
const u8 *buf = params->buf;
|
||||
size_t len = params->len;
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
bool tx_status = false;
|
||||
struct ieee80211_mgmt *mgmt_frame = (void *)buf;
|
||||
struct wmi_sw_tx_req_cmd *cmd;
|
||||
struct {
|
||||
|
@ -460,8 +461,10 @@ static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy,
|
|||
} __packed evt;
|
||||
|
||||
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
if (!cmd) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
|
||||
cmd->len = cpu_to_le16(len);
|
||||
|
@ -470,10 +473,12 @@ static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy,
|
|||
rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
|
||||
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
|
||||
if (rc == 0)
|
||||
rc = evt.evt.status;
|
||||
tx_status = !evt.evt.status;
|
||||
|
||||
kfree(cmd);
|
||||
|
||||
out:
|
||||
cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
|
||||
tx_status, GFP_KERNEL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -562,6 +567,34 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
|
||||
{
|
||||
print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET,
|
||||
b->head, b->head_len);
|
||||
print_hex_dump_bytes("tail ", DUMP_PREFIX_OFFSET,
|
||||
b->tail, b->tail_len);
|
||||
print_hex_dump_bytes("BCON IE ", DUMP_PREFIX_OFFSET,
|
||||
b->beacon_ies, b->beacon_ies_len);
|
||||
print_hex_dump_bytes("PROBE ", DUMP_PREFIX_OFFSET,
|
||||
b->probe_resp, b->probe_resp_len);
|
||||
print_hex_dump_bytes("PROBE IE ", DUMP_PREFIX_OFFSET,
|
||||
b->proberesp_ies, b->proberesp_ies_len);
|
||||
print_hex_dump_bytes("ASSOC IE ", DUMP_PREFIX_OFFSET,
|
||||
b->assocresp_ies, b->assocresp_ies_len);
|
||||
}
|
||||
|
||||
static void wil_print_crypto(struct wil6210_priv *wil,
|
||||
struct cfg80211_crypto_settings *c)
|
||||
{
|
||||
wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n",
|
||||
c->wpa_versions, c->cipher_group);
|
||||
wil_dbg_misc(wil, "Pairwise ciphers [%d]\n", c->n_ciphers_pairwise);
|
||||
wil_dbg_misc(wil, "AKM suites [%d]\n", c->n_akm_suites);
|
||||
wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n",
|
||||
c->control_port, be16_to_cpu(c->control_port_ethertype),
|
||||
c->control_port_no_encrypt);
|
||||
}
|
||||
|
||||
static int wil_fix_bcon(struct wil6210_priv *wil,
|
||||
struct cfg80211_beacon_data *bcon)
|
||||
{
|
||||
|
@ -595,8 +628,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
struct ieee80211_channel *channel = info->chandef.chan;
|
||||
struct cfg80211_beacon_data *bcon = &info->beacon;
|
||||
struct cfg80211_crypto_settings *crypto = &info->crypto;
|
||||
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
if (!channel) {
|
||||
wil_err(wil, "AP: No channel???\n");
|
||||
return -EINVAL;
|
||||
|
@ -604,11 +640,19 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
|
||||
wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
|
||||
channel->center_freq, info->privacy ? "secure" : "open");
|
||||
wil_dbg_misc(wil, "Privacy: %d auth_type %d\n",
|
||||
info->privacy, info->auth_type);
|
||||
wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval,
|
||||
info->dtim_period);
|
||||
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
|
||||
info->ssid, info->ssid_len);
|
||||
wil_print_bcon_data(bcon);
|
||||
wil_print_crypto(wil, crypto);
|
||||
|
||||
if (wil_fix_bcon(wil, bcon))
|
||||
if (wil_fix_bcon(wil, bcon)) {
|
||||
wil_dbg_misc(wil, "Fixed bcon\n");
|
||||
wil_print_bcon_data(bcon);
|
||||
}
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
|
@ -663,6 +707,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
|
|||
int rc = 0;
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
rc = wmi_pcp_stop(wil);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/power_supply.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "txrx.h"
|
||||
|
@ -69,14 +70,32 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
|
|||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
|
||||
struct vring *vring = &(wil->vring_tx[i]);
|
||||
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
|
||||
|
||||
if (vring->va) {
|
||||
int cid = wil->vring2cid_tid[i][0];
|
||||
int tid = wil->vring2cid_tid[i][1];
|
||||
u32 swhead = vring->swhead;
|
||||
u32 swtail = vring->swtail;
|
||||
int used = (vring->size + swhead - swtail)
|
||||
% vring->size;
|
||||
int avail = vring->size - used - 1;
|
||||
char name[10];
|
||||
/* performance monitoring */
|
||||
cycles_t now = get_cycles();
|
||||
cycles_t idle = txdata->idle * 100;
|
||||
cycles_t total = now - txdata->begin;
|
||||
|
||||
do_div(idle, total);
|
||||
txdata->begin = now;
|
||||
txdata->idle = 0ULL;
|
||||
|
||||
snprintf(name, sizeof(name), "tx_%2d", i);
|
||||
|
||||
seq_printf(s, "\n%pM CID %d TID %d\n",
|
||||
wil->sta[cid].addr, cid, tid);
|
||||
seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n",
|
||||
wil->sta[cid].addr, cid, tid, used, avail,
|
||||
(int)idle);
|
||||
|
||||
wil_print_vring(s, wil, name, vring, '_', 'H');
|
||||
}
|
||||
}
|
||||
|
@ -231,6 +250,26 @@ static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
|
|||
&fops_iomem_x32);
|
||||
}
|
||||
|
||||
static int wil_debugfs_ulong_set(void *data, u64 val)
|
||||
{
|
||||
*(ulong *)data = val;
|
||||
return 0;
|
||||
}
|
||||
static int wil_debugfs_ulong_get(void *data, u64 *val)
|
||||
{
|
||||
*val = *(ulong *)data;
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
|
||||
wil_debugfs_ulong_set, "%llu\n");
|
||||
|
||||
static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
ulong *value)
|
||||
{
|
||||
return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
|
||||
}
|
||||
|
||||
static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
|
||||
const char *name,
|
||||
struct dentry *parent, u32 off)
|
||||
|
@ -284,11 +323,11 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
|
|||
if (IS_ERR_OR_NULL(d))
|
||||
return -ENODEV;
|
||||
|
||||
wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr +
|
||||
wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr +
|
||||
HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
|
||||
wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr +
|
||||
wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr +
|
||||
HOSTADDR(RGF_DMA_ITR_CNT_DATA));
|
||||
wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr +
|
||||
wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr +
|
||||
HOSTADDR(RGF_DMA_ITR_CNT_CRL));
|
||||
|
||||
return 0;
|
||||
|
@ -397,6 +436,124 @@ static const struct file_operations fops_reset = {
|
|||
.write = wil_write_file_reset,
|
||||
.open = simple_open,
|
||||
};
|
||||
/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
|
||||
static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
int rc;
|
||||
long channel;
|
||||
bool on;
|
||||
|
||||
char *kbuf = kmalloc(len + 1, GFP_KERNEL);
|
||||
if (!kbuf)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(kbuf, buf, len))
|
||||
return -EIO;
|
||||
|
||||
kbuf[len] = '\0';
|
||||
rc = kstrtol(kbuf, 0, &channel);
|
||||
kfree(kbuf);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if ((channel < 0) || (channel > 4)) {
|
||||
wil_err(wil, "Invalid channel %ld\n", channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
on = !!channel;
|
||||
|
||||
if (on) {
|
||||
rc = wmi_set_channel(wil, (int)channel);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = wmi_rxon(wil, on);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_rxon = {
|
||||
.write = wil_write_file_rxon,
|
||||
.open = simple_open,
|
||||
};
|
||||
/*---tx_mgmt---*/
|
||||
/* Write mgmt frame to this file to send it */
|
||||
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
struct cfg80211_mgmt_tx_params params;
|
||||
int rc;
|
||||
|
||||
void *frame = kmalloc(len, GFP_KERNEL);
|
||||
if (!frame)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(frame, buf, len))
|
||||
return -EIO;
|
||||
|
||||
params.buf = frame;
|
||||
params.len = len;
|
||||
params.chan = wdev->preset_chandef.chan;
|
||||
|
||||
rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL);
|
||||
|
||||
kfree(frame);
|
||||
wil_info(wil, "%s() -> %d\n", __func__, rc);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_txmgmt = {
|
||||
.write = wil_write_file_txmgmt,
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
/* Write WMI command (w/o mbox header) to this file to send it
|
||||
* WMI starts from wil6210_mbox_hdr_wmi header
|
||||
*/
|
||||
static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct wil6210_mbox_hdr_wmi *wmi;
|
||||
void *cmd;
|
||||
int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi);
|
||||
u16 cmdid;
|
||||
int rc, rc1;
|
||||
|
||||
if (cmdlen <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
wmi = kmalloc(len, GFP_KERNEL);
|
||||
if (!wmi)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = simple_write_to_buffer(wmi, len, ppos, buf, len);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
cmd = &wmi[1];
|
||||
cmdid = le16_to_cpu(wmi->id);
|
||||
|
||||
rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
|
||||
kfree(wmi);
|
||||
|
||||
wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_wmi = {
|
||||
.write = wil_write_file_wmi,
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
|
||||
const char *prefix)
|
||||
|
@ -600,8 +757,8 @@ static int wil_temp_debugfs_show(struct seq_file *s, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
print_temp(s, "MAC temperature :", t_m);
|
||||
print_temp(s, "Radio temperature :", t_r);
|
||||
print_temp(s, "T_mac =", t_m);
|
||||
print_temp(s, "T_radio =", t_r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -618,6 +775,130 @@ static const struct file_operations fops_temp = {
|
|||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*---------freq------------*/
|
||||
static int wil_freq_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
|
||||
|
||||
seq_printf(s, "Freq = %d\n", freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_freq_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_freq_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_freq = {
|
||||
.open = wil_freq_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*---------link------------*/
|
||||
static int wil_link_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct station_info sinfo;
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
struct wil_sta_info *p = &wil->sta[i];
|
||||
char *status = "unknown";
|
||||
switch (p->status) {
|
||||
case wil_sta_unused:
|
||||
status = "unused ";
|
||||
break;
|
||||
case wil_sta_conn_pending:
|
||||
status = "pending ";
|
||||
break;
|
||||
case wil_sta_connected:
|
||||
status = "connected";
|
||||
break;
|
||||
}
|
||||
seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
|
||||
(p->data_port_open ? " data_port_open" : ""));
|
||||
|
||||
if (p->status == wil_sta_connected) {
|
||||
rc = wil_cid_fill_sinfo(wil, i, &sinfo);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs);
|
||||
seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs);
|
||||
seq_printf(s, " SQ = %d\n", sinfo.signal);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_link_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_link_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_link = {
|
||||
.open = wil_link_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*---------info------------*/
|
||||
static int wil_info_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
int is_ac = power_supply_is_system_supplied();
|
||||
int rx = atomic_xchg(&wil->isr_count_rx, 0);
|
||||
int tx = atomic_xchg(&wil->isr_count_tx, 0);
|
||||
static ulong rxf_old, txf_old;
|
||||
ulong rxf = ndev->stats.rx_packets;
|
||||
ulong txf = ndev->stats.tx_packets;
|
||||
unsigned int i;
|
||||
|
||||
/* >0 : AC; 0 : battery; <0 : error */
|
||||
seq_printf(s, "AC powered : %d\n", is_ac);
|
||||
seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old);
|
||||
seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old);
|
||||
rxf_old = rxf;
|
||||
txf_old = txf;
|
||||
|
||||
|
||||
#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
|
||||
" " __stringify(x) : ""
|
||||
|
||||
for (i = 0; i < ndev->num_tx_queues; i++) {
|
||||
struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
|
||||
unsigned long state = txq->state;
|
||||
|
||||
seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state,
|
||||
CHECK_QSTATE(DRV_XOFF),
|
||||
CHECK_QSTATE(STACK_XOFF),
|
||||
CHECK_QSTATE(FROZEN)
|
||||
);
|
||||
}
|
||||
#undef CHECK_QSTATE
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_info_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_info_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_info = {
|
||||
.open = wil_info_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*---------Station matrix------------*/
|
||||
static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
|
||||
{
|
||||
|
@ -630,7 +911,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
|
|||
else
|
||||
seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
|
||||
}
|
||||
seq_puts(s, "]\n");
|
||||
seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop);
|
||||
}
|
||||
|
||||
static int wil_sta_debugfs_show(struct seq_file *s, void *data)
|
||||
|
@ -703,6 +984,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
|
|||
debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
|
||||
debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
|
||||
&wil->secure_pcp);
|
||||
wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg,
|
||||
&wil->status);
|
||||
|
||||
wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
|
||||
HOSTADDR(RGF_USER_USER_ICR));
|
||||
|
@ -719,7 +1002,13 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
|
|||
debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
|
||||
|
||||
debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
|
||||
debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon);
|
||||
debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt);
|
||||
debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi);
|
||||
debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp);
|
||||
debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq);
|
||||
debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link);
|
||||
debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info);
|
||||
|
||||
wil->rgf_blob.data = (void * __force)wil->csr + 0;
|
||||
wil->rgf_blob.size = 0xa000;
|
||||
|
|
|
@ -208,6 +208,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
|
|||
|
||||
/* Rx IRQ will be enabled when NAPI processing finished */
|
||||
|
||||
atomic_inc(&wil->isr_count_rx);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -246,6 +247,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
|
|||
|
||||
/* Tx IRQ will be enabled when NAPI processing finished */
|
||||
|
||||
atomic_inc(&wil->isr_count_tx);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -257,6 +259,7 @@ static void wil_notify_fw_error(struct wil6210_priv *wil)
|
|||
[1] = "EVENT=FW_ERROR",
|
||||
[2] = NULL,
|
||||
};
|
||||
wil_err(wil, "Notify about firmware error\n");
|
||||
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,11 +61,24 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
|
|||
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
|
||||
{
|
||||
uint i;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
|
||||
sta->status);
|
||||
|
||||
sta->data_port_open = false;
|
||||
if (sta->status != wil_sta_unused) {
|
||||
wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
/* AP-like interface */
|
||||
cfg80211_del_sta(ndev, sta->addr, GFP_KERNEL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sta->status = wil_sta_unused;
|
||||
}
|
||||
|
||||
|
@ -119,11 +132,6 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
|
|||
clear_bit(wil_status_fwconnecting, &wil->status);
|
||||
break;
|
||||
default:
|
||||
/* AP-like interface and monitor:
|
||||
* never scan, always connected
|
||||
*/
|
||||
if (bssid)
|
||||
cfg80211_del_sta(ndev, bssid, GFP_KERNEL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -465,6 +473,7 @@ void wil_link_on(struct wil6210_priv *wil)
|
|||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
netif_carrier_on(ndev);
|
||||
wil_dbg_misc(wil, "netif_tx_wake : link on\n");
|
||||
netif_tx_wake_all_queues(ndev);
|
||||
}
|
||||
|
||||
|
@ -475,6 +484,7 @@ void wil_link_off(struct wil6210_priv *wil)
|
|||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
netif_tx_stop_all_queues(ndev);
|
||||
wil_dbg_misc(wil, "netif_tx_stop : link off\n");
|
||||
netif_carrier_off(ndev);
|
||||
}
|
||||
|
||||
|
@ -552,6 +562,8 @@ static int __wil_down(struct wil6210_priv *wil)
|
|||
napi_disable(&wil->napi_tx);
|
||||
|
||||
if (wil->scan_request) {
|
||||
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
|
||||
wil->scan_request);
|
||||
del_timer_sync(&wil->scan_timer);
|
||||
cfg80211_scan_done(wil->scan_request, true);
|
||||
wil->scan_request = NULL;
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
|
@ -27,11 +26,22 @@ MODULE_PARM_DESC(use_msi,
|
|||
" Use MSI interrupt: "
|
||||
"0 - don't, 1 - (default) - single, or 3");
|
||||
|
||||
static bool debug_fw; /* = false; */
|
||||
module_param(debug_fw, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
|
||||
|
||||
/* Bus ops */
|
||||
static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
||||
{
|
||||
struct pci_dev *pdev = wil->pdev;
|
||||
int rc;
|
||||
/* on platforms with buggy ACPI, pdev->msi_enabled may be set to
|
||||
* allow pci_enable_device to work. This indicates INTx was not routed
|
||||
* and only MSI should be used
|
||||
*/
|
||||
int msi_only = pdev->msi_enabled;
|
||||
|
||||
pdev->msi_enabled = 0;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
|
@ -63,6 +73,12 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
|||
|
||||
wil->n_msi = use_msi;
|
||||
|
||||
if ((wil->n_msi == 0) && msi_only) {
|
||||
wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");
|
||||
rc = -ENODEV;
|
||||
goto stop_master;
|
||||
}
|
||||
|
||||
rc = wil6210_init_irq(wil, pdev->irq);
|
||||
if (rc)
|
||||
goto stop_master;
|
||||
|
@ -71,6 +87,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
|||
mutex_lock(&wil->mutex);
|
||||
rc = wil_reset(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
if (debug_fw)
|
||||
rc = 0;
|
||||
if (rc)
|
||||
goto release_irq;
|
||||
|
||||
|
@ -119,9 +137,16 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
rc = pci_enable_device(pdev);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "pci_enable_device failed\n");
|
||||
return -ENODEV;
|
||||
dev_err(&pdev->dev,
|
||||
"pci_enable_device failed, retry with MSI only\n");
|
||||
/* Work around for platforms that can't allocate IRQ:
|
||||
* retry with MSI only
|
||||
*/
|
||||
pdev->msi_enabled = 1;
|
||||
rc = pci_enable_device(pdev);
|
||||
}
|
||||
if (rc)
|
||||
return -ENODEV;
|
||||
/* rollback to err_disable_pdev */
|
||||
|
||||
rc = pci_request_region(pdev, 0, WIL_NAME);
|
||||
|
|
|
@ -116,6 +116,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
|
|||
|
||||
/* frame with out of date sequence number */
|
||||
if (seq_less(seq, r->head_seq_num)) {
|
||||
r->ssn_last_drop = seq;
|
||||
dev_kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -525,6 +525,17 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
|||
ndev->stats.rx_bytes += len;
|
||||
stats->rx_bytes += len;
|
||||
}
|
||||
{
|
||||
static const char * const gro_res_str[] = {
|
||||
[GRO_MERGED] = "GRO_MERGED",
|
||||
[GRO_MERGED_FREE] = "GRO_MERGED_FREE",
|
||||
[GRO_HELD] = "GRO_HELD",
|
||||
[GRO_NORMAL] = "GRO_NORMAL",
|
||||
[GRO_DROP] = "GRO_DROP",
|
||||
};
|
||||
wil_dbg_txrx(wil, "Rx complete %d bytes => %s,\n",
|
||||
len, gro_res_str[rc]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -760,7 +771,7 @@ static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
|
|||
goto found;
|
||||
}
|
||||
|
||||
wil_err(wil, "Tx while no vrings active?\n");
|
||||
wil_dbg_txrx(wil, "Tx while no vrings active?\n");
|
||||
|
||||
return NULL;
|
||||
|
||||
|
@ -881,6 +892,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
int nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
uint f = 0;
|
||||
int vring_index = vring - wil->vring_tx;
|
||||
struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index];
|
||||
uint i = swhead;
|
||||
dma_addr_t pa;
|
||||
|
||||
|
@ -953,6 +965,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
|
||||
(const void *)d, sizeof(*d), false);
|
||||
|
||||
if (wil_vring_is_empty(vring)) /* performance monitoring */
|
||||
txdata->idle += get_cycles() - txdata->last_idle;
|
||||
|
||||
/* advance swhead */
|
||||
wil_vring_advance_head(vring, nr_frags + 1);
|
||||
wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
|
||||
|
@ -1016,15 +1031,17 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
vring = wil_tx_bcast(wil, skb);
|
||||
}
|
||||
if (!vring) {
|
||||
wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest);
|
||||
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
|
||||
goto drop;
|
||||
}
|
||||
/* set up vring entry */
|
||||
rc = wil_tx_vring(wil, vring, skb);
|
||||
|
||||
/* do we still have enough room in the vring? */
|
||||
if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring))
|
||||
if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) {
|
||||
netif_tx_stop_all_queues(wil_to_ndev(wil));
|
||||
wil_dbg_txrx(wil, "netif_tx_stop : ring full\n");
|
||||
}
|
||||
|
||||
switch (rc) {
|
||||
case 0:
|
||||
|
@ -1132,8 +1149,16 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
|
|||
done++;
|
||||
}
|
||||
}
|
||||
if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring))
|
||||
|
||||
if (wil_vring_is_empty(vring)) { /* performance monitoring */
|
||||
wil_dbg_txrx(wil, "Ring[%2d] empty\n", ringid);
|
||||
txdata->last_idle = get_cycles();
|
||||
}
|
||||
|
||||
if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) {
|
||||
wil_dbg_txrx(wil, "netif_tx_wake : ring not full\n");
|
||||
netif_tx_wake_all_queues(wil_to_ndev(wil));
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <linux/timex.h>
|
||||
|
||||
#define WIL_NAME "wil6210"
|
||||
|
||||
|
@ -251,7 +252,7 @@ struct vring {
|
|||
*/
|
||||
struct vring_tx_data {
|
||||
int enabled;
|
||||
|
||||
cycles_t idle, last_idle, begin;
|
||||
};
|
||||
|
||||
enum { /* for wil6210_priv.status */
|
||||
|
@ -303,6 +304,7 @@ struct wil_tid_ampdu_rx {
|
|||
u16 ssn;
|
||||
u16 buf_size;
|
||||
u16 timeout;
|
||||
u16 ssn_last_drop;
|
||||
u8 dialog_token;
|
||||
bool first_time; /* is it 1-st time this buffer used? */
|
||||
};
|
||||
|
@ -410,6 +412,7 @@ struct wil6210_priv {
|
|||
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
|
||||
/* statistics */
|
||||
struct wil6210_stats stats;
|
||||
atomic_t isr_count_rx, isr_count_tx;
|
||||
/* debugfs */
|
||||
struct dentry *debug;
|
||||
struct debugfs_blob_wrapper fw_code_blob;
|
||||
|
@ -504,9 +507,14 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq);
|
|||
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
|
||||
void wil6210_disable_irq(struct wil6210_priv *wil);
|
||||
void wil6210_enable_irq(struct wil6210_priv *wil);
|
||||
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params,
|
||||
u64 *cookie);
|
||||
|
||||
int wil6210_debugfs_init(struct wil6210_priv *wil);
|
||||
void wil6210_debugfs_remove(struct wil6210_priv *wil);
|
||||
int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
|
||||
struct station_info *sinfo);
|
||||
|
||||
struct wireless_dev *wil_cfg80211_init(struct device *dev);
|
||||
void wil_wdev_free(struct wil6210_priv *wil);
|
||||
|
|
|
@ -75,6 +75,7 @@ static const struct {
|
|||
{0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */
|
||||
{0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */
|
||||
{0x880000, 0x88a000, 0x880000}, /* various RGF */
|
||||
{0x88b000, 0x88c000, 0x88b000}, /* Pcie_ext_rgf */
|
||||
{0x8c0000, 0x949000, 0x8c0000}, /* trivial mapping for upper area */
|
||||
/*
|
||||
* 920000..930000 ucode code RAM
|
||||
|
@ -327,6 +328,17 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
|
|||
|
||||
if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
|
||||
struct cfg80211_bss *bss;
|
||||
u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
|
||||
u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
|
||||
u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
|
||||
const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
|
||||
size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
|
||||
u.beacon.variable);
|
||||
wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
|
||||
wil_dbg_wmi(wil, "TSF : 0x%016llx\n", tsf);
|
||||
wil_dbg_wmi(wil, "Beacon interval : %d\n", bi);
|
||||
wil_hex_dump_wmi("IE ", DUMP_PREFIX_OFFSET, 16, 1, ie_buf,
|
||||
ie_len, true);
|
||||
|
||||
bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
|
||||
d_len, signal, GFP_KERNEL);
|
||||
|
@ -351,6 +363,9 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
|
|||
bool aborted = (data->status != WMI_SCAN_SUCCESS);
|
||||
|
||||
wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
|
||||
wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
|
||||
wil->scan_request, aborted);
|
||||
|
||||
del_timer_sync(&wil->scan_timer);
|
||||
cfg80211_scan_done(wil->scan_request, aborted);
|
||||
wil->scan_request = NULL;
|
||||
|
@ -668,14 +683,12 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
|||
|
||||
for (n = 0;; n++) {
|
||||
u16 len;
|
||||
bool q;
|
||||
|
||||
r->head = ioread32(wil->csr + HOST_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, rx.head));
|
||||
if (r->tail == r->head) {
|
||||
if (n == 0)
|
||||
wil_dbg_wmi(wil, "No events?\n");
|
||||
return;
|
||||
}
|
||||
if (r->tail == r->head)
|
||||
break;
|
||||
|
||||
wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n",
|
||||
r->head, r->tail);
|
||||
|
@ -684,14 +697,14 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
|||
sizeof(struct wil6210_mbox_ring_desc));
|
||||
if (d_tail.sync == 0) {
|
||||
wil_err(wil, "Mbox evt not owned by FW?\n");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
/* read cmd header from descriptor */
|
||||
if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
|
||||
wil_err(wil, "Mbox evt at 0x%08x?\n",
|
||||
le32_to_cpu(d_tail.addr));
|
||||
return;
|
||||
break;
|
||||
}
|
||||
len = le16_to_cpu(hdr.len);
|
||||
wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n",
|
||||
|
@ -705,7 +718,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
|||
event.wmi) + len, 4),
|
||||
GFP_KERNEL);
|
||||
if (!evt)
|
||||
return;
|
||||
break;
|
||||
|
||||
evt->event.hdr = hdr;
|
||||
cmd = (void *)&evt->event.wmi;
|
||||
|
@ -737,14 +750,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
|||
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
||||
list_add_tail(&evt->list, &wil->pending_wmi_ev);
|
||||
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||
{
|
||||
int q = queue_work(wil->wmi_wq,
|
||||
&wil->wmi_event_worker);
|
||||
wil_dbg_wmi(wil, "queue_work -> %d\n", q);
|
||||
}
|
||||
q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
|
||||
wil_dbg_wmi(wil, "queue_work -> %d\n", q);
|
||||
}
|
||||
if (n > 1)
|
||||
wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n);
|
||||
/* normally, 1 event per IRQ should be processed */
|
||||
wil_dbg_wmi(wil, "%s -> %d events queued\n", __func__, n);
|
||||
}
|
||||
|
||||
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
|
||||
|
|
|
@ -122,6 +122,15 @@ config B43_PIO
|
|||
select SSB_BLOCKIO
|
||||
default y
|
||||
|
||||
config B43_PHY_G
|
||||
bool "Support for G-PHY (802.11g) devices"
|
||||
depends on B43 && B43_SSB
|
||||
default y
|
||||
---help---
|
||||
This PHY type can be found in the following chipsets:
|
||||
PCI: BCM4306, BCM4311, BCM4318
|
||||
SoC: BCM4712, BCM5352E
|
||||
|
||||
config B43_PHY_N
|
||||
bool "Support for 802.11n (N-PHY) devices"
|
||||
depends on B43
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
b43-y += main.o
|
||||
b43-y += bus.o
|
||||
b43-y += tables.o
|
||||
b43-$(CONFIG_B43_PHY_G) += phy_a.o phy_g.o tables.o lo.o wa.o
|
||||
b43-$(CONFIG_B43_PHY_N) += tables_nphy.o
|
||||
b43-$(CONFIG_B43_PHY_N) += radio_2055.o
|
||||
b43-$(CONFIG_B43_PHY_N) += radio_2056.o
|
||||
b43-$(CONFIG_B43_PHY_N) += radio_2057.o
|
||||
b43-y += phy_common.o
|
||||
b43-y += phy_g.o
|
||||
b43-y += phy_a.o
|
||||
b43-$(CONFIG_B43_PHY_N) += phy_n.o
|
||||
b43-$(CONFIG_B43_PHY_LP) += phy_lp.o
|
||||
b43-$(CONFIG_B43_PHY_LP) += tables_lpphy.o
|
||||
|
@ -17,8 +15,6 @@ b43-$(CONFIG_B43_PHY_HT) += radio_2059.o
|
|||
b43-$(CONFIG_B43_PHY_LCN) += phy_lcn.o tables_phy_lcn.o
|
||||
b43-y += sysfs.o
|
||||
b43-y += xmit.o
|
||||
b43-y += lo.o
|
||||
b43-y += wa.o
|
||||
b43-y += dma.o
|
||||
b43-y += pio.o
|
||||
b43-y += rfkill.o
|
||||
|
|
|
@ -122,7 +122,11 @@ static const struct bcma_device_id b43_bcma_tbl[] = {
|
|||
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x11, BCMA_ANY_CLASS),
|
||||
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS),
|
||||
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS),
|
||||
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1C, BCMA_ANY_CLASS),
|
||||
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS),
|
||||
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1E, BCMA_ANY_CLASS),
|
||||
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x28, BCMA_ANY_CLASS),
|
||||
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x2A, BCMA_ANY_CLASS),
|
||||
BCMA_CORETABLE_END
|
||||
};
|
||||
MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl);
|
||||
|
@ -2201,52 +2205,82 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
|||
return -EPROTO;
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/Init/Firmware */
|
||||
static int b43_try_request_fw(struct b43_request_fw_context *ctx)
|
||||
{
|
||||
struct b43_wldev *dev = ctx->dev;
|
||||
struct b43_firmware *fw = &ctx->dev->fw;
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
const u8 rev = ctx->dev->dev->core_rev;
|
||||
const char *filename;
|
||||
u32 tmshigh;
|
||||
int err;
|
||||
|
||||
/* Files for HT and LCN were found by trying one by one */
|
||||
|
||||
/* Get microcode */
|
||||
if ((rev >= 5) && (rev <= 10)) {
|
||||
filename = "ucode5";
|
||||
} else if ((rev >= 11) && (rev <= 12)) {
|
||||
filename = "ucode11";
|
||||
} else if (rev == 13) {
|
||||
filename = "ucode13";
|
||||
} else if (rev == 14) {
|
||||
filename = "ucode14";
|
||||
} else if (rev == 15) {
|
||||
filename = NULL;
|
||||
switch (rev) {
|
||||
case 42:
|
||||
if (phy->type == B43_PHYTYPE_AC)
|
||||
filename = "ucode42";
|
||||
break;
|
||||
case 40:
|
||||
if (phy->type == B43_PHYTYPE_AC)
|
||||
filename = "ucode40";
|
||||
break;
|
||||
case 33:
|
||||
if (phy->type == B43_PHYTYPE_LCN40)
|
||||
filename = "ucode33_lcn40";
|
||||
break;
|
||||
case 30:
|
||||
if (phy->type == B43_PHYTYPE_N)
|
||||
filename = "ucode30_mimo";
|
||||
break;
|
||||
case 29:
|
||||
if (phy->type == B43_PHYTYPE_HT)
|
||||
filename = "ucode29_mimo";
|
||||
break;
|
||||
case 26:
|
||||
if (phy->type == B43_PHYTYPE_HT)
|
||||
filename = "ucode26_mimo";
|
||||
break;
|
||||
case 28:
|
||||
case 25:
|
||||
if (phy->type == B43_PHYTYPE_N)
|
||||
filename = "ucode25_mimo";
|
||||
else if (phy->type == B43_PHYTYPE_LCN)
|
||||
filename = "ucode25_lcn";
|
||||
break;
|
||||
case 24:
|
||||
if (phy->type == B43_PHYTYPE_LCN)
|
||||
filename = "ucode24_lcn";
|
||||
break;
|
||||
case 23:
|
||||
if (phy->type == B43_PHYTYPE_N)
|
||||
filename = "ucode16_mimo";
|
||||
break;
|
||||
case 16 ... 19:
|
||||
if (phy->type == B43_PHYTYPE_N)
|
||||
filename = "ucode16_mimo";
|
||||
else if (phy->type == B43_PHYTYPE_LP)
|
||||
filename = "ucode16_lp";
|
||||
break;
|
||||
case 15:
|
||||
filename = "ucode15";
|
||||
} else {
|
||||
switch (dev->phy.type) {
|
||||
case B43_PHYTYPE_N:
|
||||
if (rev >= 16)
|
||||
filename = "ucode16_mimo";
|
||||
else
|
||||
goto err_no_ucode;
|
||||
break;
|
||||
case B43_PHYTYPE_HT:
|
||||
if (rev == 29)
|
||||
filename = "ucode29_mimo";
|
||||
else
|
||||
goto err_no_ucode;
|
||||
break;
|
||||
case B43_PHYTYPE_LCN:
|
||||
if (rev == 24)
|
||||
filename = "ucode24_mimo";
|
||||
else
|
||||
goto err_no_ucode;
|
||||
break;
|
||||
default:
|
||||
goto err_no_ucode;
|
||||
}
|
||||
break;
|
||||
case 14:
|
||||
filename = "ucode14";
|
||||
break;
|
||||
case 13:
|
||||
filename = "ucode13";
|
||||
break;
|
||||
case 11 ... 12:
|
||||
filename = "ucode11";
|
||||
break;
|
||||
case 5 ... 10:
|
||||
filename = "ucode5";
|
||||
break;
|
||||
}
|
||||
if (!filename)
|
||||
goto err_no_ucode;
|
||||
err = b43_do_request_fw(ctx, filename, &fw->ucode, true);
|
||||
if (err)
|
||||
goto err_load;
|
||||
|
@ -2268,117 +2302,121 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
|
|||
goto err_load;
|
||||
|
||||
/* Get initvals */
|
||||
filename = NULL;
|
||||
switch (dev->phy.type) {
|
||||
case B43_PHYTYPE_A:
|
||||
if ((rev >= 5) && (rev <= 10)) {
|
||||
tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
|
||||
if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
|
||||
filename = "a0g1initvals5";
|
||||
else
|
||||
filename = "a0g0initvals5";
|
||||
} else
|
||||
goto err_no_initvals;
|
||||
break;
|
||||
case B43_PHYTYPE_G:
|
||||
if ((rev >= 5) && (rev <= 10))
|
||||
filename = "b0g0initvals5";
|
||||
else if (rev >= 13)
|
||||
if (rev == 13)
|
||||
filename = "b0g0initvals13";
|
||||
else
|
||||
goto err_no_initvals;
|
||||
else if (rev >= 5 && rev <= 10)
|
||||
filename = "b0g0initvals5";
|
||||
break;
|
||||
case B43_PHYTYPE_N:
|
||||
if (rev >= 16)
|
||||
if (rev == 30)
|
||||
filename = "n16initvals30";
|
||||
else if (rev == 28 || rev == 25)
|
||||
filename = "n0initvals25";
|
||||
else if (rev == 24)
|
||||
filename = "n0initvals24";
|
||||
else if (rev == 23)
|
||||
filename = "n0initvals16"; /* What about n0initvals22? */
|
||||
else if (rev >= 16 && rev <= 18)
|
||||
filename = "n0initvals16";
|
||||
else if ((rev >= 11) && (rev <= 12))
|
||||
else if (rev >= 11 && rev <= 12)
|
||||
filename = "n0initvals11";
|
||||
else
|
||||
goto err_no_initvals;
|
||||
break;
|
||||
case B43_PHYTYPE_LP:
|
||||
if (rev == 13)
|
||||
filename = "lp0initvals13";
|
||||
if (rev >= 16 && rev <= 18)
|
||||
filename = "lp0initvals16";
|
||||
else if (rev == 15)
|
||||
filename = "lp0initvals15";
|
||||
else if (rev == 14)
|
||||
filename = "lp0initvals14";
|
||||
else if (rev >= 15)
|
||||
filename = "lp0initvals15";
|
||||
else
|
||||
goto err_no_initvals;
|
||||
else if (rev == 13)
|
||||
filename = "lp0initvals13";
|
||||
break;
|
||||
case B43_PHYTYPE_HT:
|
||||
if (rev == 29)
|
||||
filename = "ht0initvals29";
|
||||
else
|
||||
goto err_no_initvals;
|
||||
else if (rev == 26)
|
||||
filename = "ht0initvals26";
|
||||
break;
|
||||
case B43_PHYTYPE_LCN:
|
||||
if (rev == 24)
|
||||
filename = "lcn0initvals24";
|
||||
else
|
||||
goto err_no_initvals;
|
||||
break;
|
||||
default:
|
||||
goto err_no_initvals;
|
||||
case B43_PHYTYPE_LCN40:
|
||||
if (rev == 33)
|
||||
filename = "lcn400initvals33";
|
||||
break;
|
||||
case B43_PHYTYPE_AC:
|
||||
if (rev == 42)
|
||||
filename = "ac1initvals42";
|
||||
else if (rev == 40)
|
||||
filename = "ac0initvals40";
|
||||
break;
|
||||
}
|
||||
if (!filename)
|
||||
goto err_no_initvals;
|
||||
err = b43_do_request_fw(ctx, filename, &fw->initvals, false);
|
||||
if (err)
|
||||
goto err_load;
|
||||
|
||||
/* Get bandswitch initvals */
|
||||
filename = NULL;
|
||||
switch (dev->phy.type) {
|
||||
case B43_PHYTYPE_A:
|
||||
if ((rev >= 5) && (rev <= 10)) {
|
||||
tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
|
||||
if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
|
||||
filename = "a0g1bsinitvals5";
|
||||
else
|
||||
filename = "a0g0bsinitvals5";
|
||||
} else if (rev >= 11)
|
||||
filename = NULL;
|
||||
else
|
||||
goto err_no_initvals;
|
||||
break;
|
||||
case B43_PHYTYPE_G:
|
||||
if ((rev >= 5) && (rev <= 10))
|
||||
if (rev == 13)
|
||||
filename = "b0g0bsinitvals13";
|
||||
else if (rev >= 5 && rev <= 10)
|
||||
filename = "b0g0bsinitvals5";
|
||||
else if (rev >= 11)
|
||||
filename = NULL;
|
||||
else
|
||||
goto err_no_initvals;
|
||||
break;
|
||||
case B43_PHYTYPE_N:
|
||||
if (rev >= 16)
|
||||
if (rev == 30)
|
||||
filename = "n16bsinitvals30";
|
||||
else if (rev == 28 || rev == 25)
|
||||
filename = "n0bsinitvals25";
|
||||
else if (rev == 24)
|
||||
filename = "n0bsinitvals24";
|
||||
else if (rev == 23)
|
||||
filename = "n0bsinitvals16"; /* What about n0bsinitvals22? */
|
||||
else if (rev >= 16 && rev <= 18)
|
||||
filename = "n0bsinitvals16";
|
||||
else if ((rev >= 11) && (rev <= 12))
|
||||
else if (rev >= 11 && rev <= 12)
|
||||
filename = "n0bsinitvals11";
|
||||
else
|
||||
goto err_no_initvals;
|
||||
break;
|
||||
case B43_PHYTYPE_LP:
|
||||
if (rev == 13)
|
||||
filename = "lp0bsinitvals13";
|
||||
if (rev >= 16 && rev <= 18)
|
||||
filename = "lp0bsinitvals16";
|
||||
else if (rev == 15)
|
||||
filename = "lp0bsinitvals15";
|
||||
else if (rev == 14)
|
||||
filename = "lp0bsinitvals14";
|
||||
else if (rev >= 15)
|
||||
filename = "lp0bsinitvals15";
|
||||
else
|
||||
goto err_no_initvals;
|
||||
else if (rev == 13)
|
||||
filename = "lp0bsinitvals13";
|
||||
break;
|
||||
case B43_PHYTYPE_HT:
|
||||
if (rev == 29)
|
||||
filename = "ht0bsinitvals29";
|
||||
else
|
||||
goto err_no_initvals;
|
||||
else if (rev == 26)
|
||||
filename = "ht0bsinitvals26";
|
||||
break;
|
||||
case B43_PHYTYPE_LCN:
|
||||
if (rev == 24)
|
||||
filename = "lcn0bsinitvals24";
|
||||
else
|
||||
goto err_no_initvals;
|
||||
break;
|
||||
default:
|
||||
goto err_no_initvals;
|
||||
case B43_PHYTYPE_LCN40:
|
||||
if (rev == 33)
|
||||
filename = "lcn400bsinitvals33";
|
||||
break;
|
||||
case B43_PHYTYPE_AC:
|
||||
if (rev == 42)
|
||||
filename = "ac1bsinitvals42";
|
||||
else if (rev == 40)
|
||||
filename = "ac0bsinitvals40";
|
||||
break;
|
||||
}
|
||||
if (!filename)
|
||||
goto err_no_initvals;
|
||||
err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false);
|
||||
if (err)
|
||||
goto err_load;
|
||||
|
@ -3798,39 +3836,30 @@ static void b43_set_retry_limits(struct b43_wldev *dev,
|
|||
static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
{
|
||||
struct b43_wl *wl = hw_to_b43_wl(hw);
|
||||
struct b43_wldev *dev;
|
||||
struct b43_phy *phy;
|
||||
struct b43_wldev *dev = wl->current_dev;
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
int antenna;
|
||||
int err = 0;
|
||||
bool reload_bss = false;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
dev = wl->current_dev;
|
||||
|
||||
b43_mac_suspend(dev);
|
||||
|
||||
/* Switch the band (if necessary). This might change the active core. */
|
||||
err = b43_switch_band(dev, conf->chandef.chan);
|
||||
if (err)
|
||||
goto out_unlock_mutex;
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
phy->chandef = &conf->chandef;
|
||||
phy->channel = conf->chandef.chan->hw_value;
|
||||
|
||||
/* Need to reload all settings if the core changed */
|
||||
if (dev != wl->current_dev) {
|
||||
dev = wl->current_dev;
|
||||
changed = ~0;
|
||||
reload_bss = true;
|
||||
/* Switch the band (if necessary). */
|
||||
err = b43_switch_band(dev, conf->chandef.chan);
|
||||
if (err)
|
||||
goto out_mac_enable;
|
||||
|
||||
/* Switch to the requested channel.
|
||||
* The firmware takes care of races with the TX handler.
|
||||
*/
|
||||
b43_switch_channel(dev, phy->channel);
|
||||
}
|
||||
|
||||
phy = &dev->phy;
|
||||
|
||||
if (conf_is_ht(conf))
|
||||
phy->is_40mhz =
|
||||
(conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf));
|
||||
else
|
||||
phy->is_40mhz = false;
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
|
||||
b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
|
||||
conf->long_frame_max_tx_count);
|
||||
|
@ -3838,11 +3867,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||
if (!changed)
|
||||
goto out_mac_enable;
|
||||
|
||||
/* Switch to the requested channel.
|
||||
* The firmware takes care of races with the TX handler. */
|
||||
if (conf->chandef.chan->hw_value != phy->channel)
|
||||
b43_switch_channel(dev, conf->chandef.chan->hw_value);
|
||||
|
||||
dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR);
|
||||
|
||||
/* Adjust the desired TX power level. */
|
||||
|
@ -3878,12 +3902,8 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||
|
||||
out_mac_enable:
|
||||
b43_mac_enable(dev);
|
||||
out_unlock_mutex:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
if (wl->vif && reload_bss)
|
||||
b43_op_bss_info_changed(hw, wl->vif, &wl->vif->bss_conf, ~0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -4323,20 +4343,20 @@ static int b43_phy_versioning(struct b43_wldev *dev)
|
|||
analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT;
|
||||
phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT;
|
||||
phy_rev = (tmp & B43_PHYVER_VERSION);
|
||||
|
||||
/* LCNXN is continuation of N which run out of revisions */
|
||||
if (phy_type == B43_PHYTYPE_LCNXN) {
|
||||
phy_type = B43_PHYTYPE_N;
|
||||
phy_rev += 16;
|
||||
}
|
||||
|
||||
switch (phy_type) {
|
||||
case B43_PHYTYPE_A:
|
||||
if (phy_rev >= 4)
|
||||
unsupported = 1;
|
||||
break;
|
||||
case B43_PHYTYPE_B:
|
||||
if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6
|
||||
&& phy_rev != 7)
|
||||
unsupported = 1;
|
||||
break;
|
||||
#ifdef CONFIG_B43_PHY_G
|
||||
case B43_PHYTYPE_G:
|
||||
if (phy_rev > 9)
|
||||
unsupported = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_B43_PHY_N
|
||||
case B43_PHYTYPE_N:
|
||||
if (phy_rev > 9)
|
||||
|
|
|
@ -573,7 +573,7 @@ static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev)
|
|||
{//TODO
|
||||
}
|
||||
|
||||
const struct b43_phy_operations b43_phyops_a = {
|
||||
static const struct b43_phy_operations b43_phyops_a = {
|
||||
.allocate = b43_aphy_op_allocate,
|
||||
.free = b43_aphy_op_free,
|
||||
.prepare_structs = b43_aphy_op_prepare_structs,
|
||||
|
|
|
@ -123,8 +123,4 @@ struct b43_phy_a {
|
|||
*/
|
||||
void b43_phy_inita(struct b43_wldev *dev);
|
||||
|
||||
|
||||
struct b43_phy_operations;
|
||||
extern const struct b43_phy_operations b43_phyops_a;
|
||||
|
||||
#endif /* LINUX_B43_PHY_A_H_ */
|
||||
|
|
|
@ -45,11 +45,10 @@ int b43_phy_allocate(struct b43_wldev *dev)
|
|||
phy->ops = NULL;
|
||||
|
||||
switch (phy->type) {
|
||||
case B43_PHYTYPE_A:
|
||||
phy->ops = &b43_phyops_a;
|
||||
break;
|
||||
case B43_PHYTYPE_G:
|
||||
#ifdef CONFIG_B43_PHY_G
|
||||
phy->ops = &b43_phyops_g;
|
||||
#endif
|
||||
break;
|
||||
case B43_PHYTYPE_N:
|
||||
#ifdef CONFIG_B43_PHY_N
|
||||
|
@ -94,7 +93,13 @@ int b43_phy_init(struct b43_wldev *dev)
|
|||
const struct b43_phy_operations *ops = phy->ops;
|
||||
int err;
|
||||
|
||||
phy->channel = ops->get_default_chan(dev);
|
||||
/* During PHY init we need to use some channel. On the first init this
|
||||
* function is called *before* b43_op_config, so our pointer is NULL.
|
||||
*/
|
||||
if (!phy->chandef) {
|
||||
phy->chandef = &dev->wl->hw->conf.chandef;
|
||||
phy->channel = phy->chandef->chan->hw_value;
|
||||
}
|
||||
|
||||
phy->ops->switch_analog(dev, true);
|
||||
b43_software_rfkill(dev, false);
|
||||
|
@ -106,9 +111,7 @@ int b43_phy_init(struct b43_wldev *dev)
|
|||
}
|
||||
phy->do_full_init = false;
|
||||
|
||||
/* Make sure to switch hardware and firmware (SHM) to
|
||||
* the default channel. */
|
||||
err = b43_switch_channel(dev, ops->get_default_chan(dev));
|
||||
err = b43_switch_channel(dev, phy->channel);
|
||||
if (err) {
|
||||
b43err(dev->wl, "PHY init: Channel switch to default failed\n");
|
||||
goto err_phy_exit;
|
||||
|
@ -408,9 +411,6 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
|
|||
u16 channelcookie, savedcookie;
|
||||
int err;
|
||||
|
||||
if (new_channel == B43_DEFAULT_CHANNEL)
|
||||
new_channel = phy->ops->get_default_chan(dev);
|
||||
|
||||
/* First we set the channel radio code to prevent the
|
||||
* firmware from sending ghost packets.
|
||||
*/
|
||||
|
@ -428,7 +428,6 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
|
|||
if (err)
|
||||
goto err_restore_cookie;
|
||||
|
||||
dev->phy.channel = new_channel;
|
||||
/* Wait for the radio to tune to the channel and stabilize. */
|
||||
msleep(8);
|
||||
|
||||
|
@ -547,10 +546,9 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on)
|
|||
}
|
||||
|
||||
|
||||
bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type)
|
||||
bool b43_is_40mhz(struct b43_wldev *dev)
|
||||
{
|
||||
return (channel_type == NL80211_CHAN_HT40MINUS ||
|
||||
channel_type == NL80211_CHAN_HT40PLUS);
|
||||
return dev->phy.chandef->width == NL80211_CHAN_WIDTH_40;
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
|
||||
|
|
|
@ -228,9 +228,6 @@ struct b43_phy {
|
|||
bool supports_2ghz;
|
||||
bool supports_5ghz;
|
||||
|
||||
/* HT info */
|
||||
bool is_40mhz;
|
||||
|
||||
/* Is GMODE (2 GHz mode) bit enabled? */
|
||||
bool gmode;
|
||||
|
||||
|
@ -267,9 +264,8 @@ struct b43_phy {
|
|||
unsigned long next_txpwr_check_time;
|
||||
|
||||
/* Current channel */
|
||||
struct cfg80211_chan_def *chandef;
|
||||
unsigned int channel;
|
||||
u16 channel_freq;
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
/* PHY TX errors counter. */
|
||||
atomic_t txerr_cnt;
|
||||
|
@ -400,10 +396,6 @@ void b43_phy_take_out_of_reset(struct b43_wldev *dev);
|
|||
* b43_switch_channel - Switch to another channel
|
||||
*/
|
||||
int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel);
|
||||
/**
|
||||
* B43_DEFAULT_CHANNEL - Switch to the default channel.
|
||||
*/
|
||||
#define B43_DEFAULT_CHANNEL UINT_MAX
|
||||
|
||||
/**
|
||||
* b43_software_rfkill - Turn the radio ON or OFF in software.
|
||||
|
@ -454,7 +446,7 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset);
|
|||
*/
|
||||
void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on);
|
||||
|
||||
bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type);
|
||||
bool b43_is_40mhz(struct b43_wldev *dev);
|
||||
|
||||
void b43_phy_force_clock(struct b43_wldev *dev, bool force);
|
||||
|
||||
|
|
|
@ -596,7 +596,7 @@ static void b43_phy_ht_tx_power_ctl_setup(struct b43_wldev *dev)
|
|||
u8 target[3];
|
||||
s16 a1[3], b0[3], b1[3];
|
||||
|
||||
u16 freq = dev->phy.channel_freq;
|
||||
u16 freq = dev->phy.chandef->chan->center_freq;
|
||||
int i, c;
|
||||
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
|
||||
|
|
|
@ -590,7 +590,103 @@ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
|
|||
* Radio 0x2057
|
||||
**************************************************/
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rcal */
|
||||
static void b43_radio_2057_chantab_upload(struct b43_wldev *dev,
|
||||
const struct b43_nphy_chantabent_rev7 *e_r7,
|
||||
const struct b43_nphy_chantabent_rev7_2g *e_r7_2g)
|
||||
{
|
||||
if (e_r7_2g) {
|
||||
b43_radio_write(dev, R2057_VCOCAL_COUNTVAL0, e_r7_2g->radio_vcocal_countval0);
|
||||
b43_radio_write(dev, R2057_VCOCAL_COUNTVAL1, e_r7_2g->radio_vcocal_countval1);
|
||||
b43_radio_write(dev, R2057_RFPLL_REFMASTER_SPAREXTALSIZE, e_r7_2g->radio_rfpll_refmaster_sparextalsize);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, e_r7_2g->radio_rfpll_loopfilter_r1);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, e_r7_2g->radio_rfpll_loopfilter_c2);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, e_r7_2g->radio_rfpll_loopfilter_c1);
|
||||
b43_radio_write(dev, R2057_CP_KPD_IDAC, e_r7_2g->radio_cp_kpd_idac);
|
||||
b43_radio_write(dev, R2057_RFPLL_MMD0, e_r7_2g->radio_rfpll_mmd0);
|
||||
b43_radio_write(dev, R2057_RFPLL_MMD1, e_r7_2g->radio_rfpll_mmd1);
|
||||
b43_radio_write(dev, R2057_VCOBUF_TUNE, e_r7_2g->radio_vcobuf_tune);
|
||||
b43_radio_write(dev, R2057_LOGEN_MX2G_TUNE, e_r7_2g->radio_logen_mx2g_tune);
|
||||
b43_radio_write(dev, R2057_LOGEN_INDBUF2G_TUNE, e_r7_2g->radio_logen_indbuf2g_tune);
|
||||
b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, e_r7_2g->radio_txmix2g_tune_boost_pu_core0);
|
||||
b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE0, e_r7_2g->radio_pad2g_tune_pus_core0);
|
||||
b43_radio_write(dev, R2057_LNA2G_TUNE_CORE0, e_r7_2g->radio_lna2g_tune_core0);
|
||||
b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1, e_r7_2g->radio_txmix2g_tune_boost_pu_core1);
|
||||
b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE1, e_r7_2g->radio_pad2g_tune_pus_core1);
|
||||
b43_radio_write(dev, R2057_LNA2G_TUNE_CORE1, e_r7_2g->radio_lna2g_tune_core1);
|
||||
|
||||
} else {
|
||||
b43_radio_write(dev, R2057_VCOCAL_COUNTVAL0, e_r7->radio_vcocal_countval0);
|
||||
b43_radio_write(dev, R2057_VCOCAL_COUNTVAL1, e_r7->radio_vcocal_countval1);
|
||||
b43_radio_write(dev, R2057_RFPLL_REFMASTER_SPAREXTALSIZE, e_r7->radio_rfpll_refmaster_sparextalsize);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, e_r7->radio_rfpll_loopfilter_r1);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, e_r7->radio_rfpll_loopfilter_c2);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, e_r7->radio_rfpll_loopfilter_c1);
|
||||
b43_radio_write(dev, R2057_CP_KPD_IDAC, e_r7->radio_cp_kpd_idac);
|
||||
b43_radio_write(dev, R2057_RFPLL_MMD0, e_r7->radio_rfpll_mmd0);
|
||||
b43_radio_write(dev, R2057_RFPLL_MMD1, e_r7->radio_rfpll_mmd1);
|
||||
b43_radio_write(dev, R2057_VCOBUF_TUNE, e_r7->radio_vcobuf_tune);
|
||||
b43_radio_write(dev, R2057_LOGEN_MX2G_TUNE, e_r7->radio_logen_mx2g_tune);
|
||||
b43_radio_write(dev, R2057_LOGEN_MX5G_TUNE, e_r7->radio_logen_mx5g_tune);
|
||||
b43_radio_write(dev, R2057_LOGEN_INDBUF2G_TUNE, e_r7->radio_logen_indbuf2g_tune);
|
||||
b43_radio_write(dev, R2057_LOGEN_INDBUF5G_TUNE, e_r7->radio_logen_indbuf5g_tune);
|
||||
b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, e_r7->radio_txmix2g_tune_boost_pu_core0);
|
||||
b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE0, e_r7->radio_pad2g_tune_pus_core0);
|
||||
b43_radio_write(dev, R2057_PGA_BOOST_TUNE_CORE0, e_r7->radio_pga_boost_tune_core0);
|
||||
b43_radio_write(dev, R2057_TXMIX5G_BOOST_TUNE_CORE0, e_r7->radio_txmix5g_boost_tune_core0);
|
||||
b43_radio_write(dev, R2057_PAD5G_TUNE_MISC_PUS_CORE0, e_r7->radio_pad5g_tune_misc_pus_core0);
|
||||
b43_radio_write(dev, R2057_LNA2G_TUNE_CORE0, e_r7->radio_lna2g_tune_core0);
|
||||
b43_radio_write(dev, R2057_LNA5G_TUNE_CORE0, e_r7->radio_lna5g_tune_core0);
|
||||
b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1, e_r7->radio_txmix2g_tune_boost_pu_core1);
|
||||
b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE1, e_r7->radio_pad2g_tune_pus_core1);
|
||||
b43_radio_write(dev, R2057_PGA_BOOST_TUNE_CORE1, e_r7->radio_pga_boost_tune_core1);
|
||||
b43_radio_write(dev, R2057_TXMIX5G_BOOST_TUNE_CORE1, e_r7->radio_txmix5g_boost_tune_core1);
|
||||
b43_radio_write(dev, R2057_PAD5G_TUNE_MISC_PUS_CORE1, e_r7->radio_pad5g_tune_misc_pus_core1);
|
||||
b43_radio_write(dev, R2057_LNA2G_TUNE_CORE1, e_r7->radio_lna2g_tune_core1);
|
||||
b43_radio_write(dev, R2057_LNA5G_TUNE_CORE1, e_r7->radio_lna5g_tune_core1);
|
||||
}
|
||||
}
|
||||
|
||||
static void b43_radio_2057_setup(struct b43_wldev *dev,
|
||||
const struct b43_nphy_chantabent_rev7 *tabent_r7,
|
||||
const struct b43_nphy_chantabent_rev7_2g *tabent_r7_2g)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
|
||||
b43_radio_2057_chantab_upload(dev, tabent_r7, tabent_r7_2g);
|
||||
|
||||
switch (phy->radio_rev) {
|
||||
case 0 ... 4:
|
||||
case 6:
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, 0x3f);
|
||||
b43_radio_write(dev, R2057_CP_KPD_IDAC, 0x3f);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, 0x8);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, 0x8);
|
||||
} else {
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, 0x1f);
|
||||
b43_radio_write(dev, R2057_CP_KPD_IDAC, 0x3f);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, 0x8);
|
||||
b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, 0x8);
|
||||
}
|
||||
break;
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
|
||||
usleep_range(50, 100);
|
||||
|
||||
/* VCO calibration */
|
||||
b43_radio_mask(dev, R2057_RFPLL_MISC_EN, ~0x01);
|
||||
b43_radio_mask(dev, R2057_RFPLL_MISC_CAL_RESETN, ~0x04);
|
||||
b43_radio_set(dev, R2057_RFPLL_MISC_CAL_RESETN, 0x4);
|
||||
b43_radio_set(dev, R2057_RFPLL_MISC_EN, 0x01);
|
||||
usleep_range(300, 600);
|
||||
}
|
||||
|
||||
/* Calibrate resistors in LPF of PLL?
|
||||
* http://bcm-v4.sipsolutions.net/PHY/radio205x_rcal
|
||||
*/
|
||||
static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
|
@ -603,15 +699,25 @@ static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
|
|||
b43_radio_maskset(dev, 0x1ca, ~0x2, 0x1);
|
||||
}
|
||||
|
||||
/* Enable */
|
||||
b43_radio_set(dev, R2057_RCAL_CONFIG, 0x1);
|
||||
udelay(10);
|
||||
b43_radio_set(dev, R2057_RCAL_CONFIG, 0x3);
|
||||
if (!b43_radio_wait_value(dev, R2057_RCCAL_N1_1, 1, 1, 100, 1000000)) {
|
||||
|
||||
/* Start */
|
||||
b43_radio_set(dev, R2057_RCAL_CONFIG, 0x2);
|
||||
usleep_range(100, 200);
|
||||
|
||||
/* Stop */
|
||||
b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x2);
|
||||
|
||||
/* Wait and check for result */
|
||||
if (!b43_radio_wait_value(dev, R2057_RCAL_STATUS, 1, 1, 100, 1000000)) {
|
||||
b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
|
||||
return 0;
|
||||
}
|
||||
b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x2);
|
||||
tmp = b43_radio_read(dev, R2057_RCAL_STATUS) & 0x3E;
|
||||
|
||||
/* Disable */
|
||||
b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x1);
|
||||
|
||||
if (phy->radio_rev == 5) {
|
||||
|
@ -627,7 +733,9 @@ static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
|
|||
return tmp & 0x3e;
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal */
|
||||
/* Calibrate the internal RC oscillator?
|
||||
* http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal
|
||||
*/
|
||||
static u16 b43_radio_2057_rccal(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
|
@ -635,49 +743,76 @@ static u16 b43_radio_2057_rccal(struct b43_wldev *dev)
|
|||
phy->radio_rev == 6);
|
||||
u16 tmp;
|
||||
|
||||
/* Setup cal */
|
||||
if (special) {
|
||||
b43_radio_write(dev, R2057_RCCAL_MASTER, 0x61);
|
||||
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xC0);
|
||||
} else {
|
||||
b43_radio_write(dev, 0x1AE, 0x61);
|
||||
b43_radio_write(dev, R2057v7_RCCAL_MASTER, 0x61);
|
||||
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xE1);
|
||||
}
|
||||
b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
|
||||
|
||||
/* Start, wait, stop */
|
||||
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
|
||||
if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
|
||||
if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 2, 2, 500,
|
||||
5000000))
|
||||
b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
|
||||
usleep_range(35, 70);
|
||||
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
|
||||
usleep_range(70, 140);
|
||||
|
||||
/* Setup cal */
|
||||
if (special) {
|
||||
b43_radio_write(dev, R2057_RCCAL_MASTER, 0x69);
|
||||
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
|
||||
} else {
|
||||
b43_radio_write(dev, 0x1AE, 0x69);
|
||||
b43_radio_write(dev, R2057v7_RCCAL_MASTER, 0x69);
|
||||
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xD5);
|
||||
}
|
||||
b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
|
||||
|
||||
/* Start, wait, stop */
|
||||
usleep_range(35, 70);
|
||||
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
|
||||
if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
|
||||
usleep_range(70, 140);
|
||||
if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 2, 2, 500,
|
||||
5000000))
|
||||
b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
|
||||
usleep_range(35, 70);
|
||||
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
|
||||
usleep_range(70, 140);
|
||||
|
||||
/* Setup cal */
|
||||
if (special) {
|
||||
b43_radio_write(dev, R2057_RCCAL_MASTER, 0x73);
|
||||
b43_radio_write(dev, R2057_RCCAL_X1, 0x28);
|
||||
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
|
||||
} else {
|
||||
b43_radio_write(dev, 0x1AE, 0x73);
|
||||
b43_radio_write(dev, R2057v7_RCCAL_MASTER, 0x73);
|
||||
b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
|
||||
b43_radio_write(dev, R2057_RCCAL_TRC0, 0x99);
|
||||
}
|
||||
|
||||
/* Start, wait, stop */
|
||||
usleep_range(35, 70);
|
||||
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
|
||||
if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
|
||||
usleep_range(70, 140);
|
||||
if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 2, 2, 500,
|
||||
5000000)) {
|
||||
b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
|
||||
return 0;
|
||||
}
|
||||
tmp = b43_radio_read(dev, R2057_RCCAL_DONE_OSCCAP);
|
||||
usleep_range(35, 70);
|
||||
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
|
||||
usleep_range(70, 140);
|
||||
|
||||
if (special)
|
||||
b43_radio_mask(dev, R2057_RCCAL_MASTER, ~0x1);
|
||||
else
|
||||
b43_radio_mask(dev, R2057v7_RCCAL_MASTER, ~0x1);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -798,6 +933,7 @@ static void b43_chantab_radio_2056_upload(struct b43_wldev *dev,
|
|||
static void b43_radio_2056_setup(struct b43_wldev *dev,
|
||||
const struct b43_nphy_channeltab_entry_rev3 *e)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct ssb_sprom *sprom = dev->dev->bus_sprom;
|
||||
enum ieee80211_band band = b43_current_band(dev->wl);
|
||||
u16 offset;
|
||||
|
@ -895,7 +1031,7 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
|
|||
offset | B2056_TX_MIXG_BOOST_TUNE,
|
||||
mixg_boost);
|
||||
} else {
|
||||
bias = dev->phy.is_40mhz ? 0x40 : 0x20;
|
||||
bias = b43_is_40mhz(dev) ? 0x40 : 0x20;
|
||||
b43_radio_write(dev,
|
||||
offset | B2056_TX_INTPAG_IMAIN_STAT,
|
||||
bias);
|
||||
|
@ -909,7 +1045,7 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
|
|||
b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee);
|
||||
}
|
||||
} else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) {
|
||||
u16 freq = dev->phy.channel_freq;
|
||||
u16 freq = phy->chandef->chan->center_freq;
|
||||
if (freq < 5100) {
|
||||
paa_boost = 0xA;
|
||||
pada_boost = 0x77;
|
||||
|
@ -1210,8 +1346,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
|
|||
u16 bw, len, rot, angle;
|
||||
struct b43_c32 *samples;
|
||||
|
||||
|
||||
bw = (dev->phy.is_40mhz) ? 40 : 20;
|
||||
bw = b43_is_40mhz(dev) ? 40 : 20;
|
||||
len = bw << 3;
|
||||
|
||||
if (test) {
|
||||
|
@ -1220,7 +1355,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
|
|||
else
|
||||
bw = 80;
|
||||
|
||||
if (dev->phy.is_40mhz)
|
||||
if (b43_is_40mhz(dev))
|
||||
bw <<= 1;
|
||||
|
||||
len = bw << 1;
|
||||
|
@ -1248,7 +1383,8 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
|
|||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */
|
||||
static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
|
||||
u16 wait, bool iqmode, bool dac_test)
|
||||
u16 wait, bool iqmode, bool dac_test,
|
||||
bool modify_bbmult)
|
||||
{
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
int i;
|
||||
|
@ -1262,12 +1398,10 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
|
|||
nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
|
||||
}
|
||||
|
||||
/* TODO: add modify_bbmult argument */
|
||||
if (!dev->phy.is_40mhz)
|
||||
tmp = 0x6464;
|
||||
else
|
||||
tmp = 0x4747;
|
||||
b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
|
||||
if (modify_bbmult) {
|
||||
tmp = !b43_is_40mhz(dev) ? 0x6464 : 0x4747;
|
||||
b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
|
||||
}
|
||||
|
||||
b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1));
|
||||
|
||||
|
@ -1285,10 +1419,8 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
|
|||
b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
|
||||
b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000);
|
||||
} else {
|
||||
if (dac_test)
|
||||
b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5);
|
||||
else
|
||||
b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
|
||||
tmp = dac_test ? 5 : 1;
|
||||
b43_phy_write(dev, B43_NPHY_SAMP_CMD, tmp);
|
||||
}
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & 1)) {
|
||||
|
@ -1675,6 +1807,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, enum n_rssi_type rssi_type,
|
|||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
|
||||
static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
|
||||
u16 saved_regs_phy_rfctl[2];
|
||||
|
@ -1897,9 +2030,9 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
|
|||
|
||||
/* Remember for which channel we store configuration */
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
|
||||
nphy->rssical_chanspec_2G.center_freq = dev->phy.channel_freq;
|
||||
nphy->rssical_chanspec_2G.center_freq = phy->chandef->chan->center_freq;
|
||||
else
|
||||
nphy->rssical_chanspec_5G.center_freq = dev->phy.channel_freq;
|
||||
nphy->rssical_chanspec_5G.center_freq = phy->chandef->chan->center_freq;
|
||||
|
||||
/* End of calibration, restore configuration */
|
||||
b43_nphy_classifier(dev, 7, class);
|
||||
|
@ -2192,7 +2325,7 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev)
|
|||
b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84);
|
||||
b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
|
||||
|
||||
if (!dev->phy.is_40mhz) {
|
||||
if (!b43_is_40mhz(dev)) {
|
||||
/* Set dwell lengths */
|
||||
b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
|
||||
b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
|
||||
|
@ -2206,7 +2339,7 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev)
|
|||
b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
|
||||
~B43_NPHY_C2_CLIPWBTHRES_CLIP2, 21);
|
||||
|
||||
if (!dev->phy.is_40mhz) {
|
||||
if (!b43_is_40mhz(dev)) {
|
||||
b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
|
||||
~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1);
|
||||
b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
|
||||
|
@ -2221,12 +2354,12 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev)
|
|||
|
||||
if (nphy->gain_boost) {
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ &&
|
||||
dev->phy.is_40mhz)
|
||||
b43_is_40mhz(dev))
|
||||
code = 4;
|
||||
else
|
||||
code = 5;
|
||||
} else {
|
||||
code = dev->phy.is_40mhz ? 6 : 7;
|
||||
code = b43_is_40mhz(dev) ? 6 : 7;
|
||||
}
|
||||
|
||||
/* Set HPVGA2 index */
|
||||
|
@ -2298,7 +2431,7 @@ static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev)
|
|||
static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset)
|
||||
{
|
||||
if (!offset)
|
||||
offset = (dev->phy.is_40mhz) ? 0x159 : 0x154;
|
||||
offset = b43_is_40mhz(dev) ? 0x159 : 0x154;
|
||||
return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7;
|
||||
}
|
||||
|
||||
|
@ -2371,13 +2504,13 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
|
|||
lpf_40 = b43_nphy_read_lpf_ctl(dev, 0x159);
|
||||
lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152);
|
||||
if (b43_nphy_ipa(dev)) {
|
||||
if ((phy->radio_rev == 5 && phy->is_40mhz) ||
|
||||
if ((phy->radio_rev == 5 && b43_is_40mhz(dev)) ||
|
||||
phy->radio_rev == 7 || phy->radio_rev == 8) {
|
||||
bcap_val = b43_radio_read(dev, 0x16b);
|
||||
scap_val = b43_radio_read(dev, 0x16a);
|
||||
scap_val_11b = scap_val;
|
||||
bcap_val_11b = bcap_val;
|
||||
if (phy->radio_rev == 5 && phy->is_40mhz) {
|
||||
if (phy->radio_rev == 5 && b43_is_40mhz(dev)) {
|
||||
scap_val_11n_20 = scap_val;
|
||||
bcap_val_11n_20 = bcap_val;
|
||||
scap_val_11n_40 = bcap_val_11n_40 = 0xc;
|
||||
|
@ -2519,7 +2652,7 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
|
|||
}
|
||||
}
|
||||
} else if (phy->radio_rev == 7 || phy->radio_rev == 8) {
|
||||
if (!phy->is_40mhz) {
|
||||
if (!b43_is_40mhz(dev)) {
|
||||
b43_radio_write(dev, 0x5F, 0x14);
|
||||
b43_radio_write(dev, 0xE8, 0x12);
|
||||
} else {
|
||||
|
@ -2528,7 +2661,7 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
u16 freq = phy->channel_freq;
|
||||
u16 freq = phy->chandef->chan->center_freq;
|
||||
if ((freq >= 5180 && freq <= 5230) ||
|
||||
(freq >= 5745 && freq <= 5805)) {
|
||||
b43_radio_write(dev, 0x7D, 0xFF);
|
||||
|
@ -2592,7 +2725,7 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
|
|||
b43_ntab_write(dev, B43_NTAB16(7, 0x123), 0x77);
|
||||
b43_ntab_write(dev, B43_NTAB16(7, 0x12A), 0x77);
|
||||
|
||||
if (!phy->is_40mhz) {
|
||||
if (!b43_is_40mhz(dev)) {
|
||||
b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x18D);
|
||||
b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x18D);
|
||||
} else {
|
||||
|
@ -2691,7 +2824,7 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
|
|||
|
||||
b43_phy_maskset(dev, B43_NPHY_SGILTRNOFFSET, 0xF0FF, 0x0700);
|
||||
|
||||
if (!dev->phy.is_40mhz) {
|
||||
if (!b43_is_40mhz(dev)) {
|
||||
b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
|
||||
b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
|
||||
} else {
|
||||
|
@ -2946,12 +3079,13 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
|
|||
* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
|
||||
*/
|
||||
static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
|
||||
bool iqmode, bool dac_test)
|
||||
bool iqmode, bool dac_test, bool modify_bbmult)
|
||||
{
|
||||
u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
|
||||
if (samp == 0)
|
||||
return -1;
|
||||
b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
|
||||
b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test,
|
||||
modify_bbmult);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3114,7 +3248,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
|
|||
b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
|
||||
~B43_NPHY_BPHY_CTL3_SCALE, 0x5A);
|
||||
|
||||
if (dev->phy.rev < 2 && dev->phy.is_40mhz)
|
||||
if (dev->phy.rev < 2 && b43_is_40mhz(dev))
|
||||
b43_hf_write(dev, b43_hf_read(dev) | B43_HF_TSSIRPSMW);
|
||||
} else {
|
||||
b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84,
|
||||
|
@ -3168,7 +3302,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
|
|||
else if (dev->phy.rev < 2)
|
||||
b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x40);
|
||||
|
||||
if (dev->phy.rev < 2 && dev->phy.is_40mhz)
|
||||
if (dev->phy.rev < 2 && b43_is_40mhz(dev))
|
||||
b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_TSSIRPSMW);
|
||||
|
||||
if (b43_nphy_ipa(dev)) {
|
||||
|
@ -3184,12 +3318,13 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
|
|||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */
|
||||
static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
struct ssb_sprom *sprom = dev->dev->bus_sprom;
|
||||
|
||||
u8 txpi[2], bbmult, i;
|
||||
u16 tmp, radio_gain, dac_gain;
|
||||
u16 freq = dev->phy.channel_freq;
|
||||
u16 freq = phy->chandef->chan->center_freq;
|
||||
u32 txgain;
|
||||
/* u32 gaintbl; rev3+ */
|
||||
|
||||
|
@ -3388,7 +3523,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
|
|||
b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, false);
|
||||
|
||||
b43_nphy_stop_playback(dev);
|
||||
b43_nphy_tx_tone(dev, 0xFA0, 0, false, false);
|
||||
b43_nphy_tx_tone(dev, 4000, 0, false, false, false);
|
||||
udelay(20);
|
||||
tmp = b43_nphy_poll_rssi(dev, N_RSSI_TSSI_2G, rssi, 1);
|
||||
b43_nphy_stop_playback(dev);
|
||||
|
@ -3439,21 +3574,21 @@ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev)
|
|||
delta = 0;
|
||||
switch (stf_mode) {
|
||||
case 0:
|
||||
if (dev->phy.is_40mhz && dev->phy.rev >= 5) {
|
||||
if (b43_is_40mhz(dev) && dev->phy.rev >= 5) {
|
||||
idx = 68;
|
||||
} else {
|
||||
delta = 1;
|
||||
idx = dev->phy.is_40mhz ? 52 : 4;
|
||||
idx = b43_is_40mhz(dev) ? 52 : 4;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
idx = dev->phy.is_40mhz ? 76 : 28;
|
||||
idx = b43_is_40mhz(dev) ? 76 : 28;
|
||||
break;
|
||||
case 2:
|
||||
idx = dev->phy.is_40mhz ? 84 : 36;
|
||||
idx = b43_is_40mhz(dev) ? 84 : 36;
|
||||
break;
|
||||
case 3:
|
||||
idx = dev->phy.is_40mhz ? 92 : 44;
|
||||
idx = b43_is_40mhz(dev) ? 92 : 44;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3474,6 +3609,7 @@ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev)
|
|||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlSetup */
|
||||
static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
struct ssb_sprom *sprom = dev->dev->bus_sprom;
|
||||
|
||||
|
@ -3483,7 +3619,7 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
|
|||
s32 num, den, pwr;
|
||||
u32 regval[64];
|
||||
|
||||
u16 freq = dev->phy.channel_freq;
|
||||
u16 freq = phy->chandef->chan->center_freq;
|
||||
u16 tmp;
|
||||
u16 r; /* routing */
|
||||
u8 i, c;
|
||||
|
@ -3705,21 +3841,28 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */
|
||||
static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
|
||||
/*
|
||||
* TX low-pass filter bandwidth setup
|
||||
* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw
|
||||
*/
|
||||
static void b43_nphy_tx_lpf_bw(struct b43_wldev *dev)
|
||||
{
|
||||
u16 tmp;
|
||||
|
||||
if (dev->phy.rev >= 3) {
|
||||
if (b43_nphy_ipa(dev)) {
|
||||
tmp = 4;
|
||||
b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2,
|
||||
(((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
|
||||
}
|
||||
if (dev->phy.rev < 3 || dev->phy.rev >= 7)
|
||||
return;
|
||||
|
||||
tmp = 1;
|
||||
if (b43_nphy_ipa(dev))
|
||||
tmp = b43_is_40mhz(dev) ? 5 : 4;
|
||||
else
|
||||
tmp = b43_is_40mhz(dev) ? 3 : 1;
|
||||
b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2,
|
||||
(tmp << 9) | (tmp << 6) | (tmp << 3) | tmp);
|
||||
|
||||
if (b43_nphy_ipa(dev)) {
|
||||
tmp = b43_is_40mhz(dev) ? 4 : 1;
|
||||
b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S2,
|
||||
(((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
|
||||
(tmp << 9) | (tmp << 6) | (tmp << 3) | tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3992,7 +4135,7 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev)
|
|||
|
||||
if (nphy->gband_spurwar_en) {
|
||||
/* TODO: N PHY Adjust Analog Pfbw (7) */
|
||||
if (channel == 11 && dev->phy.is_40mhz)
|
||||
if (channel == 11 && b43_is_40mhz(dev))
|
||||
; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/
|
||||
else
|
||||
; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
|
||||
|
@ -4286,7 +4429,7 @@ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev)
|
|||
b43_phy_write(dev, B43_PHY_N(offset[i] + j),
|
||||
tbl_tx_filter_coef_rev4[i][j]);
|
||||
|
||||
if (dev->phy.is_40mhz) {
|
||||
if (b43_is_40mhz(dev)) {
|
||||
for (j = 0; j < 15; j++)
|
||||
b43_phy_write(dev, B43_PHY_N(offset[0] + j),
|
||||
tbl_tx_filter_coef_rev4[3][j]);
|
||||
|
@ -4500,8 +4643,9 @@ static void b43_nphy_save_cal(struct b43_wldev *dev)
|
|||
txcal_radio_regs[2] = b43_radio_read(dev, 0x8D);
|
||||
txcal_radio_regs[3] = b43_radio_read(dev, 0xBC);
|
||||
}
|
||||
iqcal_chanspec->center_freq = dev->phy.channel_freq;
|
||||
iqcal_chanspec->channel_type = dev->phy.channel_type;
|
||||
iqcal_chanspec->center_freq = dev->phy.chandef->chan->center_freq;
|
||||
iqcal_chanspec->channel_type =
|
||||
cfg80211_get_chandef_type(dev->phy.chandef);
|
||||
b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 8, table);
|
||||
|
||||
if (nphy->hang_avoid)
|
||||
|
@ -4581,6 +4725,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
|
|||
struct nphy_txgains target,
|
||||
bool full, bool mphase)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
int i;
|
||||
int error = 0;
|
||||
|
@ -4621,7 +4766,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
|
|||
(dev->phy.rev == 5 && nphy->ipa2g_on &&
|
||||
b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ);
|
||||
if (phy6or5x) {
|
||||
if (dev->phy.is_40mhz) {
|
||||
if (b43_is_40mhz(dev)) {
|
||||
b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18,
|
||||
tbl_tx_iqlo_cal_loft_ladder_40);
|
||||
b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18,
|
||||
|
@ -4636,16 +4781,16 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
|
|||
|
||||
b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9);
|
||||
|
||||
if (!dev->phy.is_40mhz)
|
||||
if (!b43_is_40mhz(dev))
|
||||
freq = 2500;
|
||||
else
|
||||
freq = 5000;
|
||||
|
||||
if (nphy->mphase_cal_phase_id > 2)
|
||||
b43_nphy_run_samples(dev, (dev->phy.is_40mhz ? 40 : 20) * 8,
|
||||
0xFFFF, 0, true, false);
|
||||
b43_nphy_run_samples(dev, (b43_is_40mhz(dev) ? 40 : 20) * 8,
|
||||
0xFFFF, 0, true, false, false);
|
||||
else
|
||||
error = b43_nphy_tx_tone(dev, freq, 250, true, false);
|
||||
error = b43_nphy_tx_tone(dev, freq, 250, true, false, false);
|
||||
|
||||
if (error == 0) {
|
||||
if (nphy->mphase_cal_phase_id > 2) {
|
||||
|
@ -4773,9 +4918,9 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
|
|||
nphy->txiqlocal_bestc);
|
||||
nphy->txiqlocal_coeffsvalid = true;
|
||||
nphy->txiqlocal_chanspec.center_freq =
|
||||
dev->phy.channel_freq;
|
||||
phy->chandef->chan->center_freq;
|
||||
nphy->txiqlocal_chanspec.channel_type =
|
||||
dev->phy.channel_type;
|
||||
cfg80211_get_chandef_type(phy->chandef);
|
||||
} else {
|
||||
length = 11;
|
||||
if (dev->phy.rev < 3)
|
||||
|
@ -4811,8 +4956,8 @@ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev)
|
|||
bool equal = true;
|
||||
|
||||
if (!nphy->txiqlocal_coeffsvalid ||
|
||||
nphy->txiqlocal_chanspec.center_freq != dev->phy.channel_freq ||
|
||||
nphy->txiqlocal_chanspec.channel_type != dev->phy.channel_type)
|
||||
nphy->txiqlocal_chanspec.center_freq != dev->phy.chandef->chan->center_freq ||
|
||||
nphy->txiqlocal_chanspec.channel_type != cfg80211_get_chandef_type(dev->phy.chandef))
|
||||
return;
|
||||
|
||||
b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
|
||||
|
@ -4968,11 +5113,11 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
|
|||
if (playtone) {
|
||||
ret = b43_nphy_tx_tone(dev, 4000,
|
||||
(nphy->rxcalparams & 0xFFFF),
|
||||
false, false);
|
||||
false, false, true);
|
||||
playtone = false;
|
||||
} else {
|
||||
b43_nphy_run_samples(dev, 160, 0xFFFF, 0,
|
||||
false, false);
|
||||
b43_nphy_run_samples(dev, 160, 0xFFFF, 0, false,
|
||||
false, true);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
|
@ -5344,7 +5489,7 @@ static int b43_phy_initn(struct b43_wldev *dev)
|
|||
b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320);
|
||||
if (phy->rev >= 3 && phy->rev <= 6)
|
||||
b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0032);
|
||||
b43_nphy_tx_lp_fbw(dev);
|
||||
b43_nphy_tx_lpf_bw(dev);
|
||||
if (phy->rev >= 3)
|
||||
b43_nphy_spur_workaround(dev);
|
||||
|
||||
|
@ -5430,14 +5575,14 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev,
|
|||
if (dev->phy.rev < 3)
|
||||
b43_nphy_adjust_lna_gain_table(dev);
|
||||
|
||||
b43_nphy_tx_lp_fbw(dev);
|
||||
b43_nphy_tx_lpf_bw(dev);
|
||||
|
||||
if (dev->phy.rev >= 3 &&
|
||||
dev->phy.n->spur_avoid != B43_SPUR_AVOID_DISABLE) {
|
||||
bool avoid = false;
|
||||
if (dev->phy.n->spur_avoid == B43_SPUR_AVOID_FORCE) {
|
||||
avoid = true;
|
||||
} else if (!b43_channel_type_is_40mhz(phy->channel_type)) {
|
||||
} else if (!b43_is_40mhz(dev)) {
|
||||
if ((ch >= 5 && ch <= 8) || ch == 13 || ch == 14)
|
||||
avoid = true;
|
||||
} else { /* 40MHz */
|
||||
|
@ -5484,10 +5629,17 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
|
|||
|
||||
const struct b43_nphy_channeltab_entry_rev2 *tabent_r2 = NULL;
|
||||
const struct b43_nphy_channeltab_entry_rev3 *tabent_r3 = NULL;
|
||||
const struct b43_nphy_chantabent_rev7 *tabent_r7 = NULL;
|
||||
const struct b43_nphy_chantabent_rev7_2g *tabent_r7_2g = NULL;
|
||||
|
||||
u8 tmp;
|
||||
|
||||
if (dev->phy.rev >= 3) {
|
||||
if (phy->rev >= 7) {
|
||||
r2057_get_chantabent_rev7(dev, channel->center_freq,
|
||||
&tabent_r7, &tabent_r7_2g);
|
||||
if (!tabent_r7 && !tabent_r7_2g)
|
||||
return -ESRCH;
|
||||
} else if (phy->rev >= 3) {
|
||||
tabent_r3 = b43_nphy_get_chantabent_rev3(dev,
|
||||
channel->center_freq);
|
||||
if (!tabent_r3)
|
||||
|
@ -5502,20 +5654,36 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
|
|||
/* Channel is set later in common code, but we need to set it on our
|
||||
own to let this function's subcalls work properly. */
|
||||
phy->channel = channel->hw_value;
|
||||
phy->channel_freq = channel->center_freq;
|
||||
|
||||
#if 0
|
||||
if (b43_channel_type_is_40mhz(phy->channel_type) !=
|
||||
b43_channel_type_is_40mhz(channel_type))
|
||||
; /* TODO: BMAC BW Set (channel_type) */
|
||||
#endif
|
||||
|
||||
if (channel_type == NL80211_CHAN_HT40PLUS)
|
||||
b43_phy_set(dev, B43_NPHY_RXCTL,
|
||||
B43_NPHY_RXCTL_BSELU20);
|
||||
else if (channel_type == NL80211_CHAN_HT40MINUS)
|
||||
b43_phy_mask(dev, B43_NPHY_RXCTL,
|
||||
~B43_NPHY_RXCTL_BSELU20);
|
||||
if (channel_type == NL80211_CHAN_HT40PLUS) {
|
||||
b43_phy_set(dev, B43_NPHY_RXCTL, B43_NPHY_RXCTL_BSELU20);
|
||||
if (phy->rev >= 7)
|
||||
b43_phy_set(dev, 0x310, 0x8000);
|
||||
} else if (channel_type == NL80211_CHAN_HT40MINUS) {
|
||||
b43_phy_mask(dev, B43_NPHY_RXCTL, ~B43_NPHY_RXCTL_BSELU20);
|
||||
if (phy->rev >= 7)
|
||||
b43_phy_mask(dev, 0x310, (u16)~0x8000);
|
||||
}
|
||||
|
||||
if (dev->phy.rev >= 3) {
|
||||
if (phy->rev >= 7) {
|
||||
const struct b43_phy_n_sfo_cfg *phy_regs = tabent_r7 ?
|
||||
&(tabent_r7->phy_regs) : &(tabent_r7_2g->phy_regs);
|
||||
|
||||
if (phy->radio_rev <= 4 || phy->radio_rev == 6) {
|
||||
tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 2 : 0;
|
||||
b43_radio_maskset(dev, R2057_TIA_CONFIG_CORE0, ~2, tmp);
|
||||
b43_radio_maskset(dev, R2057_TIA_CONFIG_CORE1, ~2, tmp);
|
||||
}
|
||||
|
||||
b43_radio_2057_setup(dev, tabent_r7, tabent_r7_2g);
|
||||
b43_nphy_channel_setup(dev, phy_regs, channel);
|
||||
} else if (phy->rev >= 3) {
|
||||
tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 4 : 0;
|
||||
b43_radio_maskset(dev, 0x08, 0xFFFB, tmp);
|
||||
b43_radio_2056_setup(dev, tabent_r3);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "radio_2057.h"
|
||||
#include "phy_common.h"
|
||||
|
||||
static u16 r2057_rev4_init[42][2] = {
|
||||
static u16 r2057_rev4_init[][2] = {
|
||||
{ 0x0E, 0x20 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 },
|
||||
{ 0x35, 0x26 }, { 0x3C, 0xff }, { 0x3D, 0xff }, { 0x3E, 0xff },
|
||||
{ 0x3F, 0xff }, { 0x62, 0x33 }, { 0x8A, 0xf0 }, { 0x8B, 0x10 },
|
||||
|
@ -40,7 +40,7 @@ static u16 r2057_rev4_init[42][2] = {
|
|||
{ 0x1AB, 0x00 }, { 0x1AC, 0x00 },
|
||||
};
|
||||
|
||||
static u16 r2057_rev5_init[44][2] = {
|
||||
static u16 r2057_rev5_init[][2] = {
|
||||
{ 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
|
||||
{ 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
|
||||
{ 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f },
|
||||
|
@ -54,7 +54,7 @@ static u16 r2057_rev5_init[44][2] = {
|
|||
{ 0x1AC, 0x00 }, { 0x1B7, 0x0c }, { 0x1C1, 0x01 }, { 0x1C2, 0x80 },
|
||||
};
|
||||
|
||||
static u16 r2057_rev5a_init[45][2] = {
|
||||
static u16 r2057_rev5a_init[][2] = {
|
||||
{ 0x00, 0x15 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
|
||||
{ 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
|
||||
{ 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f },
|
||||
|
@ -69,7 +69,7 @@ static u16 r2057_rev5a_init[45][2] = {
|
|||
{ 0x1C2, 0x80 },
|
||||
};
|
||||
|
||||
static u16 r2057_rev7_init[54][2] = {
|
||||
static u16 r2057_rev7_init[][2] = {
|
||||
{ 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
|
||||
{ 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
|
||||
{ 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x13 },
|
||||
|
@ -86,7 +86,8 @@ static u16 r2057_rev7_init[54][2] = {
|
|||
{ 0x1B7, 0x05 }, { 0x1C2, 0xa0 },
|
||||
};
|
||||
|
||||
static u16 r2057_rev8_init[54][2] = {
|
||||
/* TODO: Which devices should use it?
|
||||
static u16 r2057_rev8_init[][2] = {
|
||||
{ 0x00, 0x08 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
|
||||
{ 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
|
||||
{ 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x0f },
|
||||
|
@ -102,6 +103,47 @@ static u16 r2057_rev8_init[54][2] = {
|
|||
{ 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
|
||||
{ 0x1B7, 0x05 }, { 0x1C2, 0xa0 },
|
||||
};
|
||||
*/
|
||||
|
||||
#define RADIOREGS7(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
|
||||
r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \
|
||||
r20, r21, r22, r23, r24, r25, r26, r27) \
|
||||
.radio_vcocal_countval0 = r00, \
|
||||
.radio_vcocal_countval1 = r01, \
|
||||
.radio_rfpll_refmaster_sparextalsize = r02, \
|
||||
.radio_rfpll_loopfilter_r1 = r03, \
|
||||
.radio_rfpll_loopfilter_c2 = r04, \
|
||||
.radio_rfpll_loopfilter_c1 = r05, \
|
||||
.radio_cp_kpd_idac = r06, \
|
||||
.radio_rfpll_mmd0 = r07, \
|
||||
.radio_rfpll_mmd1 = r08, \
|
||||
.radio_vcobuf_tune = r09, \
|
||||
.radio_logen_mx2g_tune = r10, \
|
||||
.radio_logen_mx5g_tune = r11, \
|
||||
.radio_logen_indbuf2g_tune = r12, \
|
||||
.radio_logen_indbuf5g_tune = r13, \
|
||||
.radio_txmix2g_tune_boost_pu_core0 = r14, \
|
||||
.radio_pad2g_tune_pus_core0 = r15, \
|
||||
.radio_pga_boost_tune_core0 = r16, \
|
||||
.radio_txmix5g_boost_tune_core0 = r17, \
|
||||
.radio_pad5g_tune_misc_pus_core0 = r18, \
|
||||
.radio_lna2g_tune_core0 = r19, \
|
||||
.radio_lna5g_tune_core0 = r20, \
|
||||
.radio_txmix2g_tune_boost_pu_core1 = r21, \
|
||||
.radio_pad2g_tune_pus_core1 = r22, \
|
||||
.radio_pga_boost_tune_core1 = r23, \
|
||||
.radio_txmix5g_boost_tune_core1 = r24, \
|
||||
.radio_pad5g_tune_misc_pus_core1 = r25, \
|
||||
.radio_lna2g_tune_core1 = r26, \
|
||||
.radio_lna5g_tune_core1 = r27
|
||||
|
||||
#define PHYREGS(r0, r1, r2, r3, r4, r5) \
|
||||
.phy_regs.phy_bw1a = r0, \
|
||||
.phy_regs.phy_bw2 = r1, \
|
||||
.phy_regs.phy_bw3 = r2, \
|
||||
.phy_regs.phy_bw4 = r3, \
|
||||
.phy_regs.phy_bw5 = r4, \
|
||||
.phy_regs.phy_bw6 = r5
|
||||
|
||||
void r2057_upload_inittabs(struct b43_wldev *dev)
|
||||
{
|
||||
|
@ -109,33 +151,69 @@ void r2057_upload_inittabs(struct b43_wldev *dev)
|
|||
u16 *table = NULL;
|
||||
u16 size, i;
|
||||
|
||||
if (phy->rev == 7) {
|
||||
switch (phy->rev) {
|
||||
case 7:
|
||||
table = r2057_rev4_init[0];
|
||||
size = ARRAY_SIZE(r2057_rev4_init);
|
||||
} else if (phy->rev == 8 || phy->rev == 9) {
|
||||
break;
|
||||
case 8:
|
||||
if (phy->radio_rev == 5) {
|
||||
if (phy->radio_rev == 8) {
|
||||
table = r2057_rev5_init[0];
|
||||
size = ARRAY_SIZE(r2057_rev5_init);
|
||||
} else {
|
||||
table = r2057_rev5a_init[0];
|
||||
size = ARRAY_SIZE(r2057_rev5a_init);
|
||||
}
|
||||
table = r2057_rev5_init[0];
|
||||
size = ARRAY_SIZE(r2057_rev5_init);
|
||||
} else if (phy->radio_rev == 7) {
|
||||
table = r2057_rev7_init[0];
|
||||
size = ARRAY_SIZE(r2057_rev7_init);
|
||||
} else if (phy->radio_rev == 9) {
|
||||
table = r2057_rev8_init[0];
|
||||
size = ARRAY_SIZE(r2057_rev8_init);
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
if (phy->radio_rev == 5) {
|
||||
table = r2057_rev5a_init[0];
|
||||
size = ARRAY_SIZE(r2057_rev5a_init);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
B43_WARN_ON(!table);
|
||||
|
||||
if (table) {
|
||||
for (i = 0; i < 10; i++) {
|
||||
pr_info("radio_write 0x%X ", *table);
|
||||
table++;
|
||||
pr_info("0x%X\n", *table);
|
||||
table++;
|
||||
}
|
||||
for (i = 0; i < size; i++, table += 2)
|
||||
b43_radio_write(dev, table[0], table[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void r2057_get_chantabent_rev7(struct b43_wldev *dev, u16 freq,
|
||||
const struct b43_nphy_chantabent_rev7 **tabent_r7,
|
||||
const struct b43_nphy_chantabent_rev7_2g **tabent_r7_2g)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
const struct b43_nphy_chantabent_rev7 *e_r7 = NULL;
|
||||
const struct b43_nphy_chantabent_rev7_2g *e_r7_2g = NULL;
|
||||
unsigned int len, i;
|
||||
|
||||
*tabent_r7 = NULL;
|
||||
*tabent_r7_2g = NULL;
|
||||
|
||||
/* TODO */
|
||||
switch (phy->rev) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (e_r7) {
|
||||
for (i = 0; i < len; i++, e_r7++) {
|
||||
if (e_r7->freq == freq) {
|
||||
*tabent_r7 = e_r7;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (e_r7_2g) {
|
||||
for (i = 0; i < len; i++, e_r7_2g++) {
|
||||
if (e_r7_2g->freq == freq) {
|
||||
*tabent_r7_2g = e_r7_2g;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -425,6 +425,72 @@
|
|||
|
||||
#define R2057_VCM_MASK 0x7
|
||||
|
||||
struct b43_nphy_chantabent_rev7 {
|
||||
/* The channel frequency in MHz */
|
||||
u16 freq;
|
||||
/* Radio regs values on channelswitch */
|
||||
u8 radio_vcocal_countval0;
|
||||
u8 radio_vcocal_countval1;
|
||||
u8 radio_rfpll_refmaster_sparextalsize;
|
||||
u8 radio_rfpll_loopfilter_r1;
|
||||
u8 radio_rfpll_loopfilter_c2;
|
||||
u8 radio_rfpll_loopfilter_c1;
|
||||
u8 radio_cp_kpd_idac;
|
||||
u8 radio_rfpll_mmd0;
|
||||
u8 radio_rfpll_mmd1;
|
||||
u8 radio_vcobuf_tune;
|
||||
u8 radio_logen_mx2g_tune;
|
||||
u8 radio_logen_mx5g_tune;
|
||||
u8 radio_logen_indbuf2g_tune;
|
||||
u8 radio_logen_indbuf5g_tune;
|
||||
u8 radio_txmix2g_tune_boost_pu_core0;
|
||||
u8 radio_pad2g_tune_pus_core0;
|
||||
u8 radio_pga_boost_tune_core0;
|
||||
u8 radio_txmix5g_boost_tune_core0;
|
||||
u8 radio_pad5g_tune_misc_pus_core0;
|
||||
u8 radio_lna2g_tune_core0;
|
||||
u8 radio_lna5g_tune_core0;
|
||||
u8 radio_txmix2g_tune_boost_pu_core1;
|
||||
u8 radio_pad2g_tune_pus_core1;
|
||||
u8 radio_pga_boost_tune_core1;
|
||||
u8 radio_txmix5g_boost_tune_core1;
|
||||
u8 radio_pad5g_tune_misc_pus_core1;
|
||||
u8 radio_lna2g_tune_core1;
|
||||
u8 radio_lna5g_tune_core1;
|
||||
/* PHY res values on channelswitch */
|
||||
struct b43_phy_n_sfo_cfg phy_regs;
|
||||
};
|
||||
|
||||
struct b43_nphy_chantabent_rev7_2g {
|
||||
/* The channel frequency in MHz */
|
||||
u16 freq;
|
||||
/* Radio regs values on channelswitch */
|
||||
u8 radio_vcocal_countval0;
|
||||
u8 radio_vcocal_countval1;
|
||||
u8 radio_rfpll_refmaster_sparextalsize;
|
||||
u8 radio_rfpll_loopfilter_r1;
|
||||
u8 radio_rfpll_loopfilter_c2;
|
||||
u8 radio_rfpll_loopfilter_c1;
|
||||
u8 radio_cp_kpd_idac;
|
||||
u8 radio_rfpll_mmd0;
|
||||
u8 radio_rfpll_mmd1;
|
||||
u8 radio_vcobuf_tune;
|
||||
u8 radio_logen_mx2g_tune;
|
||||
u8 radio_logen_indbuf2g_tune;
|
||||
u8 radio_txmix2g_tune_boost_pu_core0;
|
||||
u8 radio_pad2g_tune_pus_core0;
|
||||
u8 radio_lna2g_tune_core0;
|
||||
u8 radio_txmix2g_tune_boost_pu_core1;
|
||||
u8 radio_pad2g_tune_pus_core1;
|
||||
u8 radio_lna2g_tune_core1;
|
||||
/* PHY regs values on channelswitch */
|
||||
struct b43_phy_n_sfo_cfg phy_regs;
|
||||
};
|
||||
|
||||
void r2057_upload_inittabs(struct b43_wldev *dev);
|
||||
|
||||
void r2057_get_chantabent_rev7(struct b43_wldev *dev, u16 freq,
|
||||
const struct b43_nphy_chantabent_rev7 **tabent_r7,
|
||||
const struct b43_nphy_chantabent_rev7_2g **tabent_r7_2g);
|
||||
|
||||
#endif /* B43_RADIO_2057_H_ */
|
||||
|
|
|
@ -3191,7 +3191,7 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
|
|||
/* Some workarounds to the workarounds... */
|
||||
if (ghz5 && dev->phy.rev >= 6) {
|
||||
if (dev->phy.radio_rev == 11 &&
|
||||
!b43_channel_type_is_40mhz(dev->phy.channel_type))
|
||||
!b43_is_40mhz(dev))
|
||||
e->cliplo_gain = 0x2d;
|
||||
} else if (!ghz5 && dev->phy.rev >= 5) {
|
||||
static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,
|
||||
|
|
|
@ -34,7 +34,8 @@ brcmfmac-objs += \
|
|||
dhd_common.o \
|
||||
dhd_linux.o \
|
||||
firmware.o \
|
||||
btcoex.o
|
||||
btcoex.o \
|
||||
vendor.o
|
||||
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
|
||||
dhd_sdio.o \
|
||||
bcmsdh.o
|
||||
|
|
|
@ -157,7 +157,7 @@ static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci,
|
|||
*/
|
||||
|
||||
/* save current */
|
||||
brcmf_dbg(TRACE, "new SCO/eSCO coex algo {save & override}\n");
|
||||
brcmf_dbg(INFO, "new SCO/eSCO coex algo {save & override}\n");
|
||||
brcmf_btcoex_params_read(ifp, 50, &btci->reg50);
|
||||
brcmf_btcoex_params_read(ifp, 51, &btci->reg51);
|
||||
brcmf_btcoex_params_read(ifp, 64, &btci->reg64);
|
||||
|
@ -165,7 +165,7 @@ static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci,
|
|||
brcmf_btcoex_params_read(ifp, 71, &btci->reg71);
|
||||
|
||||
btci->saved_regs_part2 = true;
|
||||
brcmf_dbg(TRACE,
|
||||
brcmf_dbg(INFO,
|
||||
"saved bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
||||
btci->reg50, btci->reg51, btci->reg64,
|
||||
btci->reg65, btci->reg71);
|
||||
|
@ -179,21 +179,21 @@ static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci,
|
|||
|
||||
} else if (btci->saved_regs_part2) {
|
||||
/* restore previously saved bt params */
|
||||
brcmf_dbg(TRACE, "Do new SCO/eSCO coex algo {restore}\n");
|
||||
brcmf_dbg(INFO, "Do new SCO/eSCO coex algo {restore}\n");
|
||||
brcmf_btcoex_params_write(ifp, 50, btci->reg50);
|
||||
brcmf_btcoex_params_write(ifp, 51, btci->reg51);
|
||||
brcmf_btcoex_params_write(ifp, 64, btci->reg64);
|
||||
brcmf_btcoex_params_write(ifp, 65, btci->reg65);
|
||||
brcmf_btcoex_params_write(ifp, 71, btci->reg71);
|
||||
|
||||
brcmf_dbg(TRACE,
|
||||
brcmf_dbg(INFO,
|
||||
"restored bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
||||
btci->reg50, btci->reg51, btci->reg64,
|
||||
btci->reg65, btci->reg71);
|
||||
|
||||
btci->saved_regs_part2 = false;
|
||||
} else {
|
||||
brcmf_err("attempted to restore not saved BTCOEX params\n");
|
||||
brcmf_dbg(INFO, "attempted to restore not saved BTCOEX params\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,14 +219,14 @@ static bool brcmf_btcoex_is_sco_active(struct brcmf_if *ifp)
|
|||
break;
|
||||
}
|
||||
|
||||
brcmf_dbg(TRACE, "sample[%d], btc_params 27:%x\n", i, param27);
|
||||
brcmf_dbg(INFO, "sample[%d], btc_params 27:%x\n", i, param27);
|
||||
|
||||
if ((param27 & 0x6) == 2) { /* count both sco & esco */
|
||||
sco_id_cnt++;
|
||||
}
|
||||
|
||||
if (sco_id_cnt > 2) {
|
||||
brcmf_dbg(TRACE,
|
||||
brcmf_dbg(INFO,
|
||||
"sco/esco detected, pkt id_cnt:%d samples:%d\n",
|
||||
sco_id_cnt, i);
|
||||
res = true;
|
||||
|
@ -250,7 +250,7 @@ static void btcmf_btcoex_save_part1(struct brcmf_btcoex_info *btci)
|
|||
brcmf_btcoex_params_read(ifp, 41, &btci->reg41);
|
||||
brcmf_btcoex_params_read(ifp, 68, &btci->reg68);
|
||||
btci->saved_regs_part1 = true;
|
||||
brcmf_dbg(TRACE,
|
||||
brcmf_dbg(INFO,
|
||||
"saved btc_params regs (66,41,68) 0x%x 0x%x 0x%x\n",
|
||||
btci->reg66, btci->reg41,
|
||||
btci->reg68);
|
||||
|
@ -270,7 +270,7 @@ static void brcmf_btcoex_restore_part1(struct brcmf_btcoex_info *btci)
|
|||
brcmf_btcoex_params_write(ifp, 66, btci->reg66);
|
||||
brcmf_btcoex_params_write(ifp, 41, btci->reg41);
|
||||
brcmf_btcoex_params_write(ifp, 68, btci->reg68);
|
||||
brcmf_dbg(TRACE,
|
||||
brcmf_dbg(INFO,
|
||||
"restored btc_params regs {66,41,68} 0x%x 0x%x 0x%x\n",
|
||||
btci->reg66, btci->reg41,
|
||||
btci->reg68);
|
||||
|
@ -307,7 +307,7 @@ static void brcmf_btcoex_handler(struct work_struct *work)
|
|||
/* DHCP started provide OPPORTUNITY window
|
||||
to get DHCP address
|
||||
*/
|
||||
brcmf_dbg(TRACE, "DHCP started\n");
|
||||
brcmf_dbg(INFO, "DHCP started\n");
|
||||
btci->bt_state = BRCMF_BT_DHCP_OPPR_WIN;
|
||||
if (btci->timeout < BRCMF_BTCOEX_OPPR_WIN_TIME) {
|
||||
mod_timer(&btci->timer, btci->timer.expires);
|
||||
|
@ -322,12 +322,12 @@ static void brcmf_btcoex_handler(struct work_struct *work)
|
|||
|
||||
case BRCMF_BT_DHCP_OPPR_WIN:
|
||||
if (btci->dhcp_done) {
|
||||
brcmf_dbg(TRACE, "DHCP done before T1 expiration\n");
|
||||
brcmf_dbg(INFO, "DHCP done before T1 expiration\n");
|
||||
goto idle;
|
||||
}
|
||||
|
||||
/* DHCP is not over yet, start lowering BT priority */
|
||||
brcmf_dbg(TRACE, "DHCP T1:%d expired\n",
|
||||
brcmf_dbg(INFO, "DHCP T1:%d expired\n",
|
||||
BRCMF_BTCOEX_OPPR_WIN_TIME);
|
||||
brcmf_btcoex_boost_wifi(btci, true);
|
||||
|
||||
|
@ -339,9 +339,9 @@ static void brcmf_btcoex_handler(struct work_struct *work)
|
|||
|
||||
case BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT:
|
||||
if (btci->dhcp_done)
|
||||
brcmf_dbg(TRACE, "DHCP done before T2 expiration\n");
|
||||
brcmf_dbg(INFO, "DHCP done before T2 expiration\n");
|
||||
else
|
||||
brcmf_dbg(TRACE, "DHCP T2:%d expired\n",
|
||||
brcmf_dbg(INFO, "DHCP T2:%d expired\n",
|
||||
BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT);
|
||||
|
||||
goto idle;
|
||||
|
@ -440,13 +440,13 @@ static void brcmf_btcoex_dhcp_end(struct brcmf_btcoex_info *btci)
|
|||
/* Stop any bt timer because DHCP session is done */
|
||||
btci->dhcp_done = true;
|
||||
if (btci->timer_on) {
|
||||
brcmf_dbg(TRACE, "disable BT DHCP Timer\n");
|
||||
brcmf_dbg(INFO, "disable BT DHCP Timer\n");
|
||||
btci->timer_on = false;
|
||||
del_timer_sync(&btci->timer);
|
||||
|
||||
/* schedule worker if transition to IDLE is needed */
|
||||
if (btci->bt_state != BRCMF_BT_DHCP_IDLE) {
|
||||
brcmf_dbg(TRACE, "bt_state:%d\n",
|
||||
brcmf_dbg(INFO, "bt_state:%d\n",
|
||||
btci->bt_state);
|
||||
schedule_work(&btci->work);
|
||||
}
|
||||
|
@ -472,7 +472,7 @@ int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
|
|||
|
||||
switch (mode) {
|
||||
case BRCMF_BTCOEX_DISABLED:
|
||||
brcmf_dbg(TRACE, "DHCP session starts\n");
|
||||
brcmf_dbg(INFO, "DHCP session starts\n");
|
||||
if (btci->bt_state != BRCMF_BT_DHCP_IDLE)
|
||||
return -EBUSY;
|
||||
/* Start BT timer only for SCO connection */
|
||||
|
@ -484,14 +484,14 @@ int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
|
|||
break;
|
||||
|
||||
case BRCMF_BTCOEX_ENABLED:
|
||||
brcmf_dbg(TRACE, "DHCP session ends\n");
|
||||
brcmf_dbg(INFO, "DHCP session ends\n");
|
||||
if (btci->bt_state != BRCMF_BT_DHCP_IDLE &&
|
||||
vif == btci->vif) {
|
||||
brcmf_btcoex_dhcp_end(btci);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
brcmf_dbg(TRACE, "Unknown mode, ignored\n");
|
||||
brcmf_dbg(INFO, "Unknown mode, ignored\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -49,16 +49,6 @@
|
|||
*/
|
||||
#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32
|
||||
|
||||
/* Bus independent dongle command */
|
||||
struct brcmf_dcmd {
|
||||
uint cmd; /* common dongle cmd definition */
|
||||
void *buf; /* pointer to user buffer */
|
||||
uint len; /* length of user buffer */
|
||||
u8 set; /* get or set request (optional) */
|
||||
uint used; /* bytes read or written (optional) */
|
||||
uint needed; /* bytes needed (optional) */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
|
||||
*
|
||||
|
|
|
@ -282,6 +282,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
|
|||
ptr = strrchr(buf, ' ') + 1;
|
||||
strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
|
||||
|
||||
/* set mpc */
|
||||
err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
|
||||
if (err) {
|
||||
brcmf_err("failed setting mpc\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup timeout if Beacons are lost and roam is off to report
|
||||
* link down
|
||||
|
|
|
@ -54,7 +54,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
|
|||
if (err >= 0)
|
||||
err = 0;
|
||||
else
|
||||
brcmf_err("Failed err=%d\n", err);
|
||||
brcmf_dbg(FIL, "Failed err=%d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -708,7 +708,7 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
|
|||
active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS;
|
||||
else if (num_chans == AF_PEER_SEARCH_CNT)
|
||||
active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS;
|
||||
else if (wl_get_vif_state_all(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED))
|
||||
else if (brcmf_get_vif_state_any(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED))
|
||||
active = -1;
|
||||
else
|
||||
active = P2PAPI_SCAN_DWELL_TIME_MS;
|
||||
|
|
|
@ -29,32 +29,24 @@
|
|||
#include "usb_rdl.h"
|
||||
#include "usb.h"
|
||||
|
||||
#define IOCTL_RESP_TIMEOUT 2000
|
||||
#define IOCTL_RESP_TIMEOUT 2000
|
||||
|
||||
#define BRCMF_USB_RESET_GETVER_SPINWAIT 100 /* in unit of ms */
|
||||
#define BRCMF_USB_RESET_GETVER_LOOP_CNT 10
|
||||
|
||||
#define BRCMF_POSTBOOT_ID 0xA123 /* ID to detect if dongle
|
||||
has boot up */
|
||||
#define BRCMF_USB_NRXQ 50
|
||||
#define BRCMF_USB_NTXQ 50
|
||||
#define BRCMF_USB_NRXQ 50
|
||||
#define BRCMF_USB_NTXQ 50
|
||||
|
||||
#define CONFIGDESC(usb) (&((usb)->actconfig)->desc)
|
||||
#define IFPTR(usb, idx) ((usb)->actconfig->interface[(idx)])
|
||||
#define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0])
|
||||
#define IFDESC(usb, idx) IFALTS((usb), (idx)).desc
|
||||
#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[(ep)]).desc
|
||||
#define BRCMF_USB_CBCTL_WRITE 0
|
||||
#define BRCMF_USB_CBCTL_READ 1
|
||||
#define BRCMF_USB_MAX_PKT_SIZE 1600
|
||||
|
||||
#define CONTROL_IF 0
|
||||
#define BULK_IF 0
|
||||
|
||||
#define BRCMF_USB_CBCTL_WRITE 0
|
||||
#define BRCMF_USB_CBCTL_READ 1
|
||||
#define BRCMF_USB_MAX_PKT_SIZE 1600
|
||||
|
||||
#define BRCMF_USB_43143_FW_NAME "brcm/brcmfmac43143.bin"
|
||||
#define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin"
|
||||
#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin"
|
||||
#define BRCMF_USB_43143_FW_NAME "brcm/brcmfmac43143.bin"
|
||||
#define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin"
|
||||
#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin"
|
||||
#define BRCMF_USB_43569_FW_NAME "brcm/brcmfmac43569.bin"
|
||||
|
||||
struct brcmf_usb_image {
|
||||
struct list_head list;
|
||||
|
@ -70,7 +62,7 @@ struct brcmf_usbdev_info {
|
|||
struct list_head rx_postq;
|
||||
struct list_head tx_freeq;
|
||||
struct list_head tx_postq;
|
||||
uint rx_pipe, tx_pipe, rx_pipe2;
|
||||
uint rx_pipe, tx_pipe;
|
||||
|
||||
int rx_low_watermark;
|
||||
int tx_low_watermark;
|
||||
|
@ -97,6 +89,7 @@ struct brcmf_usbdev_info {
|
|||
int ctl_completed;
|
||||
wait_queue_head_t ioctl_resp_wait;
|
||||
ulong ctl_op;
|
||||
u8 ifnum;
|
||||
|
||||
struct urb *bulk_urb; /* used for FW download */
|
||||
};
|
||||
|
@ -576,7 +569,6 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
|
|||
static int brcmf_usb_up(struct device *dev)
|
||||
{
|
||||
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
|
||||
u16 ifnum;
|
||||
|
||||
brcmf_dbg(USB, "Enter\n");
|
||||
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP)
|
||||
|
@ -589,21 +581,19 @@ static int brcmf_usb_up(struct device *dev)
|
|||
devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0);
|
||||
devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0);
|
||||
|
||||
ifnum = IFDESC(devinfo->usbdev, CONTROL_IF).bInterfaceNumber;
|
||||
|
||||
/* CTL Write */
|
||||
devinfo->ctl_write.bRequestType =
|
||||
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
|
||||
devinfo->ctl_write.bRequest = 0;
|
||||
devinfo->ctl_write.wValue = cpu_to_le16(0);
|
||||
devinfo->ctl_write.wIndex = cpu_to_le16p(&ifnum);
|
||||
devinfo->ctl_write.wIndex = cpu_to_le16(devinfo->ifnum);
|
||||
|
||||
/* CTL Read */
|
||||
devinfo->ctl_read.bRequestType =
|
||||
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
|
||||
devinfo->ctl_read.bRequest = 1;
|
||||
devinfo->ctl_read.wValue = cpu_to_le16(0);
|
||||
devinfo->ctl_read.wIndex = cpu_to_le16p(&ifnum);
|
||||
devinfo->ctl_read.wIndex = cpu_to_le16(devinfo->ifnum);
|
||||
}
|
||||
brcmf_usb_rx_fill_all(devinfo);
|
||||
return 0;
|
||||
|
@ -642,19 +632,19 @@ brcmf_usb_sync_complete(struct urb *urb)
|
|||
brcmf_usb_ioctl_resp_wake(devinfo);
|
||||
}
|
||||
|
||||
static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
|
||||
void *buffer, int buflen)
|
||||
static int brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
|
||||
void *buffer, int buflen)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
char *tmpbuf;
|
||||
u16 size;
|
||||
|
||||
if ((!devinfo) || (devinfo->ctl_urb == NULL))
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
tmpbuf = kmalloc(buflen, GFP_ATOMIC);
|
||||
if (!tmpbuf)
|
||||
return false;
|
||||
return -ENOMEM;
|
||||
|
||||
size = buflen;
|
||||
devinfo->ctl_urb->transfer_buffer_length = size;
|
||||
|
@ -675,14 +665,16 @@ static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
|
|||
ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
|
||||
if (ret < 0) {
|
||||
brcmf_err("usb_submit_urb failed %d\n", ret);
|
||||
kfree(tmpbuf);
|
||||
return false;
|
||||
goto finalize;
|
||||
}
|
||||
|
||||
ret = brcmf_usb_ioctl_resp_wait(devinfo);
|
||||
memcpy(buffer, tmpbuf, buflen);
|
||||
kfree(tmpbuf);
|
||||
if (!brcmf_usb_ioctl_resp_wait(devinfo))
|
||||
ret = -ETIMEDOUT;
|
||||
else
|
||||
memcpy(buffer, tmpbuf, buflen);
|
||||
|
||||
finalize:
|
||||
kfree(tmpbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -724,6 +716,7 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
|
|||
{
|
||||
struct bootrom_id_le id;
|
||||
u32 loop_cnt;
|
||||
int err;
|
||||
|
||||
brcmf_dbg(USB, "Enter\n");
|
||||
|
||||
|
@ -732,7 +725,9 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
|
|||
mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT);
|
||||
loop_cnt++;
|
||||
id.chip = cpu_to_le32(0xDEAD); /* Get the ID */
|
||||
brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
|
||||
err = brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
|
||||
if ((err) && (err != -ETIMEDOUT))
|
||||
return err;
|
||||
if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID))
|
||||
break;
|
||||
} while (loop_cnt < BRCMF_USB_RESET_GETVER_LOOP_CNT);
|
||||
|
@ -794,8 +789,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
|
|||
}
|
||||
|
||||
/* 1) Prepare USB boot loader for runtime image */
|
||||
brcmf_usb_dl_cmd(devinfo, DL_START, &state,
|
||||
sizeof(struct rdl_state_le));
|
||||
brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state));
|
||||
|
||||
rdlstate = le32_to_cpu(state.state);
|
||||
rdlbytes = le32_to_cpu(state.bytes);
|
||||
|
@ -839,10 +833,10 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
|
|||
dlpos += sendlen;
|
||||
sent += sendlen;
|
||||
}
|
||||
if (!brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
|
||||
sizeof(struct rdl_state_le))) {
|
||||
brcmf_err("DL_GETSTATE Failed xxxx\n");
|
||||
err = -EINVAL;
|
||||
err = brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
|
||||
sizeof(state));
|
||||
if (err) {
|
||||
brcmf_err("DL_GETSTATE Failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -898,13 +892,12 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
|
|||
return -EINVAL;
|
||||
|
||||
/* Check we are runnable */
|
||||
brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
|
||||
sizeof(struct rdl_state_le));
|
||||
state.state = 0;
|
||||
brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, sizeof(state));
|
||||
|
||||
/* Start the image */
|
||||
if (state.state == cpu_to_le32(DL_RUNNABLE)) {
|
||||
if (!brcmf_usb_dl_cmd(devinfo, DL_GO, &state,
|
||||
sizeof(struct rdl_state_le)))
|
||||
if (brcmf_usb_dl_cmd(devinfo, DL_GO, &state, sizeof(state)))
|
||||
return -ENODEV;
|
||||
if (brcmf_usb_resetcfg(devinfo))
|
||||
return -ENODEV;
|
||||
|
@ -928,6 +921,9 @@ static bool brcmf_usb_chip_support(int chipid, int chiprev)
|
|||
return (chiprev == 3);
|
||||
case 43242:
|
||||
return true;
|
||||
case 43566:
|
||||
case 43569:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1028,6 +1024,9 @@ static const char *brcmf_usb_get_fwname(struct brcmf_usbdev_info *devinfo)
|
|||
return BRCMF_USB_43236_FW_NAME;
|
||||
case 43242:
|
||||
return BRCMF_USB_43242_FW_NAME;
|
||||
case 43566:
|
||||
case 43569:
|
||||
return BRCMF_USB_43569_FW_NAME;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1221,15 +1220,15 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
|
|||
static int
|
||||
brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
int ep;
|
||||
struct usb_device *usb = interface_to_usbdev(intf);
|
||||
struct brcmf_usbdev_info *devinfo;
|
||||
struct usb_interface_descriptor *desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
int ret = 0;
|
||||
struct usb_device *usb = interface_to_usbdev(intf);
|
||||
int num_of_eps;
|
||||
u8 endpoint_num;
|
||||
struct brcmf_usbdev_info *devinfo;
|
||||
u32 num_of_eps;
|
||||
u8 endpoint_num, ep;
|
||||
|
||||
brcmf_dbg(USB, "Enter\n");
|
||||
brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct);
|
||||
|
||||
devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC);
|
||||
if (devinfo == NULL)
|
||||
|
@ -1237,92 +1236,71 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
|
||||
devinfo->usbdev = usb;
|
||||
devinfo->dev = &usb->dev;
|
||||
|
||||
usb_set_intfdata(intf, devinfo);
|
||||
|
||||
/* Check that the device supports only one configuration */
|
||||
if (usb->descriptor.bNumConfigurations != 1) {
|
||||
ret = -1;
|
||||
brcmf_err("Number of configurations: %d not supported\n",
|
||||
usb->descriptor.bNumConfigurations);
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
|
||||
ret = -1;
|
||||
if ((usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) &&
|
||||
(usb->descriptor.bDeviceClass != USB_CLASS_MISC) &&
|
||||
(usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS_CONTROLLER)) {
|
||||
brcmf_err("Device class: 0x%x not supported\n",
|
||||
usb->descriptor.bDeviceClass);
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only the BDC interface configuration is supported:
|
||||
* Device class: USB_CLASS_VENDOR_SPEC
|
||||
* if0 class: USB_CLASS_VENDOR_SPEC
|
||||
* if0/ep0: control
|
||||
* if0/ep1: bulk in
|
||||
* if0/ep2: bulk out (ok if swapped with bulk in)
|
||||
*/
|
||||
if (CONFIGDESC(usb)->bNumInterfaces != 1) {
|
||||
ret = -1;
|
||||
desc = &intf->altsetting[0].desc;
|
||||
if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
|
||||
(desc->bInterfaceSubClass != 2) ||
|
||||
(desc->bInterfaceProtocol != 0xff)) {
|
||||
brcmf_err("non WLAN interface %d: 0x%x:0x%x:0x%x\n",
|
||||
desc->bInterfaceNumber, desc->bInterfaceClass,
|
||||
desc->bInterfaceSubClass, desc->bInterfaceProtocol);
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check interface */
|
||||
if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
|
||||
IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 ||
|
||||
IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) {
|
||||
brcmf_err("invalid control interface: class %d, subclass %d, proto %d\n",
|
||||
IFDESC(usb, CONTROL_IF).bInterfaceClass,
|
||||
IFDESC(usb, CONTROL_IF).bInterfaceSubClass,
|
||||
IFDESC(usb, CONTROL_IF).bInterfaceProtocol);
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check control endpoint */
|
||||
endpoint = &IFEPDESC(usb, CONTROL_IF, 0);
|
||||
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
||||
!= USB_ENDPOINT_XFER_INT) {
|
||||
brcmf_err("invalid control endpoint %d\n",
|
||||
endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
devinfo->rx_pipe = 0;
|
||||
devinfo->rx_pipe2 = 0;
|
||||
devinfo->tx_pipe = 0;
|
||||
num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1;
|
||||
|
||||
/* Check data endpoints and get pipes */
|
||||
for (ep = 1; ep <= num_of_eps; ep++) {
|
||||
endpoint = &IFEPDESC(usb, BULK_IF, ep);
|
||||
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
|
||||
USB_ENDPOINT_XFER_BULK) {
|
||||
brcmf_err("invalid data endpoint %d\n", ep);
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
endpoint_num = endpoint->bEndpointAddress &
|
||||
USB_ENDPOINT_NUMBER_MASK;
|
||||
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
||||
== USB_DIR_IN) {
|
||||
if (!devinfo->rx_pipe) {
|
||||
num_of_eps = desc->bNumEndpoints;
|
||||
for (ep = 0; ep < num_of_eps; ep++) {
|
||||
endpoint = &intf->altsetting[0].endpoint[ep].desc;
|
||||
endpoint_num = usb_endpoint_num(endpoint);
|
||||
if (!usb_endpoint_xfer_bulk(endpoint))
|
||||
continue;
|
||||
if (usb_endpoint_dir_in(endpoint)) {
|
||||
if (!devinfo->rx_pipe)
|
||||
devinfo->rx_pipe =
|
||||
usb_rcvbulkpipe(usb, endpoint_num);
|
||||
} else {
|
||||
devinfo->rx_pipe2 =
|
||||
usb_rcvbulkpipe(usb, endpoint_num);
|
||||
}
|
||||
} else {
|
||||
devinfo->tx_pipe = usb_sndbulkpipe(usb, endpoint_num);
|
||||
if (!devinfo->tx_pipe)
|
||||
devinfo->tx_pipe =
|
||||
usb_sndbulkpipe(usb, endpoint_num);
|
||||
}
|
||||
}
|
||||
if (devinfo->rx_pipe == 0) {
|
||||
brcmf_err("No RX (in) Bulk EP found\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
if (devinfo->tx_pipe == 0) {
|
||||
brcmf_err("No TX (out) Bulk EP found\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
devinfo->ifnum = desc->bInterfaceNumber;
|
||||
|
||||
if (usb->speed == USB_SPEED_SUPER)
|
||||
brcmf_dbg(USB, "Broadcom super speed USB wireless device detected\n");
|
||||
brcmf_dbg(USB, "Broadcom super speed USB WLAN interface detected\n");
|
||||
else if (usb->speed == USB_SPEED_HIGH)
|
||||
brcmf_dbg(USB, "Broadcom high speed USB wireless device detected\n");
|
||||
brcmf_dbg(USB, "Broadcom high speed USB WLAN interface detected\n");
|
||||
else
|
||||
brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n");
|
||||
brcmf_dbg(USB, "Broadcom full speed USB WLAN interface detected\n");
|
||||
|
||||
ret = brcmf_usb_probe_cb(devinfo);
|
||||
if (ret)
|
||||
|
@ -1332,11 +1310,9 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
brcmf_err("failed with errno %d\n", ret);
|
||||
kfree(devinfo);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1381,6 +1357,7 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf)
|
|||
{
|
||||
struct usb_device *usb = interface_to_usbdev(intf);
|
||||
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
|
||||
|
||||
brcmf_dbg(USB, "Enter\n");
|
||||
|
||||
return brcmf_fw_get_firmwares(&usb->dev, 0,
|
||||
|
@ -1392,12 +1369,14 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf)
|
|||
#define BRCMF_USB_DEVICE_ID_43143 0xbd1e
|
||||
#define BRCMF_USB_DEVICE_ID_43236 0xbd17
|
||||
#define BRCMF_USB_DEVICE_ID_43242 0xbd1f
|
||||
#define BRCMF_USB_DEVICE_ID_43569 0xbd27
|
||||
#define BRCMF_USB_DEVICE_ID_BCMFW 0x0bdc
|
||||
|
||||
static struct usb_device_id brcmf_usb_devid_table[] = {
|
||||
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43143) },
|
||||
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) },
|
||||
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43242) },
|
||||
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43569) },
|
||||
/* special entry for device with firmware loaded and running */
|
||||
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) },
|
||||
{ }
|
||||
|
@ -1407,6 +1386,7 @@ MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
|
|||
MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_USB_43569_FW_NAME);
|
||||
|
||||
static struct usb_driver brcmf_usbdrvr = {
|
||||
.name = KBUILD_MODNAME,
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2014 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/vmalloc.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <brcmu_wifi.h>
|
||||
#include "fwil_types.h"
|
||||
#include "dhd.h"
|
||||
#include "p2p.h"
|
||||
#include "dhd_dbg.h"
|
||||
#include "wl_cfg80211.h"
|
||||
#include "vendor.h"
|
||||
#include "fwil.h"
|
||||
|
||||
static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int len)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
struct net_device *ndev = cfg_to_ndev(cfg);
|
||||
const struct brcmf_vndr_dcmd_hdr *cmdhdr = data;
|
||||
struct sk_buff *reply;
|
||||
int ret, payload, ret_len;
|
||||
void *dcmd_buf = NULL, *wr_pointer;
|
||||
u16 msglen, maxmsglen = PAGE_SIZE - 0x100;
|
||||
|
||||
brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set,
|
||||
cmdhdr->len);
|
||||
|
||||
len -= sizeof(struct brcmf_vndr_dcmd_hdr);
|
||||
ret_len = cmdhdr->len;
|
||||
if (ret_len > 0 || len > 0) {
|
||||
if (len > BRCMF_DCMD_MAXLEN) {
|
||||
brcmf_err("oversize input buffer %d\n", len);
|
||||
len = BRCMF_DCMD_MAXLEN;
|
||||
}
|
||||
if (ret_len > BRCMF_DCMD_MAXLEN) {
|
||||
brcmf_err("oversize return buffer %d\n", ret_len);
|
||||
ret_len = BRCMF_DCMD_MAXLEN;
|
||||
}
|
||||
payload = max(ret_len, len) + 1;
|
||||
dcmd_buf = vzalloc(payload);
|
||||
if (NULL == dcmd_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(dcmd_buf, (void *)cmdhdr + cmdhdr->offset, len);
|
||||
*(char *)(dcmd_buf + len) = '\0';
|
||||
}
|
||||
|
||||
if (cmdhdr->set)
|
||||
ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), cmdhdr->cmd,
|
||||
dcmd_buf, ret_len);
|
||||
else
|
||||
ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), cmdhdr->cmd,
|
||||
dcmd_buf, ret_len);
|
||||
if (ret != 0)
|
||||
goto exit;
|
||||
|
||||
wr_pointer = dcmd_buf;
|
||||
while (ret_len > 0) {
|
||||
msglen = ret_len > maxmsglen ? maxmsglen : ret_len;
|
||||
ret_len -= msglen;
|
||||
payload = msglen + sizeof(msglen);
|
||||
reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
|
||||
if (NULL == reply) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nla_put(reply, BRCMF_NLATTR_DATA, msglen, wr_pointer) ||
|
||||
nla_put_u16(reply, BRCMF_NLATTR_LEN, msglen)) {
|
||||
kfree_skb(reply);
|
||||
ret = -ENOBUFS;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = cfg80211_vendor_cmd_reply(reply);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
wr_pointer += msglen;
|
||||
}
|
||||
|
||||
exit:
|
||||
vfree(dcmd_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct wiphy_vendor_command brcmf_vendor_cmds[] = {
|
||||
{
|
||||
{
|
||||
.vendor_id = BROADCOM_OUI,
|
||||
.subcmd = BRCMF_VNDR_CMDS_DCMD
|
||||
},
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_NETDEV,
|
||||
.doit = brcmf_cfg80211_vndr_cmds_dcmd_handler
|
||||
},
|
||||
};
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2014 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 _vendor_h_
|
||||
#define _vendor_h_
|
||||
|
||||
#define BROADCOM_OUI 0x001018
|
||||
|
||||
enum brcmf_vndr_cmds {
|
||||
BRCMF_VNDR_CMDS_UNSPEC,
|
||||
BRCMF_VNDR_CMDS_DCMD,
|
||||
BRCMF_VNDR_CMDS_LAST
|
||||
};
|
||||
|
||||
/**
|
||||
* enum brcmf_nlattrs - nl80211 message attributes
|
||||
*
|
||||
* @BRCMF_NLATTR_LEN: message body length
|
||||
* @BRCMF_NLATTR_DATA: message body
|
||||
*/
|
||||
enum brcmf_nlattrs {
|
||||
BRCMF_NLATTR_UNSPEC,
|
||||
|
||||
BRCMF_NLATTR_LEN,
|
||||
BRCMF_NLATTR_DATA,
|
||||
|
||||
__BRCMF_NLATTR_AFTER_LAST,
|
||||
BRCMF_NLATTR_MAX = __BRCMF_NLATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_vndr_dcmd_hdr - message header for cfg80211 vendor command dcmd
|
||||
* support
|
||||
*
|
||||
* @cmd: common dongle cmd definition
|
||||
* @len: length of expecting return buffer
|
||||
* @offset: offset of data buffer
|
||||
* @set: get or set request(optional)
|
||||
* @magic: magic number for verification
|
||||
*/
|
||||
struct brcmf_vndr_dcmd_hdr {
|
||||
uint cmd;
|
||||
int len;
|
||||
uint offset;
|
||||
uint set;
|
||||
uint magic;
|
||||
};
|
||||
|
||||
extern const struct wiphy_vendor_command brcmf_vendor_cmds[];
|
||||
|
||||
#endif /* _vendor_h_ */
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
|
@ -33,6 +34,7 @@
|
|||
#include "btcoex.h"
|
||||
#include "wl_cfg80211.h"
|
||||
#include "fwil.h"
|
||||
#include "vendor.h"
|
||||
|
||||
#define BRCMF_SCAN_IE_LEN_MAX 2048
|
||||
#define BRCMF_PNO_VERSION 2
|
||||
|
@ -588,6 +590,12 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
|
|||
}
|
||||
}
|
||||
|
||||
static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
|
||||
{
|
||||
if ((brcmf_get_chip_info(ifp) >> 4) == 0x4329)
|
||||
brcmf_set_mpc(ifp, mpc);
|
||||
}
|
||||
|
||||
void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
|
||||
{
|
||||
s32 err = 0;
|
||||
|
@ -641,7 +649,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
|
|||
brcmf_err("Scan abort failed\n");
|
||||
}
|
||||
|
||||
brcmf_set_mpc(ifp, 1);
|
||||
brcmf_scan_config_mpc(ifp, 1);
|
||||
|
||||
/*
|
||||
* e-scan can be initiated by scheduled scan
|
||||
|
@ -920,7 +928,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
|
|||
brcmf_err("error (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
brcmf_set_mpc(ifp, 0);
|
||||
brcmf_scan_config_mpc(ifp, 0);
|
||||
results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
|
||||
results->version = 0;
|
||||
results->count = 0;
|
||||
|
@ -928,7 +936,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
|
|||
|
||||
err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
|
||||
if (err)
|
||||
brcmf_set_mpc(ifp, 1);
|
||||
brcmf_scan_config_mpc(ifp, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1019,7 +1027,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
|
|||
brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
|
||||
goto scan_out;
|
||||
}
|
||||
brcmf_set_mpc(ifp, 0);
|
||||
brcmf_scan_config_mpc(ifp, 0);
|
||||
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
|
||||
&sr->ssid_le, sizeof(sr->ssid_le));
|
||||
if (err) {
|
||||
|
@ -1029,7 +1037,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
|
|||
else
|
||||
brcmf_err("WLC_SCAN error (%d)\n", err);
|
||||
|
||||
brcmf_set_mpc(ifp, 1);
|
||||
brcmf_scan_config_mpc(ifp, 1);
|
||||
goto scan_out;
|
||||
}
|
||||
}
|
||||
|
@ -1331,7 +1339,6 @@ static s32
|
|||
brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
|
||||
{
|
||||
struct brcmf_if *ifp = netdev_priv(ndev);
|
||||
s32 err = 0;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
if (!check_vif_up(ifp->vif))
|
||||
|
@ -1341,7 +1348,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
|
|||
|
||||
brcmf_dbg(TRACE, "Exit\n");
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 brcmf_set_wpa_version(struct net_device *ndev,
|
||||
|
@ -2388,7 +2395,6 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
|
|||
struct cfg80211_bss *bss;
|
||||
struct ieee80211_supported_band *band;
|
||||
struct brcmu_chan ch;
|
||||
s32 err = 0;
|
||||
u16 channel;
|
||||
u32 freq;
|
||||
u16 notify_capability;
|
||||
|
@ -2438,7 +2444,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
|
|||
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct brcmf_bss_info_le *
|
||||
|
@ -2690,7 +2696,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
|
|||
{
|
||||
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
|
||||
s32 status;
|
||||
s32 err = 0;
|
||||
struct brcmf_escan_result_le *escan_result_le;
|
||||
struct brcmf_bss_info_le *bss_info_le;
|
||||
struct brcmf_bss_info_le *bss = NULL;
|
||||
|
@ -2781,7 +2786,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
|
|||
status);
|
||||
}
|
||||
exit:
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
|
||||
|
@ -3260,35 +3265,6 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
static int brcmf_cfg80211_testmode(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
void *data, int len)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
struct net_device *ndev = cfg_to_ndev(cfg);
|
||||
struct brcmf_dcmd *dcmd = data;
|
||||
struct sk_buff *reply;
|
||||
int ret;
|
||||
|
||||
brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
|
||||
dcmd->buf, dcmd->len);
|
||||
|
||||
if (dcmd->set)
|
||||
ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
|
||||
dcmd->buf, dcmd->len);
|
||||
else
|
||||
ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
|
||||
dcmd->buf, dcmd->len);
|
||||
if (ret == 0) {
|
||||
reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
|
||||
nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
|
||||
ret = cfg80211_testmode_reply(reply);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
|
||||
{
|
||||
s32 err;
|
||||
|
@ -3507,7 +3483,6 @@ static s32
|
|||
brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
|
||||
struct parsed_vndr_ies *vndr_ies)
|
||||
{
|
||||
s32 err = 0;
|
||||
struct brcmf_vs_tlv *vndrie;
|
||||
struct brcmf_tlv *ie;
|
||||
struct parsed_vndr_ie_info *parsed_info;
|
||||
|
@ -3560,7 +3535,7 @@ brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
|
|||
ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
|
||||
TLV_HDR_LEN);
|
||||
}
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32
|
||||
|
@ -4307,7 +4282,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
|
|||
.crit_proto_start = brcmf_cfg80211_crit_proto_start,
|
||||
.crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
|
||||
.tdls_oper = brcmf_cfg80211_tdls_oper,
|
||||
CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
|
||||
};
|
||||
|
||||
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
|
||||
|
@ -4412,6 +4386,11 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
|
|||
brcmf_dbg(INFO, "Registering custom regulatory\n");
|
||||
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
|
||||
wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
|
||||
|
||||
/* vendor commands/events support */
|
||||
wiphy->vendor_commands = brcmf_vendor_cmds;
|
||||
wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
|
||||
|
||||
err = wiphy_register(wiphy);
|
||||
if (err < 0) {
|
||||
brcmf_err("Could not register wiphy device (%d)\n", err);
|
||||
|
@ -4650,7 +4629,6 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
|
|||
struct brcmf_if *ifp = netdev_priv(ndev);
|
||||
struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
|
||||
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
|
||||
s32 err = 0;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
|
@ -4676,7 +4654,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
|
|||
completed ? "succeeded" : "failed");
|
||||
}
|
||||
brcmf_dbg(TRACE, "Exit\n");
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32
|
||||
|
@ -4768,7 +4746,6 @@ brcmf_notify_roaming_status(struct brcmf_if *ifp,
|
|||
const struct brcmf_event_msg *e, void *data)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
|
||||
s32 err = 0;
|
||||
u32 event = e->event_code;
|
||||
u32 status = e->status;
|
||||
|
||||
|
@ -4779,7 +4756,7 @@ brcmf_notify_roaming_status(struct brcmf_if *ifp,
|
|||
brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
|
||||
}
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32
|
||||
|
@ -5057,6 +5034,9 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
|
|||
err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
|
||||
BRCMF_OBSS_COEX_AUTO);
|
||||
}
|
||||
/* clear for now and rely on update later */
|
||||
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.ht_supported = false;
|
||||
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap = 0;
|
||||
|
||||
err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
|
||||
if (err) {
|
||||
|
@ -5625,16 +5605,15 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
|
|||
return wdev->iftype;
|
||||
}
|
||||
|
||||
u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
|
||||
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state)
|
||||
{
|
||||
struct brcmf_cfg80211_vif *vif;
|
||||
bool result = 0;
|
||||
|
||||
list_for_each_entry(vif, &cfg->vif_list, list) {
|
||||
if (test_bit(state, &vif->sme_state))
|
||||
result++;
|
||||
return true;
|
||||
}
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
|
||||
|
|
|
@ -477,7 +477,7 @@ const struct brcmf_tlv *
|
|||
brcmf_parse_tlvs(const void *buf, int buflen, uint key);
|
||||
u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
|
||||
struct ieee80211_channel *ch);
|
||||
u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state);
|
||||
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state);
|
||||
void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
|
||||
struct brcmf_cfg80211_vif *vif);
|
||||
bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
|
||||
|
|
|
@ -1538,11 +1538,7 @@ static s8
|
|||
wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,
|
||||
u8 rate)
|
||||
{
|
||||
s8 offset = 0;
|
||||
|
||||
if (!pi->user_txpwr_at_rfport)
|
||||
return offset;
|
||||
return offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
|
||||
|
|
|
@ -53,9 +53,10 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan)
|
|||
|
||||
int cw1200_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
struct ieee80211_scan_request *hw_req)
|
||||
{
|
||||
struct cw1200_common *priv = hw->priv;
|
||||
struct cfg80211_scan_request *req = &hw_req->req;
|
||||
struct wsm_template_frame frame = {
|
||||
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@ struct cw1200_scan {
|
|||
|
||||
int cw1200_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req);
|
||||
struct ieee80211_scan_request *hw_req);
|
||||
void cw1200_scan_work(struct work_struct *work);
|
||||
void cw1200_scan_timeout(struct work_struct *work);
|
||||
void cw1200_clear_recent_scan_work(struct work_struct *work);
|
||||
|
|
|
@ -2289,7 +2289,6 @@ static int cw1200_upload_null(struct cw1200_common *priv)
|
|||
|
||||
static int cw1200_upload_qosnull(struct cw1200_common *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
/* TODO: This needs to be implemented
|
||||
|
||||
struct wsm_template_frame frame = {
|
||||
|
@ -2306,7 +2305,7 @@ static int cw1200_upload_qosnull(struct cw1200_common *priv)
|
|||
dev_kfree_skb(frame.skb);
|
||||
|
||||
*/
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cw1200_enable_beaconing(struct cw1200_common *priv,
|
||||
|
|
|
@ -100,8 +100,7 @@ static inline void libipw_networks_free(struct libipw_device *ieee)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < MAX_NETWORK_COUNT; i++) {
|
||||
if (ieee->networks[i]->ibss_dfs)
|
||||
kfree(ieee->networks[i]->ibss_dfs);
|
||||
kfree(ieee->networks[i]->ibss_dfs);
|
||||
kfree(ieee->networks[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1572,8 +1572,9 @@ il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif)
|
|||
|
||||
int
|
||||
il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
struct ieee80211_scan_request *hw_req)
|
||||
{
|
||||
struct cfg80211_scan_request *req = &hw_req->req;
|
||||
struct il_priv *il = hw->priv;
|
||||
int ret;
|
||||
|
||||
|
|
|
@ -1787,7 +1787,7 @@ int il_scan_cancel(struct il_priv *il);
|
|||
int il_scan_cancel_timeout(struct il_priv *il, unsigned long ms);
|
||||
void il_force_scan_end(struct il_priv *il);
|
||||
int il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req);
|
||||
struct ieee80211_scan_request *hw_req);
|
||||
void il_internal_short_hw_scan(struct il_priv *il);
|
||||
int il_force_reset(struct il_priv *il, bool external);
|
||||
u16 il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame,
|
||||
|
|
|
@ -1495,9 +1495,10 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
|
|||
|
||||
static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
struct ieee80211_scan_request *hw_req)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
struct cfg80211_scan_request *req = &hw_req->req;
|
||||
int ret;
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "enter\n");
|
||||
|
|
|
@ -1556,9 +1556,10 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
|
|||
|
||||
static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
struct ieee80211_scan_request *hw_req)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct cfg80211_scan_request *req = &hw_req->req;
|
||||
int ret;
|
||||
|
||||
if (req->n_channels == 0 ||
|
||||
|
@ -1847,7 +1848,7 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
|
|||
static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies)
|
||||
struct ieee80211_scan_ies *ies)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
int ret;
|
||||
|
|
|
@ -867,7 +867,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
|
|||
int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies);
|
||||
struct ieee80211_scan_ies *ies);
|
||||
int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
|
||||
struct cfg80211_sched_scan_request *req);
|
||||
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
||||
|
|
|
@ -204,7 +204,8 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
|
|||
*/
|
||||
static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
|
||||
int n_ssids, const u8 *ssid, int ssid_len,
|
||||
const u8 *ie, int ie_len,
|
||||
const u8 *band_ie, int band_ie_len,
|
||||
const u8 *common_ie, int common_ie_len,
|
||||
int left)
|
||||
{
|
||||
int len = 0;
|
||||
|
@ -244,12 +245,19 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
|
|||
|
||||
len += ssid_len + 2;
|
||||
|
||||
if (WARN_ON(left < ie_len))
|
||||
if (WARN_ON(left < band_ie_len + common_ie_len))
|
||||
return len;
|
||||
|
||||
if (ie && ie_len) {
|
||||
memcpy(pos, ie, ie_len);
|
||||
len += ie_len;
|
||||
if (band_ie && band_ie_len) {
|
||||
memcpy(pos, band_ie, band_ie_len);
|
||||
pos += band_ie_len;
|
||||
len += band_ie_len;
|
||||
}
|
||||
|
||||
if (common_ie && common_ie_len) {
|
||||
memcpy(pos, common_ie, common_ie_len);
|
||||
pos += common_ie_len;
|
||||
len += common_ie_len;
|
||||
}
|
||||
|
||||
return (u16)len;
|
||||
|
@ -383,7 +391,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|||
(struct ieee80211_mgmt *)cmd->data,
|
||||
vif->addr,
|
||||
req->n_ssids, ssid, ssid_len,
|
||||
req->ie, req->ie_len,
|
||||
req->ie, req->ie_len, NULL, 0,
|
||||
mvm->fw->ucode_capa.max_probe_length));
|
||||
|
||||
iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, ¶ms);
|
||||
|
@ -562,7 +570,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
|
|||
|
||||
static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sched_scan_ies *ies,
|
||||
struct ieee80211_scan_ies *ies,
|
||||
enum ieee80211_band band,
|
||||
struct iwl_tx_cmd *cmd,
|
||||
u8 *data)
|
||||
|
@ -578,7 +586,8 @@ static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm,
|
|||
cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data,
|
||||
vif->addr,
|
||||
1, NULL, 0,
|
||||
ies->ie[band], ies->len[band],
|
||||
ies->ies[band], ies->len[band],
|
||||
ies->common_ies, ies->common_ie_len,
|
||||
SCAN_OFFLOAD_PROBE_REQ_SIZE);
|
||||
cmd->len = cpu_to_le16(cmd_len);
|
||||
}
|
||||
|
@ -716,7 +725,7 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
|
|||
int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies)
|
||||
struct ieee80211_scan_ies *ies)
|
||||
{
|
||||
int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
|
||||
int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
|
||||
|
|
|
@ -16,7 +16,7 @@ config LIBERTAS_USB
|
|||
|
||||
config LIBERTAS_CS
|
||||
tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
|
||||
depends on LIBERTAS && PCMCIA
|
||||
depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP
|
||||
---help---
|
||||
A driver for Marvell Libertas 8385 CompactFlash devices.
|
||||
|
||||
|
|
|
@ -1111,6 +1111,7 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
|
|||
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_ACT_SET);
|
||||
cmd.control = 0;
|
||||
|
||||
/* Only v8 and below support setting the preamble */
|
||||
if (priv->fwrelease < 0x09000000) {
|
||||
|
|
|
@ -781,6 +781,36 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan,
|
|||
netif_rx(skb);
|
||||
}
|
||||
|
||||
struct mac80211_hwsim_addr_match_data {
|
||||
u8 addr[ETH_ALEN];
|
||||
bool ret;
|
||||
};
|
||||
|
||||
static void mac80211_hwsim_addr_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mac80211_hwsim_addr_match_data *md = data;
|
||||
|
||||
if (memcmp(mac, md->addr, ETH_ALEN) == 0)
|
||||
md->ret = true;
|
||||
}
|
||||
|
||||
static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct mac80211_hwsim_addr_match_data md = {
|
||||
.ret = false,
|
||||
};
|
||||
|
||||
memcpy(md.addr, addr, ETH_ALEN);
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(data->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
mac80211_hwsim_addr_iter,
|
||||
&md);
|
||||
|
||||
return md.ret;
|
||||
}
|
||||
|
||||
static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
|
||||
struct sk_buff *skb)
|
||||
|
@ -798,8 +828,7 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
|
|||
/* Allow unicast frames to own address if there is a pending
|
||||
* PS-Poll */
|
||||
if (data->ps_poll_pending &&
|
||||
memcmp(data->hw->wiphy->perm_addr, skb->data + 4,
|
||||
ETH_ALEN) == 0) {
|
||||
mac80211_hwsim_addr_match(data, skb->data + 4)) {
|
||||
data->ps_poll_pending = false;
|
||||
return true;
|
||||
}
|
||||
|
@ -809,39 +838,6 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct mac80211_hwsim_addr_match_data {
|
||||
bool ret;
|
||||
const u8 *addr;
|
||||
};
|
||||
|
||||
static void mac80211_hwsim_addr_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mac80211_hwsim_addr_match_data *md = data;
|
||||
if (memcmp(mac, md->addr, ETH_ALEN) == 0)
|
||||
md->ret = true;
|
||||
}
|
||||
|
||||
|
||||
static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct mac80211_hwsim_addr_match_data md;
|
||||
|
||||
if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0)
|
||||
return true;
|
||||
|
||||
md.ret = false;
|
||||
md.addr = addr;
|
||||
ieee80211_iterate_active_interfaces_atomic(data->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
mac80211_hwsim_addr_iter,
|
||||
&md);
|
||||
|
||||
return md.ret;
|
||||
}
|
||||
|
||||
static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
||||
struct sk_buff *my_skb,
|
||||
int dst_portid)
|
||||
|
@ -1740,9 +1736,10 @@ static void hw_scan_work(struct work_struct *work)
|
|||
|
||||
static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
struct ieee80211_scan_request *hw_req)
|
||||
{
|
||||
struct mac80211_hwsim_data *hwsim = hw->priv;
|
||||
struct cfg80211_scan_request *req = &hw_req->req;
|
||||
|
||||
mutex_lock(&hwsim->mutex);
|
||||
if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11ac
|
||||
*
|
||||
* Copyright (C) 2013, Marvell International Ltd.
|
||||
* Copyright (C) 2013-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11ac
|
||||
*
|
||||
* Copyright (C) 2013, Marvell International Ltd.
|
||||
* Copyright (C) 2013-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11h
|
||||
*
|
||||
* Copyright (C) 2013, Marvell International Ltd.
|
||||
* Copyright (C) 2013-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11n
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11n
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11n Aggregation
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11n Aggregation
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11n RX Re-ordering
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11n RX Re-ordering
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (C) 2011, Marvell International Ltd.
|
||||
# Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
#
|
||||
# This software file (the "File") is distributed by Marvell International
|
||||
# Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2011, Marvell International Ltd.
|
||||
# Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
#
|
||||
# This software file (the "File") is distributed by Marvell International
|
||||
# Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
@ -194,6 +194,36 @@ rdeeprom
|
|||
Example:
|
||||
echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0
|
||||
|
||||
hscfg
|
||||
This command is used to debug/simulate host sleep feature using
|
||||
different configuration parameters.
|
||||
|
||||
Usage:
|
||||
echo "<condition> [GPIO# [gap]]]" > hscfg
|
||||
cat hscfg
|
||||
|
||||
where the parameters are,
|
||||
<condition>: bit 0 = 1 -- broadcast data
|
||||
bit 1 = 1 -- unicast data
|
||||
bit 2 = 1 -- mac event
|
||||
bit 3 = 1 -- multicast data
|
||||
[GPIO#]: pin number of GPIO used to wakeup the host.
|
||||
GPIO pin# (e.g. 0-7) or 0xff (interface, e.g. SDIO
|
||||
will be used instead).
|
||||
[gap]: the gap in milliseconds between wakeup signal and
|
||||
wakeup event or 0xff for special setting (host
|
||||
acknowledge required) when GPIO is used to wakeup host.
|
||||
|
||||
Examples:
|
||||
echo "-1" > hscfg : Cancel host sleep mode
|
||||
echo "3" > hscfg : Broadcast and unicast data;
|
||||
Use GPIO and gap set previously
|
||||
echo "2 3" > hscfg : Unicast data and GPIO 3;
|
||||
Use gap set previously
|
||||
echo "2 1 160" > hscfg : Unicast data, GPIO 1 and gap 160 ms
|
||||
echo "2 1 0xff" > hscfg : Unicast data, GPIO 1; Wait for host
|
||||
to ack before sending wakeup event
|
||||
|
||||
getlog
|
||||
This command is used to get the statistics available in the station.
|
||||
Usage:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: CFG80211
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
@ -42,36 +42,6 @@ static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = {
|
|||
.beacon_int_infra_match = true,
|
||||
};
|
||||
|
||||
static const struct ieee80211_regdomain mwifiex_world_regdom_custom = {
|
||||
.n_reg_rules = 7,
|
||||
.alpha2 = "99",
|
||||
.reg_rules = {
|
||||
/* Channel 1 - 11 */
|
||||
REG_RULE(2412-10, 2462+10, 40, 3, 20, 0),
|
||||
/* Channel 12 - 13 */
|
||||
REG_RULE(2467-10, 2472+10, 20, 3, 20,
|
||||
NL80211_RRF_NO_IR),
|
||||
/* Channel 14 */
|
||||
REG_RULE(2484-10, 2484+10, 20, 3, 20,
|
||||
NL80211_RRF_NO_IR |
|
||||
NL80211_RRF_NO_OFDM),
|
||||
/* Channel 36 - 48 */
|
||||
REG_RULE(5180-10, 5240+10, 40, 3, 20,
|
||||
NL80211_RRF_NO_IR),
|
||||
/* Channel 149 - 165 */
|
||||
REG_RULE(5745-10, 5825+10, 40, 3, 20,
|
||||
NL80211_RRF_NO_IR),
|
||||
/* Channel 52 - 64 */
|
||||
REG_RULE(5260-10, 5320+10, 40, 3, 30,
|
||||
NL80211_RRF_NO_IR |
|
||||
NL80211_RRF_DFS),
|
||||
/* Channel 100 - 140 */
|
||||
REG_RULE(5500-10, 5700+10, 40, 3, 30,
|
||||
NL80211_RRF_NO_IR |
|
||||
NL80211_RRF_DFS),
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* This function maps the nl802.11 channel type into driver channel type.
|
||||
*
|
||||
|
@ -151,7 +121,6 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
|
|||
u8 addr[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
u16 pkt_len;
|
||||
u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT;
|
||||
struct timeval tv;
|
||||
|
||||
pkt_len = len + ETH_ALEN;
|
||||
|
||||
|
@ -173,8 +142,7 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
|
|||
len - sizeof(struct ieee80211_hdr_3addr));
|
||||
|
||||
skb->priority = LOW_PRIO_TID;
|
||||
do_gettimeofday(&tv);
|
||||
skb->tstamp = timeval_to_ktime(tv);
|
||||
__net_timestamp(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2483,6 +2451,16 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
|
|||
mef_entry->filter[filt_num].filt_type = TYPE_EQ;
|
||||
if (filt_num)
|
||||
mef_entry->filter[filt_num].filt_action = TYPE_OR;
|
||||
|
||||
filt_num++;
|
||||
mef_entry->filter[filt_num].repeat = 16;
|
||||
memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr,
|
||||
ETH_ALEN);
|
||||
mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] =
|
||||
ETH_ALEN;
|
||||
mef_entry->filter[filt_num].offset = 56;
|
||||
mef_entry->filter[filt_num].filt_type = TYPE_EQ;
|
||||
mef_entry->filter[filt_num].filt_action = TYPE_OR;
|
||||
}
|
||||
|
||||
if (!mef_cfg.criteria)
|
||||
|
@ -2631,7 +2609,8 @@ static int
|
|||
mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *peer, u8 action_code, u8 dialog_token,
|
||||
u16 status_code, u32 peer_capability,
|
||||
const u8 *extra_ies, size_t extra_ies_len)
|
||||
bool initiator, const u8 *extra_ies,
|
||||
size_t extra_ies_len)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
int ret;
|
||||
|
@ -2916,12 +2895,6 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
|||
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
|
||||
WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
|
||||
|
||||
wiphy->regulatory_flags |=
|
||||
REGULATORY_CUSTOM_REG |
|
||||
REGULATORY_STRICT_REG;
|
||||
|
||||
wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
wiphy->wowlan = &mwifiex_wowlan_support;
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: CFG80211
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: Channel, Frequence and Power
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: commands and events
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
@ -273,6 +273,7 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
|
|||
(struct mwifiex_opt_sleep_confirm *)
|
||||
adapter->sleep_cfm->data;
|
||||
struct sk_buff *sleep_cfm_tmp;
|
||||
struct timeval ts;
|
||||
__le32 tmp;
|
||||
|
||||
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
|
||||
|
@ -283,6 +284,14 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
|
|||
(adapter->seq_num, priv->bss_num,
|
||||
priv->bss_type)));
|
||||
|
||||
do_gettimeofday(&ts);
|
||||
dev_dbg(adapter->dev,
|
||||
"cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d, seqno %#x\n",
|
||||
ts.tv_sec, ts.tv_usec, le16_to_cpu(sleep_cfm_buf->command),
|
||||
le16_to_cpu(sleep_cfm_buf->action),
|
||||
le16_to_cpu(sleep_cfm_buf->size),
|
||||
le16_to_cpu(sleep_cfm_buf->seq_num));
|
||||
|
||||
if (adapter->iface_type == MWIFIEX_USB) {
|
||||
sleep_cfm_tmp =
|
||||
dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm)
|
||||
|
@ -457,11 +466,10 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
|
|||
rx_info->bss_type = priv->bss_type;
|
||||
}
|
||||
|
||||
if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) {
|
||||
do_gettimeofday(&tstamp);
|
||||
dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n",
|
||||
tstamp.tv_sec, tstamp.tv_usec, eventcause);
|
||||
} else {
|
||||
do_gettimeofday(&tstamp);
|
||||
dev_dbg(adapter->dev, "EVENT: %lu.%lu: cause: %#x\n",
|
||||
tstamp.tv_sec, tstamp.tv_usec, eventcause);
|
||||
if (eventcause == EVENT_PS_SLEEP || eventcause == EVENT_PS_AWAKE) {
|
||||
/* Handle PS_SLEEP/AWAKE events on STA */
|
||||
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
|
||||
if (!priv)
|
||||
|
@ -960,6 +968,9 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
|
|||
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
|
||||
mwifiex_init_fw_complete(adapter);
|
||||
|
||||
if (adapter->if_ops.fw_dump)
|
||||
adapter->if_ops.fw_dump(adapter);
|
||||
|
||||
if (adapter->if_ops.card_reset)
|
||||
adapter->if_ops.card_reset(adapter);
|
||||
}
|
||||
|
@ -1225,12 +1236,19 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
|
|||
uint16_t result = le16_to_cpu(cmd->result);
|
||||
uint16_t command = le16_to_cpu(cmd->command);
|
||||
uint16_t seq_num = le16_to_cpu(cmd->seq_num);
|
||||
struct timeval ts;
|
||||
|
||||
if (!upld_len) {
|
||||
dev_err(adapter->dev, "%s: cmd size is 0\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
do_gettimeofday(&ts);
|
||||
dev_dbg(adapter->dev,
|
||||
"cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d, len %d, seqno 0x%x\n",
|
||||
ts.tv_sec, ts.tv_usec, command, result, le16_to_cpu(cmd->size),
|
||||
seq_num);
|
||||
|
||||
/* Get BSS number and corresponding priv */
|
||||
priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
|
||||
HostCmd_GET_BSS_TYPE(seq_num));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: debugfs
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
@ -692,6 +692,97 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Proc hscfg file write handler
|
||||
* This function can be used to configure the host sleep parameters.
|
||||
*/
|
||||
static ssize_t
|
||||
mwifiex_hscfg_write(struct file *file, const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mwifiex_private *priv = (void *)file->private_data;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
|
||||
int ret, arg_num;
|
||||
struct mwifiex_ds_hs_cfg hscfg;
|
||||
int conditions = HS_CFG_COND_DEF;
|
||||
u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF;
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(buf, ubuf, buf_size)) {
|
||||
ret = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap);
|
||||
|
||||
memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));
|
||||
|
||||
if (arg_num > 3) {
|
||||
dev_err(priv->adapter->dev, "Too many arguments\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (arg_num >= 1 && arg_num < 3)
|
||||
mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
|
||||
MWIFIEX_SYNC_CMD, &hscfg);
|
||||
|
||||
if (arg_num) {
|
||||
if (conditions == HS_CFG_CANCEL) {
|
||||
mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD);
|
||||
ret = count;
|
||||
goto done;
|
||||
}
|
||||
hscfg.conditions = conditions;
|
||||
}
|
||||
if (arg_num >= 2)
|
||||
hscfg.gpio = gpio;
|
||||
if (arg_num == 3)
|
||||
hscfg.gap = gap;
|
||||
|
||||
hscfg.is_invoke_hostcmd = false;
|
||||
mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
|
||||
MWIFIEX_SYNC_CMD, &hscfg);
|
||||
|
||||
mwifiex_enable_hs(priv->adapter);
|
||||
priv->adapter->hs_enabling = false;
|
||||
ret = count;
|
||||
done:
|
||||
free_page(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Proc hscfg file read handler
|
||||
* This function can be used to read host sleep configuration
|
||||
* parameters from driver.
|
||||
*/
|
||||
static ssize_t
|
||||
mwifiex_hscfg_read(struct file *file, char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mwifiex_private *priv = (void *)file->private_data;
|
||||
unsigned long addr = get_zeroed_page(GFP_KERNEL);
|
||||
char *buf = (char *)addr;
|
||||
int pos, ret;
|
||||
struct mwifiex_ds_hs_cfg hscfg;
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
|
||||
MWIFIEX_SYNC_CMD, &hscfg);
|
||||
|
||||
pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions,
|
||||
hscfg.gpio, hscfg.gap);
|
||||
|
||||
ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
|
||||
|
||||
free_page(addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MWIFIEX_DFS_ADD_FILE(name) do { \
|
||||
if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \
|
||||
|
@ -725,6 +816,7 @@ MWIFIEX_DFS_FILE_READ_OPS(getlog);
|
|||
MWIFIEX_DFS_FILE_READ_OPS(fw_dump);
|
||||
MWIFIEX_DFS_FILE_OPS(regrdwr);
|
||||
MWIFIEX_DFS_FILE_OPS(rdeeprom);
|
||||
MWIFIEX_DFS_FILE_OPS(hscfg);
|
||||
|
||||
/*
|
||||
* This function creates the debug FS directory structure and the files.
|
||||
|
@ -747,6 +839,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
|
|||
MWIFIEX_DFS_ADD_FILE(regrdwr);
|
||||
MWIFIEX_DFS_ADD_FILE(rdeeprom);
|
||||
MWIFIEX_DFS_ADD_FILE(fw_dump);
|
||||
MWIFIEX_DFS_ADD_FILE(hscfg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: generic data structures and APIs
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: ethtool
|
||||
*
|
||||
* Copyright (C) 2013, Marvell International Ltd.
|
||||
* Copyright (C) 2013-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
@ -64,7 +64,90 @@ static int mwifiex_ethtool_set_wol(struct net_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mwifiex_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
struct memory_type_mapping *entry;
|
||||
|
||||
if (!adapter->if_ops.fw_dump)
|
||||
return -ENOTSUPP;
|
||||
|
||||
dump->flag = adapter->curr_mem_idx;
|
||||
dump->version = 1;
|
||||
if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) {
|
||||
entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
|
||||
dump->len = entry->mem_size;
|
||||
} else {
|
||||
dump->len = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mwifiex_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
|
||||
void *buffer)
|
||||
{
|
||||
u8 *p = buffer;
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
struct memory_type_mapping *entry;
|
||||
|
||||
if (!adapter->if_ops.fw_dump)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
|
||||
dev_err(adapter->dev, "firmware dump in progress!!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
|
||||
|
||||
if (!entry->mem_ptr)
|
||||
return -EFAULT;
|
||||
|
||||
memcpy(p, entry->mem_ptr, entry->mem_size);
|
||||
|
||||
entry->mem_size = 0;
|
||||
vfree(entry->mem_ptr);
|
||||
entry->mem_ptr = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mwifiex_set_dump(struct net_device *dev, struct ethtool_dump *val)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
|
||||
if (!adapter->if_ops.fw_dump)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
|
||||
dev_err(adapter->dev, "firmware dump in progress!!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (val->flag == MWIFIEX_FW_DUMP_IDX) {
|
||||
adapter->curr_mem_idx = val->flag;
|
||||
adapter->if_ops.fw_dump(adapter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val->flag < 0 || val->flag >= adapter->num_mem_types)
|
||||
return -EINVAL;
|
||||
|
||||
adapter->curr_mem_idx = val->flag;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ethtool_ops mwifiex_ethtool_ops = {
|
||||
.get_wol = mwifiex_ethtool_get_wol,
|
||||
.set_wol = mwifiex_ethtool_set_wol,
|
||||
.get_dump_flag = mwifiex_get_dump_flag,
|
||||
.get_dump_data = mwifiex_get_dump_data,
|
||||
.set_dump = mwifiex_set_dump,
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: Firmware specific macros & structures
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Marvell Wireless LAN device driver: management IE handling- setting and
|
||||
* deleting IE.
|
||||
*
|
||||
* Copyright (C) 2012, Marvell International Ltd.
|
||||
* Copyright (C) 2012-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: HW/FW Initialization
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
@ -382,6 +382,8 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
|
|||
static void
|
||||
mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (!adapter) {
|
||||
pr_err("%s: adapter is NULL\n", __func__);
|
||||
return;
|
||||
|
@ -396,7 +398,16 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
|
|||
dev_dbg(adapter->dev, "info: free cmd buffer\n");
|
||||
mwifiex_free_cmd_buffer(adapter);
|
||||
|
||||
dev_dbg(adapter->dev, "info: free scan table\n");
|
||||
for (idx = 0; idx < adapter->num_mem_types; idx++) {
|
||||
struct memory_type_mapping *entry =
|
||||
&adapter->mem_type_mapping_tbl[idx];
|
||||
|
||||
if (entry->mem_ptr) {
|
||||
vfree(entry->mem_ptr);
|
||||
entry->mem_ptr = NULL;
|
||||
}
|
||||
entry->mem_size = 0;
|
||||
}
|
||||
|
||||
if (adapter->sleep_cfm)
|
||||
dev_kfree_skb_any(adapter->sleep_cfm);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: ioctl data structures & APIs
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: association and ad-hoc start/join
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Marvell Wireless LAN device driver: major functions
|
||||
*
|
||||
* Copyright (C) 2011, Marvell International Ltd.
|
||||
* Copyright (C) 2011-2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
|
@ -609,7 +609,6 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
struct sk_buff *new_skb;
|
||||
struct mwifiex_txinfo *tx_info;
|
||||
struct timeval tv;
|
||||
|
||||
dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n",
|
||||
jiffies, priv->bss_type, priv->bss_num);
|
||||
|
@ -656,8 +655,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
* firmware for aggregate delay calculation for stats and
|
||||
* MSDU lifetime expiry.
|
||||
*/
|
||||
do_gettimeofday(&tv);
|
||||
skb->tstamp = timeval_to_ktime(tv);
|
||||
__net_timestamp(skb);
|
||||
|
||||
mwifiex_queue_tx_pkt(priv, skb);
|
||||
|
||||
|
@ -881,6 +879,8 @@ mwifiex_add_card(void *card, struct semaphore *sem,
|
|||
goto err_kmalloc;
|
||||
|
||||
INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
|
||||
if (adapter->if_ops.iface_work)
|
||||
INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work);
|
||||
|
||||
/* Register the device. Fill up the private data structure with relevant
|
||||
information from the card. */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue