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

This commit is contained in:
Emmanuel Grumbach 2014-07-06 11:15:30 +03:00
commit 6e55eed8f1
208 changed files with 7160 additions and 3623 deletions

View file

@ -5629,16 +5629,6 @@ F: Documentation/networking/mac80211-injection.txt
F: include/net/mac80211.h F: include/net/mac80211.h
F: net/mac80211/ 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 MACVLAN DRIVER
M: Patrick McHardy <kaber@trash.net> M: Patrick McHardy <kaber@trash.net>
L: netdev@vger.kernel.org L: netdev@vger.kernel.org

View file

@ -220,6 +220,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
#endif #endif
switch (cc->core->bus->chipinfo.id) { switch (cc->core->bus->chipinfo.id) {
case BCMA_CHIP_ID_BCM5357: case BCMA_CHIP_ID_BCM5357:
case BCMA_CHIP_ID_BCM53572:
chip->ngpio = 32; chip->ngpio = 32;
break; break;
default: default:

View file

@ -1955,8 +1955,9 @@ static void at76_dwork_hw_scan(struct work_struct *work)
static int at76_hw_scan(struct ieee80211_hw *hw, static int at76_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, 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_priv *priv = hw->priv;
struct at76_req_scan scan; struct at76_req_scan scan;
u8 *ssid = NULL; u8 *ssid = NULL;

View file

@ -63,6 +63,7 @@ enum ath_op_flags {
ATH_OP_PRIM_STA_VIF, ATH_OP_PRIM_STA_VIF,
ATH_OP_HW_RESET, ATH_OP_HW_RESET,
ATH_OP_SCANNING, ATH_OP_SCANNING,
ATH_OP_MULTI_CHANNEL,
}; };
enum ath_bus_type { enum ath_bus_type {

View file

@ -3137,10 +3137,11 @@ exit:
static int ath10k_hw_scan(struct ieee80211_hw *hw, static int ath10k_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct cfg80211_scan_request *req) struct ieee80211_scan_request *hw_req)
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct cfg80211_scan_request *req = &hw_req->req;
struct wmi_start_scan_arg arg; struct wmi_start_scan_arg arg;
int ret = 0; int ret = 0;
int i; int i;

View file

@ -1285,6 +1285,7 @@ struct ath5k_hw {
#define ATH_STAT_STARTED 3 /* opened & irqs enabled */ #define ATH_STAT_STARTED 3 /* opened & irqs enabled */
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ 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 */ struct ieee80211_channel *curchan; /* current h/w channel */
u16 nvifs; u16 nvifs;

View file

@ -1382,6 +1382,9 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
rxs->flag = 0; rxs->flag = 0;
if (unlikely(rs->rs_status & AR5K_RXERR_MIC)) if (unlikely(rs->rs_status & AR5K_RXERR_MIC))
rxs->flag |= RX_FLAG_MMIC_ERROR; 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 * 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; ah->stats.rx_bytes_count += rs->rs_datalen;
if (unlikely(rs->rs_status)) { if (unlikely(rs->rs_status)) {
unsigned int filters;
if (rs->rs_status & AR5K_RXERR_CRC) if (rs->rs_status & AR5K_RXERR_CRC)
ah->stats.rxerr_crc++; ah->stats.rxerr_crc++;
if (rs->rs_status & AR5K_RXERR_FIFO) 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++; ah->stats.rxerr_phy++;
if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32) if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32)
ah->stats.rxerr_phy_code[rs->rs_phyerr]++; 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) { 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; 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; return false;
} }

View file

@ -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 /* Set the cached hw filter flags, this will later actually
* be set in HW */ * be set in HW */
ah->filter_flags = rfilt; ah->filter_flags = rfilt;
/* Store current FIF filter flags */
ah->fif_filter_flags = *new_flags;
mutex_unlock(&ah->lock); mutex_unlock(&ah->lock);
} }

View file

@ -5,7 +5,8 @@ ath9k-y += beacon.o \
recv.o \ recv.o \
xmit.o \ xmit.o \
link.o \ link.o \
antenna.o antenna.o \
channel.o
ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o

View file

@ -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; 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); 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)) 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); REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);

View file

@ -314,10 +314,17 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
qca953x_1p0_mac_core); qca953x_1p0_mac_core);
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
qca953x_1p0_mac_postamble); qca953x_1p0_mac_postamble);
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], if (AR_SREV_9531_20(ah)) {
qca953x_1p0_baseband_core); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], qca953x_2p0_baseband_core);
qca953x_1p0_baseband_postamble); 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], INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
qca953x_1p0_radio_core); qca953x_1p0_radio_core);
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],

View file

@ -1552,13 +1552,15 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
u8 *ini_reloaded) u8 *ini_reloaded)
{ {
unsigned int regWrites = 0; unsigned int regWrites = 0;
u32 modesIndex; u32 modesIndex, txgain_index;
if (IS_CHAN_5GHZ(chan)) if (IS_CHAN_5GHZ(chan))
modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; modesIndex = IS_CHAN_HT40(chan) ? 2 : 1;
else else
modesIndex = IS_CHAN_HT40(chan) ? 3 : 4; modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;
txgain_index = AR_SREV_9531(ah) ? 1 : modesIndex;
if (modesIndex == ah->modes_index) { if (modesIndex == ah->modes_index) {
*ini_reloaded = false; *ini_reloaded = false;
goto set_rfmode; 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, ar9003_hw_prog_ini(ah, &ah->ini_radio_post_sys2ant,
modesIndex); modesIndex);
REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); REG_WRITE_ARRAY(&ah->iniModesTxGain, txgain_index, regWrites);
if (AR_SREV_9462_20_OR_LATER(ah)) { if (AR_SREV_9462_20_OR_LATER(ah)) {
/* /*

View file

@ -219,7 +219,7 @@ static const u32 qca953x_1p0_baseband_core[][2] = {
{0x00009d04, 0x40206c10}, {0x00009d04, 0x40206c10},
{0x00009d08, 0x009c4060}, {0x00009d08, 0x009c4060},
{0x00009d0c, 0x9883800a}, {0x00009d0c, 0x9883800a},
{0x00009d10, 0x01884061}, {0x00009d10, 0x018848c6},
{0x00009d14, 0x00c0040b}, {0x00009d14, 0x00c0040b},
{0x00009d18, 0x00000000}, {0x00009d18, 0x00000000},
{0x00009e08, 0x0038230c}, {0x00009e08, 0x0038230c},
@ -715,4 +715,203 @@ static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = {
{0x00016448, 0x6c927a70}, {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 */ #endif /* INITVALS_953X_H */

View file

@ -22,6 +22,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/time.h>
#include "common.h" #include "common.h"
#include "debug.h" #include "debug.h"
@ -35,10 +36,7 @@ extern struct ieee80211_ops ath9k_ops;
extern int ath9k_modparam_nohwcrypt; extern int ath9k_modparam_nohwcrypt;
extern int led_blink; extern int led_blink;
extern bool is_ath9k_unloaded; extern bool is_ath9k_unloaded;
extern int ath9k_use_chanctx;
struct ath_config {
u16 txpowlimit;
};
/*************************/ /*************************/
/* Descriptor Management */ /* Descriptor Management */
@ -167,7 +165,6 @@ struct ath_txq {
u32 axq_ampdu_depth; u32 axq_ampdu_depth;
bool stopped; bool stopped;
bool axq_tx_inprogress; bool axq_tx_inprogress;
struct list_head axq_acq;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
u8 txq_headidx; u8 txq_headidx;
u8 txq_tailidx; u8 txq_tailidx;
@ -280,8 +277,9 @@ struct ath_node {
struct ath_tx_control { struct ath_tx_control {
struct ath_txq *txq; struct ath_txq *txq;
struct ath_node *an; struct ath_node *an;
u8 paprd;
struct ieee80211_sta *sta; struct ieee80211_sta *sta;
u8 paprd;
bool force_channel;
}; };
@ -325,6 +323,116 @@ struct ath_rx {
u32 ampdu_ref; 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); int ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc);
u32 ath_calcrxfilter(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_init(struct ath_softc *sc, struct ath_node *an);
void ath_tx_node_cleanup(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(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_tx_init(struct ath_softc *sc, int nbufs);
int ath_txq_update(struct ath_softc *sc, int qnum, int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *q); struct ath9k_tx_queue_info *q);
@ -370,32 +479,47 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
/********/ /********/
struct ath_vif { struct ath_vif {
struct list_head list;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
struct ath_node mcast_node; struct ath_node mcast_node;
int av_bslot; int av_bslot;
bool primary_sta_vif;
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */ __le64 tsf_adjust; /* TSF adjustment for staggered beacons */
struct ath_buf *av_bcbuf; struct ath_buf *av_bcbuf;
struct ath_chanctx *chanctx;
/* P2P Client */ /* P2P Client */
struct ieee80211_noa_data noa; 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 { struct ath9k_vif_iter_data {
u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */ u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */
u8 mask[ETH_ALEN]; /* bssid mask */ u8 mask[ETH_ALEN]; /* bssid mask */
bool has_hw_macaddr; bool has_hw_macaddr;
u8 slottime;
bool beacons;
int naps; /* number of AP vifs */ int naps; /* number of AP vifs */
int nmeshes; /* number of mesh vifs */ int nmeshes; /* number of mesh vifs */
int nstations; /* number of station vifs */ int nstations; /* number of station vifs */
int nwds; /* number of WDS vifs */ int nwds; /* number of WDS vifs */
int nadhocs; /* number of adhoc vifs */ int nadhocs; /* number of adhoc vifs */
struct ieee80211_vif *primary_sta;
}; };
void ath9k_calculate_iter_data(struct ieee80211_hw *hw, void ath9k_calculate_iter_data(struct ath_softc *sc,
struct ieee80211_vif *vif, struct ath_chanctx *ctx,
struct ath9k_vif_iter_data *iter_data); struct ath9k_vif_iter_data *iter_data);
void ath9k_calculate_summary_state(struct ath_softc *sc,
struct ath_chanctx *ctx);
/*******************/ /*******************/
/* Beacon Handling */ /* Beacon Handling */
@ -458,6 +582,7 @@ void ath9k_csa_update(struct ath_softc *sc);
#define ATH_PAPRD_TIMEOUT 100 /* msecs */ #define ATH_PAPRD_TIMEOUT 100 /* msecs */
#define ATH_PLL_WORK_INTERVAL 100 #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_tx_complete_poll_work(struct work_struct *work);
void ath_reset_work(struct work_struct *work); void ath_reset_work(struct work_struct *work);
bool ath_hw_check(struct ath_softc *sc); 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 ath_ps_full_sleep(unsigned long data);
void ath9k_p2p_ps_timer(void *priv); void ath9k_p2p_ps_timer(void *priv);
void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif); 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 */ /* 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_BEACON_SYNC BIT(4)
#define PS_WAIT_FOR_ANI BIT(5) #define PS_WAIT_FOR_ANI BIT(5)
#define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */
struct ath_softc { struct ath_softc {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct device *dev; struct device *dev;
@ -720,6 +848,7 @@ struct ath_softc {
struct mutex mutex; struct mutex mutex;
struct work_struct paprd_work; struct work_struct paprd_work;
struct work_struct hw_reset_work; struct work_struct hw_reset_work;
struct work_struct chanctx_work;
struct completion paprd_complete; struct completion paprd_complete;
wait_queue_head_t tx_wait; wait_queue_head_t tx_wait;
@ -738,23 +867,27 @@ struct ath_softc {
short nvifs; short nvifs;
unsigned long ps_usecount; unsigned long ps_usecount;
struct ath_config config;
struct ath_rx rx; struct ath_rx rx;
struct ath_tx tx; struct ath_tx tx;
struct ath_beacon beacon; 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 #ifdef CONFIG_MAC80211_LEDS
bool led_registered; bool led_registered;
char led_name[32]; char led_name[32];
struct led_classdev led_cdev; struct led_classdev led_cdev;
#endif #endif
struct ath9k_hw_cal_data caldata;
#ifdef CONFIG_ATH9K_DEBUGFS #ifdef CONFIG_ATH9K_DEBUGFS
struct ath9k_debug debug; struct ath9k_debug debug;
#endif #endif
struct ath_beacon_config cur_beacon_conf;
struct delayed_work tx_complete_work; struct delayed_work tx_complete_work;
struct delayed_work hw_pll_work; struct delayed_work hw_pll_work;
struct timer_list sleep_timer; struct timer_list sleep_timer;

View file

@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
u8 chainmask = ah->txchainmask; u8 chainmask = ah->txchainmask;
u8 rate = 0; 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; rate = sband->bitrates[rateidx].hw_value;
if (vif->bss_conf.use_short_preamble) if (vif->bss_conf.use_short_preamble)
rate |= sband->bitrates[rateidx].hw_value_short; 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); 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, static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
struct ieee80211_vif *vif) 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); 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, bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
skb->len, DMA_TO_DEVICE); skb->len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { 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) static int ath9k_beacon_choose_slot(struct ath_softc *sc)
{ {
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
u16 intval; u16 intval;
u32 tsftu; u32 tsftu;
u64 tsf; 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) 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_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_vif *avp = (void *)vif->drv_priv;
struct ath_beacon_config *cur_conf = &avp->chanctx->beacon;
u32 tsfadjust; u32 tsfadjust;
if (avp->av_bslot == 0) if (avp->av_bslot == 0)
@ -374,12 +426,19 @@ void ath9k_beacon_tasklet(unsigned long data)
vif = sc->beacon.bslot[slot]; vif = sc->beacon.bslot[slot];
/* EDMA devices check that in the tx completion function. */ /* EDMA devices check that in the tx completion function. */
if (!edma && ath9k_csa_is_finished(sc, vif)) if (!edma) {
return; 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) if (!vif || !vif->bss_conf.enable_beacon)
return; return;
ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
bf = ath9k_beacon_generate(sc->hw, vif); bf = ath9k_beacon_generate(sc->hw, vif);
if (sc->beacon.bmisscnt != 0) { if (sc->beacon.bmisscnt != 0) {
@ -500,7 +559,6 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct ath_common *common = ath9k_hw_common(sc->sc_ah); 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 (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
if ((vif->type != 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 (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
if ((vif->type == NL80211_IFTYPE_STATION) && if ((vif->type == NL80211_IFTYPE_STATION) &&
test_bit(ATH_OP_BEACONS, &common->op_flags) && test_bit(ATH_OP_BEACONS, &common->op_flags) &&
!avp->primary_sta_vif) { vif != sc->cur_chan->primary_sta) {
ath_dbg(common, CONFIG, ath_dbg(common, CONFIG,
"Beacon already configured for a station interface\n"); "Beacon already configured for a station interface\n");
return false; 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, static void ath9k_cache_beacon_config(struct ath_softc *sc,
struct ath_chanctx *ctx,
struct ieee80211_bss_conf *bss_conf) struct ieee80211_bss_conf *bss_conf)
{ {
struct ath_common *common = ath9k_hw_common(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 = &ctx->beacon;
ath_dbg(common, BEACON, ath_dbg(common, BEACON,
"Caching beacon data for BSS: %pM\n", bss_conf->bssid); "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) u32 changed)
{ {
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 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_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(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; unsigned long flags;
bool skip_beacon = false; bool skip_beacon = false;
if (!ctx)
return;
cur_conf = &avp->chanctx->beacon;
if (vif->type == NL80211_IFTYPE_AP) if (vif->type == NL80211_IFTYPE_AP)
ath9k_set_tsfadjust(sc, vif); ath9k_set_tsfadjust(sc, vif);
if (!ath9k_allow_beacon_config(sc, vif)) if (!ath9k_allow_beacon_config(sc, vif))
return; return;
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { if (vif->type == NL80211_IFTYPE_STATION) {
ath9k_cache_beacon_config(sc, bss_conf); ath9k_cache_beacon_config(sc, ctx, bss_conf);
if (ctx != sc->cur_chan)
return;
ath9k_set_beacon(sc); ath9k_set_beacon(sc);
set_bit(ATH_OP_BEACONS, &common->op_flags); set_bit(ATH_OP_BEACONS, &common->op_flags);
return; return;
@ -593,10 +661,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
cur_conf->enable_beacon = false; cur_conf->enable_beacon = false;
} else if (bss_conf->enable_beacon) { } else if (bss_conf->enable_beacon) {
cur_conf->enable_beacon = true; 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 * Configure the HW beacon registers only when we have a valid
* beacon interval. * 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) void ath9k_set_beacon(struct ath_softc *sc)
{ {
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
switch (sc->sc_ah->opmode) { switch (sc->sc_ah->opmode) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:

View file

@ -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);
}

View file

@ -57,7 +57,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
struct ath9k_beacon_state *bs) struct ath9k_beacon_state *bs)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
int dtim_intval; int dtim_intval, sleepduration;
u64 tsf; u64 tsf;
/* No need to configure beacon if we are not associated */ /* 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). * last beacon we received (which may be none).
*/ */
dtim_intval = conf->intval * conf->dtim_period; dtim_intval = conf->intval * conf->dtim_period;
sleepduration = ah->hw->conf.listen_interval * conf->intval;
/* /*
* Pull nexttbtt forward to reflect the current * 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), bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
conf->intval)); sleepduration));
if (bs->bs_sleepduration > bs->bs_dtimperiod) if (bs->bs_sleepduration > bs->bs_dtimperiod)
bs->bs_sleepduration = bs->bs_dtimperiod; bs->bs_sleepduration = bs->bs_dtimperiod;

View file

@ -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_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_hw *hw = sc->hw;
struct ath9k_vif_iter_data iter_data; struct ath9k_vif_iter_data iter_data;
struct ath_chanctx *ctx;
char buf[512]; char buf[512];
unsigned int len = 0; unsigned int len = 0;
ssize_t retval = 0; ssize_t retval = 0;
unsigned int reg; unsigned int reg;
u32 rxfilter; u32 rxfilter, i;
len += scnprintf(buf + len, sizeof(buf) - len, len += scnprintf(buf + len, sizeof(buf) - len,
"BSSID: %pM\n", common->curbssid); "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"); 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, len += scnprintf(buf + len, sizeof(buf) - len,
"VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i" "VIF-COUNTS: CTX %i AP: %i STA: %i MESH: %i WDS: %i",
" ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", i++, iter_data.naps, iter_data.nstations,
iter_data.naps, iter_data.nstations, iter_data.nmeshes, iter_data.nmeshes, iter_data.nwds);
iter_data.nwds, iter_data.nadhocs, len += scnprintf(buf + len, sizeof(buf) - len,
sc->nvifs, sc->nbcnvifs); " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
iter_data.nadhocs, sc->nvifs, sc->nbcnvifs);
}
if (len > sizeof(buf)) if (len > sizeof(buf))
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_softc *sc = file->private_data;
struct ath_hw *ah = sc->sc_ah; 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 ath_common *common = ath9k_hw_common(ah);
struct ieee80211_conf *conf = &common->hw->conf; struct ieee80211_conf *conf = &common->hw->conf;
u32 len = 0, size = 1500; u32 len = 0, size = 1500;

View file

@ -791,7 +791,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
refdiv = 5; refdiv = 5;
} else { } else {
pll2_divint = 0x11; pll2_divint = 0x11;
pll2_divfrac = 0x26666; pll2_divfrac =
AR_SREV_9531(ah) ? 0x26665 : 0x26666;
refdiv = 1; refdiv = 1;
} }
} }
@ -1730,6 +1731,23 @@ fail:
return -EINVAL; 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, int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool fastcc) 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 saveDefAntenna;
u32 macStaId1; u32 macStaId1;
u64 tsf = 0; u64 tsf = 0;
s64 usec = 0;
int r; int r;
bool start_mci_reset = false; bool start_mci_reset = false;
bool save_fullsleep = ah->chip_fullsleep; 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 */ /* Save TSF before chip reset, a cold reset clears it */
tsf = ath9k_hw_gettsf64(ah); tsf = ath9k_hw_gettsf64(ah);
getrawmonotonic(&ts); getrawmonotonic(&ts);
usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;
saveLedState = REG_READ(ah, AR_CFG_LED) & saveLedState = REG_READ(ah, AR_CFG_LED) &
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | (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 */ /* Restore TSF */
getrawmonotonic(&ts); ath9k_hw_settsf64(ah, tsf + ath9k_hw_get_tsf_offset(&ts, NULL));
usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec;
ath9k_hw_settsf64(ah, tsf + usec);
if (AR_SREV_9280_20_OR_LATER(ah)) if (AR_SREV_9280_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);

View file

@ -1000,6 +1000,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah);
u64 ath9k_hw_gettsf64(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_settsf64(struct ath_hw *ah, u64 tsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah); 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_set_tsfadjust(struct ath_hw *ah, bool set);
void ath9k_hw_init_global_settings(struct ath_hw *ah); void ath9k_hw_init_global_settings(struct ath_hw *ah);
u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);

View file

@ -61,7 +61,7 @@ static int ath9k_ps_enable;
module_param_named(ps_enable, ath9k_ps_enable, int, 0444); module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); 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_param_named(use_chanctx, ath9k_use_chanctx, int, 0444);
MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); 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 */ /* Set tx power */
if (ah->curchan) { 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_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; sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
/* synchronize DFS detector if regulatory domain changed */ /* synchronize DFS detector if regulatory domain changed */
if (sc->dfs_detector != NULL) 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); setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
common->last_rssi = ATH_RSSI_DUMMY_MARKER; common->last_rssi = ATH_RSSI_DUMMY_MARKER;
sc->config.txpowlimit = ATH_TXPOWER_MAX;
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9; sc->beacon.slottime = ATH9K_SLOT_TIME_9;
@ -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->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
sc->tx99_power = MAX_RATE_POWER + 1; sc->tx99_power = MAX_RATE_POWER + 1;
init_waitqueue_head(&sc->tx_wait); 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) { if (!pdata || pdata->use_eeprom) {
ah->ah_flags |= AH_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(&common->cc_lock);
spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_serial_rw);
spin_lock_init(&sc->sc_pm_lock); spin_lock_init(&sc->sc_pm_lock);
spin_lock_init(&sc->chan_lock);
mutex_init(&sc->mutex); mutex_init(&sc->mutex);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, 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); setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc);
INIT_WORK(&sc->hw_reset_work, ath_reset_work); INIT_WORK(&sc->hw_reset_work, ath_reset_work);
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); 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); 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 * 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_cmn_init_crypto(sc->sc_ah);
ath9k_init_misc(sc); ath9k_init_misc(sc);
ath_fill_led_pin(sc); ath_fill_led_pin(sc);
ath_chanctx_init(sc);
if (common->bus_ops->aspm_init) if (common->bus_ops->aspm_init)
common->bus_ops->aspm_init(common); 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) }, { .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[] = { static const struct ieee80211_iface_limit if_dfs_limits[] = {
{ .max = 1, .types = BIT(NL80211_IFTYPE_AP) | { .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
#ifdef CONFIG_MAC80211_MESH #ifdef CONFIG_MAC80211_MESH
@ -672,6 +686,16 @@ static const struct ieee80211_iface_limit if_dfs_limits[] = {
BIT(NL80211_IFTYPE_ADHOC) }, 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[] = { static const struct ieee80211_iface_combination if_comb[] = {
{ {
.limits = if_limits, .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_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_SUPPORTS_RC_TABLE | IEEE80211_HW_SUPPORTS_RC_TABLE |
IEEE80211_HW_QUEUE_CONTROL |
IEEE80211_HW_SUPPORTS_HT_CCK_RATES; IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
if (ath9k_ps_enable) 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_STATION) |
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT); BIT(NL80211_IFTYPE_MESH_POINT);
hw->wiphy->iface_combinations = if_comb;
if (!ath9k_use_chanctx) { if (!ath9k_use_chanctx) {
hw->wiphy->iface_combinations = if_comb;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS); hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS);
} else } else {
hw->wiphy->n_iface_combinations = 1; 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; 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_HAS_CHANNEL_SWITCH;
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 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_rates = 4;
hw->max_listen_interval = 1; hw->max_listen_interval = 10;
hw->max_rate_tries = 10; hw->max_rate_tries = 10;
hw->sta_data_size = sizeof(struct ath_node); hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vif); hw->vif_data_size = sizeof(struct ath_vif);

View file

@ -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]; txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE];
memset(tx_info, 0, sizeof(*tx_info)); 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->flags |= IEEE80211_TX_CTL_NO_ACK;
tx_info->control.rates[0].idx = 0; tx_info->control.rates[0].idx = 0;
tx_info->control.rates[0].count = 1; tx_info->control.rates[0].count = 1;
@ -416,7 +416,7 @@ void ath_start_ani(struct ath_softc *sc)
if (common->disable_ani || if (common->disable_ani ||
!test_bit(ATH_OP_ANI_RUN, &common->op_flags) || !test_bit(ATH_OP_ANI_RUN, &common->op_flags) ||
(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) sc->cur_chan->offchannel)
return; return;
common->ani.longcal_timer = timestamp; 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_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(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 * Check for the various conditions in which ANI has to

File diff suppressed because it is too large Load diff

View file

@ -706,7 +706,7 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
return; return;
if (setchannel) { 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) && if (IS_CHAN_HT40PLUS(ah->curchan) &&
(ah->curchan->channel > caldata->channel) && (ah->curchan->channel > caldata->channel) &&
(ah->curchan->channel <= caldata->channel + 20)) (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; mci_hw->concur_tx = concur_tx;
if (old_concur_tx != mci_hw->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) static void ath9k_mci_stomp_audio(struct ath_softc *sc)

View file

@ -843,6 +843,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENODEV; return -ENODEV;
} }
ath9k_fill_chanctx_ops();
hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
if (!hw) { if (!hw) {
dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); dev_err(&pdev->dev, "No memory for ieee80211_hw\n");

View file

@ -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_HP);
ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP); ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP);
ath_opmode_init(sc); 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) 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) u32 ath_calcrxfilter(struct ath_softc *sc)
{ {
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u32 rfilt; u32 rfilt;
if (config_enabled(CONFIG_ATH9K_TX99)) 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)) if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
rfilt |= ATH9K_RX_FILTER_4ADDRESS; rfilt |= ATH9K_RX_FILTER_4ADDRESS;
if (ath9k_use_chanctx &&
test_bit(ATH_OP_SCANNING, &common->op_flags))
rfilt |= ATH9K_RX_FILTER_BEACON;
return rfilt; return rfilt;
} }
@ -457,7 +462,7 @@ int ath_startrecv(struct ath_softc *sc)
start_recv: start_recv:
ath_opmode_init(sc); 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; 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; sc->ps_flags &= ~PS_BEACON_SYNC;
ath_dbg(common, PS, ath_dbg(common, PS,
"Reconfigure beacon timers based on synchronized timestamp\n"); "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); ath9k_set_beacon(sc);
if (sc->p2p_ps_vif) if (sc->p2p_ps_vif)
ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->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; 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); ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
rx_status->band = ah->curchan->chan->band; rx_status->band = ah->curchan->chan->band;

View file

@ -813,6 +813,7 @@
#define AR_SREV_VERSION_9531 0x500 #define AR_SREV_VERSION_9531 0x500
#define AR_SREV_REVISION_9531_10 0 #define AR_SREV_REVISION_9531_10 0
#define AR_SREV_REVISION_9531_11 1 #define AR_SREV_REVISION_9531_11 1
#define AR_SREV_REVISION_9531_20 2
#define AR_SREV_5416(_ah) \ #define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@ -958,6 +959,9 @@
#define AR_SREV_9531_11(_ah) \ #define AR_SREV_9531_11(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11)) ((_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 */ /* NOTE: When adding chips newer than Peacock, add chip check here */
#define AR_SREV_9580_10_OR_LATER(_ah) \ #define AR_SREV_9580_10_OR_LATER(_ah) \

View file

@ -76,7 +76,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
tx_info = IEEE80211_SKB_CB(skb); tx_info = IEEE80211_SKB_CB(skb);
memset(tx_info, 0, sizeof(*tx_info)); memset(tx_info, 0, sizeof(*tx_info));
rate = &tx_info->control.rates[0]; 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->flags = IEEE80211_TX_CTL_NO_ACK;
tx_info->control.vif = sc->tx99_vif; tx_info->control.vif = sc->tx99_vif;
rate->count = 1; rate->count = 1;

View file

@ -193,6 +193,7 @@ int ath9k_suspend(struct ieee80211_hw *hw,
u32 wow_triggers_enabled = 0; u32 wow_triggers_enabled = 0;
int ret = 0; int ret = 0;
cancel_work_sync(&sc->chanctx_work);
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
ath_cancel_work(sc); ath_cancel_work(sc);

View file

@ -103,9 +103,16 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
ieee80211_tx_status(sc->hw, skb); 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 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) if (tid->sched)
return; return;
@ -117,7 +124,9 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
return; return;
ac->sched = true; 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) 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, static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb) 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); q = skb_get_queue_mapping(skb);
if (txq == sc->tx.uapsdq) 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)) if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames = 0; txq->pending_frames = 0;
hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue;
if (txq->stopped && if (txq->stopped &&
txq->pending_frames < sc->tx.txq_max_pending[q]) { 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; 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); skb_queue_splice_tail(&bf_pending, &tid->retry_q);
if (!an->sleeping) { 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)) if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
tid->ac->clear_ps_filter = true; 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; ac->clear_ps_filter = true;
if (ath_tid_has_buffered(tid)) { if (ath_tid_has_buffered(tid)) {
ath_tx_queue_tid(txq, tid); ath_tx_queue_tid(sc, txq, tid);
ath_txq_schedule(sc, txq); 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; tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
if (ath_tid_has_buffered(tid)) { if (ath_tid_has_buffered(tid)) {
ath_tx_queue_tid(txq, tid); ath_tx_queue_tid(sc, txq, tid);
ath_txq_schedule(sc, txq); 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; txq->axq_link = NULL;
__skb_queue_head_init(&txq->complete_q); __skb_queue_head_init(&txq->complete_q);
INIT_LIST_HEAD(&txq->axq_q); INIT_LIST_HEAD(&txq->axq_q);
INIT_LIST_HEAD(&txq->axq_acq);
spin_lock_init(&txq->axq_lock); spin_lock_init(&txq->axq_lock);
txq->axq_depth = 0; txq->axq_depth = 0;
txq->axq_ampdu_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) int ath_cabq_update(struct ath_softc *sc)
{ {
struct ath9k_tx_queue_info qi; 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; int qnum = sc->beacon.cabq->axq_qnum;
ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); 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); 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. * for transmit until ampdu_depth has reached min Q depth.
*/ */
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) 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_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_ac *ac, *last_ac; struct ath_atx_ac *ac, *last_ac;
struct ath_atx_tid *tid, *last_tid; struct ath_atx_tid *tid, *last_tid;
struct list_head *ac_list;
bool sent = false; bool sent = false;
if (test_bit(ATH_OP_HW_RESET, &common->op_flags) || if (txq->mac80211_qnum < 0)
list_empty(&txq->axq_acq))
return; 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(); rcu_read_lock();
last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list);
while (!list_empty(&txq->axq_acq)) { while (!list_empty(ac_list)) {
bool stop = false; 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); last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
list_del(&ac->list); list_del(&ac->list);
ac->sched = false; ac->sched = false;
@ -1844,7 +1866,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
* are pending for the tid * are pending for the tid
*/ */
if (ath_tid_has_buffered(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) if (stop || tid == last_tid)
break; 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) { if (!list_empty(&ac->tid_q) && !ac->sched) {
ac->sched = true; ac->sched = true;
list_add_tail(&ac->list, &txq->axq_acq); list_add_tail(&ac->list, ac_list);
} }
if (stop) if (stop)
@ -1863,12 +1885,27 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
break; break;
sent = false; sent = false;
last_ac = list_entry(txq->axq_acq.prev, last_ac = list_entry(ac_list->prev,
struct ath_atx_ac, list); struct ath_atx_ac, list);
} }
} }
rcu_read_unlock(); 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_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = txctl->sta; struct ieee80211_sta *sta = txctl->sta;
struct ieee80211_vif *vif = info->control.vif; struct ieee80211_vif *vif = info->control.vif;
struct ath_vif *avp = NULL;
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_txq *txq = txctl->txq; struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL; struct ath_atx_tid *tid = NULL;
struct ath_buf *bf; struct ath_buf *bf;
int q; bool queue;
int q, hw_queue;
int ret; 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); ret = ath_tx_prepare(hw, skb, txctl);
if (ret) if (ret)
return 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); q = skb_get_queue_mapping(skb);
hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue;
ath_txq_lock(sc, txq); ath_txq_lock(sc, txq);
if (txq == sc->tx.txq_map[q] && if (txq == sc->tx.txq_map[q] &&
++txq->pending_frames > sc->tx.txq_max_pending[q] && ++txq->pending_frames > sc->tx.txq_max_pending[q] &&
!txq->stopped) { !txq->stopped) {
ieee80211_stop_queue(sc->hw, q); ieee80211_stop_queue(sc->hw, hw_queue);
txq->stopped = true; 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); 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); ath_txq_unlock(sc, txq);
txq = sc->tx.uapsdq; txq = sc->tx.uapsdq;
ath_txq_lock(sc, txq); ath_txq_lock(sc, txq);
} else if (txctl->an && } else if (txctl->an && queue) {
ieee80211_is_data_present(hdr->frame_control)) {
WARN_ON(tid->ac->txq != txctl->txq); WARN_ON(tid->ac->txq != txctl->txq);
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) 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); TX_STAT_INC(txq->axq_qnum, a_queued_sw);
__skb_queue_tail(&tid->buf_q, skb); __skb_queue_tail(&tid->buf_q, skb);
if (!txctl->an->sleeping) if (!txctl->an->sleeping)
ath_tx_queue_tid(txq, tid); ath_tx_queue_tid(sc, txq, tid);
ath_txq_schedule(sc, txq); ath_txq_schedule(sc, txq);
goto out; goto out;
@ -2244,8 +2304,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int max_duration; int max_duration;
max_duration = max_duration =
sc->cur_beacon_conf.beacon_interval * 1000 * sc->cur_chan->beacon.beacon_interval * 1000 *
sc->cur_beacon_conf.dtim_period / ATH_BCBUF; sc->cur_chan->beacon.dtim_period / ATH_BCBUF;
do { do {
struct ath_frame_info *fi = get_frame_info(skb); 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_processed = true;
sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
ath_chanctx_event(sc, NULL,
ATH_CHANCTX_EVENT_BEACON_SENT);
ath9k_csa_update(sc); ath9k_csa_update(sc);
continue; continue;
} }

View file

@ -104,8 +104,8 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
struct station_info *sinfo) struct station_info *sinfo)
{ {
struct wmi_notify_req_cmd cmd = { struct wmi_notify_req_cmd cmd = {
.cid = cid, .cid = cid,
@ -287,6 +287,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
return -EBUSY; return -EBUSY;
} }
wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
wil->scan_request = request; wil->scan_request = request;
mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);
@ -443,15 +444,15 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
return rc; return rc;
} }
static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct wireless_dev *wdev, struct cfg80211_mgmt_tx_params *params,
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
u64 *cookie)
{ {
const u8 *buf = params->buf; const u8 *buf = params->buf;
size_t len = params->len; size_t len = params->len;
struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int rc; int rc;
bool tx_status = false;
struct ieee80211_mgmt *mgmt_frame = (void *)buf; struct ieee80211_mgmt *mgmt_frame = (void *)buf;
struct wmi_sw_tx_req_cmd *cmd; struct wmi_sw_tx_req_cmd *cmd;
struct { struct {
@ -460,8 +461,10 @@ static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy,
} __packed evt; } __packed evt;
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
if (!cmd) if (!cmd) {
return -ENOMEM; rc = -ENOMEM;
goto out;
}
memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
cmd->len = cpu_to_le16(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, rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
if (rc == 0) if (rc == 0)
rc = evt.evt.status; tx_status = !evt.evt.status;
kfree(cmd); kfree(cmd);
out:
cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
tx_status, GFP_KERNEL);
return rc; return rc;
} }
@ -562,6 +567,34 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
return rc; 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, static int wil_fix_bcon(struct wil6210_priv *wil,
struct cfg80211_beacon_data *bcon) 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 wireless_dev *wdev = ndev->ieee80211_ptr;
struct ieee80211_channel *channel = info->chandef.chan; struct ieee80211_channel *channel = info->chandef.chan;
struct cfg80211_beacon_data *bcon = &info->beacon; struct cfg80211_beacon_data *bcon = &info->beacon;
struct cfg80211_crypto_settings *crypto = &info->crypto;
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
wil_dbg_misc(wil, "%s()\n", __func__);
if (!channel) { if (!channel) {
wil_err(wil, "AP: No channel???\n"); wil_err(wil, "AP: No channel???\n");
return -EINVAL; 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, wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
channel->center_freq, info->privacy ? "secure" : "open"); 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, print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
info->ssid, info->ssid_len); 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_dbg_misc(wil, "Fixed bcon\n");
wil_print_bcon_data(bcon);
}
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
@ -663,6 +707,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
int rc = 0; int rc = 0;
struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_priv *wil = wiphy_to_wil(wiphy);
wil_dbg_misc(wil, "%s()\n", __func__);
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
rc = wmi_pcp_stop(wil); rc = wmi_pcp_stop(wil);

View file

@ -19,6 +19,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/power_supply.h>
#include "wil6210.h" #include "wil6210.h"
#include "txrx.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++) { for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
struct vring *vring = &(wil->vring_tx[i]); struct vring *vring = &(wil->vring_tx[i]);
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
if (vring->va) { if (vring->va) {
int cid = wil->vring2cid_tid[i][0]; int cid = wil->vring2cid_tid[i][0];
int tid = wil->vring2cid_tid[i][1]; 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]; 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); snprintf(name, sizeof(name), "tx_%2d", i);
seq_printf(s, "\n%pM CID %d TID %d\n", seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n",
wil->sta[cid].addr, cid, tid); wil->sta[cid].addr, cid, tid, used, avail,
(int)idle);
wil_print_vring(s, wil, name, vring, '_', 'H'); 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); &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, static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
const char *name, const char *name,
struct dentry *parent, u32 off) 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)) if (IS_ERR_OR_NULL(d))
return -ENODEV; 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)); 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)); 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)); HOSTADDR(RGF_DMA_ITR_CNT_CRL));
return 0; return 0;
@ -397,6 +436,124 @@ static const struct file_operations fops_reset = {
.write = wil_write_file_reset, .write = wil_write_file_reset,
.open = simple_open, .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, &params, 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, static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
const char *prefix) const char *prefix)
@ -600,8 +757,8 @@ static int wil_temp_debugfs_show(struct seq_file *s, void *data)
return 0; return 0;
} }
print_temp(s, "MAC temperature :", t_m); print_temp(s, "T_mac =", t_m);
print_temp(s, "Radio temperature :", t_r); print_temp(s, "T_radio =", t_r);
return 0; return 0;
} }
@ -618,6 +775,130 @@ static const struct file_operations fops_temp = {
.llseek = seq_lseek, .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------------*/ /*---------Station matrix------------*/
static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) 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 else
seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); 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) 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_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
&wil->secure_pcp); &wil->secure_pcp);
wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg,
&wil->status);
wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
HOSTADDR(RGF_USER_USER_ICR)); 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("mem_val", S_IRUGO, dbg, wil, &fops_memread);
debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); 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("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.data = (void * __force)wil->csr + 0;
wil->rgf_blob.size = 0xa000; wil->rgf_blob.size = 0xa000;

View file

@ -208,6 +208,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
/* Rx IRQ will be enabled when NAPI processing finished */ /* Rx IRQ will be enabled when NAPI processing finished */
atomic_inc(&wil->isr_count_rx);
return IRQ_HANDLED; 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 */ /* Tx IRQ will be enabled when NAPI processing finished */
atomic_inc(&wil->isr_count_tx);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -257,6 +259,7 @@ static void wil_notify_fw_error(struct wil6210_priv *wil)
[1] = "EVENT=FW_ERROR", [1] = "EVENT=FW_ERROR",
[2] = NULL, [2] = NULL,
}; };
wil_err(wil, "Notify about firmware error\n");
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
} }

View file

@ -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) static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
{ {
uint i; uint i;
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wil_sta_info *sta = &wil->sta[cid]; 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; sta->data_port_open = false;
if (sta->status != wil_sta_unused) { if (sta->status != wil_sta_unused) {
wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); 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; 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); clear_bit(wil_status_fwconnecting, &wil->status);
break; break;
default: default:
/* AP-like interface and monitor:
* never scan, always connected
*/
if (bssid)
cfg80211_del_sta(ndev, bssid, GFP_KERNEL);
break; break;
} }
} }
@ -465,6 +473,7 @@ void wil_link_on(struct wil6210_priv *wil)
wil_dbg_misc(wil, "%s()\n", __func__); wil_dbg_misc(wil, "%s()\n", __func__);
netif_carrier_on(ndev); netif_carrier_on(ndev);
wil_dbg_misc(wil, "netif_tx_wake : link on\n");
netif_tx_wake_all_queues(ndev); 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__); wil_dbg_misc(wil, "%s()\n", __func__);
netif_tx_stop_all_queues(ndev); netif_tx_stop_all_queues(ndev);
wil_dbg_misc(wil, "netif_tx_stop : link off\n");
netif_carrier_off(ndev); netif_carrier_off(ndev);
} }
@ -552,6 +562,8 @@ static int __wil_down(struct wil6210_priv *wil)
napi_disable(&wil->napi_tx); napi_disable(&wil->napi_tx);
if (wil->scan_request) { if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
wil->scan_request);
del_timer_sync(&wil->scan_timer); del_timer_sync(&wil->scan_timer);
cfg80211_scan_done(wil->scan_request, true); cfg80211_scan_done(wil->scan_request, true);
wil->scan_request = NULL; wil->scan_request = NULL;

View file

@ -15,7 +15,6 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
@ -27,11 +26,22 @@ MODULE_PARM_DESC(use_msi,
" Use MSI interrupt: " " Use MSI interrupt: "
"0 - don't, 1 - (default) - single, or 3"); "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 */ /* Bus ops */
static int wil_if_pcie_enable(struct wil6210_priv *wil) static int wil_if_pcie_enable(struct wil6210_priv *wil)
{ {
struct pci_dev *pdev = wil->pdev; struct pci_dev *pdev = wil->pdev;
int rc; 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); pci_set_master(pdev);
@ -63,6 +73,12 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
wil->n_msi = use_msi; 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); rc = wil6210_init_irq(wil, pdev->irq);
if (rc) if (rc)
goto stop_master; goto stop_master;
@ -71,6 +87,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
rc = wil_reset(wil); rc = wil_reset(wil);
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
if (debug_fw)
rc = 0;
if (rc) if (rc)
goto release_irq; 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); rc = pci_enable_device(pdev);
if (rc) { if (rc) {
dev_err(&pdev->dev, "pci_enable_device failed\n"); dev_err(&pdev->dev,
return -ENODEV; "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 */ /* rollback to err_disable_pdev */
rc = pci_request_region(pdev, 0, WIL_NAME); rc = pci_request_region(pdev, 0, WIL_NAME);

View file

@ -116,6 +116,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
/* frame with out of date sequence number */ /* frame with out of date sequence number */
if (seq_less(seq, r->head_seq_num)) { if (seq_less(seq, r->head_seq_num)) {
r->ssn_last_drop = seq;
dev_kfree_skb(skb); dev_kfree_skb(skb);
goto out; goto out;
} }

View file

@ -525,6 +525,17 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
ndev->stats.rx_bytes += len; ndev->stats.rx_bytes += len;
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; goto found;
} }
wil_err(wil, "Tx while no vrings active?\n"); wil_dbg_txrx(wil, "Tx while no vrings active?\n");
return NULL; 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; int nr_frags = skb_shinfo(skb)->nr_frags;
uint f = 0; uint f = 0;
int vring_index = vring - wil->vring_tx; int vring_index = vring - wil->vring_tx;
struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index];
uint i = swhead; uint i = swhead;
dma_addr_t pa; 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, wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false); (const void *)d, sizeof(*d), false);
if (wil_vring_is_empty(vring)) /* performance monitoring */
txdata->idle += get_cycles() - txdata->last_idle;
/* advance swhead */ /* advance swhead */
wil_vring_advance_head(vring, nr_frags + 1); wil_vring_advance_head(vring, nr_frags + 1);
wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); 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); vring = wil_tx_bcast(wil, skb);
} }
if (!vring) { 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; goto drop;
} }
/* set up vring entry */ /* set up vring entry */
rc = wil_tx_vring(wil, vring, skb); rc = wil_tx_vring(wil, vring, skb);
/* do we still have enough room in the vring? */ /* 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)); netif_tx_stop_all_queues(wil_to_ndev(wil));
wil_dbg_txrx(wil, "netif_tx_stop : ring full\n");
}
switch (rc) { switch (rc) {
case 0: case 0:
@ -1132,8 +1149,16 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
done++; 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)); netif_tx_wake_all_queues(wil_to_ndev(wil));
}
return done; return done;
} }

View file

@ -20,6 +20,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/wireless.h> #include <linux/wireless.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <linux/timex.h>
#define WIL_NAME "wil6210" #define WIL_NAME "wil6210"
@ -251,7 +252,7 @@ struct vring {
*/ */
struct vring_tx_data { struct vring_tx_data {
int enabled; int enabled;
cycles_t idle, last_idle, begin;
}; };
enum { /* for wil6210_priv.status */ enum { /* for wil6210_priv.status */
@ -303,6 +304,7 @@ struct wil_tid_ampdu_rx {
u16 ssn; u16 ssn;
u16 buf_size; u16 buf_size;
u16 timeout; u16 timeout;
u16 ssn_last_drop;
u8 dialog_token; u8 dialog_token;
bool first_time; /* is it 1-st time this buffer used? */ 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} */ struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
/* statistics */ /* statistics */
struct wil6210_stats stats; struct wil6210_stats stats;
atomic_t isr_count_rx, isr_count_tx;
/* debugfs */ /* debugfs */
struct dentry *debug; struct dentry *debug;
struct debugfs_blob_wrapper fw_code_blob; 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_fini_irq(struct wil6210_priv *wil, int irq);
void wil6210_disable_irq(struct wil6210_priv *wil); void wil6210_disable_irq(struct wil6210_priv *wil);
void wil6210_enable_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); int wil6210_debugfs_init(struct wil6210_priv *wil);
void wil6210_debugfs_remove(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); struct wireless_dev *wil_cfg80211_init(struct device *dev);
void wil_wdev_free(struct wil6210_priv *wil); void wil_wdev_free(struct wil6210_priv *wil);

View file

@ -75,6 +75,7 @@ static const struct {
{0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */ {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */
{0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */ {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */
{0x880000, 0x88a000, 0x880000}, /* various RGF */ {0x880000, 0x88a000, 0x880000}, /* various RGF */
{0x88b000, 0x88c000, 0x88b000}, /* Pcie_ext_rgf */
{0x8c0000, 0x949000, 0x8c0000}, /* trivial mapping for upper area */ {0x8c0000, 0x949000, 0x8c0000}, /* trivial mapping for upper area */
/* /*
* 920000..930000 ucode code RAM * 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)) { if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
struct cfg80211_bss *bss; 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, bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
d_len, signal, GFP_KERNEL); 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); bool aborted = (data->status != WMI_SCAN_SUCCESS);
wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); 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); del_timer_sync(&wil->scan_timer);
cfg80211_scan_done(wil->scan_request, aborted); cfg80211_scan_done(wil->scan_request, aborted);
wil->scan_request = NULL; wil->scan_request = NULL;
@ -668,14 +683,12 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
for (n = 0;; n++) { for (n = 0;; n++) {
u16 len; u16 len;
bool q;
r->head = ioread32(wil->csr + HOST_MBOX + r->head = ioread32(wil->csr + HOST_MBOX +
offsetof(struct wil6210_mbox_ctl, rx.head)); offsetof(struct wil6210_mbox_ctl, rx.head));
if (r->tail == r->head) { if (r->tail == r->head)
if (n == 0) break;
wil_dbg_wmi(wil, "No events?\n");
return;
}
wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n", wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n",
r->head, r->tail); r->head, r->tail);
@ -684,14 +697,14 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
sizeof(struct wil6210_mbox_ring_desc)); sizeof(struct wil6210_mbox_ring_desc));
if (d_tail.sync == 0) { if (d_tail.sync == 0) {
wil_err(wil, "Mbox evt not owned by FW?\n"); wil_err(wil, "Mbox evt not owned by FW?\n");
return; break;
} }
/* read cmd header from descriptor */ /* read cmd header from descriptor */
if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) { if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
wil_err(wil, "Mbox evt at 0x%08x?\n", wil_err(wil, "Mbox evt at 0x%08x?\n",
le32_to_cpu(d_tail.addr)); le32_to_cpu(d_tail.addr));
return; break;
} }
len = le16_to_cpu(hdr.len); len = le16_to_cpu(hdr.len);
wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", 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), event.wmi) + len, 4),
GFP_KERNEL); GFP_KERNEL);
if (!evt) if (!evt)
return; break;
evt->event.hdr = hdr; evt->event.hdr = hdr;
cmd = (void *)&evt->event.wmi; 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); spin_lock_irqsave(&wil->wmi_ev_lock, flags);
list_add_tail(&evt->list, &wil->pending_wmi_ev); list_add_tail(&evt->list, &wil->pending_wmi_ev);
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
{ q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
int q = queue_work(wil->wmi_wq, wil_dbg_wmi(wil, "queue_work -> %d\n", q);
&wil->wmi_event_worker);
wil_dbg_wmi(wil, "queue_work -> %d\n", q);
}
} }
if (n > 1) /* normally, 1 event per IRQ should be processed */
wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n); wil_dbg_wmi(wil, "%s -> %d events queued\n", __func__, n);
} }
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,

View file

@ -122,6 +122,15 @@ config B43_PIO
select SSB_BLOCKIO select SSB_BLOCKIO
default y 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 config B43_PHY_N
bool "Support for 802.11n (N-PHY) devices" bool "Support for 802.11n (N-PHY) devices"
depends on B43 depends on B43

View file

@ -1,13 +1,11 @@
b43-y += main.o b43-y += main.o
b43-y += bus.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) += tables_nphy.o
b43-$(CONFIG_B43_PHY_N) += radio_2055.o b43-$(CONFIG_B43_PHY_N) += radio_2055.o
b43-$(CONFIG_B43_PHY_N) += radio_2056.o b43-$(CONFIG_B43_PHY_N) += radio_2056.o
b43-$(CONFIG_B43_PHY_N) += radio_2057.o b43-$(CONFIG_B43_PHY_N) += radio_2057.o
b43-y += phy_common.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_N) += phy_n.o
b43-$(CONFIG_B43_PHY_LP) += phy_lp.o b43-$(CONFIG_B43_PHY_LP) += phy_lp.o
b43-$(CONFIG_B43_PHY_LP) += tables_lpphy.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-$(CONFIG_B43_PHY_LCN) += phy_lcn.o tables_phy_lcn.o
b43-y += sysfs.o b43-y += sysfs.o
b43-y += xmit.o b43-y += xmit.o
b43-y += lo.o
b43-y += wa.o
b43-y += dma.o b43-y += dma.o
b43-y += pio.o b43-y += pio.o
b43-y += rfkill.o b43-y += rfkill.o

View file

@ -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, 0x11, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, 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, 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, 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 BCMA_CORETABLE_END
}; };
MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl); MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl);
@ -2201,52 +2205,82 @@ err_format:
return -EPROTO; return -EPROTO;
} }
/* http://bcm-v4.sipsolutions.net/802.11/Init/Firmware */
static int b43_try_request_fw(struct b43_request_fw_context *ctx) static int b43_try_request_fw(struct b43_request_fw_context *ctx)
{ {
struct b43_wldev *dev = ctx->dev; struct b43_wldev *dev = ctx->dev;
struct b43_firmware *fw = &ctx->dev->fw; struct b43_firmware *fw = &ctx->dev->fw;
struct b43_phy *phy = &dev->phy;
const u8 rev = ctx->dev->dev->core_rev; const u8 rev = ctx->dev->dev->core_rev;
const char *filename; const char *filename;
u32 tmshigh;
int err; int err;
/* Files for HT and LCN were found by trying one by one */
/* Get microcode */ /* Get microcode */
if ((rev >= 5) && (rev <= 10)) { filename = NULL;
filename = "ucode5"; switch (rev) {
} else if ((rev >= 11) && (rev <= 12)) { case 42:
filename = "ucode11"; if (phy->type == B43_PHYTYPE_AC)
} else if (rev == 13) { filename = "ucode42";
filename = "ucode13"; break;
} else if (rev == 14) { case 40:
filename = "ucode14"; if (phy->type == B43_PHYTYPE_AC)
} else if (rev == 15) { 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"; filename = "ucode15";
} else { break;
switch (dev->phy.type) { case 14:
case B43_PHYTYPE_N: filename = "ucode14";
if (rev >= 16) break;
filename = "ucode16_mimo"; case 13:
else filename = "ucode13";
goto err_no_ucode; break;
break; case 11 ... 12:
case B43_PHYTYPE_HT: filename = "ucode11";
if (rev == 29) break;
filename = "ucode29_mimo"; case 5 ... 10:
else filename = "ucode5";
goto err_no_ucode; break;
break;
case B43_PHYTYPE_LCN:
if (rev == 24)
filename = "ucode24_mimo";
else
goto err_no_ucode;
break;
default:
goto err_no_ucode;
}
} }
if (!filename)
goto err_no_ucode;
err = b43_do_request_fw(ctx, filename, &fw->ucode, true); err = b43_do_request_fw(ctx, filename, &fw->ucode, true);
if (err) if (err)
goto err_load; goto err_load;
@ -2268,117 +2302,121 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
goto err_load; goto err_load;
/* Get initvals */ /* Get initvals */
filename = NULL;
switch (dev->phy.type) { 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: case B43_PHYTYPE_G:
if ((rev >= 5) && (rev <= 10)) if (rev == 13)
filename = "b0g0initvals5";
else if (rev >= 13)
filename = "b0g0initvals13"; filename = "b0g0initvals13";
else else if (rev >= 5 && rev <= 10)
goto err_no_initvals; filename = "b0g0initvals5";
break; break;
case B43_PHYTYPE_N: 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"; filename = "n0initvals16";
else if ((rev >= 11) && (rev <= 12)) else if (rev >= 11 && rev <= 12)
filename = "n0initvals11"; filename = "n0initvals11";
else
goto err_no_initvals;
break; break;
case B43_PHYTYPE_LP: case B43_PHYTYPE_LP:
if (rev == 13) if (rev >= 16 && rev <= 18)
filename = "lp0initvals13"; filename = "lp0initvals16";
else if (rev == 15)
filename = "lp0initvals15";
else if (rev == 14) else if (rev == 14)
filename = "lp0initvals14"; filename = "lp0initvals14";
else if (rev >= 15) else if (rev == 13)
filename = "lp0initvals15"; filename = "lp0initvals13";
else
goto err_no_initvals;
break; break;
case B43_PHYTYPE_HT: case B43_PHYTYPE_HT:
if (rev == 29) if (rev == 29)
filename = "ht0initvals29"; filename = "ht0initvals29";
else else if (rev == 26)
goto err_no_initvals; filename = "ht0initvals26";
break; break;
case B43_PHYTYPE_LCN: case B43_PHYTYPE_LCN:
if (rev == 24) if (rev == 24)
filename = "lcn0initvals24"; filename = "lcn0initvals24";
else
goto err_no_initvals;
break; break;
default: case B43_PHYTYPE_LCN40:
goto err_no_initvals; 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); err = b43_do_request_fw(ctx, filename, &fw->initvals, false);
if (err) if (err)
goto err_load; goto err_load;
/* Get bandswitch initvals */ /* Get bandswitch initvals */
filename = NULL;
switch (dev->phy.type) { 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: case B43_PHYTYPE_G:
if ((rev >= 5) && (rev <= 10)) if (rev == 13)
filename = "b0g0bsinitvals13";
else if (rev >= 5 && rev <= 10)
filename = "b0g0bsinitvals5"; filename = "b0g0bsinitvals5";
else if (rev >= 11)
filename = NULL;
else
goto err_no_initvals;
break; break;
case B43_PHYTYPE_N: 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"; filename = "n0bsinitvals16";
else if ((rev >= 11) && (rev <= 12)) else if (rev >= 11 && rev <= 12)
filename = "n0bsinitvals11"; filename = "n0bsinitvals11";
else
goto err_no_initvals;
break; break;
case B43_PHYTYPE_LP: case B43_PHYTYPE_LP:
if (rev == 13) if (rev >= 16 && rev <= 18)
filename = "lp0bsinitvals13"; filename = "lp0bsinitvals16";
else if (rev == 15)
filename = "lp0bsinitvals15";
else if (rev == 14) else if (rev == 14)
filename = "lp0bsinitvals14"; filename = "lp0bsinitvals14";
else if (rev >= 15) else if (rev == 13)
filename = "lp0bsinitvals15"; filename = "lp0bsinitvals13";
else
goto err_no_initvals;
break; break;
case B43_PHYTYPE_HT: case B43_PHYTYPE_HT:
if (rev == 29) if (rev == 29)
filename = "ht0bsinitvals29"; filename = "ht0bsinitvals29";
else else if (rev == 26)
goto err_no_initvals; filename = "ht0bsinitvals26";
break; break;
case B43_PHYTYPE_LCN: case B43_PHYTYPE_LCN:
if (rev == 24) if (rev == 24)
filename = "lcn0bsinitvals24"; filename = "lcn0bsinitvals24";
else
goto err_no_initvals;
break; break;
default: case B43_PHYTYPE_LCN40:
goto err_no_initvals; 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); err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false);
if (err) if (err)
goto err_load; 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) static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
{ {
struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev; struct b43_wldev *dev = wl->current_dev;
struct b43_phy *phy; struct b43_phy *phy = &dev->phy;
struct ieee80211_conf *conf = &hw->conf; struct ieee80211_conf *conf = &hw->conf;
int antenna; int antenna;
int err = 0; int err = 0;
bool reload_bss = false;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
dev = wl->current_dev;
b43_mac_suspend(dev); b43_mac_suspend(dev);
/* Switch the band (if necessary). This might change the active core. */ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
err = b43_switch_band(dev, conf->chandef.chan); phy->chandef = &conf->chandef;
if (err) phy->channel = conf->chandef.chan->hw_value;
goto out_unlock_mutex;
/* Need to reload all settings if the core changed */ /* Switch the band (if necessary). */
if (dev != wl->current_dev) { err = b43_switch_band(dev, conf->chandef.chan);
dev = wl->current_dev; if (err)
changed = ~0; goto out_mac_enable;
reload_bss = true;
/* 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) if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
b43_set_retry_limits(dev, conf->short_frame_max_tx_count, b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
conf->long_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) if (!changed)
goto out_mac_enable; 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); dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR);
/* Adjust the desired TX power level. */ /* Adjust the desired TX power level. */
@ -3878,12 +3902,8 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
out_mac_enable: out_mac_enable:
b43_mac_enable(dev); b43_mac_enable(dev);
out_unlock_mutex:
mutex_unlock(&wl->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; 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; analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT;
phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT; phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT;
phy_rev = (tmp & B43_PHYVER_VERSION); 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) { switch (phy_type) {
case B43_PHYTYPE_A: #ifdef CONFIG_B43_PHY_G
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;
case B43_PHYTYPE_G: case B43_PHYTYPE_G:
if (phy_rev > 9) if (phy_rev > 9)
unsupported = 1; unsupported = 1;
break; break;
#endif
#ifdef CONFIG_B43_PHY_N #ifdef CONFIG_B43_PHY_N
case B43_PHYTYPE_N: case B43_PHYTYPE_N:
if (phy_rev > 9) if (phy_rev > 9)

View file

@ -573,7 +573,7 @@ static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev)
{//TODO {//TODO
} }
const struct b43_phy_operations b43_phyops_a = { static const struct b43_phy_operations b43_phyops_a = {
.allocate = b43_aphy_op_allocate, .allocate = b43_aphy_op_allocate,
.free = b43_aphy_op_free, .free = b43_aphy_op_free,
.prepare_structs = b43_aphy_op_prepare_structs, .prepare_structs = b43_aphy_op_prepare_structs,

View file

@ -123,8 +123,4 @@ struct b43_phy_a {
*/ */
void b43_phy_inita(struct b43_wldev *dev); 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_ */ #endif /* LINUX_B43_PHY_A_H_ */

View file

@ -45,11 +45,10 @@ int b43_phy_allocate(struct b43_wldev *dev)
phy->ops = NULL; phy->ops = NULL;
switch (phy->type) { switch (phy->type) {
case B43_PHYTYPE_A:
phy->ops = &b43_phyops_a;
break;
case B43_PHYTYPE_G: case B43_PHYTYPE_G:
#ifdef CONFIG_B43_PHY_G
phy->ops = &b43_phyops_g; phy->ops = &b43_phyops_g;
#endif
break; break;
case B43_PHYTYPE_N: case B43_PHYTYPE_N:
#ifdef CONFIG_B43_PHY_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; const struct b43_phy_operations *ops = phy->ops;
int err; 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); phy->ops->switch_analog(dev, true);
b43_software_rfkill(dev, false); b43_software_rfkill(dev, false);
@ -106,9 +111,7 @@ int b43_phy_init(struct b43_wldev *dev)
} }
phy->do_full_init = false; phy->do_full_init = false;
/* Make sure to switch hardware and firmware (SHM) to err = b43_switch_channel(dev, phy->channel);
* the default channel. */
err = b43_switch_channel(dev, ops->get_default_chan(dev));
if (err) { if (err) {
b43err(dev->wl, "PHY init: Channel switch to default failed\n"); b43err(dev->wl, "PHY init: Channel switch to default failed\n");
goto err_phy_exit; goto err_phy_exit;
@ -408,9 +411,6 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
u16 channelcookie, savedcookie; u16 channelcookie, savedcookie;
int err; 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 /* First we set the channel radio code to prevent the
* firmware from sending ghost packets. * firmware from sending ghost packets.
*/ */
@ -428,7 +428,6 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
if (err) if (err)
goto err_restore_cookie; goto err_restore_cookie;
dev->phy.channel = new_channel;
/* Wait for the radio to tune to the channel and stabilize. */ /* Wait for the radio to tune to the channel and stabilize. */
msleep(8); 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 || return dev->phy.chandef->width == NL80211_CHAN_WIDTH_40;
channel_type == NL80211_CHAN_HT40PLUS);
} }
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */

View file

@ -228,9 +228,6 @@ struct b43_phy {
bool supports_2ghz; bool supports_2ghz;
bool supports_5ghz; bool supports_5ghz;
/* HT info */
bool is_40mhz;
/* Is GMODE (2 GHz mode) bit enabled? */ /* Is GMODE (2 GHz mode) bit enabled? */
bool gmode; bool gmode;
@ -267,9 +264,8 @@ struct b43_phy {
unsigned long next_txpwr_check_time; unsigned long next_txpwr_check_time;
/* Current channel */ /* Current channel */
struct cfg80211_chan_def *chandef;
unsigned int channel; unsigned int channel;
u16 channel_freq;
enum nl80211_channel_type channel_type;
/* PHY TX errors counter. */ /* PHY TX errors counter. */
atomic_t txerr_cnt; 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 * b43_switch_channel - Switch to another channel
*/ */
int b43_switch_channel(struct b43_wldev *dev, unsigned int new_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. * 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); 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); void b43_phy_force_clock(struct b43_wldev *dev, bool force);

View file

@ -596,7 +596,7 @@ static void b43_phy_ht_tx_power_ctl_setup(struct b43_wldev *dev)
u8 target[3]; u8 target[3];
s16 a1[3], b0[3], b1[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; int i, c;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {

View file

@ -590,7 +590,103 @@ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
* Radio 0x2057 * 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) static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
{ {
struct b43_phy *phy = &dev->phy; 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); b43_radio_maskset(dev, 0x1ca, ~0x2, 0x1);
} }
/* Enable */
b43_radio_set(dev, R2057_RCAL_CONFIG, 0x1); b43_radio_set(dev, R2057_RCAL_CONFIG, 0x1);
udelay(10); 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"); b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
return 0; return 0;
} }
b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x2);
tmp = b43_radio_read(dev, R2057_RCAL_STATUS) & 0x3E; tmp = b43_radio_read(dev, R2057_RCAL_STATUS) & 0x3E;
/* Disable */
b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x1); b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x1);
if (phy->radio_rev == 5) { if (phy->radio_rev == 5) {
@ -627,7 +733,9 @@ static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
return tmp & 0x3e; 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) static u16 b43_radio_2057_rccal(struct b43_wldev *dev)
{ {
struct b43_phy *phy = &dev->phy; struct b43_phy *phy = &dev->phy;
@ -635,49 +743,76 @@ static u16 b43_radio_2057_rccal(struct b43_wldev *dev)
phy->radio_rev == 6); phy->radio_rev == 6);
u16 tmp; u16 tmp;
/* Setup cal */
if (special) { if (special) {
b43_radio_write(dev, R2057_RCCAL_MASTER, 0x61); b43_radio_write(dev, R2057_RCCAL_MASTER, 0x61);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xC0); b43_radio_write(dev, R2057_RCCAL_TRC0, 0xC0);
} else { } 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_TRC0, 0xE1);
} }
b43_radio_write(dev, R2057_RCCAL_X1, 0x6E); b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
/* Start, wait, stop */
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55); 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)) 5000000))
b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n"); b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
usleep_range(35, 70);
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15); b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
usleep_range(70, 140);
/* Setup cal */
if (special) { if (special) {
b43_radio_write(dev, R2057_RCCAL_MASTER, 0x69); b43_radio_write(dev, R2057_RCCAL_MASTER, 0x69);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0); b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
} else { } 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_TRC0, 0xD5);
} }
b43_radio_write(dev, R2057_RCCAL_X1, 0x6E); 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); 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)) 5000000))
b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n"); b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
usleep_range(35, 70);
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15); b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
usleep_range(70, 140);
/* Setup cal */
if (special) { if (special) {
b43_radio_write(dev, R2057_RCCAL_MASTER, 0x73); b43_radio_write(dev, R2057_RCCAL_MASTER, 0x73);
b43_radio_write(dev, R2057_RCCAL_X1, 0x28); b43_radio_write(dev, R2057_RCCAL_X1, 0x28);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0); b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
} else { } 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_X1, 0x6E);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0x99); 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); 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)) { 5000000)) {
b43err(dev->wl, "Radio 0x2057 rcal timeout\n"); b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
return 0; return 0;
} }
tmp = b43_radio_read(dev, R2057_RCCAL_DONE_OSCCAP); tmp = b43_radio_read(dev, R2057_RCCAL_DONE_OSCCAP);
usleep_range(35, 70);
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15); 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; 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, static void b43_radio_2056_setup(struct b43_wldev *dev,
const struct b43_nphy_channeltab_entry_rev3 *e) const struct b43_nphy_channeltab_entry_rev3 *e)
{ {
struct b43_phy *phy = &dev->phy;
struct ssb_sprom *sprom = dev->dev->bus_sprom; struct ssb_sprom *sprom = dev->dev->bus_sprom;
enum ieee80211_band band = b43_current_band(dev->wl); enum ieee80211_band band = b43_current_band(dev->wl);
u16 offset; u16 offset;
@ -895,7 +1031,7 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
offset | B2056_TX_MIXG_BOOST_TUNE, offset | B2056_TX_MIXG_BOOST_TUNE,
mixg_boost); mixg_boost);
} else { } else {
bias = dev->phy.is_40mhz ? 0x40 : 0x20; bias = b43_is_40mhz(dev) ? 0x40 : 0x20;
b43_radio_write(dev, b43_radio_write(dev,
offset | B2056_TX_INTPAG_IMAIN_STAT, offset | B2056_TX_INTPAG_IMAIN_STAT,
bias); 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); b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee);
} }
} else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) { } 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) { if (freq < 5100) {
paa_boost = 0xA; paa_boost = 0xA;
pada_boost = 0x77; 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; u16 bw, len, rot, angle;
struct b43_c32 *samples; struct b43_c32 *samples;
bw = b43_is_40mhz(dev) ? 40 : 20;
bw = (dev->phy.is_40mhz) ? 40 : 20;
len = bw << 3; len = bw << 3;
if (test) { if (test) {
@ -1220,7 +1355,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
else else
bw = 80; bw = 80;
if (dev->phy.is_40mhz) if (b43_is_40mhz(dev))
bw <<= 1; bw <<= 1;
len = 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 */ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */
static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, 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; struct b43_phy_n *nphy = dev->phy.n;
int i; 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; nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
} }
/* TODO: add modify_bbmult argument */ if (modify_bbmult) {
if (!dev->phy.is_40mhz) tmp = !b43_is_40mhz(dev) ? 0x6464 : 0x4747;
tmp = 0x6464; b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
else }
tmp = 0x4747;
b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1)); 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_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000); b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000);
} else { } else {
if (dac_test) tmp = dac_test ? 5 : 1;
b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5); b43_phy_write(dev, B43_NPHY_SAMP_CMD, tmp);
else
b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
} }
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & 1)) { 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 */ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) 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; struct b43_phy_n *nphy = dev->phy.n;
u16 saved_regs_phy_rfctl[2]; 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 */ /* Remember for which channel we store configuration */
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) 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 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 */ /* End of calibration, restore configuration */
b43_nphy_classifier(dev, 7, class); 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_C1_NBCLIPTHRES, 0x84);
b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84); b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
if (!dev->phy.is_40mhz) { if (!b43_is_40mhz(dev)) {
/* Set dwell lengths */ /* Set dwell lengths */
b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B); b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
b43_phy_write(dev, B43_NPHY_CLIP2_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_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
~B43_NPHY_C2_CLIPWBTHRES_CLIP2, 21); ~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_phy_maskset(dev, B43_NPHY_C1_CGAINI,
~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1); ~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1);
b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, 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 (nphy->gain_boost) {
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ && if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ &&
dev->phy.is_40mhz) b43_is_40mhz(dev))
code = 4; code = 4;
else else
code = 5; code = 5;
} else { } else {
code = dev->phy.is_40mhz ? 6 : 7; code = b43_is_40mhz(dev) ? 6 : 7;
} }
/* Set HPVGA2 index */ /* 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) static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset)
{ {
if (!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; 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_40 = b43_nphy_read_lpf_ctl(dev, 0x159);
lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152); lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152);
if (b43_nphy_ipa(dev)) { 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) { phy->radio_rev == 7 || phy->radio_rev == 8) {
bcap_val = b43_radio_read(dev, 0x16b); bcap_val = b43_radio_read(dev, 0x16b);
scap_val = b43_radio_read(dev, 0x16a); scap_val = b43_radio_read(dev, 0x16a);
scap_val_11b = scap_val; scap_val_11b = scap_val;
bcap_val_11b = bcap_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; scap_val_11n_20 = scap_val;
bcap_val_11n_20 = bcap_val; bcap_val_11n_20 = bcap_val;
scap_val_11n_40 = bcap_val_11n_40 = 0xc; 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) { } 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, 0x5F, 0x14);
b43_radio_write(dev, 0xE8, 0x12); b43_radio_write(dev, 0xE8, 0x12);
} else { } else {
@ -2528,7 +2661,7 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
} }
} }
} else { } else {
u16 freq = phy->channel_freq; u16 freq = phy->chandef->chan->center_freq;
if ((freq >= 5180 && freq <= 5230) || if ((freq >= 5180 && freq <= 5230) ||
(freq >= 5745 && freq <= 5805)) { (freq >= 5745 && freq <= 5805)) {
b43_radio_write(dev, 0x7D, 0xFF); 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, 0x123), 0x77);
b43_ntab_write(dev, B43_NTAB16(7, 0x12A), 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, 0x03), 0x18D);
b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x18D); b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x18D);
} else { } else {
@ -2691,7 +2824,7 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_NPHY_SGILTRNOFFSET, 0xF0FF, 0x0700); 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, 3), 0x18D);
b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D); b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
} else { } else {
@ -2946,12 +3079,13 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone * 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, 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); u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
if (samp == 0) if (samp == 0)
return -1; 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; 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_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
~B43_NPHY_BPHY_CTL3_SCALE, 0x5A); ~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); b43_hf_write(dev, b43_hf_read(dev) | B43_HF_TSSIRPSMW);
} else { } else {
b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84, 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) else if (dev->phy.rev < 2)
b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x40); 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); b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_TSSIRPSMW);
if (b43_nphy_ipa(dev)) { 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 */ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */
static void b43_nphy_tx_power_fix(struct b43_wldev *dev) 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 b43_phy_n *nphy = dev->phy.n;
struct ssb_sprom *sprom = dev->dev->bus_sprom; struct ssb_sprom *sprom = dev->dev->bus_sprom;
u8 txpi[2], bbmult, i; u8 txpi[2], bbmult, i;
u16 tmp, radio_gain, dac_gain; u16 tmp, radio_gain, dac_gain;
u16 freq = dev->phy.channel_freq; u16 freq = phy->chandef->chan->center_freq;
u32 txgain; u32 txgain;
/* u32 gaintbl; rev3+ */ /* 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_rf_ctl_override(dev, 0x2000, 0, 3, false);
b43_nphy_stop_playback(dev); 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); udelay(20);
tmp = b43_nphy_poll_rssi(dev, N_RSSI_TSSI_2G, rssi, 1); tmp = b43_nphy_poll_rssi(dev, N_RSSI_TSSI_2G, rssi, 1);
b43_nphy_stop_playback(dev); b43_nphy_stop_playback(dev);
@ -3439,21 +3574,21 @@ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev)
delta = 0; delta = 0;
switch (stf_mode) { switch (stf_mode) {
case 0: case 0:
if (dev->phy.is_40mhz && dev->phy.rev >= 5) { if (b43_is_40mhz(dev) && dev->phy.rev >= 5) {
idx = 68; idx = 68;
} else { } else {
delta = 1; delta = 1;
idx = dev->phy.is_40mhz ? 52 : 4; idx = b43_is_40mhz(dev) ? 52 : 4;
} }
break; break;
case 1: case 1:
idx = dev->phy.is_40mhz ? 76 : 28; idx = b43_is_40mhz(dev) ? 76 : 28;
break; break;
case 2: case 2:
idx = dev->phy.is_40mhz ? 84 : 36; idx = b43_is_40mhz(dev) ? 84 : 36;
break; break;
case 3: case 3:
idx = dev->phy.is_40mhz ? 92 : 44; idx = b43_is_40mhz(dev) ? 92 : 44;
break; 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 */ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlSetup */
static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev) 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 b43_phy_n *nphy = dev->phy.n;
struct ssb_sprom *sprom = dev->dev->bus_sprom; 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; s32 num, den, pwr;
u32 regval[64]; u32 regval[64];
u16 freq = dev->phy.channel_freq; u16 freq = phy->chandef->chan->center_freq;
u16 tmp; u16 tmp;
u16 r; /* routing */ u16 r; /* routing */
u8 i, c; 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; u16 tmp;
if (dev->phy.rev >= 3) { if (dev->phy.rev < 3 || dev->phy.rev >= 7)
if (b43_nphy_ipa(dev)) { return;
tmp = 4;
b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2,
(((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
}
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, 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) { if (nphy->gband_spurwar_en) {
/* TODO: N PHY Adjust Analog Pfbw (7) */ /* 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)*/ ; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/
else else
; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/ ; /* 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), b43_phy_write(dev, B43_PHY_N(offset[i] + j),
tbl_tx_filter_coef_rev4[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++) for (j = 0; j < 15; j++)
b43_phy_write(dev, B43_PHY_N(offset[0] + j), b43_phy_write(dev, B43_PHY_N(offset[0] + j),
tbl_tx_filter_coef_rev4[3][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[2] = b43_radio_read(dev, 0x8D);
txcal_radio_regs[3] = b43_radio_read(dev, 0xBC); txcal_radio_regs[3] = b43_radio_read(dev, 0xBC);
} }
iqcal_chanspec->center_freq = dev->phy.channel_freq; iqcal_chanspec->center_freq = dev->phy.chandef->chan->center_freq;
iqcal_chanspec->channel_type = dev->phy.channel_type; iqcal_chanspec->channel_type =
cfg80211_get_chandef_type(dev->phy.chandef);
b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 8, table); b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 8, table);
if (nphy->hang_avoid) if (nphy->hang_avoid)
@ -4581,6 +4725,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
struct nphy_txgains target, struct nphy_txgains target,
bool full, bool mphase) bool full, bool mphase)
{ {
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = dev->phy.n; struct b43_phy_n *nphy = dev->phy.n;
int i; int i;
int error = 0; 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 && (dev->phy.rev == 5 && nphy->ipa2g_on &&
b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ); b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ);
if (phy6or5x) { if (phy6or5x) {
if (dev->phy.is_40mhz) { if (b43_is_40mhz(dev)) {
b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18, b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18,
tbl_tx_iqlo_cal_loft_ladder_40); tbl_tx_iqlo_cal_loft_ladder_40);
b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18, 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); b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9);
if (!dev->phy.is_40mhz) if (!b43_is_40mhz(dev))
freq = 2500; freq = 2500;
else else
freq = 5000; freq = 5000;
if (nphy->mphase_cal_phase_id > 2) if (nphy->mphase_cal_phase_id > 2)
b43_nphy_run_samples(dev, (dev->phy.is_40mhz ? 40 : 20) * 8, b43_nphy_run_samples(dev, (b43_is_40mhz(dev) ? 40 : 20) * 8,
0xFFFF, 0, true, false); 0xFFFF, 0, true, false, false);
else 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 (error == 0) {
if (nphy->mphase_cal_phase_id > 2) { 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_bestc);
nphy->txiqlocal_coeffsvalid = true; nphy->txiqlocal_coeffsvalid = true;
nphy->txiqlocal_chanspec.center_freq = nphy->txiqlocal_chanspec.center_freq =
dev->phy.channel_freq; phy->chandef->chan->center_freq;
nphy->txiqlocal_chanspec.channel_type = nphy->txiqlocal_chanspec.channel_type =
dev->phy.channel_type; cfg80211_get_chandef_type(phy->chandef);
} else { } else {
length = 11; length = 11;
if (dev->phy.rev < 3) if (dev->phy.rev < 3)
@ -4811,8 +4956,8 @@ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev)
bool equal = true; bool equal = true;
if (!nphy->txiqlocal_coeffsvalid || if (!nphy->txiqlocal_coeffsvalid ||
nphy->txiqlocal_chanspec.center_freq != dev->phy.channel_freq || nphy->txiqlocal_chanspec.center_freq != dev->phy.chandef->chan->center_freq ||
nphy->txiqlocal_chanspec.channel_type != dev->phy.channel_type) nphy->txiqlocal_chanspec.channel_type != cfg80211_get_chandef_type(dev->phy.chandef))
return; return;
b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer); 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) { if (playtone) {
ret = b43_nphy_tx_tone(dev, 4000, ret = b43_nphy_tx_tone(dev, 4000,
(nphy->rxcalparams & 0xFFFF), (nphy->rxcalparams & 0xFFFF),
false, false); false, false, true);
playtone = false; playtone = false;
} else { } else {
b43_nphy_run_samples(dev, 160, 0xFFFF, 0, b43_nphy_run_samples(dev, 160, 0xFFFF, 0, false,
false, false); false, true);
} }
if (ret == 0) { if (ret == 0) {
@ -5344,7 +5489,7 @@ static int b43_phy_initn(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320); b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320);
if (phy->rev >= 3 && phy->rev <= 6) if (phy->rev >= 3 && phy->rev <= 6)
b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0032); 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) if (phy->rev >= 3)
b43_nphy_spur_workaround(dev); b43_nphy_spur_workaround(dev);
@ -5430,14 +5575,14 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev,
if (dev->phy.rev < 3) if (dev->phy.rev < 3)
b43_nphy_adjust_lna_gain_table(dev); b43_nphy_adjust_lna_gain_table(dev);
b43_nphy_tx_lp_fbw(dev); b43_nphy_tx_lpf_bw(dev);
if (dev->phy.rev >= 3 && if (dev->phy.rev >= 3 &&
dev->phy.n->spur_avoid != B43_SPUR_AVOID_DISABLE) { dev->phy.n->spur_avoid != B43_SPUR_AVOID_DISABLE) {
bool avoid = false; bool avoid = false;
if (dev->phy.n->spur_avoid == B43_SPUR_AVOID_FORCE) { if (dev->phy.n->spur_avoid == B43_SPUR_AVOID_FORCE) {
avoid = true; 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) if ((ch >= 5 && ch <= 8) || ch == 13 || ch == 14)
avoid = true; avoid = true;
} else { /* 40MHz */ } 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_rev2 *tabent_r2 = NULL;
const struct b43_nphy_channeltab_entry_rev3 *tabent_r3 = 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; 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, tabent_r3 = b43_nphy_get_chantabent_rev3(dev,
channel->center_freq); channel->center_freq);
if (!tabent_r3) 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 /* Channel is set later in common code, but we need to set it on our
own to let this function's subcalls work properly. */ own to let this function's subcalls work properly. */
phy->channel = channel->hw_value; phy->channel = channel->hw_value;
phy->channel_freq = channel->center_freq;
#if 0
if (b43_channel_type_is_40mhz(phy->channel_type) != if (b43_channel_type_is_40mhz(phy->channel_type) !=
b43_channel_type_is_40mhz(channel_type)) b43_channel_type_is_40mhz(channel_type))
; /* TODO: BMAC BW Set (channel_type) */ ; /* TODO: BMAC BW Set (channel_type) */
#endif
if (channel_type == NL80211_CHAN_HT40PLUS) if (channel_type == NL80211_CHAN_HT40PLUS) {
b43_phy_set(dev, B43_NPHY_RXCTL, b43_phy_set(dev, B43_NPHY_RXCTL, B43_NPHY_RXCTL_BSELU20);
B43_NPHY_RXCTL_BSELU20); if (phy->rev >= 7)
else if (channel_type == NL80211_CHAN_HT40MINUS) b43_phy_set(dev, 0x310, 0x8000);
b43_phy_mask(dev, B43_NPHY_RXCTL, } else if (channel_type == NL80211_CHAN_HT40MINUS) {
~B43_NPHY_RXCTL_BSELU20); 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; tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 4 : 0;
b43_radio_maskset(dev, 0x08, 0xFFFB, tmp); b43_radio_maskset(dev, 0x08, 0xFFFB, tmp);
b43_radio_2056_setup(dev, tabent_r3); b43_radio_2056_setup(dev, tabent_r3);

View file

@ -26,7 +26,7 @@
#include "radio_2057.h" #include "radio_2057.h"
#include "phy_common.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 }, { 0x0E, 0x20 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 },
{ 0x35, 0x26 }, { 0x3C, 0xff }, { 0x3D, 0xff }, { 0x3E, 0xff }, { 0x35, 0x26 }, { 0x3C, 0xff }, { 0x3D, 0xff }, { 0x3E, 0xff },
{ 0x3F, 0xff }, { 0x62, 0x33 }, { 0x8A, 0xf0 }, { 0x8B, 0x10 }, { 0x3F, 0xff }, { 0x62, 0x33 }, { 0x8A, 0xf0 }, { 0x8B, 0x10 },
@ -40,7 +40,7 @@ static u16 r2057_rev4_init[42][2] = {
{ 0x1AB, 0x00 }, { 0x1AC, 0x00 }, { 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 }, { 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
{ 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
{ 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 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 }, { 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 }, { 0x00, 0x15 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
{ 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
{ 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f },
@ -69,7 +69,7 @@ static u16 r2057_rev5a_init[45][2] = {
{ 0x1C2, 0x80 }, { 0x1C2, 0x80 },
}; };
static u16 r2057_rev7_init[54][2] = { static u16 r2057_rev7_init[][2] = {
{ 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 }, { 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
{ 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
{ 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x13 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x13 },
@ -86,7 +86,8 @@ static u16 r2057_rev7_init[54][2] = {
{ 0x1B7, 0x05 }, { 0x1C2, 0xa0 }, { 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 }, { 0x00, 0x08 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
{ 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
{ 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x0f }, { 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 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
{ 0x1B7, 0x05 }, { 0x1C2, 0xa0 }, { 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) void r2057_upload_inittabs(struct b43_wldev *dev)
{ {
@ -109,33 +151,69 @@ void r2057_upload_inittabs(struct b43_wldev *dev)
u16 *table = NULL; u16 *table = NULL;
u16 size, i; u16 size, i;
if (phy->rev == 7) { switch (phy->rev) {
case 7:
table = r2057_rev4_init[0]; table = r2057_rev4_init[0];
size = ARRAY_SIZE(r2057_rev4_init); 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 == 5) {
if (phy->radio_rev == 8) { table = r2057_rev5_init[0];
table = r2057_rev5_init[0]; size = ARRAY_SIZE(r2057_rev5_init);
size = ARRAY_SIZE(r2057_rev5_init);
} else {
table = r2057_rev5a_init[0];
size = ARRAY_SIZE(r2057_rev5a_init);
}
} else if (phy->radio_rev == 7) { } else if (phy->radio_rev == 7) {
table = r2057_rev7_init[0]; table = r2057_rev7_init[0];
size = ARRAY_SIZE(r2057_rev7_init); 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) { if (table) {
for (i = 0; i < 10; i++) { for (i = 0; i < size; i++, table += 2)
pr_info("radio_write 0x%X ", *table); b43_radio_write(dev, table[0], table[1]);
table++; }
pr_info("0x%X\n", *table); }
table++;
} 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);
} }
} }

View file

@ -425,6 +425,72 @@
#define R2057_VCM_MASK 0x7 #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_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_ */ #endif /* B43_RADIO_2057_H_ */

View file

@ -3191,7 +3191,7 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
/* Some workarounds to the workarounds... */ /* Some workarounds to the workarounds... */
if (ghz5 && dev->phy.rev >= 6) { if (ghz5 && dev->phy.rev >= 6) {
if (dev->phy.radio_rev == 11 && if (dev->phy.radio_rev == 11 &&
!b43_channel_type_is_40mhz(dev->phy.channel_type)) !b43_is_40mhz(dev))
e->cliplo_gain = 0x2d; e->cliplo_gain = 0x2d;
} else if (!ghz5 && dev->phy.rev >= 5) { } else if (!ghz5 && dev->phy.rev >= 5) {
static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a, static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,

View file

@ -34,7 +34,8 @@ brcmfmac-objs += \
dhd_common.o \ dhd_common.o \
dhd_linux.o \ dhd_linux.o \
firmware.o \ firmware.o \
btcoex.o btcoex.o \
vendor.o
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
dhd_sdio.o \ dhd_sdio.o \
bcmsdh.o bcmsdh.o

View file

@ -157,7 +157,7 @@ static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci,
*/ */
/* save current */ /* 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, 50, &btci->reg50);
brcmf_btcoex_params_read(ifp, 51, &btci->reg51); brcmf_btcoex_params_read(ifp, 51, &btci->reg51);
brcmf_btcoex_params_read(ifp, 64, &btci->reg64); 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); brcmf_btcoex_params_read(ifp, 71, &btci->reg71);
btci->saved_regs_part2 = true; 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", "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->reg50, btci->reg51, btci->reg64,
btci->reg65, btci->reg71); 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) { } else if (btci->saved_regs_part2) {
/* restore previously saved bt params */ /* 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, 50, btci->reg50);
brcmf_btcoex_params_write(ifp, 51, btci->reg51); brcmf_btcoex_params_write(ifp, 51, btci->reg51);
brcmf_btcoex_params_write(ifp, 64, btci->reg64); brcmf_btcoex_params_write(ifp, 64, btci->reg64);
brcmf_btcoex_params_write(ifp, 65, btci->reg65); brcmf_btcoex_params_write(ifp, 65, btci->reg65);
brcmf_btcoex_params_write(ifp, 71, btci->reg71); 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", "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->reg50, btci->reg51, btci->reg64,
btci->reg65, btci->reg71); btci->reg65, btci->reg71);
btci->saved_regs_part2 = false; btci->saved_regs_part2 = false;
} else { } 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; 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 */ if ((param27 & 0x6) == 2) { /* count both sco & esco */
sco_id_cnt++; sco_id_cnt++;
} }
if (sco_id_cnt > 2) { if (sco_id_cnt > 2) {
brcmf_dbg(TRACE, brcmf_dbg(INFO,
"sco/esco detected, pkt id_cnt:%d samples:%d\n", "sco/esco detected, pkt id_cnt:%d samples:%d\n",
sco_id_cnt, i); sco_id_cnt, i);
res = true; 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, 41, &btci->reg41);
brcmf_btcoex_params_read(ifp, 68, &btci->reg68); brcmf_btcoex_params_read(ifp, 68, &btci->reg68);
btci->saved_regs_part1 = true; 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", "saved btc_params regs (66,41,68) 0x%x 0x%x 0x%x\n",
btci->reg66, btci->reg41, btci->reg66, btci->reg41,
btci->reg68); 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, 66, btci->reg66);
brcmf_btcoex_params_write(ifp, 41, btci->reg41); brcmf_btcoex_params_write(ifp, 41, btci->reg41);
brcmf_btcoex_params_write(ifp, 68, btci->reg68); 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", "restored btc_params regs {66,41,68} 0x%x 0x%x 0x%x\n",
btci->reg66, btci->reg41, btci->reg66, btci->reg41,
btci->reg68); btci->reg68);
@ -307,7 +307,7 @@ static void brcmf_btcoex_handler(struct work_struct *work)
/* DHCP started provide OPPORTUNITY window /* DHCP started provide OPPORTUNITY window
to get DHCP address to get DHCP address
*/ */
brcmf_dbg(TRACE, "DHCP started\n"); brcmf_dbg(INFO, "DHCP started\n");
btci->bt_state = BRCMF_BT_DHCP_OPPR_WIN; btci->bt_state = BRCMF_BT_DHCP_OPPR_WIN;
if (btci->timeout < BRCMF_BTCOEX_OPPR_WIN_TIME) { if (btci->timeout < BRCMF_BTCOEX_OPPR_WIN_TIME) {
mod_timer(&btci->timer, btci->timer.expires); 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: case BRCMF_BT_DHCP_OPPR_WIN:
if (btci->dhcp_done) { if (btci->dhcp_done) {
brcmf_dbg(TRACE, "DHCP done before T1 expiration\n"); brcmf_dbg(INFO, "DHCP done before T1 expiration\n");
goto idle; goto idle;
} }
/* DHCP is not over yet, start lowering BT priority */ /* 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_OPPR_WIN_TIME);
brcmf_btcoex_boost_wifi(btci, true); 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: case BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT:
if (btci->dhcp_done) if (btci->dhcp_done)
brcmf_dbg(TRACE, "DHCP done before T2 expiration\n"); brcmf_dbg(INFO, "DHCP done before T2 expiration\n");
else else
brcmf_dbg(TRACE, "DHCP T2:%d expired\n", brcmf_dbg(INFO, "DHCP T2:%d expired\n",
BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT); BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT);
goto idle; 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 */ /* Stop any bt timer because DHCP session is done */
btci->dhcp_done = true; btci->dhcp_done = true;
if (btci->timer_on) { if (btci->timer_on) {
brcmf_dbg(TRACE, "disable BT DHCP Timer\n"); brcmf_dbg(INFO, "disable BT DHCP Timer\n");
btci->timer_on = false; btci->timer_on = false;
del_timer_sync(&btci->timer); del_timer_sync(&btci->timer);
/* schedule worker if transition to IDLE is needed */ /* schedule worker if transition to IDLE is needed */
if (btci->bt_state != BRCMF_BT_DHCP_IDLE) { 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); btci->bt_state);
schedule_work(&btci->work); schedule_work(&btci->work);
} }
@ -472,7 +472,7 @@ int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
switch (mode) { switch (mode) {
case BRCMF_BTCOEX_DISABLED: 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) if (btci->bt_state != BRCMF_BT_DHCP_IDLE)
return -EBUSY; return -EBUSY;
/* Start BT timer only for SCO connection */ /* Start BT timer only for SCO connection */
@ -484,14 +484,14 @@ int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
break; break;
case BRCMF_BTCOEX_ENABLED: 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 && if (btci->bt_state != BRCMF_BT_DHCP_IDLE &&
vif == btci->vif) { vif == btci->vif) {
brcmf_btcoex_dhcp_end(btci); brcmf_btcoex_dhcp_end(btci);
} }
break; break;
default: default:
brcmf_dbg(TRACE, "Unknown mode, ignored\n"); brcmf_dbg(INFO, "Unknown mode, ignored\n");
} }
return 0; return 0;
} }

View file

@ -49,16 +49,6 @@
*/ */
#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32 #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 * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
* *

View file

@ -282,6 +282,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
ptr = strrchr(buf, ' ') + 1; ptr = strrchr(buf, ' ') + 1;
strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver)); 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 * Setup timeout if Beacons are lost and roam is off to report
* link down * link down

View file

@ -54,7 +54,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
if (err >= 0) if (err >= 0)
err = 0; err = 0;
else else
brcmf_err("Failed err=%d\n", err); brcmf_dbg(FIL, "Failed err=%d\n", err);
return err; return err;
} }

View file

@ -708,7 +708,7 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS; active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS;
else if (num_chans == AF_PEER_SEARCH_CNT) else if (num_chans == AF_PEER_SEARCH_CNT)
active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS; 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; active = -1;
else else
active = P2PAPI_SCAN_DWELL_TIME_MS; active = P2PAPI_SCAN_DWELL_TIME_MS;

View file

@ -29,32 +29,24 @@
#include "usb_rdl.h" #include "usb_rdl.h"
#include "usb.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_SPINWAIT 100 /* in unit of ms */
#define BRCMF_USB_RESET_GETVER_LOOP_CNT 10 #define BRCMF_USB_RESET_GETVER_LOOP_CNT 10
#define BRCMF_POSTBOOT_ID 0xA123 /* ID to detect if dongle #define BRCMF_POSTBOOT_ID 0xA123 /* ID to detect if dongle
has boot up */ has boot up */
#define BRCMF_USB_NRXQ 50 #define BRCMF_USB_NRXQ 50
#define BRCMF_USB_NTXQ 50 #define BRCMF_USB_NTXQ 50
#define CONFIGDESC(usb) (&((usb)->actconfig)->desc) #define BRCMF_USB_CBCTL_WRITE 0
#define IFPTR(usb, idx) ((usb)->actconfig->interface[(idx)]) #define BRCMF_USB_CBCTL_READ 1
#define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0]) #define BRCMF_USB_MAX_PKT_SIZE 1600
#define IFDESC(usb, idx) IFALTS((usb), (idx)).desc
#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[(ep)]).desc
#define CONTROL_IF 0 #define BRCMF_USB_43143_FW_NAME "brcm/brcmfmac43143.bin"
#define BULK_IF 0 #define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin"
#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin"
#define BRCMF_USB_CBCTL_WRITE 0 #define BRCMF_USB_43569_FW_NAME "brcm/brcmfmac43569.bin"
#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"
struct brcmf_usb_image { struct brcmf_usb_image {
struct list_head list; struct list_head list;
@ -70,7 +62,7 @@ struct brcmf_usbdev_info {
struct list_head rx_postq; struct list_head rx_postq;
struct list_head tx_freeq; struct list_head tx_freeq;
struct list_head tx_postq; struct list_head tx_postq;
uint rx_pipe, tx_pipe, rx_pipe2; uint rx_pipe, tx_pipe;
int rx_low_watermark; int rx_low_watermark;
int tx_low_watermark; int tx_low_watermark;
@ -97,6 +89,7 @@ struct brcmf_usbdev_info {
int ctl_completed; int ctl_completed;
wait_queue_head_t ioctl_resp_wait; wait_queue_head_t ioctl_resp_wait;
ulong ctl_op; ulong ctl_op;
u8 ifnum;
struct urb *bulk_urb; /* used for FW download */ struct urb *bulk_urb; /* used for FW download */
}; };
@ -576,7 +569,6 @@ fail:
static int brcmf_usb_up(struct device *dev) static int brcmf_usb_up(struct device *dev)
{ {
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
u16 ifnum;
brcmf_dbg(USB, "Enter\n"); brcmf_dbg(USB, "Enter\n");
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) 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_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0);
devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0); devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0);
ifnum = IFDESC(devinfo->usbdev, CONTROL_IF).bInterfaceNumber;
/* CTL Write */ /* CTL Write */
devinfo->ctl_write.bRequestType = devinfo->ctl_write.bRequestType =
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
devinfo->ctl_write.bRequest = 0; devinfo->ctl_write.bRequest = 0;
devinfo->ctl_write.wValue = cpu_to_le16(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 */ /* CTL Read */
devinfo->ctl_read.bRequestType = devinfo->ctl_read.bRequestType =
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
devinfo->ctl_read.bRequest = 1; devinfo->ctl_read.bRequest = 1;
devinfo->ctl_read.wValue = cpu_to_le16(0); 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); brcmf_usb_rx_fill_all(devinfo);
return 0; return 0;
@ -642,19 +632,19 @@ brcmf_usb_sync_complete(struct urb *urb)
brcmf_usb_ioctl_resp_wake(devinfo); brcmf_usb_ioctl_resp_wake(devinfo);
} }
static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd, static int brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
void *buffer, int buflen) void *buffer, int buflen)
{ {
int ret = 0; int ret;
char *tmpbuf; char *tmpbuf;
u16 size; u16 size;
if ((!devinfo) || (devinfo->ctl_urb == NULL)) if ((!devinfo) || (devinfo->ctl_urb == NULL))
return false; return -EINVAL;
tmpbuf = kmalloc(buflen, GFP_ATOMIC); tmpbuf = kmalloc(buflen, GFP_ATOMIC);
if (!tmpbuf) if (!tmpbuf)
return false; return -ENOMEM;
size = buflen; size = buflen;
devinfo->ctl_urb->transfer_buffer_length = size; 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); ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
if (ret < 0) { if (ret < 0) {
brcmf_err("usb_submit_urb failed %d\n", ret); brcmf_err("usb_submit_urb failed %d\n", ret);
kfree(tmpbuf); goto finalize;
return false;
} }
ret = brcmf_usb_ioctl_resp_wait(devinfo); if (!brcmf_usb_ioctl_resp_wait(devinfo))
memcpy(buffer, tmpbuf, buflen); ret = -ETIMEDOUT;
kfree(tmpbuf); else
memcpy(buffer, tmpbuf, buflen);
finalize:
kfree(tmpbuf);
return ret; return ret;
} }
@ -724,6 +716,7 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
{ {
struct bootrom_id_le id; struct bootrom_id_le id;
u32 loop_cnt; u32 loop_cnt;
int err;
brcmf_dbg(USB, "Enter\n"); brcmf_dbg(USB, "Enter\n");
@ -732,7 +725,9 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT); mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT);
loop_cnt++; loop_cnt++;
id.chip = cpu_to_le32(0xDEAD); /* Get the ID */ 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)) if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID))
break; break;
} while (loop_cnt < BRCMF_USB_RESET_GETVER_LOOP_CNT); } 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 */ /* 1) Prepare USB boot loader for runtime image */
brcmf_usb_dl_cmd(devinfo, DL_START, &state, brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state));
sizeof(struct rdl_state_le));
rdlstate = le32_to_cpu(state.state); rdlstate = le32_to_cpu(state.state);
rdlbytes = le32_to_cpu(state.bytes); 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; dlpos += sendlen;
sent += sendlen; sent += sendlen;
} }
if (!brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, err = brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
sizeof(struct rdl_state_le))) { sizeof(state));
brcmf_err("DL_GETSTATE Failed xxxx\n"); if (err) {
err = -EINVAL; brcmf_err("DL_GETSTATE Failed\n");
goto fail; goto fail;
} }
@ -898,13 +892,12 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
return -EINVAL; return -EINVAL;
/* Check we are runnable */ /* Check we are runnable */
brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, state.state = 0;
sizeof(struct rdl_state_le)); brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, sizeof(state));
/* Start the image */ /* Start the image */
if (state.state == cpu_to_le32(DL_RUNNABLE)) { if (state.state == cpu_to_le32(DL_RUNNABLE)) {
if (!brcmf_usb_dl_cmd(devinfo, DL_GO, &state, if (brcmf_usb_dl_cmd(devinfo, DL_GO, &state, sizeof(state)))
sizeof(struct rdl_state_le)))
return -ENODEV; return -ENODEV;
if (brcmf_usb_resetcfg(devinfo)) if (brcmf_usb_resetcfg(devinfo))
return -ENODEV; return -ENODEV;
@ -928,6 +921,9 @@ static bool brcmf_usb_chip_support(int chipid, int chiprev)
return (chiprev == 3); return (chiprev == 3);
case 43242: case 43242:
return true; return true;
case 43566:
case 43569:
return true;
default: default:
break; break;
} }
@ -1028,6 +1024,9 @@ static const char *brcmf_usb_get_fwname(struct brcmf_usbdev_info *devinfo)
return BRCMF_USB_43236_FW_NAME; return BRCMF_USB_43236_FW_NAME;
case 43242: case 43242:
return BRCMF_USB_43242_FW_NAME; return BRCMF_USB_43242_FW_NAME;
case 43566:
case 43569:
return BRCMF_USB_43569_FW_NAME;
default: default:
return NULL; return NULL;
} }
@ -1221,15 +1220,15 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
static int static int
brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) 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; struct usb_endpoint_descriptor *endpoint;
int ret = 0; int ret = 0;
struct usb_device *usb = interface_to_usbdev(intf); u32 num_of_eps;
int num_of_eps; u8 endpoint_num, ep;
u8 endpoint_num;
struct brcmf_usbdev_info *devinfo;
brcmf_dbg(USB, "Enter\n"); brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct);
devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC); devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC);
if (devinfo == NULL) if (devinfo == NULL)
@ -1237,92 +1236,71 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
devinfo->usbdev = usb; devinfo->usbdev = usb;
devinfo->dev = &usb->dev; devinfo->dev = &usb->dev;
usb_set_intfdata(intf, devinfo); usb_set_intfdata(intf, devinfo);
/* Check that the device supports only one configuration */ /* Check that the device supports only one configuration */
if (usb->descriptor.bNumConfigurations != 1) { if (usb->descriptor.bNumConfigurations != 1) {
ret = -1; brcmf_err("Number of configurations: %d not supported\n",
usb->descriptor.bNumConfigurations);
ret = -ENODEV;
goto fail; goto fail;
} }
if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) { if ((usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) &&
ret = -1; (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; goto fail;
} }
/* desc = &intf->altsetting[0].desc;
* Only the BDC interface configuration is supported: if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
* Device class: USB_CLASS_VENDOR_SPEC (desc->bInterfaceSubClass != 2) ||
* if0 class: USB_CLASS_VENDOR_SPEC (desc->bInterfaceProtocol != 0xff)) {
* if0/ep0: control brcmf_err("non WLAN interface %d: 0x%x:0x%x:0x%x\n",
* if0/ep1: bulk in desc->bInterfaceNumber, desc->bInterfaceClass,
* if0/ep2: bulk out (ok if swapped with bulk in) desc->bInterfaceSubClass, desc->bInterfaceProtocol);
*/ ret = -ENODEV;
if (CONFIGDESC(usb)->bNumInterfaces != 1) {
ret = -1;
goto fail; goto fail;
} }
/* Check interface */ num_of_eps = desc->bNumEndpoints;
if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC || for (ep = 0; ep < num_of_eps; ep++) {
IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 || endpoint = &intf->altsetting[0].endpoint[ep].desc;
IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) { endpoint_num = usb_endpoint_num(endpoint);
brcmf_err("invalid control interface: class %d, subclass %d, proto %d\n", if (!usb_endpoint_xfer_bulk(endpoint))
IFDESC(usb, CONTROL_IF).bInterfaceClass, continue;
IFDESC(usb, CONTROL_IF).bInterfaceSubClass, if (usb_endpoint_dir_in(endpoint)) {
IFDESC(usb, CONTROL_IF).bInterfaceProtocol); if (!devinfo->rx_pipe)
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) {
devinfo->rx_pipe = devinfo->rx_pipe =
usb_rcvbulkpipe(usb, endpoint_num); usb_rcvbulkpipe(usb, endpoint_num);
} else {
devinfo->rx_pipe2 =
usb_rcvbulkpipe(usb, endpoint_num);
}
} else { } 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) 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) 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 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); ret = brcmf_usb_probe_cb(devinfo);
if (ret) if (ret)
@ -1332,11 +1310,9 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
return 0; return 0;
fail: fail:
brcmf_err("failed with errno %d\n", ret);
kfree(devinfo); kfree(devinfo);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
return ret; return ret;
} }
static void 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 usb_device *usb = interface_to_usbdev(intf);
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
brcmf_dbg(USB, "Enter\n"); brcmf_dbg(USB, "Enter\n");
return brcmf_fw_get_firmwares(&usb->dev, 0, 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_43143 0xbd1e
#define BRCMF_USB_DEVICE_ID_43236 0xbd17 #define BRCMF_USB_DEVICE_ID_43236 0xbd17
#define BRCMF_USB_DEVICE_ID_43242 0xbd1f #define BRCMF_USB_DEVICE_ID_43242 0xbd1f
#define BRCMF_USB_DEVICE_ID_43569 0xbd27
#define BRCMF_USB_DEVICE_ID_BCMFW 0x0bdc #define BRCMF_USB_DEVICE_ID_BCMFW 0x0bdc
static struct usb_device_id brcmf_usb_devid_table[] = { 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_43143) },
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) }, { 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_43242) },
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43569) },
/* special entry for device with firmware loaded and running */ /* special entry for device with firmware loaded and running */
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) }, { 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_43143_FW_NAME);
MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME); MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME); MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME);
MODULE_FIRMWARE(BRCMF_USB_43569_FW_NAME);
static struct usb_driver brcmf_usbdrvr = { static struct usb_driver brcmf_usbdrvr = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,

View file

@ -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
},
};

View file

@ -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_ */

View file

@ -19,6 +19,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/vmalloc.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/netlink.h> #include <net/netlink.h>
@ -33,6 +34,7 @@
#include "btcoex.h" #include "btcoex.h"
#include "wl_cfg80211.h" #include "wl_cfg80211.h"
#include "fwil.h" #include "fwil.h"
#include "vendor.h"
#define BRCMF_SCAN_IE_LEN_MAX 2048 #define BRCMF_SCAN_IE_LEN_MAX 2048
#define BRCMF_PNO_VERSION 2 #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) void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
{ {
s32 err = 0; s32 err = 0;
@ -641,7 +649,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
brcmf_err("Scan abort failed\n"); 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 * 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); brcmf_err("error (%d)\n", err);
return 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 = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
results->version = 0; results->version = 0;
results->count = 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); err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
if (err) if (err)
brcmf_set_mpc(ifp, 1); brcmf_scan_config_mpc(ifp, 1);
return err; 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); brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
goto scan_out; goto scan_out;
} }
brcmf_set_mpc(ifp, 0); brcmf_scan_config_mpc(ifp, 0);
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&sr->ssid_le, sizeof(sr->ssid_le)); &sr->ssid_le, sizeof(sr->ssid_le));
if (err) { if (err) {
@ -1029,7 +1037,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
else else
brcmf_err("WLC_SCAN error (%d)\n", err); brcmf_err("WLC_SCAN error (%d)\n", err);
brcmf_set_mpc(ifp, 1); brcmf_scan_config_mpc(ifp, 1);
goto scan_out; goto scan_out;
} }
} }
@ -1331,7 +1339,6 @@ static s32
brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
{ {
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
if (!check_vif_up(ifp->vif)) 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"); brcmf_dbg(TRACE, "Exit\n");
return err; return 0;
} }
static s32 brcmf_set_wpa_version(struct net_device *ndev, 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 cfg80211_bss *bss;
struct ieee80211_supported_band *band; struct ieee80211_supported_band *band;
struct brcmu_chan ch; struct brcmu_chan ch;
s32 err = 0;
u16 channel; u16 channel;
u32 freq; u32 freq;
u16 notify_capability; u16 notify_capability;
@ -2438,7 +2444,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
cfg80211_put_bss(wiphy, bss); cfg80211_put_bss(wiphy, bss);
return err; return 0;
} }
static struct brcmf_bss_info_le * 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; struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
s32 status; s32 status;
s32 err = 0;
struct brcmf_escan_result_le *escan_result_le; struct brcmf_escan_result_le *escan_result_le;
struct brcmf_bss_info_le *bss_info_le; struct brcmf_bss_info_le *bss_info_le;
struct brcmf_bss_info_le *bss = NULL; struct brcmf_bss_info_le *bss = NULL;
@ -2781,7 +2786,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
status); status);
} }
exit: exit:
return err; return 0;
} }
static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) 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; 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) static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
{ {
s32 err; s32 err;
@ -3507,7 +3483,6 @@ static s32
brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len, brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
struct parsed_vndr_ies *vndr_ies) struct parsed_vndr_ies *vndr_ies)
{ {
s32 err = 0;
struct brcmf_vs_tlv *vndrie; struct brcmf_vs_tlv *vndrie;
struct brcmf_tlv *ie; struct brcmf_tlv *ie;
struct parsed_vndr_ie_info *parsed_info; struct parsed_vndr_ie_info *parsed_info;
@ -3560,7 +3535,7 @@ next:
ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len + ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
TLV_HDR_LEN); TLV_HDR_LEN);
} }
return err; return 0;
} }
static u32 static u32
@ -4307,7 +4282,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.crit_proto_start = brcmf_cfg80211_crit_proto_start, .crit_proto_start = brcmf_cfg80211_crit_proto_start,
.crit_proto_stop = brcmf_cfg80211_crit_proto_stop, .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
.tdls_oper = brcmf_cfg80211_tdls_oper, .tdls_oper = brcmf_cfg80211_tdls_oper,
CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
}; };
static void brcmf_wiphy_pno_params(struct wiphy *wiphy) 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"); brcmf_dbg(INFO, "Registering custom regulatory\n");
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); 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); err = wiphy_register(wiphy);
if (err < 0) { if (err < 0) {
brcmf_err("Could not register wiphy device (%d)\n", err); 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_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
@ -4676,7 +4654,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
completed ? "succeeded" : "failed"); completed ? "succeeded" : "failed");
} }
brcmf_dbg(TRACE, "Exit\n"); brcmf_dbg(TRACE, "Exit\n");
return err; return 0;
} }
static s32 static s32
@ -4768,7 +4746,6 @@ brcmf_notify_roaming_status(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data) const struct brcmf_event_msg *e, void *data)
{ {
struct brcmf_cfg80211_info *cfg = ifp->drvr->config; struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
s32 err = 0;
u32 event = e->event_code; u32 event = e->event_code;
u32 status = e->status; 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); brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
} }
return err; return 0;
} }
static s32 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", err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
BRCMF_OBSS_COEX_AUTO); 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); err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
if (err) { if (err) {
@ -5625,16 +5605,15 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
return wdev->iftype; 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; struct brcmf_cfg80211_vif *vif;
bool result = 0;
list_for_each_entry(vif, &cfg->vif_list, list) { list_for_each_entry(vif, &cfg->vif_list, list) {
if (test_bit(state, &vif->sme_state)) 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, static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,

View file

@ -477,7 +477,7 @@ const struct brcmf_tlv *
brcmf_parse_tlvs(const void *buf, int buflen, uint key); brcmf_parse_tlvs(const void *buf, int buflen, uint key);
u16 channel_to_chanspec(struct brcmu_d11inf *d11inf, u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
struct ieee80211_channel *ch); 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, void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif); struct brcmf_cfg80211_vif *vif);
bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);

View file

@ -1538,11 +1538,7 @@ static s8
wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band, wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,
u8 rate) u8 rate)
{ {
s8 offset = 0; return 0;
if (!pi->user_txpwr_at_rfport)
return offset;
return offset;
} }
void wlc_phy_txpower_recalc_target(struct brcms_phy *pi) void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)

View file

@ -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, int cw1200_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct cfg80211_scan_request *req) struct ieee80211_scan_request *hw_req)
{ {
struct cw1200_common *priv = hw->priv; struct cw1200_common *priv = hw->priv;
struct cfg80211_scan_request *req = &hw_req->req;
struct wsm_template_frame frame = { struct wsm_template_frame frame = {
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
}; };

View file

@ -41,7 +41,7 @@ struct cw1200_scan {
int cw1200_hw_scan(struct ieee80211_hw *hw, int cw1200_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, 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_work(struct work_struct *work);
void cw1200_scan_timeout(struct work_struct *work); void cw1200_scan_timeout(struct work_struct *work);
void cw1200_clear_recent_scan_work(struct work_struct *work); void cw1200_clear_recent_scan_work(struct work_struct *work);

View file

@ -2289,7 +2289,6 @@ static int cw1200_upload_null(struct cw1200_common *priv)
static int cw1200_upload_qosnull(struct cw1200_common *priv) static int cw1200_upload_qosnull(struct cw1200_common *priv)
{ {
int ret = 0;
/* TODO: This needs to be implemented /* TODO: This needs to be implemented
struct wsm_template_frame frame = { struct wsm_template_frame frame = {
@ -2306,7 +2305,7 @@ static int cw1200_upload_qosnull(struct cw1200_common *priv)
dev_kfree_skb(frame.skb); dev_kfree_skb(frame.skb);
*/ */
return ret; return 0;
} }
static int cw1200_enable_beaconing(struct cw1200_common *priv, static int cw1200_enable_beaconing(struct cw1200_common *priv,

View file

@ -100,8 +100,7 @@ static inline void libipw_networks_free(struct libipw_device *ieee)
int i; int i;
for (i = 0; i < MAX_NETWORK_COUNT; 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]); kfree(ieee->networks[i]);
} }
} }

View file

@ -1572,8 +1572,9 @@ il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif)
int int
il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 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; struct il_priv *il = hw->priv;
int ret; int ret;

View file

@ -1787,7 +1787,7 @@ int il_scan_cancel(struct il_priv *il);
int il_scan_cancel_timeout(struct il_priv *il, unsigned long ms); int il_scan_cancel_timeout(struct il_priv *il, unsigned long ms);
void il_force_scan_end(struct il_priv *il); void il_force_scan_end(struct il_priv *il);
int il_mac_hw_scan(struct ieee80211_hw *hw, 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);
void il_internal_short_hw_scan(struct il_priv *il); void il_internal_short_hw_scan(struct il_priv *il);
int il_force_reset(struct il_priv *il, bool external); int il_force_reset(struct il_priv *il, bool external);
u16 il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame, u16 il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame,

View file

@ -1495,9 +1495,10 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, 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 iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
struct cfg80211_scan_request *req = &hw_req->req;
int ret; int ret;
IWL_DEBUG_MAC80211(priv, "enter\n"); IWL_DEBUG_MAC80211(priv, "enter\n");

View file

@ -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, static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, 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 iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct cfg80211_scan_request *req = &hw_req->req;
int ret; int ret;
if (req->n_channels == 0 || 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, static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req, 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); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret; int ret;

View file

@ -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, int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req, 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, int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
struct cfg80211_sched_scan_request *req); struct cfg80211_sched_scan_request *req);
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,

View file

@ -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, static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
int n_ssids, const u8 *ssid, int ssid_len, 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 left)
{ {
int len = 0; 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; len += ssid_len + 2;
if (WARN_ON(left < ie_len)) if (WARN_ON(left < band_ie_len + common_ie_len))
return len; return len;
if (ie && ie_len) { if (band_ie && band_ie_len) {
memcpy(pos, ie, ie_len); memcpy(pos, band_ie, band_ie_len);
len += 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; return (u16)len;
@ -383,7 +391,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
(struct ieee80211_mgmt *)cmd->data, (struct ieee80211_mgmt *)cmd->data,
vif->addr, vif->addr,
req->n_ssids, ssid, ssid_len, 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)); mvm->fw->ucode_capa.max_probe_length));
iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, &params); iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, &params);
@ -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, static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sched_scan_ies *ies, struct ieee80211_scan_ies *ies,
enum ieee80211_band band, enum ieee80211_band band,
struct iwl_tx_cmd *cmd, struct iwl_tx_cmd *cmd,
u8 *data) 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, cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data,
vif->addr, vif->addr,
1, NULL, 0, 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); SCAN_OFFLOAD_PROBE_REQ_SIZE);
cmd->len = cpu_to_le16(cmd_len); 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, int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req, 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_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;

View file

@ -16,7 +16,7 @@ config LIBERTAS_USB
config LIBERTAS_CS config LIBERTAS_CS
tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
depends on LIBERTAS && PCMCIA depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP
---help--- ---help---
A driver for Marvell Libertas 8385 CompactFlash devices. A driver for Marvell Libertas 8385 CompactFlash devices.

View file

@ -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.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_SET); cmd.action = cpu_to_le16(CMD_ACT_SET);
cmd.control = 0;
/* Only v8 and below support setting the preamble */ /* Only v8 and below support setting the preamble */
if (priv->fwrelease < 0x09000000) { if (priv->fwrelease < 0x09000000) {

View file

@ -781,6 +781,36 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan,
netif_rx(skb); 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, static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
struct sk_buff *skb) 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 /* Allow unicast frames to own address if there is a pending
* PS-Poll */ * PS-Poll */
if (data->ps_poll_pending && if (data->ps_poll_pending &&
memcmp(data->hw->wiphy->perm_addr, skb->data + 4, mac80211_hwsim_addr_match(data, skb->data + 4)) {
ETH_ALEN) == 0) {
data->ps_poll_pending = false; data->ps_poll_pending = false;
return true; return true;
} }
@ -809,39 +838,6 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
return true; 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, static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
struct sk_buff *my_skb, struct sk_buff *my_skb,
int dst_portid) 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, static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct cfg80211_scan_request *req) struct ieee80211_scan_request *hw_req)
{ {
struct mac80211_hwsim_data *hwsim = hw->priv; struct mac80211_hwsim_data *hwsim = hw->priv;
struct cfg80211_scan_request *req = &hw_req->req;
mutex_lock(&hwsim->mutex); mutex_lock(&hwsim->mutex);
if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) {

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: 802.11ac * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: 802.11ac * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: 802.11h * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: 802.11n * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: 802.11n * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: 802.11n Aggregation * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: 802.11n Aggregation * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: 802.11n RX Re-ordering * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: 802.11n RX Re-ordering * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -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 # This software file (the "File") is distributed by Marvell International
# Ltd. under the terms of the GNU General Public License Version 2, June 1991 # Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -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 # This software file (the "File") is distributed by Marvell International
# Ltd. under the terms of the GNU General Public License Version 2, June 1991 # Ltd. under the terms of the GNU General Public License Version 2, June 1991
@ -194,6 +194,36 @@ rdeeprom
Example: Example:
echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0 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 getlog
This command is used to get the statistics available in the station. This command is used to get the statistics available in the station.
Usage: Usage:

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: CFG80211 * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * 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, .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. * 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}; u8 addr[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
u16 pkt_len; u16 pkt_len;
u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT; u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT;
struct timeval tv;
pkt_len = len + ETH_ALEN; 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)); len - sizeof(struct ieee80211_hdr_3addr));
skb->priority = LOW_PRIO_TID; skb->priority = LOW_PRIO_TID;
do_gettimeofday(&tv); __net_timestamp(skb);
skb->tstamp = timeval_to_ktime(tv);
return 0; return 0;
} }
@ -2483,6 +2451,16 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
mef_entry->filter[filt_num].filt_type = TYPE_EQ; mef_entry->filter[filt_num].filt_type = TYPE_EQ;
if (filt_num) if (filt_num)
mef_entry->filter[filt_num].filt_action = TYPE_OR; 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) if (!mef_cfg.criteria)
@ -2631,7 +2609,8 @@ static int
mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u8 action_code, u8 dialog_token, const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability, 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); struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
int ret; int ret;
@ -2916,12 +2895,6 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_TDLS_EXTERNAL_SETUP; 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 #ifdef CONFIG_PM
wiphy->wowlan = &mwifiex_wowlan_support; wiphy->wowlan = &mwifiex_wowlan_support;
#endif #endif

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: CFG80211 * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: Channel, Frequence and Power * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: commands and events * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * 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 *) (struct mwifiex_opt_sleep_confirm *)
adapter->sleep_cfm->data; adapter->sleep_cfm->data;
struct sk_buff *sleep_cfm_tmp; struct sk_buff *sleep_cfm_tmp;
struct timeval ts;
__le32 tmp; __le32 tmp;
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 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, (adapter->seq_num, priv->bss_num,
priv->bss_type))); 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) { if (adapter->iface_type == MWIFIEX_USB) {
sleep_cfm_tmp = sleep_cfm_tmp =
dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm) 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; rx_info->bss_type = priv->bss_type;
} }
if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) { do_gettimeofday(&tstamp);
do_gettimeofday(&tstamp); dev_dbg(adapter->dev, "EVENT: %lu.%lu: cause: %#x\n",
dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n", tstamp.tv_sec, tstamp.tv_usec, eventcause);
tstamp.tv_sec, tstamp.tv_usec, eventcause); if (eventcause == EVENT_PS_SLEEP || eventcause == EVENT_PS_AWAKE) {
} else {
/* Handle PS_SLEEP/AWAKE events on STA */ /* Handle PS_SLEEP/AWAKE events on STA */
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
if (!priv) if (!priv)
@ -960,6 +968,9 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
mwifiex_init_fw_complete(adapter); mwifiex_init_fw_complete(adapter);
if (adapter->if_ops.fw_dump)
adapter->if_ops.fw_dump(adapter);
if (adapter->if_ops.card_reset) if (adapter->if_ops.card_reset)
adapter->if_ops.card_reset(adapter); 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 result = le16_to_cpu(cmd->result);
uint16_t command = le16_to_cpu(cmd->command); uint16_t command = le16_to_cpu(cmd->command);
uint16_t seq_num = le16_to_cpu(cmd->seq_num); uint16_t seq_num = le16_to_cpu(cmd->seq_num);
struct timeval ts;
if (!upld_len) { if (!upld_len) {
dev_err(adapter->dev, "%s: cmd size is 0\n", __func__); dev_err(adapter->dev, "%s: cmd size is 0\n", __func__);
return; 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 */ /* Get BSS number and corresponding priv */
priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
HostCmd_GET_BSS_TYPE(seq_num)); HostCmd_GET_BSS_TYPE(seq_num));

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: debugfs * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
@ -692,6 +692,97 @@ done:
return ret; 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 { \ #define MWIFIEX_DFS_ADD_FILE(name) do { \
if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ 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_READ_OPS(fw_dump);
MWIFIEX_DFS_FILE_OPS(regrdwr); MWIFIEX_DFS_FILE_OPS(regrdwr);
MWIFIEX_DFS_FILE_OPS(rdeeprom); MWIFIEX_DFS_FILE_OPS(rdeeprom);
MWIFIEX_DFS_FILE_OPS(hscfg);
/* /*
* This function creates the debug FS directory structure and the files. * 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(regrdwr);
MWIFIEX_DFS_ADD_FILE(rdeeprom); MWIFIEX_DFS_ADD_FILE(rdeeprom);
MWIFIEX_DFS_ADD_FILE(fw_dump); MWIFIEX_DFS_ADD_FILE(fw_dump);
MWIFIEX_DFS_ADD_FILE(hscfg);
} }
/* /*

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: generic data structures and APIs * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: ethtool * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * 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; 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 = { const struct ethtool_ops mwifiex_ethtool_ops = {
.get_wol = mwifiex_ethtool_get_wol, .get_wol = mwifiex_ethtool_get_wol,
.set_wol = mwifiex_ethtool_set_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,
}; };

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: Firmware specific macros & structures * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -2,7 +2,7 @@
* Marvell Wireless LAN device driver: management IE handling- setting and * Marvell Wireless LAN device driver: management IE handling- setting and
* deleting IE. * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: HW/FW Initialization * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * 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 static void
mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
{ {
int idx;
if (!adapter) { if (!adapter) {
pr_err("%s: adapter is NULL\n", __func__); pr_err("%s: adapter is NULL\n", __func__);
return; return;
@ -396,7 +398,16 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
dev_dbg(adapter->dev, "info: free cmd buffer\n"); dev_dbg(adapter->dev, "info: free cmd buffer\n");
mwifiex_free_cmd_buffer(adapter); 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) if (adapter->sleep_cfm)
dev_kfree_skb_any(adapter->sleep_cfm); dev_kfree_skb_any(adapter->sleep_cfm);

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: ioctl data structures & APIs * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: association and ad-hoc start/join * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991

View file

@ -1,7 +1,7 @@
/* /*
* Marvell Wireless LAN device driver: major functions * 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 * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * 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 mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
struct sk_buff *new_skb; struct sk_buff *new_skb;
struct mwifiex_txinfo *tx_info; struct mwifiex_txinfo *tx_info;
struct timeval tv;
dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n",
jiffies, priv->bss_type, priv->bss_num); 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 * firmware for aggregate delay calculation for stats and
* MSDU lifetime expiry. * MSDU lifetime expiry.
*/ */
do_gettimeofday(&tv); __net_timestamp(skb);
skb->tstamp = timeval_to_ktime(tv);
mwifiex_queue_tx_pkt(priv, skb); mwifiex_queue_tx_pkt(priv, skb);
@ -881,6 +879,8 @@ mwifiex_add_card(void *card, struct semaphore *sem,
goto err_kmalloc; goto err_kmalloc;
INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); 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 /* Register the device. Fill up the private data structure with relevant
information from the card. */ information from the card. */

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