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

This commit is contained in:
Kalle Valo 2013-12-23 08:35:19 +02:00
commit 248544dc4e
269 changed files with 7763 additions and 5897 deletions

View File

@ -1435,7 +1435,7 @@ F: Documentation/aoe/
F: drivers/block/aoe/
ATHEROS ATH GENERIC UTILITIES
M: "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
M: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
L: linux-wireless@vger.kernel.org
S: Supported
F: drivers/net/wireless/ath/*
@ -1443,7 +1443,7 @@ F: drivers/net/wireless/ath/*
ATHEROS ATH5K WIRELESS DRIVER
M: Jiri Slaby <jirislaby@gmail.com>
M: Nick Kossifidis <mickflemm@gmail.com>
M: "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
M: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
L: linux-wireless@vger.kernel.org
L: ath5k-devel@lists.ath5k.org
W: http://wireless.kernel.org/en/users/Drivers/ath5k
@ -8553,12 +8553,11 @@ S: Maintained
F: sound/soc/codecs/twl4030*
TI WILINK WIRELESS DRIVERS
M: Luciano Coelho <luca@coelho.fi>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/wl12xx
W: http://wireless.kernel.org/en/users/Drivers/wl1251
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
S: Maintained
S: Orphan
F: drivers/net/wireless/ti/
F: include/linux/wl12xx.h

View File

@ -176,6 +176,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
bcma_err(bus,
"Could not register dev for core 0x%03X\n",
core->id.id);
put_device(&core->dev);
continue;
}
core->dev_registered = true;

View File

@ -616,7 +616,16 @@ ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
* SISRs will also clear PISR so no need to worry here.
*/
pisr_clear = pisr & ~AR5K_ISR_BITS_FROM_SISRS;
/* XXX: There seems to be an issue on some cards
* with tx interrupt flags not being updated
* on PISR despite that all Tx interrupt bits
* are cleared on SISRs. Since we handle all
* Tx queues all together it shouldn't be an
* issue if we clear Tx interrupt flags also
* on PISR to avoid that.
*/
pisr_clear = (pisr & ~AR5K_ISR_BITS_FROM_SISRS) |
(pisr & AR5K_INT_TX_ALL);
/*
* Write to clear them...

View File

@ -2754,9 +2754,9 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
mask->control[band].legacy << 4;
/* copy mcs rate mask */
mcsrate = mask->control[band].mcs[1];
mcsrate = mask->control[band].ht_mcs[1];
mcsrate <<= 8;
mcsrate |= mask->control[band].mcs[0];
mcsrate |= mask->control[band].ht_mcs[0];
ratemask[band] |= mcsrate << 12;
ratemask[band] |= mcsrate << 28;
}
@ -2806,7 +2806,7 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
mask->control[band].legacy << 4;
/* copy mcs rate mask */
mcsrate = mask->control[band].mcs[0];
mcsrate = mask->control[band].ht_mcs[0];
ratemask[band] |= mcsrate << 12;
ratemask[band] |= mcsrate << 20;
}

View File

@ -11,12 +11,14 @@ ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o
ath9k-$(CONFIG_ATH9K_PCI) += pci.o
ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o
ath9k-$(CONFIG_ATH9K_TX99) += tx99.o
ath9k-$(CONFIG_ATH9K_WOW) += wow.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o \
spectral.o
obj-$(CONFIG_ATH9K) += ath9k.o
ath9k_hw-y:= \

View File

@ -724,14 +724,14 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
struct ath_ant_comb *antcomb = &sc->ant_comb;
int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
int curr_main_set;
int main_rssi = rs->rs_rssi_ctl0;
int alt_rssi = rs->rs_rssi_ctl1;
int main_rssi = rs->rs_rssi_ctl[0];
int alt_rssi = rs->rs_rssi_ctl[1];
int rx_ant_conf, main_ant_conf;
bool short_scan = false, ret;
rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
ATH_ANT_RX_MASK;
main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
ATH_ANT_RX_MASK;
if (alt_rssi >= antcomb->low_rssi_thresh) {

View File

@ -32,12 +32,8 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
return 0;
}
if (ah->config.pcie_clock_req)
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9280PciePhy_clkreq_off_L1_9280);
else
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9280PciePhy_clkreq_always_on_L1_9280);
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9280PciePhy_clkreq_always_on_L1_9280);
if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1);

View File

@ -29,7 +29,8 @@ static void ar9002_hw_set_desc_link(void *ds, u32 ds_link)
((struct ath_desc*) ds)->ds_link = ds_link;
}
static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked,
u32 *sync_cause_p)
{
u32 isr = 0;
u32 mask2 = 0;
@ -136,7 +137,8 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
}
if (sync_cause) {
ath9k_debug_sync_cause(common, sync_cause);
if (sync_cause_p)
*sync_cause_p = sync_cause;
fatal_int =
(sync_cause &
(AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))

View File

@ -201,7 +201,6 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
ath9k_hw_get_channel_centers(ah, chan, &centers);
freq = centers.synth_center;
ah->config.spurmode = SPUR_ENABLE_EEPROM;
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);

View File

@ -131,6 +131,7 @@ static const struct ar9300_eeprom ar9300_default = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -138,7 +139,7 @@ static const struct ar9300_eeprom ar9300_default = {
},
.base_ext1 = {
.ant_div_control = 0,
.future = {0, 0, 0},
.future = {0, 0},
.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
},
.calFreqPier2G = {
@ -333,6 +334,7 @@ static const struct ar9300_eeprom ar9300_default = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0c80c080),
.papdRateMaskHt40 = LE32(0x0080c080),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -707,6 +709,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0c80c080),
.papdRateMaskHt40 = LE32(0x0080c080),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -714,7 +717,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
},
.base_ext1 = {
.ant_div_control = 0,
.future = {0, 0, 0},
.future = {0, 0},
.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
},
.calFreqPier2G = {
@ -909,6 +912,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -1284,6 +1288,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0c80c080),
.papdRateMaskHt40 = LE32(0x0080c080),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -1291,7 +1296,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
},
.base_ext1 = {
.ant_div_control = 0,
.future = {0, 0, 0},
.future = {0, 0},
.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
},
.calFreqPier2G = {
@ -1486,6 +1491,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -1861,6 +1867,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0c80c080),
.papdRateMaskHt40 = LE32(0x0080c080),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -1868,7 +1875,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
},
.base_ext1 = {
.ant_div_control = 0,
.future = {0, 0, 0},
.future = {0, 0},
.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
},
.calFreqPier2G = {
@ -2063,6 +2070,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -2437,6 +2445,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0c80C080),
.papdRateMaskHt40 = LE32(0x0080C080),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -2444,7 +2453,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
},
.base_ext1 = {
.ant_div_control = 0,
.future = {0, 0, 0},
.future = {0, 0},
.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}
},
.calFreqPier2G = {
@ -2639,6 +2648,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
.thresh62 = 28,
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.switchcomspdt = 0,
.xlna_bias_strength = 0,
.futureModal = {
0, 0, 0, 0, 0, 0, 0,
@ -4111,6 +4121,37 @@ static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah)
}
}
static void ar9003_hw_apply_minccapwr_thresh(struct ath_hw *ah,
bool is2ghz)
{
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
const u_int32_t cca_ctrl[AR9300_MAX_CHAINS] = {
AR_PHY_CCA_CTRL_0,
AR_PHY_CCA_CTRL_1,
AR_PHY_CCA_CTRL_2,
};
int chain;
u32 val;
if (is2ghz) {
if (!(eep->base_ext1.misc_enable & BIT(2)))
return;
} else {
if (!(eep->base_ext1.misc_enable & BIT(3)))
return;
}
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if (!(ah->caps.tx_chainmask & BIT(chain)))
continue;
val = ar9003_modal_header(ah, is2ghz)->noiseFloorThreshCh[chain];
REG_RMW_FIELD(ah, cca_ctrl[chain],
AR_PHY_EXT_CCA0_THRESH62_1, val);
}
}
static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@ -4125,6 +4166,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah))
ar9003_hw_internal_regulator_apply(ah);
ar9003_hw_apply_tuning_caps(ah);
ar9003_hw_apply_minccapwr_thresh(ah, chan);
ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz);
ar9003_hw_thermometer_apply(ah);
ar9003_hw_thermo_cal_apply(ah);

View File

@ -270,10 +270,20 @@ struct cal_ctl_data_5g {
u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G];
} __packed;
#define MAX_BASE_EXTENSION_FUTURE 2
struct ar9300_BaseExtension_1 {
u8 ant_div_control;
u8 future[3];
u8 tempslopextension[8];
u8 future[MAX_BASE_EXTENSION_FUTURE];
/*
* misc_enable:
*
* BIT 0 - TX Gain Cap enable.
* BIT 1 - Uncompressed Checksum enable.
* BIT 2/3 - MinCCApwr enable 2g/5g.
*/
u8 misc_enable;
int8_t tempslopextension[8];
int8_t quick_drop_low;
int8_t quick_drop_high;
} __packed;

View File

@ -175,7 +175,8 @@ static void ar9003_hw_set_desc_link(void *ds, u32 ds_link)
ads->ctl10 |= ar9003_calc_ptr_chksum(ads);
}
static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked,
u32 *sync_cause_p)
{
u32 isr = 0;
u32 mask2 = 0;
@ -310,7 +311,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
ar9003_mci_get_isr(ah, masked);
if (sync_cause) {
ath9k_debug_sync_cause(common, sync_cause);
if (sync_cause_p)
*sync_cause_p = sync_cause;
fatal_int =
(sync_cause &
(AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
@ -476,12 +478,12 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
/* XXX: Keycache */
rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined);
rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00);
rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01);
rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02);
rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10);
rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11);
rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12);
rxs->rs_rssi_ctl[0] = MS(rxsp->status1, AR_RxRSSIAnt00);
rxs->rs_rssi_ctl[1] = MS(rxsp->status1, AR_RxRSSIAnt01);
rxs->rs_rssi_ctl[2] = MS(rxsp->status1, AR_RxRSSIAnt02);
rxs->rs_rssi_ext[0] = MS(rxsp->status5, AR_RxRSSIAnt10);
rxs->rs_rssi_ext[1] = MS(rxsp->status5, AR_RxRSSIAnt11);
rxs->rs_rssi_ext[2] = MS(rxsp->status5, AR_RxRSSIAnt12);
if (rxsp->status11 & AR_RxKeyIdxValid)
rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx);

View File

@ -270,7 +270,7 @@
#define AR_PHY_AGC (AR_AGC_BASE + 0x14)
#define AR_PHY_EXT_ATTEN_CTL_0 (AR_AGC_BASE + 0x18)
#define AR_PHY_CCA_0 (AR_AGC_BASE + 0x1c)
#define AR_PHY_EXT_CCA0 (AR_AGC_BASE + 0x20)
#define AR_PHY_CCA_CTRL_0 (AR_AGC_BASE + 0x20)
#define AR_PHY_RESTART (AR_AGC_BASE + 0x24)
/*
@ -398,6 +398,8 @@
#define AR9280_PHY_CCA_THRESH62_S 12
#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF
#define AR_PHY_EXT_CCA0_THRESH62_S 0
#define AR_PHY_EXT_CCA0_THRESH62_1 0x000001FF
#define AR_PHY_EXT_CCA0_THRESH62_1_S 0
#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F
#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0
#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0

View File

@ -27,40 +27,15 @@
#include "common.h"
#include "mci.h"
#include "dfs.h"
/*
* Header for the ath9k.ko driver core *only* -- hw code nor any other driver
* should rely on this file or its contents.
*/
#include "spectral.h"
struct ath_node;
struct ath_rate_table;
/* Macro to expand scalars to 64-bit objects */
#define ito64(x) (sizeof(x) == 1) ? \
(((unsigned long long int)(x)) & (0xff)) : \
(sizeof(x) == 2) ? \
(((unsigned long long int)(x)) & 0xffff) : \
((sizeof(x) == 4) ? \
(((unsigned long long int)(x)) & 0xffffffff) : \
(unsigned long long int)(x))
/* increment with wrap-around */
#define INCR(_l, _sz) do { \
(_l)++; \
(_l) &= ((_sz) - 1); \
} while (0)
/* decrement with wrap-around */
#define DECR(_l, _sz) do { \
(_l)--; \
(_l) &= ((_sz) - 1); \
} while (0)
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i))
extern struct ieee80211_ops ath9k_ops;
extern int ath9k_modparam_nohwcrypt;
extern int led_blink;
extern bool is_ath9k_unloaded;
struct ath_config {
u16 txpowlimit;
@ -70,6 +45,17 @@ struct ath_config {
/* Descriptor Management */
/*************************/
#define ATH_TXSTATUS_RING_SIZE 512
/* Macro to expand scalars to 64-bit objects */
#define ito64(x) (sizeof(x) == 1) ? \
(((unsigned long long int)(x)) & (0xff)) : \
(sizeof(x) == 2) ? \
(((unsigned long long int)(x)) & 0xffff) : \
((sizeof(x) == 4) ? \
(((unsigned long long int)(x)) & 0xffffffff) : \
(unsigned long long int)(x))
#define ATH_TXBUF_RESET(_bf) do { \
(_bf)->bf_lastbf = NULL; \
(_bf)->bf_next = NULL; \
@ -77,23 +63,6 @@ struct ath_config {
sizeof(struct ath_buf_state)); \
} while (0)
/**
* enum buffer_type - Buffer type flags
*
* @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
* @BUF_AGGR: Indicates whether the buffer can be aggregated
* (used in aggregation scheduling)
*/
enum buffer_type {
BUF_AMPDU = BIT(0),
BUF_AGGR = BIT(1),
};
#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU)
#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR)
#define ATH_TXSTATUS_RING_SIZE 512
#define DS2PHYS(_dd, _ds) \
((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
@ -113,11 +82,20 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
/* RX / TX */
/***********/
#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i))
/* increment with wrap-around */
#define INCR(_l, _sz) do { \
(_l)++; \
(_l) &= ((_sz) - 1); \
} while (0)
#define ATH_RXBUF 512
#define ATH_TXBUF 512
#define ATH_TXBUF_RESERVE 5
#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MAX_SW_RETRIES 30
#define TID_TO_WME_AC(_tid) \
((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE : \
@ -133,6 +111,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_AGGR_MIN_QDEPTH 2
/* minimum h/w qdepth for non-aggregated traffic */
#define ATH_NON_AGGR_MIN_QDEPTH 8
#define ATH_TX_COMPLETE_POLL_INT 1000
#define ATH_TXFIFO_DEPTH 8
#define ATH_TX_ERROR 0x01
#define IEEE80211_SEQ_SEQ_SHIFT 4
#define IEEE80211_SEQ_MAX 4096
@ -167,9 +148,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
#define ATH_TX_COMPLETE_POLL_INT 1000
#define ATH_TXFIFO_DEPTH 8
struct ath_txq {
int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
u32 axq_qnum; /* ath9k hardware queue number */
@ -214,6 +192,21 @@ struct ath_rxbuf {
dma_addr_t bf_buf_addr;
};
/**
* enum buffer_type - Buffer type flags
*
* @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
* @BUF_AGGR: Indicates whether the buffer can be aggregated
* (used in aggregation scheduling)
*/
enum buffer_type {
BUF_AMPDU = BIT(0),
BUF_AGGR = BIT(1),
};
#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU)
#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR)
struct ath_buf_state {
u8 bf_type;
u8 bfs_paprd;
@ -278,7 +271,6 @@ struct ath_tx_control {
struct ieee80211_sta *sta;
};
#define ATH_TX_ERROR 0x01
/**
* @txq_map: Index is mac80211 queue number. This is
@ -372,6 +364,22 @@ struct ath_vif {
struct ath_buf *av_bcbuf;
};
struct ath9k_vif_iter_data {
u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */
u8 mask[ETH_ALEN]; /* bssid mask */
bool has_hw_macaddr;
int naps; /* number of AP vifs */
int nmeshes; /* number of mesh vifs */
int nstations; /* number of station vifs */
int nwds; /* number of WDS vifs */
int nadhocs; /* number of adhoc vifs */
};
void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ath9k_vif_iter_data *iter_data);
/*******************/
/* Beacon Handling */
/*******************/
@ -387,6 +395,9 @@ struct ath_vif {
#define ATH_DEFAULT_BMISS_LIMIT 10
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
struct ath_beacon_config {
int beacon_interval;
u16 listen_interval;
@ -420,12 +431,10 @@ struct ath_beacon {
};
void ath9k_beacon_tasklet(unsigned long data);
bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
u32 changed);
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_set_beacon(struct ath_softc *sc);
bool ath9k_csa_is_finished(struct ath_softc *sc);
@ -440,10 +449,9 @@ bool ath9k_csa_is_finished(struct ath_softc *sc);
#define ATH_LONG_CALINTERVAL_INT 1000 /* 1000 ms */
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
#define ATH_ANI_MAX_SKIP_COUNT 10
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
#define ATH_PLL_WORK_INTERVAL 100
#define ATH_ANI_MAX_SKIP_COUNT 10
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
#define ATH_PLL_WORK_INTERVAL 100
void ath_tx_complete_poll_work(struct work_struct *work);
void ath_reset_work(struct work_struct *work);
@ -477,20 +485,19 @@ enum bt_op_flags {
};
struct ath_btcoex {
bool hw_timer_enabled;
spinlock_t btcoex_lock;
struct timer_list period_timer; /* Timer for BT period */
struct timer_list no_stomp_timer;
u32 bt_priority_cnt;
unsigned long bt_priority_time;
unsigned long op_flags;
int bt_stomp_type; /* Types of BT stomping */
u32 btcoex_no_stomp; /* in usec */
u32 btcoex_no_stomp; /* in msec */
u32 btcoex_period; /* in msec */
u32 btscan_no_stomp; /* in usec */
u32 btscan_no_stomp; /* in msec */
u32 duty_cycle;
u32 bt_wait_time;
int rssi_count;
struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
struct ath_mci_profile mci;
u8 stomp_audio;
};
@ -538,12 +545,6 @@ static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
}
#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
struct ath9k_wow_pattern {
u8 pattern_bytes[MAX_PATTERN_SIZE];
u8 mask_bytes[MAX_PATTERN_SIZE];
u32 pattern_len;
};
/********************/
/* LED Control */
/********************/
@ -575,6 +576,12 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)
/* Wake on Wireless LAN */
/************************/
struct ath9k_wow_pattern {
u8 pattern_bytes[MAX_PATTERN_SIZE];
u8 mask_bytes[MAX_PATTERN_SIZE];
u32 pattern_len;
};
#ifdef CONFIG_ATH9K_WOW
void ath9k_init_wow(struct ieee80211_hw *hw);
int ath9k_suspend(struct ieee80211_hw *hw,
@ -678,13 +685,8 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
* Used when PCI device not fully initialized by bootrom/BIOS
*/
#define DEFAULT_CACHELINE 32
#define ATH_REGCLASSIDS_MAX 10
#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
#define ATH_MAX_SW_RETRIES 30
#define ATH_CHAN_MAX 255
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
#define ATH_RATE_DUMMY_MARKER 0
enum sc_op_flags {
SC_OP_INVALID,
@ -703,37 +705,6 @@ enum sc_op_flags {
#define PS_BEACON_SYNC BIT(4)
#define PS_WAIT_FOR_ANI BIT(5)
struct ath_rate_table;
struct ath9k_vif_iter_data {
u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */
u8 mask[ETH_ALEN]; /* bssid mask */
bool has_hw_macaddr;
int naps; /* number of AP vifs */
int nmeshes; /* number of mesh vifs */
int nstations; /* number of station vifs */
int nwds; /* number of WDS vifs */
int nadhocs; /* number of adhoc vifs */
};
/* enum spectral_mode:
*
* @SPECTRAL_DISABLED: spectral mode is disabled
* @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
* something else.
* @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
* is performed manually.
* @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
* during a channel scan.
*/
enum spectral_mode {
SPECTRAL_DISABLED = 0,
SPECTRAL_BACKGROUND,
SPECTRAL_MANUAL,
SPECTRAL_CHANSCAN,
};
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
@ -823,162 +794,6 @@ struct ath_softc {
#endif
};
#define SPECTRAL_SCAN_BITMASK 0x10
/* Radar info packet format, used for DFS and spectral formats. */
struct ath_radar_info {
u8 pulse_length_pri;
u8 pulse_length_ext;
u8 pulse_bw_info;
} __packed;
/* The HT20 spectral data has 4 bytes of additional information at it's end.
*
* [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
* [7:0]: all bins max_magnitude[9:2]
* [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
* [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
*/
struct ath_ht20_mag_info {
u8 all_bins[3];
u8 max_exp;
} __packed;
#define SPECTRAL_HT20_NUM_BINS 56
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data by -1/+2. This struct is for reference only.
*/
struct ath_ht20_fft_packet {
u8 data[SPECTRAL_HT20_NUM_BINS];
struct ath_ht20_mag_info mag_info;
struct ath_radar_info radar_info;
} __packed;
#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet))
/* Dynamic 20/40 mode:
*
* [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
* [7:0]: lower bins max_magnitude[9:2]
* [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
* [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
* [7:0]: upper bins max_magnitude[9:2]
* [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
* [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
*/
struct ath_ht20_40_mag_info {
u8 lower_bins[3];
u8 upper_bins[3];
u8 max_exp;
} __packed;
#define SPECTRAL_HT20_40_NUM_BINS 128
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data. This struct is for reference only.
*/
struct ath_ht20_40_fft_packet {
u8 data[SPECTRAL_HT20_40_NUM_BINS];
struct ath_ht20_40_mag_info mag_info;
struct ath_radar_info radar_info;
} __packed;
#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet))
/* grabs the max magnitude from the all/upper/lower bins */
static inline u16 spectral_max_magnitude(u8 *bins)
{
return (bins[0] & 0xc0) >> 6 |
(bins[1] & 0xff) << 2 |
(bins[2] & 0x03) << 10;
}
/* return the max magnitude from the all/upper/lower bins */
static inline u8 spectral_max_index(u8 *bins)
{
s8 m = (bins[2] & 0xfc) >> 2;
/* TODO: this still doesn't always report the right values ... */
if (m > 32)
m |= 0xe0;
else
m &= ~0xe0;
return m + 29;
}
/* return the bitmap weight from the all/upper/lower bins */
static inline u8 spectral_bitmap_weight(u8 *bins)
{
return bins[0] & 0x3f;
}
/* FFT sample format given to userspace via debugfs.
*
* Please keep the type/length at the front position and change
* other fields after adding another sample type
*
* TODO: this might need rework when switching to nl80211-based
* interface.
*/
enum ath_fft_sample_type {
ATH_FFT_SAMPLE_HT20 = 1,
ATH_FFT_SAMPLE_HT20_40,
};
struct fft_sample_tlv {
u8 type; /* see ath_fft_sample */
__be16 length;
/* type dependent data follows */
} __packed;
struct fft_sample_ht20 {
struct fft_sample_tlv tlv;
u8 max_exp;
__be16 freq;
s8 rssi;
s8 noise;
__be16 max_magnitude;
u8 max_index;
u8 bitmap_weight;
__be64 tsf;
u8 data[SPECTRAL_HT20_NUM_BINS];
} __packed;
struct fft_sample_ht20_40 {
struct fft_sample_tlv tlv;
u8 channel_type;
__be16 freq;
s8 lower_rssi;
s8 upper_rssi;
__be64 tsf;
s8 lower_noise;
s8 upper_noise;
__be16 lower_max_magnitude;
__be16 upper_max_magnitude;
u8 lower_max_index;
u8 upper_max_index;
u8 lower_bitmap_weight;
u8 upper_bitmap_weight;
u8 max_exp;
u8 data[SPECTRAL_HT20_40_NUM_BINS];
} __packed;
/********/
/* TX99 */
/********/
@ -999,19 +814,13 @@ static inline int ath9k_tx99_send(struct ath_softc *sc,
}
#endif /* CONFIG_ATH9K_TX99 */
void ath9k_tasklet(unsigned long data);
int ath_cabq_update(struct ath_softc *);
static inline void ath_read_cachesize(struct ath_common *common, int *csz)
{
common->bus_ops->read_cachesize(common, csz);
}
extern struct ieee80211_ops ath9k_ops;
extern int ath9k_modparam_nohwcrypt;
extern int led_blink;
extern bool is_ath9k_unloaded;
void ath9k_tasklet(unsigned long data);
int ath_cabq_update(struct ath_softc *);
u8 ath9k_parse_mpdudensity(u8 mpdudensity);
irqreturn_t ath_isr(int irq, void *dev);
int ath_reset(struct ath_softc *sc);
@ -1020,13 +829,12 @@ void ath_restart_work(struct ath_softc *sc);
int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops);
void ath9k_deinit_device(struct ath_softc *sc);
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath9k_reload_chainmask_settings(struct ath_softc *sc);
void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
enum spectral_mode spectral_mode);
u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
void ath_start_rfkill_poll(struct ath_softc *sc);
void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
void ath9k_ps_wakeup(struct ath_softc *sc);
void ath9k_ps_restore(struct ath_softc *sc);
#ifdef CONFIG_ATH9K_PCI
int ath_pci_init(void);
@ -1044,15 +852,4 @@ static inline int ath_ahb_init(void) { return 0; };
static inline void ath_ahb_exit(void) {};
#endif
void ath9k_ps_wakeup(struct ath_softc *sc);
void ath9k_ps_restore(struct ath_softc *sc);
u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
void ath_start_rfkill_poll(struct ath_softc *sc);
void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ath9k_vif_iter_data *iter_data);
#endif /* ATH9K_H */

View File

@ -274,18 +274,19 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
return slot;
}
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_beacon_config *cur_conf = &sc->cur_beacon_conf;
struct ath_vif *avp = (void *)vif->drv_priv;
u64 tsfadjust;
u32 tsfadjust;
if (avp->av_bslot == 0)
return;
tsfadjust = cur_conf->beacon_interval * avp->av_bslot / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(tsfadjust);
ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
(unsigned long long)tsfadjust, avp->av_bslot);
@ -431,6 +432,33 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
ath9k_hw_enable_interrupts(ah);
}
/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */
static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu)
{
u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo;
tsf_mod = tsf & (BIT(10) - 1);
tsf_hi = tsf >> 32;
tsf_lo = ((u32) tsf) >> 10;
mod_hi = tsf_hi % div_tu;
mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu;
return (mod_lo << 10) | tsf_mod;
}
static u32 ath9k_get_next_tbtt(struct ath_softc *sc, u64 tsf,
unsigned int interval)
{
struct ath_hw *ah = sc->sc_ah;
unsigned int offset;
tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time);
offset = ath9k_mod_tsf64_tu(tsf, interval);
return (u32) tsf + TU_TO_USEC(interval) - offset;
}
/*
* For multi-bss ap support beacons are either staggered evenly over N slots or
* burst together. For the former arrange for the SWBA to be delivered for each
@ -446,7 +474,8 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
/* NB: the beacon interval is kept internally in TU's */
intval = TU_TO_USEC(conf->beacon_interval);
intval /= ATH_BCBUF;
nexttbtt = intval;
nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah),
conf->beacon_interval);
if (conf->enable_beacon)
ah->imask |= ATH9K_INT_SWBA;
@ -458,7 +487,7 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
(conf->enable_beacon) ? "Enable" : "Disable",
nexttbtt, intval, conf->beacon_interval);
ath9k_beacon_init(sc, nexttbtt, intval, true);
ath9k_beacon_init(sc, nexttbtt, intval, false);
}
/*
@ -475,11 +504,9 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_beacon_state bs;
int dtimperiod, dtimcount, sleepduration;
int cfpperiod, cfpcount;
u32 nexttbtt = 0, intval, tsftu;
int dtim_intval, sleepduration;
u32 nexttbtt = 0, intval;
u64 tsf;
int num_beacons, offset, dtim_dec_count, cfp_dec_count;
/* No need to configure beacon if we are not associated */
if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
@ -492,53 +519,25 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
intval = conf->beacon_interval;
/*
* Setup dtim and cfp parameters according to
* Setup dtim parameters according to
* last beacon we received (which may be none).
*/
dtimperiod = conf->dtim_period;
dtimcount = conf->dtim_count;
if (dtimcount >= dtimperiod) /* NB: sanity check */
dtimcount = 0;
cfpperiod = 1; /* NB: no PCF support yet */
cfpcount = 0;
dtim_intval = intval * conf->dtim_period;
sleepduration = conf->listen_interval * intval;
/*
* Pull nexttbtt forward to reflect the current
* TSF and calculate dtim+cfp state for the result.
* TSF and calculate dtim state for the result.
*/
tsf = ath9k_hw_gettsf64(ah);
tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
nexttbtt = ath9k_get_next_tbtt(sc, tsf, intval);
num_beacons = tsftu / intval + 1;
offset = tsftu % intval;
nexttbtt = tsftu - offset;
if (offset)
nexttbtt += intval;
/* DTIM Beacon every dtimperiod Beacon */
dtim_dec_count = num_beacons % dtimperiod;
/* CFP every cfpperiod DTIM Beacon */
cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
if (dtim_dec_count)
cfp_dec_count++;
dtimcount -= dtim_dec_count;
if (dtimcount < 0)
dtimcount += dtimperiod;
cfpcount -= cfp_dec_count;
if (cfpcount < 0)
cfpcount += cfpperiod;
bs.bs_intval = intval;
bs.bs_intval = TU_TO_USEC(intval);
bs.bs_dtimperiod = conf->dtim_period * bs.bs_intval;
bs.bs_nexttbtt = nexttbtt;
bs.bs_dtimperiod = dtimperiod*intval;
bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
bs.bs_cfpmaxduration = 0;
bs.bs_nextdtim = nexttbtt;
if (conf->dtim_period > 1)
bs.bs_nextdtim = ath9k_get_next_tbtt(sc, tsf, dtim_intval);
/*
* Calculate the number of consecutive beacons to miss* before taking
@ -566,18 +565,16 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
* XXX fixed at 100ms
*/
bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
sleepduration));
if (bs.bs_sleepduration > bs.bs_dtimperiod)
bs.bs_sleepduration = bs.bs_dtimperiod;
/* TSF out of range threshold fixed at 1 second */
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
ath_dbg(common, BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
ath_dbg(common, BEACON,
"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
bs.bs_bmissthreshold, bs.bs_sleepduration,
bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n",
bs.bs_bmissthreshold, bs.bs_sleepduration);
/* Set the computed STA beacon timers */
@ -600,25 +597,11 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
intval = TU_TO_USEC(conf->beacon_interval);
if (conf->ibss_creator) {
if (conf->ibss_creator)
nexttbtt = intval;
} else {
u32 tbtt, offset, tsftu;
u64 tsf;
/*
* Pull nexttbtt forward to reflect the current
* sync'd TSF.
*/
tsf = ath9k_hw_gettsf64(ah);
tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
offset = tsftu % conf->beacon_interval;
tbtt = tsftu - offset;
if (offset)
tbtt += conf->beacon_interval;
nexttbtt = TU_TO_USEC(tbtt);
}
else
nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah),
conf->beacon_interval);
if (conf->enable_beacon)
ah->imask |= ATH9K_INT_SWBA;
@ -640,7 +623,8 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
set_bit(SC_OP_BEACONS, &sc->sc_flags);
}
bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
@ -711,12 +695,17 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
unsigned long flags;
bool skip_beacon = false;
if (vif->type == NL80211_IFTYPE_AP)
ath9k_set_tsfadjust(sc, vif);
if (!ath9k_allow_beacon_config(sc, vif))
return;
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
ath9k_cache_beacon_config(sc, bss_conf);
ath9k_set_beacon(sc);
set_bit(SC_OP_BEACONS, &sc->sc_flags);
return;
}
/*

View File

@ -66,7 +66,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
.bt_first_slot_time = 5,
.bt_hold_rx_clear = true,
};
u32 i, idx;
bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
if (AR_SREV_9300_20_OR_LATER(ah))
@ -88,11 +87,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
AR_BT_DISABLE_BT_ANT;
for (i = 0; i < 32; i++) {
idx = (debruijn32 << i) >> 27;
ah->hw_gen_timers.gen_timer_index[idx] = i;
}
}
EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);

View File

@ -98,10 +98,8 @@ struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw,
{
struct ieee80211_channel *curchan = chandef->chan;
struct ath9k_channel *channel;
u8 chan_idx;
chan_idx = curchan->hw_value;
channel = &ah->channels[chan_idx];
channel = &ah->channels[curchan->hw_value];
ath9k_cmn_update_ichannel(channel, chandef);
return channel;

View File

@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <linux/relay.h>
#include <asm/unaligned.h>
#include "ath9k.h"
@ -27,6 +26,47 @@
#define REG_READ_D(_ah, _reg) \
ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause)
{
if (sync_cause)
sc->debug.stats.istats.sync_cause_all++;
if (sync_cause & AR_INTR_SYNC_RTC_IRQ)
sc->debug.stats.istats.sync_rtc_irq++;
if (sync_cause & AR_INTR_SYNC_MAC_IRQ)
sc->debug.stats.istats.sync_mac_irq++;
if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS)
sc->debug.stats.istats.eeprom_illegal_access++;
if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT)
sc->debug.stats.istats.apb_timeout++;
if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT)
sc->debug.stats.istats.pci_mode_conflict++;
if (sync_cause & AR_INTR_SYNC_HOST1_FATAL)
sc->debug.stats.istats.host1_fatal++;
if (sync_cause & AR_INTR_SYNC_HOST1_PERR)
sc->debug.stats.istats.host1_perr++;
if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR)
sc->debug.stats.istats.trcv_fifo_perr++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP)
sc->debug.stats.istats.radm_cpl_ep++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT)
sc->debug.stats.istats.radm_cpl_dllp_abort++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT)
sc->debug.stats.istats.radm_cpl_tlp_abort++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR)
sc->debug.stats.istats.radm_cpl_ecrc_err++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT)
sc->debug.stats.istats.radm_cpl_timeout++;
if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT)
sc->debug.stats.istats.local_timeout++;
if (sync_cause & AR_INTR_SYNC_PM_ACCESS)
sc->debug.stats.istats.pm_access++;
if (sync_cause & AR_INTR_SYNC_MAC_AWAKE)
sc->debug.stats.istats.mac_awake++;
if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP)
sc->debug.stats.istats.mac_asleep++;
if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS)
sc->debug.stats.istats.mac_sleep_access++;
}
static ssize_t ath9k_debugfs_read_buf(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@ -1016,293 +1056,6 @@ static const struct file_operations fops_recv = {
.llseek = default_llseek,
};
static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char *mode = "";
unsigned int len;
switch (sc->spectral_mode) {
case SPECTRAL_DISABLED:
mode = "disable";
break;
case SPECTRAL_BACKGROUND:
mode = "background";
break;
case SPECTRAL_CHANSCAN:
mode = "chanscan";
break;
case SPECTRAL_MANUAL:
mode = "manual";
break;
}
len = strlen(mode);
return simple_read_from_buffer(user_buf, count, ppos, mode, len);
}
static ssize_t write_file_spec_scan_ctl(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32];
ssize_t len;
if (config_enabled(CONFIG_ATH9K_TX99))
return -EOPNOTSUPP;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (strncmp("trigger", buf, 7) == 0) {
ath9k_spectral_scan_trigger(sc->hw);
} else if (strncmp("background", buf, 9) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
} else if (strncmp("chanscan", buf, 8) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
} else if (strncmp("manual", buf, 6) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
} else if (strncmp("disable", buf, 7) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
ath_dbg(common, CONFIG, "spectral scan: disabled\n");
} else {
return -EINVAL;
}
return count;
}
static const struct file_operations fops_spec_scan_ctl = {
.read = read_file_spec_scan_ctl,
.write = write_file_spec_scan_ctl,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_spectral_short_repeat(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d\n", sc->spec_config.short_repeat);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_spectral_short_repeat(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val < 0 || val > 1)
return -EINVAL;
sc->spec_config.short_repeat = val;
return count;
}
static const struct file_operations fops_spectral_short_repeat = {
.read = read_file_spectral_short_repeat,
.write = write_file_spectral_short_repeat,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_spectral_count(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d\n", sc->spec_config.count);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_spectral_count(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val < 0 || val > 255)
return -EINVAL;
sc->spec_config.count = val;
return count;
}
static const struct file_operations fops_spectral_count = {
.read = read_file_spectral_count,
.write = write_file_spectral_count,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_spectral_period(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d\n", sc->spec_config.period);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_spectral_period(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val < 0 || val > 255)
return -EINVAL;
sc->spec_config.period = val;
return count;
}
static const struct file_operations fops_spectral_period = {
.read = read_file_spectral_period,
.write = write_file_spectral_period,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t read_file_spectral_fft_period(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d\n", sc->spec_config.fft_period);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_spectral_fft_period(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val < 0 || val > 15)
return -EINVAL;
sc->spec_config.fft_period = val;
return count;
}
static const struct file_operations fops_spectral_fft_period = {
.read = read_file_spectral_fft_period,
.write = write_file_spectral_fft_period,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static struct dentry *create_buf_file_handler(const char *filename,
struct dentry *parent,
umode_t mode,
struct rchan_buf *buf,
int *is_global)
{
struct dentry *buf_file;
buf_file = debugfs_create_file(filename, mode, parent, buf,
&relay_file_operations);
*is_global = 1;
return buf_file;
}
static int remove_buf_file_handler(struct dentry *dentry)
{
debugfs_remove(dentry);
return 0;
}
void ath_debug_send_fft_sample(struct ath_softc *sc,
struct fft_sample_tlv *fft_sample_tlv)
{
int length;
if (!sc->rfs_chan_spec_scan)
return;
length = __be16_to_cpu(fft_sample_tlv->length) +
sizeof(*fft_sample_tlv);
relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length);
}
static struct rchan_callbacks rfs_spec_scan_cb = {
.create_buf_file = create_buf_file_handler,
.remove_buf_file = remove_buf_file_handler,
};
static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@ -1772,10 +1525,7 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
void ath9k_deinit_debug(struct ath_softc *sc)
{
if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
relay_close(sc->rfs_chan_spec_scan);
sc->rfs_chan_spec_scan = NULL;
}
ath9k_spectral_deinit_debug(sc);
}
int ath9k_init_debug(struct ath_hw *ah)
@ -1795,6 +1545,7 @@ int ath9k_init_debug(struct ath_hw *ah)
ath9k_dfs_init_debug(sc);
ath9k_tx99_init_debug(sc);
ath9k_spectral_init_debug(sc);
debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_dma);
@ -1841,23 +1592,6 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_base_eeprom);
debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_modal_eeprom);
sc->rfs_chan_spec_scan = relay_open("spectral_scan",
sc->debug.debugfs_phy,
1024, 256, &rfs_spec_scan_cb,
NULL);
debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_spec_scan_ctl);
debugfs_create_file("spectral_short_repeat", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_spectral_short_repeat);
debugfs_create_file("spectral_count", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_spectral_count);
debugfs_create_file("spectral_period", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc, &fops_spectral_period);
debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_spectral_fft_period);
debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,

View File

@ -292,11 +292,11 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct dentry *dir);
void ath_debug_send_fft_sample(struct ath_softc *sc,
struct fft_sample_tlv *fft_sample);
void ath9k_debug_stat_ant(struct ath_softc *sc,
struct ath_hw_antcomb_conf *div_ant_conf,
int main_rssi_avg, int alt_rssi_avg);
void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause);
#else
#define RX_STAT_INC(c) /* NOP */
@ -331,6 +331,11 @@ static inline void ath9k_debug_stat_ant(struct ath_softc *sc,
}
static inline void
ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause)
{
}
#endif /* CONFIG_ATH9K_DEBUGFS */
#endif /* DEBUG_H */

View File

@ -158,8 +158,8 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
return;
}
ard.rssi = rs->rs_rssi_ctl0;
ard.ext_rssi = rs->rs_rssi_ext0;
ard.rssi = rs->rs_rssi_ctl[0];
ard.ext_rssi = rs->rs_rssi_ext[0];
/*
* hardware stores this as 8 bit signed value.

View File

@ -1085,31 +1085,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
{
#define EEP_MAP4K_SPURCHAN \
(ah->eeprom.map4k.modalHeader.spurChans[i].spurChan)
struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n",
i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
ath_dbg(common, ANI, "Getting spur val from new loc. %d\n",
spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_MAP4K_SPURCHAN;
break;
}
return spur_val;
#undef EEP_MAP4K_SPURCHAN
return ah->eeprom.map4k.modalHeader.spurChans[i].spurChan;
}
const struct eeprom_ops eep_4k_ops = {

View File

@ -1004,31 +1004,7 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
u16 i, bool is2GHz)
{
#define EEP_MAP9287_SPURCHAN \
(ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n",
i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
ath_dbg(common, ANI, "Getting spur val from new loc. %d\n",
spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_MAP9287_SPURCHAN;
break;
}
return spur_val;
#undef EEP_MAP9287_SPURCHAN
return ah->eeprom.map9287.modalHeader.spurChans[i].spurChan;
}
const struct eeprom_ops eep_ar9287_ops = {

View File

@ -1348,31 +1348,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
{
#define EEP_DEF_SPURCHAN \
(ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n",
i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
ath_dbg(common, ANI, "Getting spur val from new loc. %d\n",
spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_DEF_SPURCHAN;
break;
}
return spur_val;
#undef EEP_DEF_SPURCHAN
return ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan;
}
const struct eeprom_ops eep_def_ops = {

View File

@ -157,36 +157,6 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
}
}
static void ath9k_gen_timer_start(struct ath_hw *ah,
struct ath_gen_timer *timer,
u32 trig_timeout,
u32 timer_period)
{
ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period);
if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
ath9k_hw_disable_interrupts(ah);
ah->imask |= ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
}
}
static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
ath9k_hw_gen_timer_stop(ah, timer);
/* if no timer is enabled, turn off interrupt mask */
if (timer_table->timer_mask.val == 0) {
ath9k_hw_disable_interrupts(ah);
ah->imask &= ~ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
}
}
static void ath_mci_ftp_adjust(struct ath_softc *sc)
{
struct ath_btcoex *btcoex = &sc->btcoex;
@ -257,19 +227,9 @@ static void ath_btcoex_period_timer(unsigned long data)
spin_unlock_bh(&btcoex->btcoex_lock);
/*
* btcoex_period is in msec while (btocex/btscan_)no_stomp are in usec,
* ensure that we properly convert btcoex_period to usec
* for any comparision with (btcoex/btscan_)no_stomp.
*/
if (btcoex->btcoex_period * 1000 != btcoex->btcoex_no_stomp) {
if (btcoex->hw_timer_enabled)
ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period,
timer_period * 10);
btcoex->hw_timer_enabled = true;
}
if (btcoex->btcoex_period != btcoex->btcoex_no_stomp)
mod_timer(&btcoex->no_stomp_timer,
jiffies + msecs_to_jiffies(timer_period));
ath9k_ps_restore(sc);
@ -282,7 +242,7 @@ skip_hw_wakeup:
* Generic tsf based hw timer which configures weight
* registers to time slice between wlan and bt traffic
*/
static void ath_btcoex_no_stomp_timer(void *arg)
static void ath_btcoex_no_stomp_timer(unsigned long arg)
{
struct ath_softc *sc = (struct ath_softc *)arg;
struct ath_hw *ah = sc->sc_ah;
@ -311,24 +271,18 @@ static int ath_init_btcoex_timer(struct ath_softc *sc)
struct ath_btcoex *btcoex = &sc->btcoex;
btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 1000 *
btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
btcoex->btcoex_period / 100;
btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 1000 *
btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
btcoex->btcoex_period / 100;
setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
(unsigned long) sc);
setup_timer(&btcoex->no_stomp_timer, ath_btcoex_no_stomp_timer,
(unsigned long) sc);
spin_lock_init(&btcoex->btcoex_lock);
btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
ath_btcoex_no_stomp_timer,
ath_btcoex_no_stomp_timer,
(void *) sc, AR_FIRST_NDP_TIMER);
if (!btcoex->no_stomp_timer)
return -ENOMEM;
return 0;
}
@ -343,10 +297,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n");
/* make sure duty cycle timer is also stopped when resuming */
if (btcoex->hw_timer_enabled) {
ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
btcoex->hw_timer_enabled = false;
}
del_timer_sync(&btcoex->no_stomp_timer);
btcoex->bt_priority_cnt = 0;
btcoex->bt_priority_time = jiffies;
@ -363,24 +314,16 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
void ath9k_btcoex_timer_pause(struct ath_softc *sc)
{
struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_hw *ah = sc->sc_ah;
del_timer_sync(&btcoex->period_timer);
if (btcoex->hw_timer_enabled) {
ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
btcoex->hw_timer_enabled = false;
}
del_timer_sync(&btcoex->no_stomp_timer);
}
void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
{
struct ath_btcoex *btcoex = &sc->btcoex;
if (btcoex->hw_timer_enabled) {
ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
btcoex->hw_timer_enabled = false;
}
del_timer_sync(&btcoex->no_stomp_timer);
}
u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
@ -400,12 +343,6 @@ u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status)
{
struct ath_hw *ah = sc->sc_ah;
if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
if (status & ATH9K_INT_GENTIMER)
ath_gen_timer_isr(sc->sc_ah);
if (status & ATH9K_INT_MCI)
ath_mci_intr(sc);
}
@ -447,10 +384,6 @@ void ath9k_deinit_btcoex(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
if ((sc->btcoex.no_stomp_timer) &&
ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE)
ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
if (ath9k_hw_mci_is_enabled(ah))
ath_mci_cleanup(sc);
}

View File

@ -600,10 +600,15 @@ void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);
struct base_eep_header *ath9k_htc_get_eeprom_base(struct ath9k_htc_priv *priv);
#ifdef CONFIG_MAC80211_LEDS
void ath9k_configure_leds(struct ath9k_htc_priv *priv);
void ath9k_init_leds(struct ath9k_htc_priv *priv);
void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
void ath9k_led_work(struct work_struct *work);
#else
static inline void ath9k_configure_leds(struct ath9k_htc_priv *priv)
{
}
static inline void ath9k_init_leds(struct ath9k_htc_priv *priv)
{
}

View File

@ -70,11 +70,11 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
struct ath9k_beacon_state bs;
enum ath9k_int imask = 0;
int dtimperiod, dtimcount, sleepduration;
int cfpperiod, cfpcount, bmiss_timeout;
int bmiss_timeout;
u32 nexttbtt = 0, intval, tsftu;
__be32 htc_imask = 0;
u64 tsf;
int num_beacons, offset, dtim_dec_count, cfp_dec_count;
int num_beacons, offset, dtim_dec_count;
int ret __attribute__ ((unused));
u8 cmd_rsp;
@ -84,7 +84,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval);
/*
* Setup dtim and cfp parameters according to
* Setup dtim parameters according to
* last beacon we received (which may be none).
*/
dtimperiod = bss_conf->dtim_period;
@ -93,8 +93,6 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
dtimcount = 1;
if (dtimcount >= dtimperiod) /* NB: sanity check */
dtimcount = 0;
cfpperiod = 1; /* NB: no PCF support yet */
cfpcount = 0;
sleepduration = intval;
if (sleepduration <= 0)
@ -102,7 +100,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
/*
* Pull nexttbtt forward to reflect the current
* TSF and calculate dtim+cfp state for the result.
* TSF and calculate dtim state for the result.
*/
tsf = ath9k_hw_gettsf64(priv->ah);
tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
@ -115,26 +113,14 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
/* DTIM Beacon every dtimperiod Beacon */
dtim_dec_count = num_beacons % dtimperiod;
/* CFP every cfpperiod DTIM Beacon */
cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
if (dtim_dec_count)
cfp_dec_count++;
dtimcount -= dtim_dec_count;
if (dtimcount < 0)
dtimcount += dtimperiod;
cfpcount -= cfp_dec_count;
if (cfpcount < 0)
cfpcount += cfpperiod;
bs.bs_intval = intval;
bs.bs_nexttbtt = nexttbtt;
bs.bs_dtimperiod = dtimperiod*intval;
bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
bs.bs_cfpmaxduration = 0;
bs.bs_intval = TU_TO_USEC(intval);
bs.bs_nexttbtt = TU_TO_USEC(nexttbtt);
bs.bs_dtimperiod = dtimperiod * bs.bs_intval;
bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount * bs.bs_intval;
/*
* Calculate the number of consecutive beacons to miss* before taking
@ -161,7 +147,8 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
* XXX fixed at 100ms
*/
bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
sleepduration));
if (bs.bs_sleepduration > bs.bs_dtimperiod)
bs.bs_sleepduration = bs.bs_dtimperiod;
@ -170,10 +157,8 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n",
intval, tsf, tsftu);
ath_dbg(common, CONFIG,
"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
bs.bs_bmissthreshold, bs.bs_sleepduration,
bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
ath_dbg(common, CONFIG, "bmiss: %u sleep: %u\n",
bs.bs_bmissthreshold, bs.bs_sleepduration);
/* Set the computed STA beacon timers */

View File

@ -255,6 +255,17 @@ void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
cancel_work_sync(&priv->led_work);
}
void ath9k_configure_leds(struct ath9k_htc_priv *priv)
{
/* Configure gpio 1 for output */
ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
/* LED off, active low */
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
}
void ath9k_init_leds(struct ath9k_htc_priv *priv)
{
int ret;
@ -268,11 +279,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
else
priv->ah->led_pin = ATH_LED_PIN_DEF;
/* Configure gpio 1 for output */
ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
/* LED off, active low */
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
ath9k_configure_leds(priv);
snprintf(priv->led_name, sizeof(priv->led_name),
"ath9k_htc-%s", wiphy_name(priv->hw->wiphy));

View File

@ -1000,6 +1000,8 @@ int ath9k_htc_resume(struct htc_target *htc_handle)
ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid,
priv->ah->hw_version.usbdev);
ath9k_configure_leds(priv);
return ret;
}
#endif

View File

@ -49,9 +49,10 @@ static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
}
static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked,
u32 *sync_cause_p)
{
return ath9k_hw_ops(ah)->get_isr(ah, masked);
return ath9k_hw_ops(ah)->get_isr(ah, masked, sync_cause_p);
}
static inline void ath9k_hw_set_txdesc(struct ath_hw *ah, void *ds,

View File

@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/bitops.h>
#include <asm/unaligned.h>
#include "hw.h"
@ -84,48 +85,6 @@ static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
#ifdef CONFIG_ATH9K_DEBUGFS
void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause)
{
struct ath_softc *sc = common->priv;
if (sync_cause)
sc->debug.stats.istats.sync_cause_all++;
if (sync_cause & AR_INTR_SYNC_RTC_IRQ)
sc->debug.stats.istats.sync_rtc_irq++;
if (sync_cause & AR_INTR_SYNC_MAC_IRQ)
sc->debug.stats.istats.sync_mac_irq++;
if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS)
sc->debug.stats.istats.eeprom_illegal_access++;
if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT)
sc->debug.stats.istats.apb_timeout++;
if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT)
sc->debug.stats.istats.pci_mode_conflict++;
if (sync_cause & AR_INTR_SYNC_HOST1_FATAL)
sc->debug.stats.istats.host1_fatal++;
if (sync_cause & AR_INTR_SYNC_HOST1_PERR)
sc->debug.stats.istats.host1_perr++;
if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR)
sc->debug.stats.istats.trcv_fifo_perr++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP)
sc->debug.stats.istats.radm_cpl_ep++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT)
sc->debug.stats.istats.radm_cpl_dllp_abort++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT)
sc->debug.stats.istats.radm_cpl_tlp_abort++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR)
sc->debug.stats.istats.radm_cpl_ecrc_err++;
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT)
sc->debug.stats.istats.radm_cpl_timeout++;
if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT)
sc->debug.stats.istats.local_timeout++;
if (sync_cause & AR_INTR_SYNC_PM_ACCESS)
sc->debug.stats.istats.pm_access++;
if (sync_cause & AR_INTR_SYNC_MAC_AWAKE)
sc->debug.stats.istats.mac_awake++;
if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP)
sc->debug.stats.istats.mac_asleep++;
if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS)
sc->debug.stats.istats.mac_sleep_access++;
}
#endif
@ -438,21 +397,12 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
static void ath9k_hw_init_config(struct ath_hw *ah)
{
int i;
ah->config.dma_beacon_response_time = 1;
ah->config.sw_beacon_response_time = 6;
ah->config.additional_swba_backoff = 0;
ah->config.ack_6mb = 0x0;
ah->config.cwm_ignore_extcca = 0;
ah->config.pcie_clock_req = 0;
ah->config.analog_shiftreg = 1;
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
ah->config.spurchans[i][0] = AR_NO_SPUR;
ah->config.spurchans[i][1] = AR_NO_SPUR;
}
ah->config.rx_intr_mitigation = true;
/*
@ -485,7 +435,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
ah->hw_version.magic = AR5416_MAGIC;
ah->hw_version.subvendorid = 0;
ah->atim_window = 0;
ah->sta_id1_defaults =
AR_STA_ID1_CRPT_MIC_ENABLE |
AR_STA_ID1_MCAST_KSRCH;
@ -1281,6 +1230,42 @@ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
*coef_exponent = coef_exp - 16;
}
/* AR9330 WAR:
* call external reset function to reset WMAC if:
* - doing a cold reset
* - we have pending frames in the TX queues.
*/
static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type)
{
int i, npend = 0;
for (i = 0; i < AR_NUM_QCU; i++) {
npend = ath9k_hw_numtxpending(ah, i);
if (npend)
break;
}
if (ah->external_reset &&
(npend || type == ATH9K_RESET_COLD)) {
int reset_err = 0;
ath_dbg(ath9k_hw_common(ah), RESET,
"reset MAC via external reset\n");
reset_err = ah->external_reset();
if (reset_err) {
ath_err(ath9k_hw_common(ah),
"External reset failed, err=%d\n",
reset_err);
return false;
}
REG_WRITE(ah, AR_RTC_RESET, 1);
}
return true;
}
static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
{
u32 rst_flags;
@ -1331,38 +1316,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
}
if (AR_SREV_9330(ah)) {
int npend = 0;
int i;
/* AR9330 WAR:
* call external reset function to reset WMAC if:
* - doing a cold reset
* - we have pending frames in the TX queues
*/
for (i = 0; i < AR_NUM_QCU; i++) {
npend = ath9k_hw_numtxpending(ah, i);
if (npend)
break;
}
if (ah->external_reset &&
(npend || type == ATH9K_RESET_COLD)) {
int reset_err = 0;
ath_dbg(ath9k_hw_common(ah), RESET,
"reset MAC via external reset\n");
reset_err = ah->external_reset();
if (reset_err) {
ath_err(ath9k_hw_common(ah),
"External reset failed, err=%d\n",
reset_err);
return false;
}
REG_WRITE(ah, AR_RTC_RESET, 1);
}
if (!ath9k_hw_ar9330_reset_war(ah, type))
return false;
}
if (ath9k_hw_mci_is_enabled(ah))
@ -1372,7 +1327,12 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
REGWRITE_BUFFER_FLUSH(ah);
udelay(50);
if (AR_SREV_9300_20_OR_LATER(ah))
udelay(50);
else if (AR_SREV_9100(ah))
udelay(10000);
else
udelay(100);
REG_WRITE(ah, AR_RTC_RC, 0);
if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
@ -1408,8 +1368,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
REGWRITE_BUFFER_FLUSH(ah);
if (!AR_SREV_9300_20_OR_LATER(ah))
udelay(2);
udelay(2);
if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
REG_WRITE(ah, AR_RC, 0);
@ -1485,7 +1444,6 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,
if (AR_SREV_9330(ah))
ar9003_hw_internal_regulator_apply(ah);
ath9k_hw_init_pll(ah, chan);
ath9k_hw_set_rfmode(ah, chan);
return true;
}
@ -1954,6 +1912,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (r)
return r;
ath9k_hw_set_rfmode(ah, chan);
if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
@ -2264,9 +2224,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
case NL80211_IFTYPE_ADHOC:
REG_SET_BIT(ah, AR_TXCFG,
AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon +
TU_TO_USEC(ah->atim_window ? ah->atim_window : 1));
flags |= AR_NDP_TIMER_EN;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon);
@ -2287,7 +2244,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period);
REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period);
REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period);
REG_WRITE(ah, AR_NDP_PERIOD, beacon_period);
REGWRITE_BUFFER_FLUSH(ah);
@ -2304,12 +2260,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
ENABLE_REGWRITE_BUFFER(ah);
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
REG_WRITE(ah, AR_BEACON_PERIOD,
TU_TO_USEC(bs->bs_intval));
REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
TU_TO_USEC(bs->bs_intval));
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, bs->bs_nexttbtt);
REG_WRITE(ah, AR_BEACON_PERIOD, bs->bs_intval);
REG_WRITE(ah, AR_DMA_BEACON_PERIOD, bs->bs_intval);
REGWRITE_BUFFER_FLUSH(ah);
@ -2337,9 +2290,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
ENABLE_REGWRITE_BUFFER(ah);
REG_WRITE(ah, AR_NEXT_DTIM,
TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
REG_WRITE(ah, AR_NEXT_DTIM, bs->bs_nextdtim - SLEEP_SLOP);
REG_WRITE(ah, AR_NEXT_TIM, nextTbtt - SLEEP_SLOP);
REG_WRITE(ah, AR_SLEEP1,
SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
@ -2353,8 +2305,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
REG_WRITE(ah, AR_SLEEP2,
SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
REG_WRITE(ah, AR_TIM_PERIOD, beaconintval);
REG_WRITE(ah, AR_DTIM_PERIOD, dtimperiod);
REGWRITE_BUFFER_FLUSH(ah);
@ -2990,20 +2942,6 @@ static const struct ath_gen_timer_configuration gen_tmr_configuration[] =
/* HW generic timer primitives */
/* compute and clear index of rightmost 1 */
static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask)
{
u32 b;
b = *mask;
b &= (0-b);
*mask &= ~b;
b *= debruijn32;
b >>= 27;
return timer_table->gen_timer_index[b];
}
u32 ath9k_hw_gettsf32(struct ath_hw *ah)
{
return REG_READ(ah, AR_TSF_L32);
@ -3019,6 +2957,10 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
struct ath_gen_timer *timer;
if ((timer_index < AR_FIRST_NDP_TIMER) ||
(timer_index >= ATH_MAX_GEN_TIMER))
return NULL;
timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
if (timer == NULL)
return NULL;
@ -3036,23 +2978,13 @@ EXPORT_SYMBOL(ath_gen_timer_alloc);
void ath9k_hw_gen_timer_start(struct ath_hw *ah,
struct ath_gen_timer *timer,
u32 trig_timeout,
u32 timer_next,
u32 timer_period)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
u32 tsf, timer_next;
u32 mask = 0;
BUG_ON(!timer_period);
set_bit(timer->index, &timer_table->timer_mask.timer_bits);
tsf = ath9k_hw_gettsf32(ah);
timer_next = tsf + trig_timeout;
ath_dbg(ath9k_hw_common(ah), BTCOEX,
"current tsf %x period %x timer_next %x\n",
tsf, timer_period, timer_next);
timer_table->timer_mask |= BIT(timer->index);
/*
* Program generic timer registers
@ -3078,10 +3010,19 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah,
(1 << timer->index));
}
/* Enable both trigger and thresh interrupt masks */
REG_SET_BIT(ah, AR_IMR_S5,
(SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
if (timer->trigger)
mask |= SM(AR_GENTMR_BIT(timer->index),
AR_IMR_S5_GENTIMER_TRIG);
if (timer->overflow)
mask |= SM(AR_GENTMR_BIT(timer->index),
AR_IMR_S5_GENTIMER_THRESH);
REG_SET_BIT(ah, AR_IMR_S5, mask);
if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
ah->imask |= ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah);
}
}
EXPORT_SYMBOL(ath9k_hw_gen_timer_start);
@ -3089,11 +3030,6 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
if ((timer->index < AR_FIRST_NDP_TIMER) ||
(timer->index >= ATH_MAX_GEN_TIMER)) {
return;
}
/* Clear generic timer enable bits. */
REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
gen_tmr_configuration[timer->index].mode_mask);
@ -3113,7 +3049,12 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
(SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
clear_bit(timer->index, &timer_table->timer_mask.timer_bits);
timer_table->timer_mask &= ~BIT(timer->index);
if (timer_table->timer_mask == 0) {
ah->imask &= ~ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah);
}
}
EXPORT_SYMBOL(ath9k_hw_gen_timer_stop);
@ -3134,32 +3075,32 @@ void ath_gen_timer_isr(struct ath_hw *ah)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
struct ath_gen_timer *timer;
struct ath_common *common = ath9k_hw_common(ah);
u32 trigger_mask, thresh_mask, index;
unsigned long trigger_mask, thresh_mask;
unsigned int index;
/* get hardware generic timer interrupt status */
trigger_mask = ah->intr_gen_timer_trigger;
thresh_mask = ah->intr_gen_timer_thresh;
trigger_mask &= timer_table->timer_mask.val;
thresh_mask &= timer_table->timer_mask.val;
trigger_mask &= timer_table->timer_mask;
thresh_mask &= timer_table->timer_mask;
trigger_mask &= ~thresh_mask;
while (thresh_mask) {
index = rightmost_index(timer_table, &thresh_mask);
for_each_set_bit(index, &thresh_mask, ARRAY_SIZE(timer_table->timers)) {
timer = timer_table->timers[index];
BUG_ON(!timer);
ath_dbg(common, BTCOEX, "TSF overflow for Gen timer %d\n",
index);
if (!timer)
continue;
if (!timer->overflow)
continue;
timer->overflow(timer->arg);
}
while (trigger_mask) {
index = rightmost_index(timer_table, &trigger_mask);
for_each_set_bit(index, &trigger_mask, ARRAY_SIZE(timer_table->timers)) {
timer = timer_table->timers[index];
BUG_ON(!timer);
ath_dbg(common, BTCOEX,
"Gen timer[%d] trigger\n", index);
if (!timer)
continue;
if (!timer->trigger)
continue;
timer->trigger(timer->arg);
}
}

View File

@ -168,7 +168,7 @@
#define CAB_TIMEOUT_VAL 10
#define BEACON_TIMEOUT_VAL 10
#define MIN_BEACON_TIMEOUT_VAL 1
#define SLEEP_SLOP 3
#define SLEEP_SLOP TU_TO_USEC(3)
#define INIT_CONFIG_STATUS 0x00000000
#define INIT_RSSI_THR 0x00000700
@ -280,10 +280,8 @@ struct ath9k_hw_capabilities {
struct ath9k_ops_config {
int dma_beacon_response_time;
int sw_beacon_response_time;
int additional_swba_backoff;
int ack_6mb;
u32 cwm_ignore_extcca;
u8 pcie_clock_req;
u32 pcie_waen;
u8 analog_shiftreg;
u32 ofdm_trig_low;
@ -294,18 +292,11 @@ struct ath9k_ops_config {
int serialize_regmode;
bool rx_intr_mitigation;
bool tx_intr_mitigation;
#define SPUR_DISABLE 0
#define SPUR_ENABLE_IOCTL 1
#define SPUR_ENABLE_EEPROM 2
#define AR_SPUR_5413_1 1640
#define AR_SPUR_5413_2 1200
#define AR_NO_SPUR 0x8000
#define AR_BASE_FREQ_2GHZ 2300
#define AR_BASE_FREQ_5GHZ 4900
#define AR_SPUR_FEEQ_BOUND_HT40 19
#define AR_SPUR_FEEQ_BOUND_HT20 10
int spurmode;
u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
u8 max_txtrig_level;
u16 ani_poll_interval; /* ANI poll interval in ms */
@ -460,10 +451,6 @@ struct ath9k_beacon_state {
u32 bs_intval;
#define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */
u32 bs_dtimperiod;
u16 bs_cfpperiod;
u16 bs_cfpmaxduration;
u32 bs_cfpnext;
u16 bs_timoffset;
u16 bs_bmissthreshold;
u32 bs_sleepduration;
u32 bs_tsfoor_threshold;
@ -499,12 +486,6 @@ struct ath9k_hw_version {
#define AR_GENTMR_BIT(_index) (1 << (_index))
/*
* Using de Bruijin sequence to look up 1's index in a 32 bit number
* debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
*/
#define debruijn32 0x077CB531U
struct ath_gen_timer_configuration {
u32 next_addr;
u32 period_addr;
@ -520,12 +501,8 @@ struct ath_gen_timer {
};
struct ath_gen_timer_table {
u32 gen_timer_index[32];
struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER];
union {
unsigned long timer_bits;
u16 val;
} timer_mask;
u16 timer_mask;
};
struct ath_hw_antcomb_conf {
@ -690,7 +667,8 @@ struct ath_hw_ops {
struct ath9k_channel *chan,
u8 rxchainmask,
bool longcal);
bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked);
bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked,
u32 *sync_cause_p);
void (*set_txdesc)(struct ath_hw *ah, void *ds,
struct ath_tx_info *i);
int (*proc_txdesc)(struct ath_hw *ah, void *ds,
@ -786,7 +764,6 @@ struct ath_hw {
u32 txurn_interrupt_mask;
atomic_t intr_ref_cnt;
bool chip_fullsleep;
u32 atim_window;
u32 modes_index;
/* Calibration */
@ -1018,13 +995,6 @@ bool ath9k_hw_check_alive(struct ath_hw *ah);
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
#ifdef CONFIG_ATH9K_DEBUGFS
void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause);
#else
static inline void ath9k_debug_sync_cause(struct ath_common *common,
u32 sync_cause) {}
#endif
/* Generic hw timer primitives */
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*trigger)(void *),

View File

@ -470,7 +470,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);
sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
ath_cabq_update(sc);
sc->tx.uapsdq = ath_txq_setup(sc, ATH9K_TX_QUEUE_UAPSD, 0);
@ -705,7 +704,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ah->reg_ops.read = ath9k_ioread32;
ah->reg_ops.write = ath9k_iowrite32;
ah->reg_ops.rmw = ath9k_reg_rmw;
atomic_set(&ah->intr_ref_cnt, -1);
sc->sc_ah = ah;
pCap = &ah->caps;
@ -899,7 +897,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
}
};
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);

View File

@ -481,8 +481,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
| AR_Q_MISC_CBR_INCR_DIS0);
value = (qi->tqi_readyTime -
(ah->config.sw_beacon_response_time -
ah->config.dma_beacon_response_time) -
ah->config.additional_swba_backoff) * 1024;
ah->config.dma_beacon_response_time)) * 1024;
REG_WRITE(ah, AR_QRDYTIMECFG(q),
value | AR_Q_RDYTIMECFG_EN);
REG_SET_BIT(ah, AR_DMISC(q),
@ -550,25 +549,25 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
rs->rs_rssi = ATH9K_RSSI_BAD;
rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD;
rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD;
rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD;
rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD;
rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD;
rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD;
} else {
rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0,
AR_RxRSSIAnt00);
rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0,
AR_RxRSSIAnt01);
rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0,
AR_RxRSSIAnt02);
rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4,
AR_RxRSSIAnt10);
rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4,
AR_RxRSSIAnt11);
rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4,
AR_RxRSSIAnt12);
}
if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)

View File

@ -133,12 +133,8 @@ struct ath_rx_status {
u8 rs_rate;
u8 rs_antenna;
u8 rs_more;
int8_t rs_rssi_ctl0;
int8_t rs_rssi_ctl1;
int8_t rs_rssi_ctl2;
int8_t rs_rssi_ext0;
int8_t rs_rssi_ext1;
int8_t rs_rssi_ext2;
int8_t rs_rssi_ctl[3];
int8_t rs_rssi_ext[3];
u8 rs_isaggr;
u8 rs_firstaggr;
u8 rs_moreaggr;

View File

@ -508,6 +508,9 @@ void ath9k_tasklet(unsigned long data)
wake_up(&sc->tx_wait);
}
if (status & ATH9K_INT_GENTIMER)
ath_gen_timer_isr(sc->sc_ah);
ath9k_btcoex_handle_interrupt(sc, status);
/* re-enable hardware interrupt */
@ -538,6 +541,7 @@ irqreturn_t ath_isr(int irq, void *dev)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
enum ath9k_int status;
u32 sync_cause;
bool sched = false;
/*
@ -564,7 +568,8 @@ irqreturn_t ath_isr(int irq, void *dev)
* bits we haven't explicitly enabled so we mask the
* value to insure we only process bits we requested.
*/
ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
ath9k_hw_getisr(ah, &status, &sync_cause); /* NB: clears ISR too */
ath9k_debug_sync_cause(sc, sync_cause);
status &= ah->imask; /* discard unasked-for bits */
/*
@ -757,6 +762,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
*/
ath9k_cmn_init_crypto(sc->sc_ah);
ath9k_hw_reset_tsf(ah);
spin_unlock_bh(&sc->sc_pcu_lock);
mutex_unlock(&sc->mutex);
@ -1657,13 +1664,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
(changed & BSS_CHANGED_BEACON_INT)) {
if (ah->opmode == NL80211_IFTYPE_AP &&
bss_conf->enable_beacon)
ath9k_set_tsfadjust(sc, vif);
if (ath9k_allow_beacon_config(sc, vif))
ath9k_beacon_config(sc, vif, changed);
}
(changed & BSS_CHANGED_BEACON_INT))
ath9k_beacon_config(sc, vif, changed);
if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)

View File

@ -200,7 +200,7 @@ skip_tuning:
if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
btcoex->btcoex_no_stomp = btcoex->btcoex_period * 1000 *
btcoex->btcoex_no_stomp = btcoex->btcoex_period *
(100 - btcoex->duty_cycle) / 100;
ath9k_hw_btcoex_enable(sc->sc_ah);

View File

@ -15,7 +15,6 @@
*/
#include <linux/dma-mapping.h>
#include <linux/relay.h>
#include "ath9k.h"
#include "ar9003_mac.h"
@ -906,6 +905,7 @@ static void ath9k_process_rssi(struct ath_common *common,
struct ath_hw *ah = common->ah;
int last_rssi;
int rssi = rx_stats->rs_rssi;
int i, j;
/*
* RSSI is not available for subframes in an A-MPDU.
@ -924,6 +924,20 @@ static void ath9k_process_rssi(struct ath_common *common,
return;
}
for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
s8 rssi;
if (!(ah->rxchainmask & BIT(i)))
continue;
rssi = rx_stats->rs_rssi_ctl[i];
if (rssi != ATH9K_RSSI_BAD) {
rxs->chains |= BIT(j);
rxs->chain_signal[j] = ah->noise + rssi;
}
j++;
}
/*
* Update Beacon RSSI, this is used by ANI.
*/
@ -960,186 +974,6 @@ static void ath9k_process_tsf(struct ath_rx_status *rs,
rxs->mactime += 0x100000000ULL;
}
#ifdef CONFIG_ATH9K_DEBUGFS
static s8 fix_rssi_inv_only(u8 rssi_val)
{
if (rssi_val == 128)
rssi_val = 0;
return (s8) rssi_val;
}
#endif
/* returns 1 if this was a spectral frame, even if not handled. */
static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
struct ath_rx_status *rs, u64 tsf)
{
#ifdef CONFIG_ATH9K_DEBUGFS
struct ath_hw *ah = sc->sc_ah;
u8 num_bins, *bins, *vdata = (u8 *)hdr;
struct fft_sample_ht20 fft_sample_20;
struct fft_sample_ht20_40 fft_sample_40;
struct fft_sample_tlv *tlv;
struct ath_radar_info *radar_info;
int len = rs->rs_datalen;
int dc_pos;
u16 fft_len, length, freq = ah->curchan->chan->center_freq;
enum nl80211_channel_type chan_type;
/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
* via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
* yet, but this is supposed to be possible as well.
*/
if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
return 0;
/* check if spectral scan bit is set. This does not have to be checked
* if received through a SPECTRAL phy error, but shouldn't hurt.
*/
radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
return 0;
chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef);
if ((chan_type == NL80211_CHAN_HT40MINUS) ||
(chan_type == NL80211_CHAN_HT40PLUS)) {
fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
num_bins = SPECTRAL_HT20_40_NUM_BINS;
bins = (u8 *)fft_sample_40.data;
} else {
fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
num_bins = SPECTRAL_HT20_NUM_BINS;
bins = (u8 *)fft_sample_20.data;
}
/* Variation in the data length is possible and will be fixed later */
if ((len > fft_len + 2) || (len < fft_len - 1))
return 1;
switch (len - fft_len) {
case 0:
/* length correct, nothing to do. */
memcpy(bins, vdata, num_bins);
break;
case -1:
/* first byte missing, duplicate it. */
memcpy(&bins[1], vdata, num_bins - 1);
bins[0] = vdata[0];
break;
case 2:
/* MAC added 2 extra bytes at bin 30 and 32, remove them. */
memcpy(bins, vdata, 30);
bins[30] = vdata[31];
memcpy(&bins[31], &vdata[33], num_bins - 31);
break;
case 1:
/* MAC added 2 extra bytes AND first byte is missing. */
bins[0] = vdata[0];
memcpy(&bins[1], vdata, 30);
bins[31] = vdata[31];
memcpy(&bins[32], &vdata[33], num_bins - 32);
break;
default:
return 1;
}
/* DC value (value in the middle) is the blind spot of the spectral
* sample and invalid, interpolate it.
*/
dc_pos = num_bins / 2;
bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
if ((chan_type == NL80211_CHAN_HT40MINUS) ||
(chan_type == NL80211_CHAN_HT40PLUS)) {
s8 lower_rssi, upper_rssi;
s16 ext_nf;
u8 lower_max_index, upper_max_index;
u8 lower_bitmap_w, upper_bitmap_w;
u16 lower_mag, upper_mag;
struct ath9k_hw_cal_data *caldata = ah->caldata;
struct ath_ht20_40_mag_info *mag_info;
if (caldata)
ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
caldata->nfCalHist[3].privNF);
else
ext_nf = ATH_DEFAULT_NOISE_FLOOR;
length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
fft_sample_40.tlv.length = __cpu_to_be16(length);
fft_sample_40.freq = __cpu_to_be16(freq);
fft_sample_40.channel_type = chan_type;
if (chan_type == NL80211_CHAN_HT40PLUS) {
lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext0);
fft_sample_40.lower_noise = ah->noise;
fft_sample_40.upper_noise = ext_nf;
} else {
lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext0);
upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
fft_sample_40.lower_noise = ext_nf;
fft_sample_40.upper_noise = ah->noise;
}
fft_sample_40.lower_rssi = lower_rssi;
fft_sample_40.upper_rssi = upper_rssi;
mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1;
lower_mag = spectral_max_magnitude(mag_info->lower_bins);
upper_mag = spectral_max_magnitude(mag_info->upper_bins);
fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
lower_max_index = spectral_max_index(mag_info->lower_bins);
upper_max_index = spectral_max_index(mag_info->upper_bins);
fft_sample_40.lower_max_index = lower_max_index;
fft_sample_40.upper_max_index = upper_max_index;
lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
fft_sample_40.max_exp = mag_info->max_exp & 0xf;
fft_sample_40.tsf = __cpu_to_be64(tsf);
tlv = (struct fft_sample_tlv *)&fft_sample_40;
} else {
u8 max_index, bitmap_w;
u16 magnitude;
struct ath_ht20_mag_info *mag_info;
length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
fft_sample_20.tlv.length = __cpu_to_be16(length);
fft_sample_20.freq = __cpu_to_be16(freq);
fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
fft_sample_20.noise = ah->noise;
mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
magnitude = spectral_max_magnitude(mag_info->all_bins);
fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
max_index = spectral_max_index(mag_info->all_bins);
fft_sample_20.max_index = max_index;
bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
fft_sample_20.bitmap_weight = bitmap_w;
fft_sample_20.max_exp = mag_info->max_exp & 0xf;
fft_sample_20.tsf = __cpu_to_be64(tsf);
tlv = (struct fft_sample_tlv *)&fft_sample_20;
}
ath_debug_send_fft_sample(sc, tlv);
return 1;
#else
return 0;
#endif
}
static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr)
{
struct ath_hw *ah = sc->sc_ah;

View File

@ -0,0 +1,543 @@
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/relay.h>
#include "ath9k.h"
static s8 fix_rssi_inv_only(u8 rssi_val)
{
if (rssi_val == 128)
rssi_val = 0;
return (s8) rssi_val;
}
static void ath_debug_send_fft_sample(struct ath_softc *sc,
struct fft_sample_tlv *fft_sample_tlv)
{
int length;
if (!sc->rfs_chan_spec_scan)
return;
length = __be16_to_cpu(fft_sample_tlv->length) +
sizeof(*fft_sample_tlv);
relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length);
}
/* returns 1 if this was a spectral frame, even if not handled. */
int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
struct ath_rx_status *rs, u64 tsf)
{
struct ath_hw *ah = sc->sc_ah;
u8 num_bins, *bins, *vdata = (u8 *)hdr;
struct fft_sample_ht20 fft_sample_20;
struct fft_sample_ht20_40 fft_sample_40;
struct fft_sample_tlv *tlv;
struct ath_radar_info *radar_info;
int len = rs->rs_datalen;
int dc_pos;
u16 fft_len, length, freq = ah->curchan->chan->center_freq;
enum nl80211_channel_type chan_type;
/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
* via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
* yet, but this is supposed to be possible as well.
*/
if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
return 0;
/* check if spectral scan bit is set. This does not have to be checked
* if received through a SPECTRAL phy error, but shouldn't hurt.
*/
radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
return 0;
chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef);
if ((chan_type == NL80211_CHAN_HT40MINUS) ||
(chan_type == NL80211_CHAN_HT40PLUS)) {
fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
num_bins = SPECTRAL_HT20_40_NUM_BINS;
bins = (u8 *)fft_sample_40.data;
} else {
fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
num_bins = SPECTRAL_HT20_NUM_BINS;
bins = (u8 *)fft_sample_20.data;
}
/* Variation in the data length is possible and will be fixed later */
if ((len > fft_len + 2) || (len < fft_len - 1))
return 1;
switch (len - fft_len) {
case 0:
/* length correct, nothing to do. */
memcpy(bins, vdata, num_bins);
break;
case -1:
/* first byte missing, duplicate it. */
memcpy(&bins[1], vdata, num_bins - 1);
bins[0] = vdata[0];
break;
case 2:
/* MAC added 2 extra bytes at bin 30 and 32, remove them. */
memcpy(bins, vdata, 30);
bins[30] = vdata[31];
memcpy(&bins[31], &vdata[33], num_bins - 31);
break;
case 1:
/* MAC added 2 extra bytes AND first byte is missing. */
bins[0] = vdata[0];
memcpy(&bins[1], vdata, 30);
bins[31] = vdata[31];
memcpy(&bins[32], &vdata[33], num_bins - 32);
break;
default:
return 1;
}
/* DC value (value in the middle) is the blind spot of the spectral
* sample and invalid, interpolate it.
*/
dc_pos = num_bins / 2;
bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
if ((chan_type == NL80211_CHAN_HT40MINUS) ||
(chan_type == NL80211_CHAN_HT40PLUS)) {
s8 lower_rssi, upper_rssi;
s16 ext_nf;
u8 lower_max_index, upper_max_index;
u8 lower_bitmap_w, upper_bitmap_w;
u16 lower_mag, upper_mag;
struct ath9k_hw_cal_data *caldata = ah->caldata;
struct ath_ht20_40_mag_info *mag_info;
if (caldata)
ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
caldata->nfCalHist[3].privNF);
else
ext_nf = ATH_DEFAULT_NOISE_FLOOR;
length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
fft_sample_40.tlv.length = __cpu_to_be16(length);
fft_sample_40.freq = __cpu_to_be16(freq);
fft_sample_40.channel_type = chan_type;
if (chan_type == NL80211_CHAN_HT40PLUS) {
lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
fft_sample_40.lower_noise = ah->noise;
fft_sample_40.upper_noise = ext_nf;
} else {
lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
fft_sample_40.lower_noise = ext_nf;
fft_sample_40.upper_noise = ah->noise;
}
fft_sample_40.lower_rssi = lower_rssi;
fft_sample_40.upper_rssi = upper_rssi;
mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1;
lower_mag = spectral_max_magnitude(mag_info->lower_bins);
upper_mag = spectral_max_magnitude(mag_info->upper_bins);
fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
lower_max_index = spectral_max_index(mag_info->lower_bins);
upper_max_index = spectral_max_index(mag_info->upper_bins);
fft_sample_40.lower_max_index = lower_max_index;
fft_sample_40.upper_max_index = upper_max_index;
lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
fft_sample_40.max_exp = mag_info->max_exp & 0xf;
fft_sample_40.tsf = __cpu_to_be64(tsf);
tlv = (struct fft_sample_tlv *)&fft_sample_40;
} else {
u8 max_index, bitmap_w;
u16 magnitude;
struct ath_ht20_mag_info *mag_info;
length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
fft_sample_20.tlv.length = __cpu_to_be16(length);
fft_sample_20.freq = __cpu_to_be16(freq);
fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
fft_sample_20.noise = ah->noise;
mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
magnitude = spectral_max_magnitude(mag_info->all_bins);
fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
max_index = spectral_max_index(mag_info->all_bins);
fft_sample_20.max_index = max_index;
bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
fft_sample_20.bitmap_weight = bitmap_w;
fft_sample_20.max_exp = mag_info->max_exp & 0xf;
fft_sample_20.tsf = __cpu_to_be64(tsf);
tlv = (struct fft_sample_tlv *)&fft_sample_20;
}
ath_debug_send_fft_sample(sc, tlv);
return 1;
}
/*********************/
/* spectral_scan_ctl */
/*********************/
static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char *mode = "";
unsigned int len;
switch (sc->spectral_mode) {
case SPECTRAL_DISABLED:
mode = "disable";
break;
case SPECTRAL_BACKGROUND:
mode = "background";
break;
case SPECTRAL_CHANSCAN:
mode = "chanscan";
break;
case SPECTRAL_MANUAL:
mode = "manual";
break;
}
len = strlen(mode);
return simple_read_from_buffer(user_buf, count, ppos, mode, len);
}
static ssize_t write_file_spec_scan_ctl(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32];
ssize_t len;
if (config_enabled(CONFIG_ATH9K_TX99))
return -EOPNOTSUPP;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (strncmp("trigger", buf, 7) == 0) {
ath9k_spectral_scan_trigger(sc->hw);
} else if (strncmp("background", buf, 9) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
} else if (strncmp("chanscan", buf, 8) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
} else if (strncmp("manual", buf, 6) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
} else if (strncmp("disable", buf, 7) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
ath_dbg(common, CONFIG, "spectral scan: disabled\n");
} else {
return -EINVAL;
}
return count;
}
static const struct file_operations fops_spec_scan_ctl = {
.read = read_file_spec_scan_ctl,
.write = write_file_spec_scan_ctl,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
/*************************/
/* spectral_short_repeat */
/*************************/
static ssize_t read_file_spectral_short_repeat(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d\n", sc->spec_config.short_repeat);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_spectral_short_repeat(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val < 0 || val > 1)
return -EINVAL;
sc->spec_config.short_repeat = val;
return count;
}
static const struct file_operations fops_spectral_short_repeat = {
.read = read_file_spectral_short_repeat,
.write = write_file_spectral_short_repeat,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
/******************/
/* spectral_count */
/******************/
static ssize_t read_file_spectral_count(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d\n", sc->spec_config.count);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_spectral_count(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val < 0 || val > 255)
return -EINVAL;
sc->spec_config.count = val;
return count;
}
static const struct file_operations fops_spectral_count = {
.read = read_file_spectral_count,
.write = write_file_spectral_count,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
/*******************/
/* spectral_period */
/*******************/
static ssize_t read_file_spectral_period(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d\n", sc->spec_config.period);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_spectral_period(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val < 0 || val > 255)
return -EINVAL;
sc->spec_config.period = val;
return count;
}
static const struct file_operations fops_spectral_period = {
.read = read_file_spectral_period,
.write = write_file_spectral_period,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
/***********************/
/* spectral_fft_period */
/***********************/
static ssize_t read_file_spectral_fft_period(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char buf[32];
unsigned int len;
len = sprintf(buf, "%d\n", sc->spec_config.fft_period);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_spectral_fft_period(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val < 0 || val > 15)
return -EINVAL;
sc->spec_config.fft_period = val;
return count;
}
static const struct file_operations fops_spectral_fft_period = {
.read = read_file_spectral_fft_period,
.write = write_file_spectral_fft_period,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
/*******************/
/* Relay interface */
/*******************/
static struct dentry *create_buf_file_handler(const char *filename,
struct dentry *parent,
umode_t mode,
struct rchan_buf *buf,
int *is_global)
{
struct dentry *buf_file;
buf_file = debugfs_create_file(filename, mode, parent, buf,
&relay_file_operations);
*is_global = 1;
return buf_file;
}
static int remove_buf_file_handler(struct dentry *dentry)
{
debugfs_remove(dentry);
return 0;
}
struct rchan_callbacks rfs_spec_scan_cb = {
.create_buf_file = create_buf_file_handler,
.remove_buf_file = remove_buf_file_handler,
};
/*********************/
/* Debug Init/Deinit */
/*********************/
void ath9k_spectral_deinit_debug(struct ath_softc *sc)
{
if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
relay_close(sc->rfs_chan_spec_scan);
sc->rfs_chan_spec_scan = NULL;
}
}
void ath9k_spectral_init_debug(struct ath_softc *sc)
{
sc->rfs_chan_spec_scan = relay_open("spectral_scan",
sc->debug.debugfs_phy,
1024, 256, &rfs_spec_scan_cb,
NULL);
debugfs_create_file("spectral_scan_ctl",
S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_spec_scan_ctl);
debugfs_create_file("spectral_short_repeat",
S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_spectral_short_repeat);
debugfs_create_file("spectral_count",
S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_spectral_count);
debugfs_create_file("spectral_period",
S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_spectral_period);
debugfs_create_file("spectral_fft_period",
S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_spectral_fft_period);
}

View File

@ -0,0 +1,212 @@
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef SPECTRAL_H
#define SPECTRAL_H
/* enum spectral_mode:
*
* @SPECTRAL_DISABLED: spectral mode is disabled
* @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
* something else.
* @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
* is performed manually.
* @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
* during a channel scan.
*/
enum spectral_mode {
SPECTRAL_DISABLED = 0,
SPECTRAL_BACKGROUND,
SPECTRAL_MANUAL,
SPECTRAL_CHANSCAN,
};
#define SPECTRAL_SCAN_BITMASK 0x10
/* Radar info packet format, used for DFS and spectral formats. */
struct ath_radar_info {
u8 pulse_length_pri;
u8 pulse_length_ext;
u8 pulse_bw_info;
} __packed;
/* The HT20 spectral data has 4 bytes of additional information at it's end.
*
* [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
* [7:0]: all bins max_magnitude[9:2]
* [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
* [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
*/
struct ath_ht20_mag_info {
u8 all_bins[3];
u8 max_exp;
} __packed;
#define SPECTRAL_HT20_NUM_BINS 56
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data by -1/+2. This struct is for reference only.
*/
struct ath_ht20_fft_packet {
u8 data[SPECTRAL_HT20_NUM_BINS];
struct ath_ht20_mag_info mag_info;
struct ath_radar_info radar_info;
} __packed;
#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet))
/* Dynamic 20/40 mode:
*
* [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
* [7:0]: lower bins max_magnitude[9:2]
* [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
* [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
* [7:0]: upper bins max_magnitude[9:2]
* [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
* [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
*/
struct ath_ht20_40_mag_info {
u8 lower_bins[3];
u8 upper_bins[3];
u8 max_exp;
} __packed;
#define SPECTRAL_HT20_40_NUM_BINS 128
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data. This struct is for reference only.
*/
struct ath_ht20_40_fft_packet {
u8 data[SPECTRAL_HT20_40_NUM_BINS];
struct ath_ht20_40_mag_info mag_info;
struct ath_radar_info radar_info;
} __packed;
#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet))
/* grabs the max magnitude from the all/upper/lower bins */
static inline u16 spectral_max_magnitude(u8 *bins)
{
return (bins[0] & 0xc0) >> 6 |
(bins[1] & 0xff) << 2 |
(bins[2] & 0x03) << 10;
}
/* return the max magnitude from the all/upper/lower bins */
static inline u8 spectral_max_index(u8 *bins)
{
s8 m = (bins[2] & 0xfc) >> 2;
/* TODO: this still doesn't always report the right values ... */
if (m > 32)
m |= 0xe0;
else
m &= ~0xe0;
return m + 29;
}
/* return the bitmap weight from the all/upper/lower bins */
static inline u8 spectral_bitmap_weight(u8 *bins)
{
return bins[0] & 0x3f;
}
/* FFT sample format given to userspace via debugfs.
*
* Please keep the type/length at the front position and change
* other fields after adding another sample type
*
* TODO: this might need rework when switching to nl80211-based
* interface.
*/
enum ath_fft_sample_type {
ATH_FFT_SAMPLE_HT20 = 1,
ATH_FFT_SAMPLE_HT20_40,
};
struct fft_sample_tlv {
u8 type; /* see ath_fft_sample */
__be16 length;
/* type dependent data follows */
} __packed;
struct fft_sample_ht20 {
struct fft_sample_tlv tlv;
u8 max_exp;
__be16 freq;
s8 rssi;
s8 noise;
__be16 max_magnitude;
u8 max_index;
u8 bitmap_weight;
__be64 tsf;
u8 data[SPECTRAL_HT20_NUM_BINS];
} __packed;
struct fft_sample_ht20_40 {
struct fft_sample_tlv tlv;
u8 channel_type;
__be16 freq;
s8 lower_rssi;
s8 upper_rssi;
__be64 tsf;
s8 lower_noise;
s8 upper_noise;
__be16 lower_max_magnitude;
__be16 upper_max_magnitude;
u8 lower_max_index;
u8 upper_max_index;
u8 lower_bitmap_weight;
u8 upper_bitmap_weight;
u8 max_exp;
u8 data[SPECTRAL_HT20_40_NUM_BINS];
} __packed;
void ath9k_spectral_init_debug(struct ath_softc *sc);
void ath9k_spectral_deinit_debug(struct ath_softc *sc);
void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
enum spectral_mode spectral_mode);
#ifdef CONFIG_ATH9K_DEBUGFS
int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
struct ath_rx_status *rs, u64 tsf);
#else
static inline int ath_process_fft(struct ath_softc *sc,
struct ieee80211_hdr *hdr,
struct ath_rx_status *rs, u64 tsf)
{
return 0;
}
#endif /* CONFIG_ATH9K_DEBUGFS */
#endif /* SPECTRAL_H */

View File

@ -48,7 +48,9 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
u32 len = 1200;
struct ieee80211_tx_rate *rate;
struct ieee80211_hw *hw = sc->hw;
struct ath_hw *ah = sc->sc_ah;
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info;
struct sk_buff *skb;
@ -73,10 +75,16 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
tx_info = IEEE80211_SKB_CB(skb);
memset(tx_info, 0, sizeof(*tx_info));
rate = &tx_info->control.rates[0];
tx_info->band = hw->conf.chandef.chan->band;
tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
tx_info->control.vif = sc->tx99_vif;
tx_info->control.rates[0].count = 1;
rate->count = 1;
if (ah->curchan && IS_CHAN_HT(ah->curchan)) {
rate->flags |= IEEE80211_TX_RC_MCS;
if (IS_CHAN_HT40(ah->curchan))
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
}
memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));

View File

@ -174,14 +174,7 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
static struct ath_atx_tid *
ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
u8 tidno = 0;
hdr = (struct ieee80211_hdr *) skb->data;
if (ieee80211_is_data_qos(hdr->frame_control))
tidno = ieee80211_get_qos_ctl(hdr)[0];
tidno &= IEEE80211_QOS_CTL_TID_MASK;
u8 tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
return ATH_AN_2_TID(an, tidno);
}

View File

@ -2060,22 +2060,28 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
case WCN36XX_HAL_OTA_TX_COMPL_IND:
case WCN36XX_HAL_MISSED_BEACON_IND:
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
mutex_lock(&wcn->hal_ind_mutex);
msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL);
if (msg_ind) {
msg_ind->msg_len = len;
msg_ind->msg = kmalloc(len, GFP_KERNEL);
memcpy(msg_ind->msg, buf, len);
list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
}
mutex_unlock(&wcn->hal_ind_mutex);
if (msg_ind)
if (!msg_ind)
goto nomem;
msg_ind->msg_len = len;
msg_ind->msg = kmalloc(len, GFP_KERNEL);
if (!msg_ind->msg) {
kfree(msg_ind);
nomem:
/*
* FIXME: Do something smarter then just
* printing an error.
*/
wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
msg_header->msg_type);
break;
/* FIXME: Do something smarter then just printing an error. */
wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
msg_header->msg_type);
}
memcpy(msg_ind->msg, buf, len);
mutex_lock(&wcn->hal_ind_mutex);
list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
mutex_unlock(&wcn->hal_ind_mutex);
wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
break;
default:
wcn36xx_err("SMD_EVENT (%d) not supported\n",

View File

@ -28,8 +28,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Atmel wireless lan drivers; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
along with Atmel wireless lan drivers; if not, see
<http://www.gnu.org/licenses/>.
For all queries about this code, please contact the current author,
Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation.
@ -4278,8 +4278,7 @@ static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data)
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with AtmelMACFW; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
along with AtmelMACFW; if not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */

View File

@ -15,8 +15,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Atmel wireless lan drivers; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
along with Atmel wireless lan drivers; if not, see
<http://www.gnu.org/licenses/>.
******************************************************************************/

View File

@ -24,8 +24,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Atmel wireless lan drivers; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
along with Atmel wireless lan drivers; if not, see
<http://www.gnu.org/licenses/>.
******************************************************************************/

View File

@ -15,8 +15,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Atmel wireless lan drivers; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
along with Atmel wireless lan drivers; if not, see
<http://www.gnu.org/licenses/>.
******************************************************************************/
#include <linux/pci.h>

View File

@ -36,7 +36,6 @@ brcmfmac-objs += \
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
dhd_sdio.o \
bcmsdh.o \
bcmsdh_sdmmc.o \
sdio_chip.o
brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
usb.o

View File

@ -101,35 +101,41 @@ struct brcmf_proto_bcdc_header {
* plus any space that might be needed
* for bus alignment padding.
*/
#define ROUND_UP_MARGIN 2048 /* Biggest bus block size possible for
* round off at the end of buffer
* Currently is SDIO
*/
struct brcmf_bcdc {
u16 reqid;
u8 bus_header[BUS_HEADER_LEN];
struct brcmf_proto_bcdc_dcmd msg;
unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
unsigned char buf[BRCMF_DCMD_MAXLEN];
};
static int brcmf_proto_bcdc_msg(struct brcmf_pub *drvr)
static int
brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
uint len, bool set)
{
struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
int len = le32_to_cpu(bcdc->msg.len) +
sizeof(struct brcmf_proto_bcdc_dcmd);
struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
u32 flags;
brcmf_dbg(BCDC, "Enter\n");
/* NOTE : bcdc->msg.len holds the desired length of the buffer to be
* returned. Only up to BCDC_MAX_MSG_SIZE of this buffer area
* is actually sent to the dongle
*/
if (len > BCDC_MAX_MSG_SIZE)
len = BCDC_MAX_MSG_SIZE;
memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT);
if (set)
flags |= BCDC_DCMD_SET;
flags = (flags & ~BCDC_DCMD_IF_MASK) |
(ifidx << BCDC_DCMD_IF_SHIFT);
msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(bcdc->buf, buf, len);
/* Send request */
return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len);
return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg,
len + sizeof(struct brcmf_proto_bcdc_dcmd));
}
static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
@ -161,19 +167,7 @@ brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT);
flags = (flags & ~BCDC_DCMD_IF_MASK) |
(ifidx << BCDC_DCMD_IF_SHIFT);
msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(bcdc->buf, buf, len);
ret = brcmf_proto_bcdc_msg(drvr);
ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false);
if (ret < 0) {
brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n",
ret);
@ -227,19 +221,7 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT) | BCDC_DCMD_SET;
flags = (flags & ~BCDC_DCMD_IF_MASK) |
(ifidx << BCDC_DCMD_IF_SHIFT);
msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(bcdc->buf, buf, len);
ret = brcmf_proto_bcdc_msg(drvr);
ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true);
if (ret < 0)
goto done;
@ -347,6 +329,15 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
return 0;
}
static int
brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset,
struct sk_buff *pktbuf)
{
brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf);
return brcmf_bus_txdata(drvr->bus_if, pktbuf);
}
int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
{
struct brcmf_bcdc *bcdc;
@ -361,15 +352,15 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
goto fail;
}
drvr->proto->hdrpush = brcmf_proto_bcdc_hdrpush;
drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull;
drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd;
drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd;
drvr->proto->txdata = brcmf_proto_bcdc_txdata;
drvr->proto->pd = bcdc;
drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
sizeof(struct brcmf_proto_bcdc_dcmd) + ROUND_UP_MARGIN;
sizeof(struct brcmf_proto_bcdc_dcmd);
return 0;
fail:

View File

@ -23,9 +23,17 @@
#include <linux/completion.h>
#include <linux/scatterlist.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/core.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/platform_device.h>
#include <linux/platform_data/brcmfmac-sdio.h>
#include <linux/suspend.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <net/cfg80211.h>
#include <defs.h>
#include <brcm_hw_ids.h>
@ -35,11 +43,21 @@
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "sdio_host.h"
#include "sdio_chip.h"
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
#define SDIO_VENDOR_ID_BROADCOM 0x02d0
static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id)
#define DMA_ALIGN_MASK 0x03
#define SDIO_FUNC1_BLOCKSIZE 64
#define SDIO_FUNC2_BLOCKSIZE 512
/* Maximum milliseconds to wait for F2 to come up */
#define SDIO_WAIT_F2RDY 3000
static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
@ -54,27 +72,46 @@ static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id)
sdiodev->irq_en = false;
}
brcmf_sdbrcm_isr(sdiodev->bus);
brcmf_sdio_isr(sdiodev->bus);
return IRQ_HANDLED;
}
static void brcmf_sdio_ib_irqhandler(struct sdio_func *func)
static void brcmf_sdiod_ib_irqhandler(struct sdio_func *func)
{
struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(INTR, "IB intr triggered\n");
brcmf_sdbrcm_isr(sdiodev->bus);
brcmf_sdio_isr(sdiodev->bus);
}
/* dummy handler for SDIO function 2 interrupt */
static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)
{
}
int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
static bool brcmf_sdiod_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
{
bool is_err = false;
#ifdef CONFIG_PM_SLEEP
is_err = atomic_read(&sdiodev->suspend);
#endif
return is_err;
}
static void brcmf_sdiod_pm_resume_wait(struct brcmf_sdio_dev *sdiodev,
wait_queue_head_t *wq)
{
#ifdef CONFIG_PM_SLEEP
int retry = 0;
while (atomic_read(&sdiodev->suspend) && retry++ != 30)
wait_event_timeout(*wq, false, HZ/100);
#endif
}
int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
u8 data;
@ -84,7 +121,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
sdiodev->pdata->oob_irq_nr);
ret = request_irq(sdiodev->pdata->oob_irq_nr,
brcmf_sdio_oob_irqhandler,
brcmf_sdiod_oob_irqhandler,
sdiodev->pdata->oob_irq_flags,
"brcmf_oob_intr",
&sdiodev->func[1]->dev);
@ -108,36 +145,36 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
sdio_claim_host(sdiodev->func[1]);
/* must configure SDIO_CCCR_IENx to enable irq */
data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
data = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
/* redirect, configure and enable io for interrupt signal */
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
data |= SDIO_SEPINT_ACT_HI;
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
sdio_release_host(sdiodev->func[1]);
} else {
brcmf_dbg(SDIO, "Entering\n");
sdio_claim_host(sdiodev->func[1]);
sdio_claim_irq(sdiodev->func[1], brcmf_sdio_ib_irqhandler);
sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
sdio_claim_irq(sdiodev->func[1], brcmf_sdiod_ib_irqhandler);
sdio_claim_irq(sdiodev->func[2], brcmf_sdiod_dummy_irqhandler);
sdio_release_host(sdiodev->func[1]);
}
return 0;
}
int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
brcmf_dbg(SDIO, "Entering\n");
if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
sdio_claim_host(sdiodev->func[1]);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
sdio_release_host(sdiodev->func[1]);
if (sdiodev->oob_irq_requested) {
@ -160,8 +197,117 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
return 0;
}
static inline int brcmf_sdiod_f0_writeb(struct sdio_func *func,
uint regaddr, u8 byte)
{
int err_ret;
/*
* Can only directly write to some F0 registers.
* Handle CCCR_IENx and CCCR_ABORT command
* as a special case.
*/
if ((regaddr == SDIO_CCCR_ABORT) ||
(regaddr == SDIO_CCCR_IENx))
sdio_writeb(func, byte, regaddr, &err_ret);
else
sdio_f0_writeb(func, byte, regaddr, &err_ret);
return err_ret;
}
static int brcmf_sdiod_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw,
uint func, uint regaddr, u8 *byte)
{
int err_ret;
brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
if (brcmf_sdiod_pm_resume_error(sdiodev))
return -EIO;
if (rw && func == 0) {
/* handle F0 separately */
err_ret = brcmf_sdiod_f0_writeb(sdiodev->func[func],
regaddr, *byte);
} else {
if (rw) /* CMD52 Write */
sdio_writeb(sdiodev->func[func], *byte, regaddr,
&err_ret);
else if (func == 0) {
*byte = sdio_f0_readb(sdiodev->func[func], regaddr,
&err_ret);
} else {
*byte = sdio_readb(sdiodev->func[func], regaddr,
&err_ret);
}
}
if (err_ret) {
/*
* SleepCSR register access can fail when
* waking up the device so reduce this noise
* in the logs.
*/
if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
rw ? "write" : "read", func, regaddr, *byte,
err_ret);
else
brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
rw ? "write" : "read", func, regaddr, *byte,
err_ret);
}
return err_ret;
}
static int brcmf_sdiod_request_word(struct brcmf_sdio_dev *sdiodev, uint rw,
uint func, uint addr, u32 *word,
uint nbytes)
{
int err_ret = -EIO;
if (func == 0) {
brcmf_err("Only CMD52 allowed to F0\n");
return -EINVAL;
}
brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
rw, func, addr, nbytes);
brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
if (brcmf_sdiod_pm_resume_error(sdiodev))
return -EIO;
if (rw) { /* CMD52 Write */
if (nbytes == 4)
sdio_writel(sdiodev->func[func], *word, addr,
&err_ret);
else if (nbytes == 2)
sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
addr, &err_ret);
else
brcmf_err("Invalid nbytes: %d\n", nbytes);
} else { /* CMD52 Read */
if (nbytes == 4)
*word = sdio_readl(sdiodev->func[func], addr, &err_ret);
else if (nbytes == 2)
*word = sdio_readw(sdiodev->func[func], addr,
&err_ret) & 0xFFFF;
else
brcmf_err("Invalid nbytes: %d\n", nbytes);
}
if (err_ret)
brcmf_err("Failed to %s word, Err: 0x%08x\n",
rw ? "write" : "read", err_ret);
return err_ret;
}
static int
brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
{
int err = 0, i;
u8 addr[3];
@ -176,7 +322,7 @@ brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
do {
if (retry)
usleep_range(1000, 2000);
err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
err = brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE,
SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
&addr[i]);
} while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
@ -192,13 +338,13 @@ brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
}
static int
brcmf_sdio_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
brcmf_sdiod_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
{
uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
if (bar0 != sdiodev->sbwad) {
err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
err = brcmf_sdiod_set_sbaddr_window(sdiodev, bar0);
if (err)
return err;
@ -213,9 +359,8 @@ brcmf_sdio_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
return 0;
}
int
brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
void *data, bool write)
static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
void *data, bool write)
{
u8 func_num, reg_size;
s32 retry = 0;
@ -237,7 +382,7 @@ brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
func_num = SDIO_FUNC_1;
reg_size = 4;
ret = brcmf_sdio_addrprep(sdiodev, reg_size, &addr);
ret = brcmf_sdiod_addrprep(sdiodev, reg_size, &addr);
if (ret)
goto done;
}
@ -248,10 +393,10 @@ brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
if (retry) /* wait for 1 ms till bus get settled down */
usleep_range(1000, 2000);
if (reg_size == 1)
ret = brcmf_sdioh_request_byte(sdiodev, write,
ret = brcmf_sdiod_request_byte(sdiodev, write,
func_num, addr, data);
else
ret = brcmf_sdioh_request_word(sdiodev, write,
ret = brcmf_sdiod_request_word(sdiodev, write,
func_num, addr, data, 4);
} while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
@ -262,13 +407,13 @@ done:
return ret;
}
u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
{
u8 data;
int retval;
brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false);
brcmf_dbg(SDIO, "data:0x%02x\n", data);
if (ret)
@ -277,13 +422,13 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
return data;
}
u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
{
u32 data;
int retval;
brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false);
brcmf_dbg(SDIO, "data:0x%08x\n", data);
if (ret)
@ -292,37 +437,37 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
return data;
}
void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
u8 data, int *ret)
{
int retval;
brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true);
if (ret)
*ret = retval;
}
void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
u32 data, int *ret)
{
int retval;
brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true);
if (ret)
*ret = retval;
}
static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
bool write, u32 addr, struct sk_buff *pkt)
{
unsigned int req_sz;
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
if (brcmf_pm_resume_error(sdiodev))
brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
if (brcmf_sdiod_pm_resume_error(sdiodev))
return -EIO;
/* Single skb use the standard mmc interface */
@ -345,7 +490,7 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
}
/**
* brcmf_sdio_sglist_rw - SDIO interface function for block data access
* brcmf_sdiod_sglist_rw - SDIO interface function for block data access
* @sdiodev: brcmfmac sdio device
* @fn: SDIO function number
* @write: direction flag
@ -356,9 +501,9 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
* stack for block data access. It assumes that the skb passed down by the
* caller has already been padded and aligned.
*/
static int brcmf_sdio_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
bool write, u32 addr,
struct sk_buff_head *pktlist)
static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
bool write, u32 addr,
struct sk_buff_head *pktlist)
{
unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset;
unsigned int max_req_sz, orig_offset, dst_offset;
@ -376,8 +521,8 @@ static int brcmf_sdio_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
if (!pktlist->qlen)
return -EINVAL;
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
if (brcmf_pm_resume_error(sdiodev))
brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
if (brcmf_sdiod_pm_resume_error(sdiodev))
return -EIO;
target_list = pktlist;
@ -524,9 +669,7 @@ exit:
return ret;
}
int
brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes)
int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)
{
struct sk_buff *mypkt;
int err;
@ -538,7 +681,7 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
return -EIO;
}
err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
err = brcmf_sdiod_recv_pkt(sdiodev, mypkt);
if (!err)
memcpy(buf, mypkt->data, nbytes);
@ -546,50 +689,47 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
return err;
}
int
brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff *pkt)
int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt)
{
uint width;
u32 addr = sdiodev->sbwad;
int err = 0;
brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);
brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pkt->len);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
err = brcmf_sdio_addrprep(sdiodev, width, &addr);
err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
if (err)
goto done;
err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, pkt);
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, pkt);
done:
return err;
}
int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff_head *pktq, uint totlen)
int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
struct sk_buff_head *pktq, uint totlen)
{
struct sk_buff *glom_skb;
struct sk_buff *skb;
uint width;
u32 addr = sdiodev->sbwad;
int err = 0;
brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pktq->qlen);
brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n",
addr, pktq->qlen);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
err = brcmf_sdio_addrprep(sdiodev, width, &addr);
err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
if (err)
goto done;
if (pktq->qlen == 1)
err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, pktq->next);
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
pktq->next);
else if (!sdiodev->sg_support) {
glom_skb = brcmu_pkt_buf_get_skb(totlen);
if (!glom_skb)
return -ENOMEM;
err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, glom_skb);
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
glom_skb);
if (err)
goto done;
@ -598,18 +738,17 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
skb_pull(glom_skb, skb->len);
}
} else
err = brcmf_sdio_sglist_rw(sdiodev, fn, false, addr, pktq);
err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, false, addr,
pktq);
done:
return err;
}
int
brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes)
int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)
{
struct sk_buff *mypkt;
uint width;
u32 addr = sdiodev->sbwad;
int err;
mypkt = brcmu_pkt_buf_get_skb(nbytes);
@ -621,48 +760,47 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
memcpy(mypkt->data, buf, nbytes);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
err = brcmf_sdio_addrprep(sdiodev, width, &addr);
err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
if (!err)
err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, mypkt);
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, true, addr,
mypkt);
brcmu_pkt_buf_free_skb(mypkt);
return err;
}
int
brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff_head *pktq)
int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,
struct sk_buff_head *pktq)
{
struct sk_buff *skb;
uint width;
u32 addr = sdiodev->sbwad;
int err;
brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pktq->qlen);
brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pktq->qlen);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
err = brcmf_sdio_addrprep(sdiodev, width, &addr);
err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);
if (err)
return err;
if (pktq->qlen == 1 || !sdiodev->sg_support)
skb_queue_walk(pktq, skb) {
err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, skb);
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, true,
addr, skb);
if (err)
break;
}
else
err = brcmf_sdio_sglist_rw(sdiodev, fn, true, addr, pktq);
err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, true, addr,
pktq);
return err;
}
int
brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
u8 *data, uint size)
brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
u8 *data, uint size)
{
int bcmerror = 0;
struct sk_buff *pkt;
@ -689,7 +827,7 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
/* Do the transfer(s) */
while (size) {
/* Set the backplane window to include the start address */
bcmerror = brcmf_sdcard_set_sbaddr_window(sdiodev, address);
bcmerror = brcmf_sdiod_set_sbaddr_window(sdiodev, address);
if (bcmerror)
break;
@ -703,8 +841,8 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
skb_put(pkt, dsize);
if (write)
memcpy(pkt->data, data, dsize);
bcmerror = brcmf_sdio_buffrw(sdiodev, SDIO_FUNC_1, write,
sdaddr, pkt);
bcmerror = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_1, write,
sdaddr, pkt);
if (bcmerror) {
brcmf_err("membytes transfer failed\n");
break;
@ -726,7 +864,7 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
dev_kfree_skb(pkt);
/* Return the window to backplane enumeration space for core access */
if (brcmf_sdcard_set_sbaddr_window(sdiodev, sdiodev->sbwad))
if (brcmf_sdiod_set_sbaddr_window(sdiodev, sdiodev->sbwad))
brcmf_err("FAILED to set window back to 0x%x\n",
sdiodev->sbwad);
@ -735,65 +873,337 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
return bcmerror;
}
int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
{
char t_func = (char)fn;
brcmf_dbg(SDIO, "Enter\n");
/* issue abort cmd52 command through F0 */
brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
SDIO_CCCR_ABORT, &t_func);
brcmf_dbg(SDIO, "Exit\n");
return 0;
}
int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
{
u32 regs = 0;
int ret = 0;
ret = brcmf_sdioh_attach(sdiodev);
if (ret)
goto out;
regs = SI_ENUM_BASE;
/* try to attach to the target device */
sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
if (!sdiodev->bus) {
brcmf_err("device attach failed\n");
ret = -ENODEV;
goto out;
}
out:
if (ret)
brcmf_sdio_remove(sdiodev);
return ret;
}
int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
{
sdiodev->bus_if->state = BRCMF_BUS_DOWN;
if (sdiodev->bus) {
brcmf_sdbrcm_disconnect(sdiodev->bus);
brcmf_sdio_remove(sdiodev->bus);
sdiodev->bus = NULL;
}
brcmf_sdioh_detach(sdiodev);
/* Disable Function 2 */
sdio_claim_host(sdiodev->func[2]);
sdio_disable_func(sdiodev->func[2]);
sdio_release_host(sdiodev->func[2]);
/* Disable Function 1 */
sdio_claim_host(sdiodev->func[1]);
sdio_disable_func(sdiodev->func[1]);
sdio_release_host(sdiodev->func[1]);
sdiodev->sbwad = 0;
return 0;
}
void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
{
if (enable)
brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
else
brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
struct sdio_func *func;
struct mmc_host *host;
uint max_blocks;
int ret = 0;
sdiodev->num_funcs = 2;
sdio_claim_host(sdiodev->func[1]);
ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
if (ret) {
brcmf_err("Failed to set F1 blocksize\n");
sdio_release_host(sdiodev->func[1]);
goto out;
}
ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
if (ret) {
brcmf_err("Failed to set F2 blocksize\n");
sdio_release_host(sdiodev->func[1]);
goto out;
}
/* increase F2 timeout */
sdiodev->func[2]->enable_timeout = SDIO_WAIT_F2RDY;
/* Enable Function 1 */
ret = sdio_enable_func(sdiodev->func[1]);
sdio_release_host(sdiodev->func[1]);
if (ret) {
brcmf_err("Failed to enable F1: err=%d\n", ret);
goto out;
}
/*
* determine host related variables after brcmf_sdiod_probe()
* as func->cur_blksize is properly set and F2 init has been
* completed successfully.
*/
func = sdiodev->func[2];
host = func->card->host;
sdiodev->sg_support = host->max_segs > 1;
max_blocks = min_t(uint, host->max_blk_count, 511u);
sdiodev->max_request_size = min_t(uint, host->max_req_size,
max_blocks * func->cur_blksize);
sdiodev->max_segment_count = min_t(uint, host->max_segs,
SG_MAX_SINGLE_ALLOC);
sdiodev->max_segment_size = host->max_seg_size;
/* try to attach to the target device */
sdiodev->bus = brcmf_sdio_probe(sdiodev);
if (!sdiodev->bus) {
ret = -ENODEV;
goto out;
}
out:
if (ret)
brcmf_sdiod_remove(sdiodev);
return ret;
}
/* devices we support, null terminated */
static const struct sdio_device_id brcmf_sdmmc_ids[] = {
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
SDIO_DEVICE_ID_BROADCOM_4335_4339)},
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
static int brcmf_ops_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
int err;
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "Class=%x\n", func->class);
brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
brcmf_dbg(SDIO, "Function#: %d\n", func->num);
/* Consume func num 1 but dont do anything with it. */
if (func->num == 1)
return 0;
/* Ignore anything but func 2 */
if (func->num != 2)
return -ENODEV;
bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
if (!bus_if)
return -ENOMEM;
sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
if (!sdiodev) {
kfree(bus_if);
return -ENOMEM;
}
/* store refs to functions used. mmc_card does
* not hold the F0 function pointer.
*/
sdiodev->func[0] = kmemdup(func, sizeof(*func), GFP_KERNEL);
sdiodev->func[0]->num = 0;
sdiodev->func[1] = func->card->sdio_func[0];
sdiodev->func[2] = func;
sdiodev->bus_if = bus_if;
bus_if->bus_priv.sdio = sdiodev;
bus_if->proto_type = BRCMF_PROTO_BCDC;
dev_set_drvdata(&func->dev, bus_if);
dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
sdiodev->dev = &sdiodev->func[1]->dev;
sdiodev->pdata = brcmfmac_sdio_pdata;
atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_byte_wait);
init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait);
brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");
err = brcmf_sdiod_probe(sdiodev);
if (err) {
brcmf_err("F2 error, probe failed %d...\n", err);
goto fail;
}
brcmf_dbg(SDIO, "F2 init completed...\n");
return 0;
fail:
dev_set_drvdata(&func->dev, NULL);
dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
kfree(sdiodev->func[0]);
kfree(sdiodev);
kfree(bus_if);
return err;
}
static void brcmf_ops_sdio_remove(struct sdio_func *func)
{
struct brcmf_bus *bus_if;
struct brcmf_sdio_dev *sdiodev;
brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
brcmf_dbg(SDIO, "Function: %d\n", func->num);
if (func->num != 1 && func->num != 2)
return;
bus_if = dev_get_drvdata(&func->dev);
if (bus_if) {
sdiodev = bus_if->bus_priv.sdio;
brcmf_sdiod_remove(sdiodev);
dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
kfree(bus_if);
kfree(sdiodev->func[0]);
kfree(sdiodev);
}
brcmf_dbg(SDIO, "Exit\n");
}
#ifdef CONFIG_PM_SLEEP
static int brcmf_ops_sdio_suspend(struct device *dev)
{
mmc_pm_flag_t sdio_flags;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
int ret = 0;
brcmf_dbg(SDIO, "\n");
atomic_set(&sdiodev->suspend, true);
sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
brcmf_err("Host can't keep power while suspended\n");
return -EINVAL;
}
ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
if (ret) {
brcmf_err("Failed to set pm_flags\n");
return ret;
}
brcmf_sdio_wd_timer(sdiodev->bus, 0);
return ret;
}
static int brcmf_ops_sdio_resume(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
atomic_set(&sdiodev->suspend, false);
return 0;
}
static const struct dev_pm_ops brcmf_sdio_pm_ops = {
.suspend = brcmf_ops_sdio_suspend,
.resume = brcmf_ops_sdio_resume,
};
#endif /* CONFIG_PM_SLEEP */
static struct sdio_driver brcmf_sdmmc_driver = {
.probe = brcmf_ops_sdio_probe,
.remove = brcmf_ops_sdio_remove,
.name = BRCMFMAC_SDIO_PDATA_NAME,
.id_table = brcmf_sdmmc_ids,
#ifdef CONFIG_PM_SLEEP
.drv = {
.pm = &brcmf_sdio_pm_ops,
},
#endif /* CONFIG_PM_SLEEP */
};
static int brcmf_sdio_pd_probe(struct platform_device *pdev)
{
brcmf_dbg(SDIO, "Enter\n");
brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
if (brcmfmac_sdio_pdata->power_on)
brcmfmac_sdio_pdata->power_on();
return 0;
}
static int brcmf_sdio_pd_remove(struct platform_device *pdev)
{
brcmf_dbg(SDIO, "Enter\n");
if (brcmfmac_sdio_pdata->power_off)
brcmfmac_sdio_pdata->power_off();
sdio_unregister_driver(&brcmf_sdmmc_driver);
return 0;
}
static struct platform_driver brcmf_sdio_pd = {
.remove = brcmf_sdio_pd_remove,
.driver = {
.name = BRCMFMAC_SDIO_PDATA_NAME,
.owner = THIS_MODULE,
}
};
void brcmf_sdio_register(void)
{
int ret;
ret = sdio_register_driver(&brcmf_sdmmc_driver);
if (ret)
brcmf_err("sdio_register_driver failed: %d\n", ret);
}
void brcmf_sdio_exit(void)
{
brcmf_dbg(SDIO, "Enter\n");
if (brcmfmac_sdio_pdata)
platform_driver_unregister(&brcmf_sdio_pd);
else
sdio_unregister_driver(&brcmf_sdmmc_driver);
}
void __init brcmf_sdio_init(void)
{
int ret;
brcmf_dbg(SDIO, "Enter\n");
ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
if (ret == -ENODEV)
brcmf_dbg(SDIO, "No platform data available.\n");
}

View File

@ -1,552 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/core.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/suspend.h>
#include <linux/errno.h>
#include <linux/sched.h> /* request_irq() */
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/platform_data/brcmfmac-sdio.h>
#include <net/cfg80211.h>
#include <defs.h>
#include <brcm_hw_ids.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "sdio_host.h"
#include "sdio_chip.h"
#include "dhd_dbg.h"
#include "dhd_bus.h"
#define SDIO_VENDOR_ID_BROADCOM 0x02d0
#define DMA_ALIGN_MASK 0x03
#define SDIO_FUNC1_BLOCKSIZE 64
#define SDIO_FUNC2_BLOCKSIZE 512
/* devices we support, null terminated */
static const struct sdio_device_id brcmf_sdmmc_ids[] = {
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
SDIO_DEVICE_ID_BROADCOM_4335_4339)},
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
bool
brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
{
bool is_err = false;
#ifdef CONFIG_PM_SLEEP
is_err = atomic_read(&sdiodev->suspend);
#endif
return is_err;
}
void
brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq)
{
#ifdef CONFIG_PM_SLEEP
int retry = 0;
while (atomic_read(&sdiodev->suspend) && retry++ != 30)
wait_event_timeout(*wq, false, HZ/100);
#endif
}
static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
uint regaddr, u8 *byte)
{
struct sdio_func *sdfunc = sdiodev->func[0];
int err_ret;
/*
* Can only directly write to some F0 registers.
* Handle F2 enable/disable and Abort command
* as a special case.
*/
if (regaddr == SDIO_CCCR_IOEx) {
sdfunc = sdiodev->func[2];
if (sdfunc) {
if (*byte & SDIO_FUNC_ENABLE_2) {
/* Enable Function 2 */
err_ret = sdio_enable_func(sdfunc);
if (err_ret)
brcmf_err("enable F2 failed:%d\n",
err_ret);
} else {
/* Disable Function 2 */
err_ret = sdio_disable_func(sdfunc);
if (err_ret)
brcmf_err("Disable F2 failed:%d\n",
err_ret);
}
} else {
err_ret = -ENOENT;
}
} else if ((regaddr == SDIO_CCCR_ABORT) ||
(regaddr == SDIO_CCCR_IENx)) {
sdfunc = kmemdup(sdiodev->func[0], sizeof(struct sdio_func),
GFP_KERNEL);
if (!sdfunc)
return -ENOMEM;
sdfunc->num = 0;
sdio_writeb(sdfunc, *byte, regaddr, &err_ret);
kfree(sdfunc);
} else if (regaddr < 0xF0) {
brcmf_err("F0 Wr:0x%02x: write disallowed\n", regaddr);
err_ret = -EPERM;
} else {
sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret);
}
return err_ret;
}
int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
uint regaddr, u8 *byte)
{
int err_ret;
brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
if (brcmf_pm_resume_error(sdiodev))
return -EIO;
if (rw && func == 0) {
/* handle F0 separately */
err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte);
} else {
if (rw) /* CMD52 Write */
sdio_writeb(sdiodev->func[func], *byte, regaddr,
&err_ret);
else if (func == 0) {
*byte = sdio_f0_readb(sdiodev->func[func], regaddr,
&err_ret);
} else {
*byte = sdio_readb(sdiodev->func[func], regaddr,
&err_ret);
}
}
if (err_ret) {
/*
* SleepCSR register access can fail when
* waking up the device so reduce this noise
* in the logs.
*/
if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
rw ? "write" : "read", func, regaddr, *byte,
err_ret);
else
brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
rw ? "write" : "read", func, regaddr, *byte,
err_ret);
}
return err_ret;
}
int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
uint rw, uint func, uint addr, u32 *word,
uint nbytes)
{
int err_ret = -EIO;
if (func == 0) {
brcmf_err("Only CMD52 allowed to F0\n");
return -EINVAL;
}
brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
rw, func, addr, nbytes);
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
if (brcmf_pm_resume_error(sdiodev))
return -EIO;
if (rw) { /* CMD52 Write */
if (nbytes == 4)
sdio_writel(sdiodev->func[func], *word, addr,
&err_ret);
else if (nbytes == 2)
sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
addr, &err_ret);
else
brcmf_err("Invalid nbytes: %d\n", nbytes);
} else { /* CMD52 Read */
if (nbytes == 4)
*word = sdio_readl(sdiodev->func[func], addr, &err_ret);
else if (nbytes == 2)
*word = sdio_readw(sdiodev->func[func], addr,
&err_ret) & 0xFFFF;
else
brcmf_err("Invalid nbytes: %d\n", nbytes);
}
if (err_ret)
brcmf_err("Failed to %s word, Err: 0x%08x\n",
rw ? "write" : "read", err_ret);
return err_ret;
}
static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr)
{
/* read 24 bits and return valid 17 bit addr */
int i, ret;
u32 scratch, regdata;
__le32 scratch_le;
u8 *ptr = (u8 *)&scratch_le;
for (i = 0; i < 3; i++) {
regdata = brcmf_sdio_regrl(sdiodev, regaddr, &ret);
if (ret != 0)
brcmf_err("Can't read!\n");
*ptr++ = (u8) regdata;
regaddr++;
}
/* Only the lower 17-bits are valid */
scratch = le32_to_cpu(scratch_le);
scratch &= 0x0001FFFF;
return scratch;
}
static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
{
int err_ret;
u32 fbraddr;
u8 func;
brcmf_dbg(SDIO, "\n");
/* Get the Card's common CIS address */
sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev,
SDIO_CCCR_CIS);
brcmf_dbg(SDIO, "Card's Common CIS Ptr = 0x%x\n",
sdiodev->func_cis_ptr[0]);
/* Get the Card's function CIS (for each function) */
for (fbraddr = SDIO_FBR_BASE(1), func = 1;
func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
sdiodev->func_cis_ptr[func] =
brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr);
brcmf_dbg(SDIO, "Function %d CIS Ptr = 0x%x\n",
func, sdiodev->func_cis_ptr[func]);
}
/* Enable Function 1 */
err_ret = sdio_enable_func(sdiodev->func[1]);
if (err_ret)
brcmf_err("Failed to enable F1 Err: 0x%08x\n", err_ret);
return false;
}
/*
* Public entry points & extern's
*/
int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
{
int err_ret = 0;
struct mmc_host *host;
struct sdio_func *func;
uint max_blocks;
brcmf_dbg(SDIO, "\n");
sdiodev->num_funcs = 2;
sdio_claim_host(sdiodev->func[1]);
err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
if (err_ret) {
brcmf_err("Failed to set F1 blocksize\n");
goto out;
}
err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
if (err_ret) {
brcmf_err("Failed to set F2 blocksize\n");
goto out;
}
brcmf_sdioh_enablefuncs(sdiodev);
/*
* determine host related variables after brcmf_sdio_probe()
* as func->cur_blksize is properly set and F2 init has been
* completed successfully.
*/
func = sdiodev->func[2];
host = func->card->host;
sdiodev->sg_support = host->max_segs > 1;
max_blocks = min_t(uint, host->max_blk_count, 511u);
sdiodev->max_request_size = min_t(uint, host->max_req_size,
max_blocks * func->cur_blksize);
sdiodev->max_segment_count = min_t(uint, host->max_segs,
SG_MAX_SINGLE_ALLOC);
sdiodev->max_segment_size = host->max_seg_size;
out:
sdio_release_host(sdiodev->func[1]);
brcmf_dbg(SDIO, "Done\n");
return err_ret;
}
void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
{
brcmf_dbg(SDIO, "\n");
/* Disable Function 2 */
sdio_claim_host(sdiodev->func[2]);
sdio_disable_func(sdiodev->func[2]);
sdio_release_host(sdiodev->func[2]);
/* Disable Function 1 */
sdio_claim_host(sdiodev->func[1]);
sdio_disable_func(sdiodev->func[1]);
sdio_release_host(sdiodev->func[1]);
}
static int brcmf_ops_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
int err;
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "Class=%x\n", func->class);
brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
brcmf_dbg(SDIO, "Function#: %d\n", func->num);
/* Consume func num 1 but dont do anything with it. */
if (func->num == 1)
return 0;
/* Ignore anything but func 2 */
if (func->num != 2)
return -ENODEV;
bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
if (!bus_if)
return -ENOMEM;
sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
if (!sdiodev) {
kfree(bus_if);
return -ENOMEM;
}
sdiodev->func[0] = func->card->sdio_func[0];
sdiodev->func[1] = func->card->sdio_func[0];
sdiodev->func[2] = func;
sdiodev->bus_if = bus_if;
bus_if->bus_priv.sdio = sdiodev;
dev_set_drvdata(&func->dev, bus_if);
dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
sdiodev->dev = &sdiodev->func[1]->dev;
sdiodev->pdata = brcmfmac_sdio_pdata;
atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_byte_wait);
init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait);
brcmf_dbg(SDIO, "F2 found, calling brcmf_sdio_probe...\n");
err = brcmf_sdio_probe(sdiodev);
if (err) {
brcmf_err("F2 error, probe failed %d...\n", err);
goto fail;
}
brcmf_dbg(SDIO, "F2 init completed...\n");
return 0;
fail:
dev_set_drvdata(&func->dev, NULL);
dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
kfree(sdiodev);
kfree(bus_if);
return err;
}
static void brcmf_ops_sdio_remove(struct sdio_func *func)
{
struct brcmf_bus *bus_if;
struct brcmf_sdio_dev *sdiodev;
brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
brcmf_dbg(SDIO, "Function: %d\n", func->num);
if (func->num != 1 && func->num != 2)
return;
bus_if = dev_get_drvdata(&func->dev);
if (bus_if) {
sdiodev = bus_if->bus_priv.sdio;
brcmf_sdio_remove(sdiodev);
dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
kfree(bus_if);
kfree(sdiodev);
}
brcmf_dbg(SDIO, "Exit\n");
}
#ifdef CONFIG_PM_SLEEP
static int brcmf_sdio_suspend(struct device *dev)
{
mmc_pm_flag_t sdio_flags;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
int ret = 0;
brcmf_dbg(SDIO, "\n");
atomic_set(&sdiodev->suspend, true);
sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
brcmf_err("Host can't keep power while suspended\n");
return -EINVAL;
}
ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
if (ret) {
brcmf_err("Failed to set pm_flags\n");
return ret;
}
brcmf_sdio_wdtmr_enable(sdiodev, false);
return ret;
}
static int brcmf_sdio_resume(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_sdio_wdtmr_enable(sdiodev, true);
atomic_set(&sdiodev->suspend, false);
return 0;
}
static const struct dev_pm_ops brcmf_sdio_pm_ops = {
.suspend = brcmf_sdio_suspend,
.resume = brcmf_sdio_resume,
};
#endif /* CONFIG_PM_SLEEP */
static struct sdio_driver brcmf_sdmmc_driver = {
.probe = brcmf_ops_sdio_probe,
.remove = brcmf_ops_sdio_remove,
.name = BRCMFMAC_SDIO_PDATA_NAME,
.id_table = brcmf_sdmmc_ids,
#ifdef CONFIG_PM_SLEEP
.drv = {
.pm = &brcmf_sdio_pm_ops,
},
#endif /* CONFIG_PM_SLEEP */
};
static int brcmf_sdio_pd_probe(struct platform_device *pdev)
{
brcmf_dbg(SDIO, "Enter\n");
brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
if (brcmfmac_sdio_pdata->power_on)
brcmfmac_sdio_pdata->power_on();
return 0;
}
static int brcmf_sdio_pd_remove(struct platform_device *pdev)
{
brcmf_dbg(SDIO, "Enter\n");
if (brcmfmac_sdio_pdata->power_off)
brcmfmac_sdio_pdata->power_off();
sdio_unregister_driver(&brcmf_sdmmc_driver);
return 0;
}
static struct platform_driver brcmf_sdio_pd = {
.remove = brcmf_sdio_pd_remove,
.driver = {
.name = BRCMFMAC_SDIO_PDATA_NAME,
.owner = THIS_MODULE,
}
};
void brcmf_sdio_register(void)
{
int ret;
ret = sdio_register_driver(&brcmf_sdmmc_driver);
if (ret)
brcmf_err("sdio_register_driver failed: %d\n", ret);
}
void brcmf_sdio_exit(void)
{
brcmf_dbg(SDIO, "Enter\n");
if (brcmfmac_sdio_pdata)
platform_driver_unregister(&brcmf_sdio_pd);
else
sdio_unregister_driver(&brcmf_sdmmc_driver);
}
void __init brcmf_sdio_init(void)
{
int ret;
brcmf_dbg(SDIO, "Enter\n");
ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
if (ret == -ENODEV)
brcmf_dbg(SDIO, "No platform data available.\n");
}

View File

@ -24,6 +24,12 @@ enum brcmf_bus_state {
BRCMF_BUS_DATA /* Ready for frame transfers */
};
/* The level of bus communication with the dongle */
enum brcmf_bus_protocol_type {
BRCMF_PROTO_BCDC,
BRCMF_PROTO_MSGBUF
};
struct brcmf_bus_dcmd {
char *name;
char *param;
@ -65,6 +71,7 @@ struct brcmf_bus_ops {
* struct brcmf_bus - interface structure between common and bus layer
*
* @bus_priv: pointer to private bus device.
* @proto_type: protocol type, bcdc or msgbuf
* @dev: device pointer of bus device.
* @drvr: public driver information.
* @state: operational state of the bus interface.
@ -80,6 +87,7 @@ struct brcmf_bus {
struct brcmf_sdio_dev *sdio;
struct brcmf_usbdev *usb;
} bus_priv;
enum brcmf_bus_protocol_type proto_type;
struct device *dev;
struct brcmf_pub *drvr;
enum brcmf_bus_state state;

File diff suppressed because it is too large Load Diff

View File

@ -68,7 +68,7 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
mutex_unlock(&ifp->drvr->proto_block);
@ -86,7 +86,7 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
mutex_unlock(&ifp->drvr->proto_block);
@ -155,7 +155,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
sizeof(drvr->proto_buf));
@ -195,7 +195,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
mutex_unlock(&drvr->proto_block);
return err;
@ -278,7 +278,7 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
drvr->proto_buf, sizeof(drvr->proto_buf));
@ -317,7 +317,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
}
brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
mutex_unlock(&drvr->proto_block);
return err;

View File

@ -838,7 +838,7 @@ static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
}
static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
{
struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
u8 *wlh;
@ -887,9 +887,7 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
if (fillers)
memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
brcmf_proto_hdrpush(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX),
data_offset >> 2, skb);
return 0;
return (u8)(data_offset >> 2);
}
static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
@ -897,10 +895,11 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
int fifo, bool send_immediately)
{
struct sk_buff *skb;
struct brcmf_bus *bus;
struct brcmf_skbuff_cb *skcb;
s32 err;
u32 len;
u8 data_offset;
int ifidx;
/* check delayedQ and suppressQ in one call using bitmap */
if (brcmu_pktq_mlen(&entry->psq, 3 << (fifo * 2)) == 0)
@ -928,13 +927,11 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
skcb->state = BRCMF_FWS_SKBSTATE_TIM;
skcb->htod = 0;
skcb->htod_seq = 0;
bus = fws->drvr->bus_if;
err = brcmf_fws_hdrpush(fws, skb);
if (err == 0) {
brcmf_fws_unlock(fws);
err = brcmf_bus_txdata(bus, skb);
brcmf_fws_lock(fws);
}
data_offset = brcmf_fws_hdrpush(fws, skb);
ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
brcmf_fws_unlock(fws);
err = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
brcmf_fws_lock(fws);
if (err)
brcmu_pkt_buf_free_skb(skb);
return true;
@ -1393,7 +1390,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
entry->generation = genbit;
ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
if (ret == 0)
if (ret == 0) {
brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit);
brcmf_skbcb(skb)->htod_seq = seq;
if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) {
@ -1404,6 +1401,8 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
}
ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo,
skb);
}
if (ret != 0) {
/* suppress q is full or hdrpull failed, drop this packet */
brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
@ -1717,7 +1716,7 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
return 0;
}
static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
struct sk_buff *p)
{
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
@ -1735,7 +1734,7 @@ static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
}
brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
brcmf_fws_hdrpush(fws, p);
return brcmf_fws_hdrpush(fws, p);
}
static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
@ -1803,20 +1802,21 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
{
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
struct brcmf_fws_mac_descriptor *entry;
struct brcmf_bus *bus = fws->drvr->bus_if;
int rc;
u8 ifidx;
u8 data_offset;
entry = skcb->mac;
if (IS_ERR(entry))
return PTR_ERR(entry);
brcmf_fws_precommit_skb(fws, fifo, skb);
data_offset = brcmf_fws_precommit_skb(fws, fifo, skb);
entry->transit_count++;
if (entry->suppressed)
entry->suppr_transit_count++;
ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
brcmf_fws_unlock(fws);
rc = brcmf_bus_txdata(bus, skb);
rc = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
brcmf_fws_lock(fws);
brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name,
skcb->if_flags, skcb->htod, rc);
@ -1977,10 +1977,9 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
&skb, true);
ifidx = brcmf_skb_if_flags_get_field(skb,
INDEX);
brcmf_proto_hdrpush(drvr, ifidx, 0, skb);
/* Use bus module to send data frame */
/* Use proto layer to send data frame */
brcmf_fws_unlock(fws);
ret = brcmf_bus_txdata(drvr->bus_if, skb);
ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);
brcmf_fws_lock(fws);
if (ret < 0)
brcmf_txfinalize(drvr, skb, false);

View File

@ -39,7 +39,7 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
if (brcmf_proto_bcdc_attach(drvr))
goto fail;
if ((proto->hdrpush == NULL) || (proto->hdrpull == NULL) ||
if ((proto->txdata == NULL) || (proto->hdrpull == NULL) ||
(proto->query_dcmd == NULL) || (proto->set_dcmd == NULL)) {
brcmf_err("Not all proto handlers have been installed\n");
goto fail;

View File

@ -17,14 +17,14 @@
#define BRCMFMAC_PROTO_H
struct brcmf_proto {
void (*hdrpush)(struct brcmf_pub *drvr, int ifidx, u8 offset,
struct sk_buff *skb);
int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
struct sk_buff *skb);
int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len);
int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
uint len);
int (*txdata)(struct brcmf_pub *drvr, int ifidx, u8 offset,
struct sk_buff *skb);
void *pd;
};
@ -32,11 +32,6 @@ struct brcmf_proto {
int brcmf_proto_attach(struct brcmf_pub *drvr);
void brcmf_proto_detach(struct brcmf_pub *drvr);
static inline void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
u8 offset, struct sk_buff *skb)
{
drvr->proto->hdrpush(drvr, ifidx, offset, skb);
}
static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
u8 *ifidx, struct sk_buff *skb)
{
@ -52,6 +47,11 @@ static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx,
{
return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len);
}
static inline int brcmf_proto_txdata(struct brcmf_pub *drvr, int ifidx,
u8 offset, struct sk_buff *skb)
{
return drvr->proto->txdata(drvr, ifidx, offset, skb);
}
#endif /* BRCMFMAC_PROTO_H */

View File

@ -112,9 +112,9 @@ brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidhigh),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidhigh),
NULL);
return SBCOREREV(regdata);
}
@ -140,9 +140,9 @@ brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
if (idx == BRCMF_MAX_CORENUM)
return false;
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
return (SSB_TMSLOW_CLOCK == regdata);
@ -160,13 +160,13 @@ brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
if (idx == BRCMF_MAX_CORENUM)
return false;
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
regdata = brcmf_sdio_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
return ret;
@ -182,79 +182,79 @@ brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
base = ci->c_inf[idx].base;
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
if (regdata & SSB_TMSLOW_RESET)
return;
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
/*
* set target reject and spin until busy is clear
* (preserve core-specific bits)
*/
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
NULL);
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
regdata | SSB_TMSLOW_REJECT, NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(base, sbtmstatelow), NULL);
brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
regdata | SSB_TMSLOW_REJECT, NULL);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(base, sbtmstatelow), NULL);
udelay(1);
SPINWAIT((brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbtmstatehigh),
NULL) &
SSB_TMSHIGH_BUSY), 100000);
SPINWAIT((brcmf_sdiod_regrl(sdiodev,
CORE_SB(base, sbtmstatehigh),
NULL) &
SSB_TMSHIGH_BUSY), 100000);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbtmstatehigh),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(base, sbtmstatehigh),
NULL);
if (regdata & SSB_TMSHIGH_BUSY)
brcmf_err("core state still busy\n");
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
NULL);
if (regdata & SSB_IDLOW_INITIATOR) {
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
regdata |= SSB_IMSTATE_REJECT;
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
regdata, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
regdata, NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
udelay(1);
SPINWAIT((brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL) &
SSB_IMSTATE_BUSY), 100000);
SPINWAIT((brcmf_sdiod_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL) &
SSB_IMSTATE_BUSY), 100000);
}
/* set reset and reject while enabling the clocks */
regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
regdata, NULL);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
NULL);
brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
regdata, NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(base, sbtmstatelow), NULL);
udelay(10);
/* clear the initiator reject bit */
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
NULL);
if (regdata & SSB_IDLOW_INITIATOR) {
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
regdata &= ~SSB_IMSTATE_REJECT;
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
regdata, NULL);
brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
regdata, NULL);
}
}
/* leave reset and reject asserted */
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
(SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
(SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
udelay(1);
}
@ -270,9 +270,9 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
return;
/* if core is already in reset, just return */
regdata = brcmf_sdio_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
if ((regdata & BCMA_RESET_CTL_RESET) != 0)
return;
@ -281,24 +281,24 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
* extra 10ms is taken into account for firmware load stage
* after 10300us carry on disabling the core anyway
*/
SPINWAIT(brcmf_sdio_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
NULL), 10300);
regdata = brcmf_sdio_regrl(sdiodev,
SPINWAIT(brcmf_sdiod_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
NULL);
NULL), 10300);
regdata = brcmf_sdiod_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
NULL);
if (regdata)
brcmf_err("disabling core 0x%x with reset status %x\n",
coreid, regdata);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
BCMA_RESET_CTL_RESET, NULL);
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
BCMA_RESET_CTL_RESET, NULL);
udelay(1);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
core_bits, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
core_bits, NULL);
regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
usleep_range(10, 20);
}
@ -325,47 +325,47 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
* set reset while enabling the clock and
* forcing them on throughout the core
*/
brcmf_sdio_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
brcmf_sdiod_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
udelay(1);
/* clear any serror */
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
NULL);
if (regdata & SSB_TMSHIGH_SERR)
brcmf_sdio_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
0, NULL);
brcmf_sdiod_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
0, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate),
NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate),
NULL);
if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
brcmf_sdio_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate),
regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
NULL);
brcmf_sdiod_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate),
regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
NULL);
/* clear reset and allow it to propagate throughout the core */
brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
udelay(1);
/* leave clock enabled */
brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_CLOCK, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_CLOCK, NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
udelay(1);
}
@ -384,21 +384,21 @@ brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits);
/* now do initialization sequence */
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
0, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
0, NULL);
regdata = brcmf_sdiod_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
udelay(1);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
core_bits | BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
core_bits | BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
udelay(1);
}
@ -438,7 +438,7 @@ static inline int brcmf_sdio_chip_cichk(struct chip_info *ci)
#endif
static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci, u32 regs)
struct chip_info *ci)
{
u32 regdata;
int ret;
@ -449,10 +449,10 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
* other ways of recognition should be added here.
*/
ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
ci->c_inf[0].base = regs;
regdata = brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipid),
NULL);
ci->c_inf[0].base = SI_ENUM_BASE;
regdata = brcmf_sdiod_regrl(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipid),
NULL);
ci->chip = regdata & CID_ID_MASK;
ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
@ -607,7 +607,7 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
/* Try forcing SDIO core to do ALPAvail request only */
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
if (err) {
brcmf_err("error writing for HT off\n");
return err;
@ -615,8 +615,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
/* If register supported, wait for ALPAvail and then force ALP */
/* This may take up to 15 milliseconds */
clkval = brcmf_sdio_regrb(sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, NULL);
clkval = brcmf_sdiod_regrb(sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, NULL);
if ((clkval & ~SBSDIO_AVBITS) != clkset) {
brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
@ -624,8 +624,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
return -EACCES;
}
SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
!SBSDIO_ALPAV(clkval)),
PMU_MAX_TRANSITION_DLY);
if (!SBSDIO_ALPAV(clkval)) {
@ -635,11 +635,11 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
}
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
udelay(65);
/* Also, disable the extra SDIO pull-ups */
brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
return 0;
}
@ -654,16 +654,16 @@ brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
/* get chipcommon capabilites */
ci->c_inf[0].caps = brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(base, capabilities),
NULL);
ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev,
CORE_CC_REG(base, capabilities),
NULL);
/* get pmu caps & rev */
if (ci->c_inf[0].caps & CC_CAP_PMU) {
ci->pmucaps =
brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(base, pmucapabilities),
NULL);
brcmf_sdiod_regrl(sdiodev,
CORE_CC_REG(base, pmucapabilities),
NULL);
ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
}
@ -681,7 +681,7 @@ brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
}
int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
struct chip_info **ci_ptr, u32 regs)
struct chip_info **ci_ptr)
{
int ret;
struct chip_info *ci;
@ -697,16 +697,16 @@ int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
if (ret != 0)
goto err;
ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
ret = brcmf_sdio_chip_recognition(sdiodev, ci);
if (ret != 0)
goto err;
brcmf_sdio_chip_buscoresetup(sdiodev, ci);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
0, NULL);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
0, NULL);
brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
0, NULL);
brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
0, NULL);
*ci_ptr = ci;
return 0;
@ -784,12 +784,12 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
}
}
addr = CORE_CC_REG(base, chipcontrol_addr);
brcmf_sdio_regwl(sdiodev, addr, 1, NULL);
cc_data_temp = brcmf_sdio_regrl(sdiodev, addr, NULL);
brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
cc_data_temp &= ~str_mask;
drivestrength_sel <<= str_shift;
cc_data_temp |= drivestrength_sel;
brcmf_sdio_regwl(sdiodev, addr, cc_data_temp, NULL);
brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
str_tab[i].strength, drivestrength, cc_data_temp);
@ -816,8 +816,8 @@ brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
memset(nvram_ularray, 0xaa, nvram_sz);
/* Read the vars list to temp buffer for comparison */
err = brcmf_sdio_ramrw(sdiodev, false, nvram_addr, nvram_ularray,
nvram_sz);
err = brcmf_sdiod_ramrw(sdiodev, false, nvram_addr, nvram_ularray,
nvram_sz);
if (err) {
brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
err, nvram_sz, nvram_addr);
@ -850,7 +850,7 @@ static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev,
nvram_addr = (ci->ramsize - 4) - nvram_sz + ci->rambase;
/* Write the vars list */
err = brcmf_sdio_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz);
err = brcmf_sdiod_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz);
if (err) {
brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
err, nvram_sz, nvram_addr);
@ -874,8 +874,8 @@ static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev,
nvram_addr, nvram_sz, token);
/* Write the length token to the last word */
if (brcmf_sdio_ramrw(sdiodev, true, (ci->ramsize - 4 + ci->rambase),
(u8 *)&token_le, 4))
if (brcmf_sdiod_ramrw(sdiodev, true, (ci->ramsize - 4 + ci->rambase),
(u8 *)&token_le, 4))
return false;
return true;
@ -891,7 +891,7 @@ brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0);
/* clear length token */
brcmf_sdio_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4);
brcmf_sdiod_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4);
}
static bool
@ -913,7 +913,7 @@ brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
reg_addr = ci->c_inf[core_idx].base;
reg_addr += offsetof(struct sdpcmd_regs, intstatus);
brcmf_sdio_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
@ -942,11 +942,11 @@ brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
reg_addr = ci->c_inf[core_idx].base;
reg_addr += offsetof(struct sdpcmd_regs, intstatus);
brcmf_sdio_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
/* Write reset vector to address 0 */
brcmf_sdio_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
sizeof(ci->rst_vec));
brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
sizeof(ci->rst_vec));
/* restore ARM */
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, 0);

View File

@ -224,7 +224,7 @@ struct sdpcmd_regs {
};
int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
struct chip_info **ci_ptr, u32 regs);
struct chip_info **ci_ptr);
void brcmf_sdio_chip_detach(struct chip_info **ci_ptr);
void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci, u32 drivestrength);

View File

@ -164,9 +164,8 @@ struct brcmf_sdio;
struct brcmf_sdio_dev {
struct sdio_func *func[SDIO_MAX_FUNCS];
u8 num_funcs; /* Supported funcs on client */
u32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
u32 sbwad; /* Save backplane window address */
void *bus;
struct brcmf_sdio *bus;
atomic_t suspend; /* suspend flag */
wait_queue_head_t request_byte_wait;
wait_queue_head_t request_word_wait;
@ -185,22 +184,19 @@ struct brcmf_sdio_dev {
};
/* Register/deregister interrupt handler. */
int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev);
/* sdio device register access interface */
u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 data,
int *ret);
void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, u32 data,
int *ret);
int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
void *data, bool write);
u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 data,
int *ret);
void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, u32 data,
int *ret);
/* Buffer transfer to/from device (client) core via cmd53.
* fn: function number
* addr: backplane address (i.e. >= regsva from attach)
* flags: backplane width, address increment, sync/async
* buf: pointer to memory data buffer
* nbytes: number of bytes to transfer to/from buf
@ -210,17 +206,14 @@ int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
* Returns 0 or error code.
* NOTE: Async operation is not currently supported.
*/
int brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff_head *pktq);
int brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes);
int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,
struct sk_buff_head *pktq);
int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes);
int brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff *pkt);
int brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, u8 *buf, uint nbytes);
int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags, struct sk_buff_head *pktq, uint totlen);
int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt);
int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes);
int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
struct sk_buff_head *pktq, uint totlen);
/* Flags bits */
@ -236,43 +229,16 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
* nbytes: number of bytes to transfer to/from buf
* Returns 0 or error code.
*/
int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
u8 *buf, uint nbytes);
int brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
u8 *data, uint size);
int brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
u8 *data, uint size);
/* Issue an abort to the specified function */
int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
/* platform specific/high level functions */
int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev);
struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdio_remove(struct brcmf_sdio *bus);
void brcmf_sdio_isr(struct brcmf_sdio *bus);
/* attach, return handler on success, NULL if failed.
* The handler shall be provided by all subsequent calls. No local cache
* cfghdl points to the starting address of pci device mapped memory
*/
int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick);
/* read or write one byte using cmd52 */
int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint fnc,
uint addr, u8 *byte);
/* read or write 2/4 bytes using cmd53 */
int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, uint rw, uint fnc,
uint addr, u32 *word, uint nbyte);
/* Watchdog timer interface for pm ops */
void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable);
void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev);
void brcmf_sdbrcm_disconnect(void *ptr);
void brcmf_sdbrcm_isr(void *arg);
void brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick);
void brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev,
wait_queue_head_t *wq);
bool brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev);
#endif /* _BRCM_SDH_H_ */

View File

@ -1253,6 +1253,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
bus->ops = &brcmf_usb_bus_ops;
bus->chip = bus_pub->devid;
bus->chiprev = bus_pub->chiprev;
bus->proto_type = BRCMF_PROTO_BCDC;
/* Attach to the common driver interface */
ret = brcmf_attach(dev);

View File

@ -48,7 +48,7 @@ il3945_stats_flag(struct il_priv *il, char *buf, int bufsz)
return p;
}
ssize_t
static ssize_t
il3945_ucode_rx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@ -313,7 +313,7 @@ il3945_ucode_rx_stats_read(struct file *file, char __user *user_buf,
return ret;
}
ssize_t
static ssize_t
il3945_ucode_tx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@ -403,7 +403,7 @@ il3945_ucode_tx_stats_read(struct file *file, char __user *user_buf,
return ret;
}
ssize_t
static ssize_t
il3945_ucode_general_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{

View File

@ -55,7 +55,7 @@ il4965_stats_flag(struct il_priv *il, char *buf, int bufsz)
return p;
}
ssize_t
static ssize_t
il4965_ucode_rx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@ -467,7 +467,7 @@ il4965_ucode_rx_stats_read(struct file *file, char __user *user_buf,
return ret;
}
ssize_t
static ssize_t
il4965_ucode_tx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@ -633,7 +633,7 @@ il4965_ucode_tx_stats_read(struct file *file, char __user *user_buf,
return ret;
}
ssize_t
static ssize_t
il4965_ucode_general_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{

View File

@ -31,7 +31,7 @@
#include "common.h"
void
static void
il_clear_traffic_stats(struct il_priv *il)
{
memset(&il->tx_stats, 0, sizeof(struct traffic_stats));

View File

@ -322,12 +322,6 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)
flush_workqueue(priv->workqueue);
/* User space software may expect getting rfkill changes
* even if interface is down, trans->down will leave the RF
* kill interrupt enabled
*/
iwl_trans_stop_hw(priv->trans, false);
IWL_DEBUG_MAC80211(priv, "leave\n");
}

View File

@ -1313,7 +1313,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
}
/* Reset chip to save power until we load uCode during "up". */
iwl_trans_stop_hw(priv->trans, false);
iwl_trans_stop_device(priv->trans);
priv->nvm_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg,
priv->eeprom_blob,
@ -1458,7 +1458,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
dev_kfree_skb(priv->beacon_skb);
iwl_trans_stop_hw(priv->trans, true);
iwl_trans_op_mode_leave(priv->trans);
ieee80211_free_hw(priv->hw);
}

View File

@ -389,13 +389,6 @@ struct iwl_lq_sta {
u8 last_bt_traffic;
};
static inline u8 num_of_ant(u8 mask)
{
return !!((mask) & ANT_A) +
!!((mask) & ANT_B) +
!!((mask) & ANT_C);
}
static inline u8 first_antenna(u8 mask)
{
if (mask & ANT_A)

View File

@ -368,6 +368,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
goto drop_unlock_priv;
memset(dev_cmd, 0, sizeof(*dev_cmd));
dev_cmd->hdr.cmd = REPLY_TX;
tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
/* Total # bytes to be transmitted */

View File

@ -108,7 +108,7 @@ static const struct iwl_base_params iwl7000_base_params = {
};
static const struct iwl_ht_params iwl7000_ht_params = {
.use_rts_for_aggregation = true, /* use rts/cts protection */
.stbc = true,
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};

View File

@ -129,6 +129,12 @@ enum iwl_led_mode {
#define ANT_BC (ANT_B | ANT_C)
#define ANT_ABC (ANT_A | ANT_B | ANT_C)
static inline u8 num_of_ant(u8 mask)
{
return !!((mask) & ANT_A) +
!!((mask) & ANT_B) +
!!((mask) & ANT_C);
}
/*
* @max_ll_items: max number of OTP blocks
@ -156,12 +162,14 @@ struct iwl_base_params {
};
/*
* @stbc: support Tx STBC and 1*SS Rx STBC
* @use_rts_for_aggregation: use rts/cts protection for HT traffic
* @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
*/
struct iwl_ht_params {
enum ieee80211_smps_mode smps_mode;
const bool ht_greenfield_support; /* if used set to true */
const bool stbc;
bool use_rts_for_aggregation;
u8 ht40_bands;
};

View File

@ -322,6 +322,41 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
pieces->img[type].sec[sec].offset = offset;
}
static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len)
{
int i, j;
struct iwl_fw_cscheme_list *l = (struct iwl_fw_cscheme_list *)data;
struct iwl_fw_cipher_scheme *fwcs;
struct ieee80211_cipher_scheme *cs;
u32 cipher;
if (len < sizeof(*l) ||
len < sizeof(l->size) + l->size * sizeof(l->cs[0]))
return -EINVAL;
for (i = 0, j = 0; i < IWL_UCODE_MAX_CS && i < l->size; i++) {
fwcs = &l->cs[j];
cipher = le32_to_cpu(fwcs->cipher);
/* we skip schemes with zero cipher suite selector */
if (!cipher)
continue;
cs = &fw->cs[j++];
cs->cipher = cipher;
cs->iftype = BIT(NL80211_IFTYPE_STATION);
cs->hdr_len = fwcs->hdr_len;
cs->pn_len = fwcs->pn_len;
cs->pn_off = fwcs->pn_off;
cs->key_idx_off = fwcs->key_idx_off;
cs->key_idx_mask = fwcs->key_idx_mask;
cs->key_idx_shift = fwcs->key_idx_shift;
cs->mic_len = fwcs->mic_len;
}
return 0;
}
/*
* Gets uCode section from tlv.
*/
@ -729,6 +764,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
return -EINVAL;
}
break;
case IWL_UCODE_TLV_CSCHEME:
if (iwl_store_cscheme(&drv->fw, tlv_data, tlv_len))
goto invalid_tlv_len;
break;
default:
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
break;

View File

@ -751,6 +751,13 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40;
if (cfg->ht_params->stbc) {
ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
if (tx_chains > 1)
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
}
if (iwlwifi_mod_params.amsdu_size_8K)
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;

View File

@ -125,6 +125,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_SECURE_SEC_INIT = 25,
IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
IWL_UCODE_TLV_NUM_OF_CPU = 27,
IWL_UCODE_TLV_CSCHEME = 28,
};
struct iwl_ucode_tlv {

View File

@ -92,6 +92,9 @@
* @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
* @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
* containing CAM (Continuous Active Mode) indication.
* @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
* single bound interface).
* @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
*/
enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
@ -113,7 +116,9 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17),
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19),
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20),
IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21),
IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24),
IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26),
};
/* The default calibrate table size if not specified by firmware file */
@ -209,6 +214,44 @@ enum iwl_fw_phy_cfg {
FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS,
};
#define IWL_UCODE_MAX_CS 1
/**
* struct iwl_fw_cipher_scheme - a cipher scheme supported by FW.
* @cipher: a cipher suite selector
* @flags: cipher scheme flags (currently reserved for a future use)
* @hdr_len: a size of MPDU security header
* @pn_len: a size of PN
* @pn_off: an offset of pn from the beginning of the security header
* @key_idx_off: an offset of key index byte in the security header
* @key_idx_mask: a bit mask of key_idx bits
* @key_idx_shift: bit shift needed to get key_idx
* @mic_len: mic length in bytes
* @hw_cipher: a HW cipher index used in host commands
*/
struct iwl_fw_cipher_scheme {
__le32 cipher;
u8 flags;
u8 hdr_len;
u8 pn_len;
u8 pn_off;
u8 key_idx_off;
u8 key_idx_mask;
u8 key_idx_shift;
u8 mic_len;
u8 hw_cipher;
} __packed;
/**
* struct iwl_fw_cscheme_list - a cipher scheme list
* @size: a number of entries
* @cs: cipher scheme entries
*/
struct iwl_fw_cscheme_list {
u8 size;
struct iwl_fw_cipher_scheme cs[];
} __packed;
/**
* struct iwl_fw - variables associated with the firmware
*
@ -224,6 +267,7 @@ enum iwl_fw_phy_cfg {
* @inst_evtlog_size: event log size for runtime ucode.
* @inst_errlog_ptr: error log offfset for runtime ucode.
* @mvm_fw: indicates this is MVM firmware
* @cipher_scheme: optional external cipher scheme.
*/
struct iwl_fw {
u32 ucode_ver;
@ -243,6 +287,8 @@ struct iwl_fw {
u32 phy_config;
bool mvm_fw;
struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
};
static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)

View File

@ -263,13 +263,20 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
struct ieee80211_sta_vht_cap *vht_cap)
{
int num_ants = num_of_ant(data->valid_rx_ant);
int bf_sts_cap = num_ants - 1;
vht_cap->vht_supported = true;
vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
IEEE80211_VHT_CAP_RXSTBC_1 |
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
bf_sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
if (num_ants > 1)
vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
if (iwlwifi_mod_params.amsdu_size_8K)
vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
@ -283,15 +290,22 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
if (data->valid_rx_ant == 1 || cfg->rx_with_siso_diversity) {
/* Max rate for Long GI NSS=2 80Mhz is 780Mbps */
vht_cap->vht_mcs.rx_highest = cpu_to_le16(780);
if (num_ants == 1 ||
cfg->rx_with_siso_diversity) {
vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
/* this works because NOT_SUPPORTED == 3 */
vht_cap->vht_mcs.rx_mcs_map |=
cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
/* Max rate for Long GI NSS=1 80Mhz is 390Mbps */
vht_cap->vht_mcs.rx_highest = cpu_to_le16(390);
}
vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
vht_cap->vht_mcs.tx_highest = vht_cap->vht_mcs.rx_highest;
}
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,

View File

@ -155,14 +155,12 @@ void iwl_opmode_deregister(const char *name);
/**
* struct iwl_op_mode - operational mode
* @ops - pointer to its own ops
*
* This holds an implementation of the mac80211 / fw API.
*
* @ops - pointer to its own ops
*/
struct iwl_op_mode {
const struct iwl_op_mode_ops *ops;
const struct iwl_trans *trans;
char op_mode_specific[0] __aligned(sizeof(void *));
};

View File

@ -102,6 +102,9 @@
/* Device system time */
#define DEVICE_SYSTEM_TIME_REG 0xA0206C
/* Device NMI register */
#define DEVICE_SET_NMI_REG 0x00a01c30
/*****************************************************************************
* 7000/3000 series SHR DTS addresses *
*****************************************************************************/

View File

@ -70,6 +70,7 @@
#include "iwl-debug.h"
#include "iwl-config.h"
#include "iwl-fw.h"
#include "iwl-op-mode.h"
/**
* DOC: Transport layer - what is it ?
@ -100,8 +101,7 @@
* start_fw
*
* 5) Then when finished (or reset):
* stop_fw (a.k.a. stop device for the moment)
* stop_hw
* stop_device
*
* 6) Eventually, the free function will be called.
*/
@ -317,6 +317,24 @@ enum iwl_d3_status {
IWL_D3_STATUS_RESET,
};
/**
* enum iwl_trans_status: transport status flags
* @STATUS_SYNC_HCMD_ACTIVE: a SYNC command is being processed
* @STATUS_DEVICE_ENABLED: APM is enabled
* @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
* @STATUS_INT_ENABLED: interrupts are enabled
* @STATUS_RFKILL: the HW RFkill switch is in KILL position
* @STATUS_FW_ERROR: the fw is in error state
*/
enum iwl_trans_status {
STATUS_SYNC_HCMD_ACTIVE,
STATUS_DEVICE_ENABLED,
STATUS_TPOWER_PMI,
STATUS_INT_ENABLED,
STATUS_RFKILL,
STATUS_FW_ERROR,
};
/**
* struct iwl_trans_config - transport configuration
*
@ -361,9 +379,7 @@ struct iwl_trans;
*
* @start_hw: starts the HW- from that point on, the HW can send interrupts
* May sleep
* @stop_hw: stops the HW- from that point on, the HW will be in low power but
* will still issue interrupt if the HW RF kill is triggered unless
* op_mode_leaving is true.
* @op_mode_leave: Turn off the HW RF kill indication if on
* May sleep
* @start_fw: allocates and inits all the resources for the transport
* layer. Also kick a fw image.
@ -371,8 +387,11 @@ struct iwl_trans;
* @fw_alive: called when the fw sends alive notification. If the fw provides
* the SCD base address in SRAM, then provide it here, or 0 otherwise.
* May sleep
* @stop_device:stops the whole device (embedded CPU put to reset)
* May sleep
* @stop_device: stops the whole device (embedded CPU put to reset) and stops
* the HW. From that point on, the HW will be in low power but will still
* issue interrupt if the HW RF kill is triggered. This callback must do
* the right thing and not crash even if start_hw() was called but not
* start_fw(). May sleep
* @d3_suspend: put the device into the correct mode for WoWLAN during
* suspend. This is optional, if not implemented WoWLAN will not be
* supported. This callback may sleep.
@ -418,7 +437,7 @@ struct iwl_trans;
struct iwl_trans_ops {
int (*start_hw)(struct iwl_trans *iwl_trans);
void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
void (*op_mode_leave)(struct iwl_trans *iwl_trans);
int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
bool run_in_rfkill);
void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
@ -479,6 +498,7 @@ enum iwl_trans_state {
* @ops - pointer to iwl_trans_ops
* @op_mode - pointer to the op_mode
* @cfg - pointer to the configuration
* @status: a bit-mask of transport status flags
* @dev - pointer to struct device * that represents the device
* @hw_id: a u32 with the ID of the device / subdevice.
* Set during transport allocation.
@ -499,6 +519,7 @@ struct iwl_trans {
struct iwl_op_mode *op_mode;
const struct iwl_cfg *cfg;
enum iwl_trans_state state;
unsigned long status;
struct device *dev;
u32 hw_rev;
@ -540,15 +561,14 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans)
return trans->ops->start_hw(trans);
}
static inline void iwl_trans_stop_hw(struct iwl_trans *trans,
bool op_mode_leaving)
static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans)
{
might_sleep();
trans->ops->stop_hw(trans, op_mode_leaving);
if (trans->ops->op_mode_leave)
trans->ops->op_mode_leave(trans);
if (op_mode_leaving)
trans->op_mode = NULL;
trans->op_mode = NULL;
trans->state = IWL_TRANS_NO_FW;
}
@ -570,6 +590,7 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans,
WARN_ON_ONCE(!trans->rx_mpdu_cmd);
clear_bit(STATUS_FW_ERROR, &trans->status);
return trans->ops->start_fw(trans, fw, run_in_rfkill);
}
@ -601,6 +622,9 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
{
int ret;
if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
return -EIO;
if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) {
IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
return -EIO;
@ -640,6 +664,9 @@ static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
struct iwl_device_cmd *dev_cmd, int queue)
{
if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
return -EIO;
if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
@ -760,7 +787,8 @@ static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
{
trans->ops->set_pmi(trans, state);
if (trans->ops->set_pmi)
trans->ops->set_pmi(trans, state);
}
static inline void
@ -780,6 +808,16 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
__release(nic_access);
}
static inline void iwl_trans_fw_error(struct iwl_trans *trans)
{
if (WARN_ON_ONCE(!trans->op_mode))
return;
/* prevent double restarts due to the same erroneous FW */
if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status))
iwl_op_mode_nic_error(trans->op_mode);
}
/*****************************************************
* driver (transport) register/unregister functions
******************************************************/

View File

@ -1,10 +1,10 @@
obj-$(CONFIG_IWLMVM) += iwlmvm.o
iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o
iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y += scan.o time-event.o rs.o
iwlmvm-y += power.o power_legacy.o bt-coex.o
iwlmvm-y += led.o tt.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../

View File

@ -183,15 +183,29 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
return -EINVAL;
/*
* Update SF - Disable if needed. if this fails, SF might still be on
* while many macs are bound, which is forbidden - so fail the binding.
*/
if (iwl_mvm_sf_update(mvm, vif, false))
return -EINVAL;
return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
}
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
return -EINVAL;
return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
ret = iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
if (!ret)
if (iwl_mvm_sf_update(mvm, vif, true))
IWL_ERR(mvm, "Failed to update SF state\n");
return ret;
}

View File

@ -396,7 +396,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
BT_VALID_ANT_ISOLATION |
BT_VALID_ANT_ISOLATION_THRS |
BT_VALID_TXTX_DELTA_FREQ_THRS |
BT_VALID_TXRX_MAX_FREQ_0);
BT_VALID_TXRX_MAX_FREQ_0 |
BT_VALID_SYNC_TO_SCO);
if (mvm->cfg->bt_shared_single_ant)
memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant,
@ -514,7 +515,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
if (IS_ERR_OR_NULL(sta))
return 0;
mvmsta = (void *)sta->drv_priv;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
/* nothing to do */
if (mvmsta->bt_reduced_txpower == enable)
@ -846,7 +847,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
if (IS_ERR_OR_NULL(sta))
return;
mvmsta = (void *)sta->drv_priv;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
data->num_bss_ifaces++;
@ -917,11 +918,11 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm,
struct ieee80211_sta *sta)
{
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
enum iwl_bt_coex_lut_type lut_type;
if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
BT_LOW_TRAFFIC)
BT_HIGH_TRAFFIC)
return LINK_QUAL_AGG_TIME_LIMIT_DEF;
lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
@ -936,7 +937,7 @@ u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm,
bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
struct ieee80211_sta *sta)
{
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
BT_HIGH_TRAFFIC)

View File

@ -1216,10 +1216,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
if (len >= sizeof(u32) * 2) {
mvm->d3_test_pme_ptr =
le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data);
} else if (test) {
/* in test mode we require the pointer */
ret = -EIO;
goto out;
}
#endif
iwl_free_resp(&d3_cfg_cmd);
@ -1231,10 +1227,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mvm->aux_sta.sta_id = old_aux_sta_id;
mvm_ap_sta->sta_id = old_ap_sta_id;
mvmvif->ap_sta_id = old_ap_sta_id;
out_noreset:
kfree(key_data.rsc_tsc);
if (ret < 0)
ieee80211_restart_hw(mvm->hw);
out_noreset:
kfree(key_data.rsc_tsc);
mutex_unlock(&mvm->mutex);
@ -1537,10 +1534,16 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
struct iwl_mvm_d3_gtk_iter_data gtkdata = {
.status = status,
};
u32 disconnection_reasons =
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH;
if (!status || !vif->bss_conf.bssid)
return false;
if (le32_to_cpu(status->wakeup_reasons) & disconnection_reasons)
return false;
/* find last GTK that we used initially, if any */
gtkdata.find_phase = true;
ieee80211_iter_keys(mvm->hw, vif,
@ -1805,6 +1808,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
iwl_mvm_read_d3_sram(mvm);
keep = iwl_mvm_query_wakeup_reasons(mvm, vif);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (keep)
mvm->keep_vif = vif;
#endif
/* has unlocked the mutex, so skip that */
goto out;
@ -1861,6 +1868,7 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
return err;
}
mvm->d3_test_active = true;
mvm->keep_vif = NULL;
return 0;
}
@ -1871,10 +1879,14 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf,
u32 pme_asserted;
while (true) {
pme_asserted = iwl_trans_read_mem32(mvm->trans,
mvm->d3_test_pme_ptr);
if (pme_asserted)
break;
/* read pme_ptr if available */
if (mvm->d3_test_pme_ptr) {
pme_asserted = iwl_trans_read_mem32(mvm->trans,
mvm->d3_test_pme_ptr);
if (pme_asserted)
break;
}
if (msleep_interruptible(100))
break;
}
@ -1885,6 +1897,10 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf,
static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
/* skip the one we keep connection on */
if (_data == vif)
return;
if (vif->type == NL80211_IFTYPE_STATION)
ieee80211_connection_loss(vif);
}
@ -1911,7 +1927,7 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_d3_test_disconn_work_iter, NULL);
iwl_mvm_d3_test_disconn_work_iter, mvm->keep_vif);
ieee80211_wake_queues(mvm->hw);

View File

@ -0,0 +1,546 @@
/******************************************************************************
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include "mvm.h"
#include "debugfs.h"
static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
enum iwl_dbgfs_pm_mask param, int val)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
dbgfs_pm->mask |= param;
switch (param) {
case MVM_DEBUGFS_PM_KEEP_ALIVE: {
struct ieee80211_hw *hw = mvm->hw;
int dtimper = hw->conf.ps_dtim_period ?: 1;
int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
if (val * MSEC_PER_SEC < 3 * dtimper_msec)
IWL_WARN(mvm,
"debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
val * MSEC_PER_SEC, 3 * dtimper_msec);
dbgfs_pm->keep_alive_seconds = val;
break;
}
case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
val ? "enabled" : "disabled");
dbgfs_pm->skip_over_dtim = val;
break;
case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
dbgfs_pm->skip_dtim_periods = val;
break;
case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
dbgfs_pm->rx_data_timeout = val;
break;
case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
dbgfs_pm->tx_data_timeout = val;
break;
case MVM_DEBUGFS_PM_DISABLE_POWER_OFF:
IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val);
dbgfs_pm->disable_power_off = val;
break;
case MVM_DEBUGFS_PM_LPRX_ENA:
IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
dbgfs_pm->lprx_ena = val;
break;
case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
dbgfs_pm->lprx_rssi_threshold = val;
break;
case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
dbgfs_pm->snooze_ena = val;
break;
case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
dbgfs_pm->uapsd_misbehaving = val;
break;
}
}
static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
enum iwl_dbgfs_pm_mask param;
int val, ret;
if (!strncmp("keep_alive=", buf, 11)) {
if (sscanf(buf + 11, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_KEEP_ALIVE;
} else if (!strncmp("skip_over_dtim=", buf, 15)) {
if (sscanf(buf + 15, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
} else if (!strncmp("skip_dtim_periods=", buf, 18)) {
if (sscanf(buf + 18, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
} else if (!strncmp("rx_data_timeout=", buf, 16)) {
if (sscanf(buf + 16, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
} else if (!strncmp("tx_data_timeout=", buf, 16)) {
if (sscanf(buf + 16, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
} else if (!strncmp("disable_power_off=", buf, 18) &&
!(mvm->fw->ucode_capa.flags &
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) {
if (sscanf(buf + 18, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF;
} else if (!strncmp("lprx=", buf, 5)) {
if (sscanf(buf + 5, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_LPRX_ENA;
} else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
if (sscanf(buf + 20, "%d", &val) != 1)
return -EINVAL;
if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
POWER_LPRX_RSSI_THRESHOLD_MIN)
return -EINVAL;
param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
} else if (!strncmp("snooze_enable=", buf, 14)) {
if (sscanf(buf + 14, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
} else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
if (sscanf(buf + 18, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
} else {
return -EINVAL;
}
mutex_lock(&mvm->mutex);
iwl_dbgfs_update_pm(mvm, vif, param, val);
ret = iwl_mvm_power_update_mode(mvm, vif);
mutex_unlock(&mvm->mutex);
return ret ?: count;
}
static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
char buf[512];
int bufsz = sizeof(buf);
int pos;
pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
u8 ap_sta_id;
struct ieee80211_chanctx_conf *chanctx_conf;
char buf[512];
int bufsz = sizeof(buf);
int pos = 0;
int i;
mutex_lock(&mvm->mutex);
ap_sta_id = mvmvif->ap_sta_id;
pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
mvmvif->id, mvmvif->color);
pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
vif->bss_conf.bssid);
pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++)
pos += scnprintf(buf+pos, bufsz-pos,
"\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
i, mvmvif->queue_params[i].txop,
mvmvif->queue_params[i].cw_min,
mvmvif->queue_params[i].cw_max,
mvmvif->queue_params[i].aifs,
mvmvif->queue_params[i].uapsd);
if (vif->type == NL80211_IFTYPE_STATION &&
ap_sta_id != IWL_MVM_STATION_COUNT) {
struct ieee80211_sta *sta;
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
lockdep_is_held(&mvm->mutex));
if (!IS_ERR_OR_NULL(sta)) {
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
pos += scnprintf(buf+pos, bufsz-pos,
"ap_sta_id %d - reduced Tx power %d\n",
ap_sta_id,
mvm_sta->bt_reduced_txpower);
}
}
rcu_read_lock();
chanctx_conf = rcu_dereference(vif->chanctx_conf);
if (chanctx_conf)
pos += scnprintf(buf+pos, bufsz-pos,
"idle rx chains %d, active rx chains: %d\n",
chanctx_conf->rx_chains_static,
chanctx_conf->rx_chains_dynamic);
rcu_read_unlock();
mutex_unlock(&mvm->mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
enum iwl_dbgfs_bf_mask param, int value)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
dbgfs_bf->mask |= param;
switch (param) {
case MVM_DEBUGFS_BF_ENERGY_DELTA:
dbgfs_bf->bf_energy_delta = value;
break;
case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
dbgfs_bf->bf_roaming_energy_delta = value;
break;
case MVM_DEBUGFS_BF_ROAMING_STATE:
dbgfs_bf->bf_roaming_state = value;
break;
case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
dbgfs_bf->bf_temp_threshold = value;
break;
case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
dbgfs_bf->bf_temp_fast_filter = value;
break;
case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
dbgfs_bf->bf_temp_slow_filter = value;
break;
case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
dbgfs_bf->bf_enable_beacon_filter = value;
break;
case MVM_DEBUGFS_BF_DEBUG_FLAG:
dbgfs_bf->bf_debug_flag = value;
break;
case MVM_DEBUGFS_BF_ESCAPE_TIMER:
dbgfs_bf->bf_escape_timer = value;
break;
case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
dbgfs_bf->ba_enable_beacon_abort = value;
break;
case MVM_DEBUGFS_BA_ESCAPE_TIMER:
dbgfs_bf->ba_escape_timer = value;
break;
}
}
static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
enum iwl_dbgfs_bf_mask param;
int value, ret = 0;
if (!strncmp("bf_energy_delta=", buf, 16)) {
if (sscanf(buf+16, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ENERGY_DELTA_MIN ||
value > IWL_BF_ENERGY_DELTA_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ENERGY_DELTA;
} else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
if (sscanf(buf+24, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
} else if (!strncmp("bf_roaming_state=", buf, 17)) {
if (sscanf(buf+17, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ROAMING_STATE_MIN ||
value > IWL_BF_ROAMING_STATE_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ROAMING_STATE;
} else if (!strncmp("bf_temp_threshold=", buf, 18)) {
if (sscanf(buf+18, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
value > IWL_BF_TEMP_THRESHOLD_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
} else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
if (sscanf(buf+20, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
value > IWL_BF_TEMP_FAST_FILTER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
} else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
if (sscanf(buf+20, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
value > IWL_BF_TEMP_SLOW_FILTER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
} else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
if (sscanf(buf+24, "%d", &value) != 1)
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
} else if (!strncmp("bf_debug_flag=", buf, 14)) {
if (sscanf(buf+14, "%d", &value) != 1)
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
param = MVM_DEBUGFS_BF_DEBUG_FLAG;
} else if (!strncmp("bf_escape_timer=", buf, 16)) {
if (sscanf(buf+16, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ESCAPE_TIMER_MIN ||
value > IWL_BF_ESCAPE_TIMER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
} else if (!strncmp("ba_escape_timer=", buf, 16)) {
if (sscanf(buf+16, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BA_ESCAPE_TIMER_MIN ||
value > IWL_BA_ESCAPE_TIMER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
} else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
if (sscanf(buf+23, "%d", &value) != 1)
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
} else {
return -EINVAL;
}
mutex_lock(&mvm->mutex);
iwl_dbgfs_update_bf(vif, param, value);
if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
ret = iwl_mvm_disable_beacon_filter(mvm, vif);
else
ret = iwl_mvm_enable_beacon_filter(mvm, vif);
mutex_unlock(&mvm->mutex);
return ret ?: count;
}
static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
char buf[256];
int pos = 0;
const size_t bufsz = sizeof(buf);
struct iwl_beacon_filter_cmd cmd = {
IWL_BF_CMD_CONFIG_DEFAULTS,
.bf_enable_beacon_filter =
cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
.ba_enable_beacon_abort =
cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
};
iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
if (mvmvif->bf_data.bf_enabled)
cmd.bf_enable_beacon_filter = cpu_to_le32(1);
else
cmd.bf_enable_beacon_filter = 0;
pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
le32_to_cpu(cmd.bf_energy_delta));
pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
le32_to_cpu(cmd.bf_roaming_energy_delta));
pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
le32_to_cpu(cmd.bf_roaming_state));
pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
le32_to_cpu(cmd.bf_temp_threshold));
pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
le32_to_cpu(cmd.bf_temp_fast_filter));
pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
le32_to_cpu(cmd.bf_temp_slow_filter));
pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
le32_to_cpu(cmd.bf_enable_beacon_filter));
pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
le32_to_cpu(cmd.bf_debug_flag));
pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
le32_to_cpu(cmd.bf_escape_timer));
pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
le32_to_cpu(cmd.ba_escape_timer));
pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
le32_to_cpu(cmd.ba_enable_beacon_abort));
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, vif, \
&iwl_dbgfs_##name##_ops)) \
goto err; \
} while (0)
MVM_DEBUGFS_READ_FILE_OPS(mac_params);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct dentry *dbgfs_dir = vif->debugfs_dir;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
char buf[100];
/*
* Check if debugfs directory already exist before creating it.
* This may happen when, for example, resetting hw or suspend-resume
*/
if (!dbgfs_dir || mvmvif->dbgfs_dir)
return;
mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
mvmvif->mvm = mvm;
if (!mvmvif->dbgfs_dir) {
IWL_ERR(mvm, "Failed to create debugfs directory under %s\n",
dbgfs_dir->d_name.name);
return;
}
if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
(vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)))
MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
S_IRUSR);
MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
S_IRUSR);
if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif)
MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
S_IRUSR | S_IWUSR);
/*
* Create symlink for convenience pointing to interface specific
* debugfs entries for the driver. For example, under
* /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
* find
* netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
*/
snprintf(buf, 100, "../../../%s/%s/%s/%s",
dbgfs_dir->d_parent->d_parent->d_name.name,
dbgfs_dir->d_parent->d_name.name,
dbgfs_dir->d_name.name,
mvmvif->dbgfs_dir->d_name.name);
mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
mvm->debugfs_dir, buf);
if (!mvmvif->dbgfs_slink)
IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n",
dbgfs_dir->d_name.name);
return;
err:
IWL_ERR(mvm, "Can't create debugfs entity\n");
}
void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
debugfs_remove(mvmvif->dbgfs_slink);
mvmvif->dbgfs_slink = NULL;
debugfs_remove_recursive(mvmvif->dbgfs_dir);
mvmvif->dbgfs_dir = NULL;
}

View File

@ -63,30 +63,18 @@
#include "mvm.h"
#include "sta.h"
#include "iwl-io.h"
#include "iwl-prph.h"
#include "debugfs.h"
struct iwl_dbgfs_mvm_ctx {
struct iwl_mvm *mvm;
struct ieee80211_vif *vif;
};
static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
const char __user *user_buf,
static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
char buf[16];
int buf_size, ret;
int ret;
u32 scd_q_msk;
if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
return -EIO;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%x", &scd_q_msk) != 1)
return -EINVAL;
@ -99,24 +87,15 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
return ret;
}
static ssize_t iwl_dbgfs_sta_drain_write(struct file *file,
const char __user *user_buf,
static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
struct ieee80211_sta *sta;
char buf[8];
int buf_size, sta_id, drain, ret;
int sta_id, drain, ret;
if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
return -EIO;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
return -EINVAL;
if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT)
@ -194,20 +173,11 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
return ret;
}
static ssize_t iwl_dbgfs_sram_write(struct file *file,
const char __user *user_buf, size_t count,
loff_t *ppos)
static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
char buf[64];
int buf_size;
u32 offset, len;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
if ((offset & 0x3) || (len & 0x3))
return -EINVAL;
@ -267,22 +237,14 @@ static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file,
const char __user *user_buf,
static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
char buf[64] = {};
int ret;
int val;
int ret, val;
if (!mvm->ucode_loaded)
return -EIO;
count = min_t(size_t, count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
if (!strncmp("disable_power_off_d0=", buf, 21)) {
if (sscanf(buf + 21, "%d", &val) != 1)
return -EINVAL;
@ -302,212 +264,6 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file,
return ret ?: count;
}
static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
enum iwl_dbgfs_pm_mask param, int val)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
dbgfs_pm->mask |= param;
switch (param) {
case MVM_DEBUGFS_PM_KEEP_ALIVE: {
struct ieee80211_hw *hw = mvm->hw;
int dtimper = hw->conf.ps_dtim_period ?: 1;
int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
if (val * MSEC_PER_SEC < 3 * dtimper_msec) {
IWL_WARN(mvm,
"debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
val * MSEC_PER_SEC, 3 * dtimper_msec);
}
dbgfs_pm->keep_alive_seconds = val;
break;
}
case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
val ? "enabled" : "disabled");
dbgfs_pm->skip_over_dtim = val;
break;
case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
dbgfs_pm->skip_dtim_periods = val;
break;
case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
dbgfs_pm->rx_data_timeout = val;
break;
case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
dbgfs_pm->tx_data_timeout = val;
break;
case MVM_DEBUGFS_PM_DISABLE_POWER_OFF:
IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val);
dbgfs_pm->disable_power_off = val;
break;
case MVM_DEBUGFS_PM_LPRX_ENA:
IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
dbgfs_pm->lprx_ena = val;
break;
case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
dbgfs_pm->lprx_rssi_threshold = val;
break;
case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
dbgfs_pm->snooze_ena = val;
break;
}
}
static ssize_t iwl_dbgfs_pm_params_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->dbgfs_data;
enum iwl_dbgfs_pm_mask param;
char buf[32] = {};
int val;
int ret;
count = min_t(size_t, count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
if (!strncmp("keep_alive=", buf, 11)) {
if (sscanf(buf + 11, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_KEEP_ALIVE;
} else if (!strncmp("skip_over_dtim=", buf, 15)) {
if (sscanf(buf + 15, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
} else if (!strncmp("skip_dtim_periods=", buf, 18)) {
if (sscanf(buf + 18, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
} else if (!strncmp("rx_data_timeout=", buf, 16)) {
if (sscanf(buf + 16, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
} else if (!strncmp("tx_data_timeout=", buf, 16)) {
if (sscanf(buf + 16, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
} else if (!strncmp("disable_power_off=", buf, 18) &&
!(mvm->fw->ucode_capa.flags &
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) {
if (sscanf(buf + 18, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF;
} else if (!strncmp("lprx=", buf, 5)) {
if (sscanf(buf + 5, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_LPRX_ENA;
} else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
if (sscanf(buf + 20, "%d", &val) != 1)
return -EINVAL;
if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
POWER_LPRX_RSSI_THRESHOLD_MIN)
return -EINVAL;
param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
} else if (!strncmp("snooze_enable=", buf, 14)) {
if (sscanf(buf + 14, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
} else {
return -EINVAL;
}
mutex_lock(&mvm->mutex);
iwl_dbgfs_update_pm(mvm, vif, param, val);
ret = iwl_mvm_power_update_mode(mvm, vif);
mutex_unlock(&mvm->mutex);
return ret ?: count;
}
static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->dbgfs_data;
char buf[512];
int bufsz = sizeof(buf);
int pos;
pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->dbgfs_data;
u8 ap_sta_id;
struct ieee80211_chanctx_conf *chanctx_conf;
char buf[512];
int bufsz = sizeof(buf);
int pos = 0;
int i;
mutex_lock(&mvm->mutex);
ap_sta_id = mvmvif->ap_sta_id;
pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
mvmvif->id, mvmvif->color);
pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
vif->bss_conf.bssid);
pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) {
pos += scnprintf(buf+pos, bufsz-pos,
"\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
i, mvmvif->queue_params[i].txop,
mvmvif->queue_params[i].cw_min,
mvmvif->queue_params[i].cw_max,
mvmvif->queue_params[i].aifs,
mvmvif->queue_params[i].uapsd);
}
if (vif->type == NL80211_IFTYPE_STATION &&
ap_sta_id != IWL_MVM_STATION_COUNT) {
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvm_sta;
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
lockdep_is_held(&mvm->mutex));
mvm_sta = (void *)sta->drv_priv;
pos += scnprintf(buf+pos, bufsz-pos,
"ap_sta_id %d - reduced Tx power %d\n",
ap_sta_id, mvm_sta->bt_reduced_txpower);
}
rcu_read_lock();
chanctx_conf = rcu_dereference(vif->chanctx_conf);
if (chanctx_conf) {
pos += scnprintf(buf+pos, bufsz-pos,
"idle rx chains %d, active rx chains: %d\n",
chanctx_conf->rx_chains_static,
chanctx_conf->rx_chains_dynamic);
}
rcu_read_unlock();
mutex_unlock(&mvm->mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
#define BT_MBOX_MSG(_notif, _num, _field) \
((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
>> BT_MBOX##_num##_##_field##_POS)
@ -783,11 +539,9 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
}
#undef PRINT_STAT_LE32
static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
const char __user *user_buf,
static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
int ret;
mutex_lock(&mvm->mutex);
@ -804,6 +558,14 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
return count;
}
static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
iwl_write_prph(mvm->trans, DEVICE_SET_NMI_REG, 1);
return count;
}
static ssize_t
iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
char __user *user_buf,
@ -828,21 +590,11 @@ iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
}
static ssize_t
iwl_dbgfs_scan_ant_rxchain_write(struct file *file,
const char __user *user_buf,
iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
char buf[8];
int buf_size;
u8 scan_rx_ant;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
/* get the argument from the user and check if it is valid */
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%hhx", &scan_rx_ant) != 1)
return -EINVAL;
if (scan_rx_ant > ANT_ABC)
@ -850,228 +602,17 @@ iwl_dbgfs_scan_ant_rxchain_write(struct file *file,
if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw))
return -EINVAL;
/* change the rx antennas for scan command */
mvm->scan_rx_ant = scan_rx_ant;
return count;
}
static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
enum iwl_dbgfs_bf_mask param, int value)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
dbgfs_bf->mask |= param;
switch (param) {
case MVM_DEBUGFS_BF_ENERGY_DELTA:
dbgfs_bf->bf_energy_delta = value;
break;
case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
dbgfs_bf->bf_roaming_energy_delta = value;
break;
case MVM_DEBUGFS_BF_ROAMING_STATE:
dbgfs_bf->bf_roaming_state = value;
break;
case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
dbgfs_bf->bf_temp_threshold = value;
break;
case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
dbgfs_bf->bf_temp_fast_filter = value;
break;
case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
dbgfs_bf->bf_temp_slow_filter = value;
break;
case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
dbgfs_bf->bf_enable_beacon_filter = value;
break;
case MVM_DEBUGFS_BF_DEBUG_FLAG:
dbgfs_bf->bf_debug_flag = value;
break;
case MVM_DEBUGFS_BF_ESCAPE_TIMER:
dbgfs_bf->bf_escape_timer = value;
break;
case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
dbgfs_bf->ba_enable_beacon_abort = value;
break;
case MVM_DEBUGFS_BA_ESCAPE_TIMER:
dbgfs_bf->ba_escape_timer = value;
break;
}
}
static ssize_t iwl_dbgfs_bf_params_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->dbgfs_data;
enum iwl_dbgfs_bf_mask param;
char buf[256];
int buf_size;
int value;
int ret = 0;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (!strncmp("bf_energy_delta=", buf, 16)) {
if (sscanf(buf+16, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ENERGY_DELTA_MIN ||
value > IWL_BF_ENERGY_DELTA_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ENERGY_DELTA;
} else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
if (sscanf(buf+24, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
} else if (!strncmp("bf_roaming_state=", buf, 17)) {
if (sscanf(buf+17, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ROAMING_STATE_MIN ||
value > IWL_BF_ROAMING_STATE_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ROAMING_STATE;
} else if (!strncmp("bf_temp_threshold=", buf, 18)) {
if (sscanf(buf+18, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
value > IWL_BF_TEMP_THRESHOLD_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
} else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
if (sscanf(buf+20, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
value > IWL_BF_TEMP_FAST_FILTER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
} else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
if (sscanf(buf+20, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
value > IWL_BF_TEMP_SLOW_FILTER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
} else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
if (sscanf(buf+24, "%d", &value) != 1)
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
} else if (!strncmp("bf_debug_flag=", buf, 14)) {
if (sscanf(buf+14, "%d", &value) != 1)
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
param = MVM_DEBUGFS_BF_DEBUG_FLAG;
} else if (!strncmp("bf_escape_timer=", buf, 16)) {
if (sscanf(buf+16, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ESCAPE_TIMER_MIN ||
value > IWL_BF_ESCAPE_TIMER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
} else if (!strncmp("ba_escape_timer=", buf, 16)) {
if (sscanf(buf+16, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BA_ESCAPE_TIMER_MIN ||
value > IWL_BA_ESCAPE_TIMER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
} else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
if (sscanf(buf+23, "%d", &value) != 1)
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
} else {
return -EINVAL;
}
mutex_lock(&mvm->mutex);
iwl_dbgfs_update_bf(vif, param, value);
if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) {
ret = iwl_mvm_disable_beacon_filter(mvm, vif);
} else {
ret = iwl_mvm_enable_beacon_filter(mvm, vif);
}
mutex_unlock(&mvm->mutex);
return ret ?: count;
}
static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
char buf[256];
int pos = 0;
const size_t bufsz = sizeof(buf);
struct iwl_beacon_filter_cmd cmd = {
IWL_BF_CMD_CONFIG_DEFAULTS,
.bf_enable_beacon_filter =
cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
.ba_enable_beacon_abort =
cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
};
iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
if (mvmvif->bf_data.bf_enabled)
cmd.bf_enable_beacon_filter = cpu_to_le32(1);
else
cmd.bf_enable_beacon_filter = 0;
pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
le32_to_cpu(cmd.bf_energy_delta));
pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
le32_to_cpu(cmd.bf_roaming_energy_delta));
pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
le32_to_cpu(cmd.bf_roaming_state));
pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
le32_to_cpu(cmd.bf_temp_threshold));
pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
le32_to_cpu(cmd.bf_temp_fast_filter));
pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
le32_to_cpu(cmd.bf_temp_slow_filter));
pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
le32_to_cpu(cmd.bf_enable_beacon_filter));
pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
le32_to_cpu(cmd.bf_debug_flag));
pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
le32_to_cpu(cmd.bf_escape_timer));
pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
le32_to_cpu(cmd.ba_escape_timer));
pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
le32_to_cpu(cmd.ba_enable_beacon_abort));
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
#ifdef CONFIG_PM_SLEEP
static ssize_t iwl_dbgfs_d3_sram_write(struct file *file,
const char __user *user_buf,
static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
char buf[8] = {};
int store;
count = min_t(size_t, count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
if (sscanf(buf, "%d", &store) != 1)
return -EINVAL;
@ -1124,61 +665,33 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
}
#endif
#define MVM_DEBUGFS_READ_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = iwl_dbgfs_##name##_write, \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define MVM_DEBUGFS_WRITE_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = iwl_dbgfs_##name##_write, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, mvm, \
&iwl_dbgfs_##name##_ops)) \
goto err; \
} while (0)
#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, vif, \
&iwl_dbgfs_##name##_ops)) \
goto err; \
} while (0)
/* Device wide debugfs entries */
MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush);
MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
MVM_DEBUGFS_READ_FILE_OPS(stations);
MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
#endif
/* Interface specific debugfs entries */
MVM_DEBUGFS_READ_FILE_OPS(mac_params);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params);
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
{
char buf[100];
@ -1196,6 +709,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
S_IWUSR | S_IRUSR);
#ifdef CONFIG_PM_SLEEP
@ -1206,6 +720,19 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
goto err;
#endif
if (!debugfs_create_blob("nvm_hw", S_IRUSR,
mvm->debugfs_dir, &mvm->nvm_hw_blob))
goto err;
if (!debugfs_create_blob("nvm_sw", S_IRUSR,
mvm->debugfs_dir, &mvm->nvm_sw_blob))
goto err;
if (!debugfs_create_blob("nvm_calib", S_IRUSR,
mvm->debugfs_dir, &mvm->nvm_calib_blob))
goto err;
if (!debugfs_create_blob("nvm_prod", S_IRUSR,
mvm->debugfs_dir, &mvm->nvm_prod_blob))
goto err;
/*
* Create a symlink with mac80211. It will be removed when mac80211
* exists (before the opmode exists which removes the target.)
@ -1221,72 +748,3 @@ err:
IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
return -ENOMEM;
}
void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct dentry *dbgfs_dir = vif->debugfs_dir;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
char buf[100];
/*
* Check if debugfs directory already exist before creating it.
* This may happen when, for example, resetting hw or suspend-resume
*/
if (!dbgfs_dir || mvmvif->dbgfs_dir)
return;
mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
mvmvif->dbgfs_data = mvm;
if (!mvmvif->dbgfs_dir) {
IWL_ERR(mvm, "Failed to create debugfs directory under %s\n",
dbgfs_dir->d_name.name);
return;
}
if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
vif->type == NL80211_IFTYPE_STATION && !vif->p2p)
MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
S_IRUSR);
MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
S_IRUSR);
if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif)
MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
S_IRUSR | S_IWUSR);
/*
* Create symlink for convenience pointing to interface specific
* debugfs entries for the driver. For example, under
* /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
* find
* netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
*/
snprintf(buf, 100, "../../../%s/%s/%s/%s",
dbgfs_dir->d_parent->d_parent->d_name.name,
dbgfs_dir->d_parent->d_name.name,
dbgfs_dir->d_name.name,
mvmvif->dbgfs_dir->d_name.name);
mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
mvm->debugfs_dir, buf);
if (!mvmvif->dbgfs_slink)
IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n",
dbgfs_dir->d_name.name);
return;
err:
IWL_ERR(mvm, "Can't create debugfs entity\n");
}
void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
debugfs_remove(mvmvif->dbgfs_slink);
mvmvif->dbgfs_slink = NULL;
debugfs_remove_recursive(mvmvif->dbgfs_dir);
mvmvif->dbgfs_dir = NULL;
}

View File

@ -0,0 +1,101 @@
/******************************************************************************
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#define MVM_DEBUGFS_READ_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
#define MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \
static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \
const char __user *user_buf, \
size_t count, loff_t *ppos) \
{ \
argtype *arg = file->private_data; \
char buf[buflen] = {}; \
size_t buf_size = min(count, sizeof(buf) - 1); \
\
if (copy_from_user(buf, user_buf, buf_size)) \
return -EFAULT; \
\
return iwl_dbgfs_##name##_write(arg, buf, buf_size, ppos); \
} \
#define _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen, argtype) \
MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = _iwl_dbgfs_##name##_write, \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define _MVM_DEBUGFS_WRITE_FILE_OPS(name, buflen, argtype) \
MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = _iwl_dbgfs_##name##_write, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};

View File

@ -127,6 +127,7 @@ enum iwl_bt_coex_valid_bit_msk {
BT_VALID_ANT_ISOLATION_THRS = BIT(15),
BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16),
BT_VALID_TXRX_MAX_FREQ_0 = BIT(17),
BT_VALID_SYNC_TO_SCO = BIT(18),
};
/**

View File

@ -85,6 +85,8 @@
* PBW Snoozing enabled
* @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
* @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
* @POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving
* detection enablement
*/
enum iwl_power_flags {
POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0),
@ -94,6 +96,7 @@ enum iwl_power_flags {
POWER_FLAGS_BT_SCO_ENA = BIT(8),
POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9),
POWER_FLAGS_LPRX_ENA_MSK = BIT(11),
POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK = BIT(12),
};
#define IWL_POWER_VEC_SIZE 5
@ -228,6 +231,19 @@ struct iwl_mac_power_cmd {
u8 reserved;
} __packed;
/*
* struct iwl_uapsd_misbehaving_ap_notif - FW sends this notification when
* associated AP is identified as improperly implementing uAPSD protocol.
* PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78
* @sta_id: index of station in uCode's station table - associated AP ID in
* this context.
*/
struct iwl_uapsd_misbehaving_ap_notif {
__le32 sta_id;
u8 mac_id;
u8 reserved[3];
} __packed;
/**
* struct iwl_beacon_filter_cmd
* REPLY_BEACON_FILTERING_CMD = 0xd2 (command)

View File

@ -281,8 +281,31 @@ enum {
/* # entries in rate scale table to support Tx retries */
#define LQ_MAX_RETRY_NUM 16
/* Link quality command flags, only this one is available */
#define LQ_FLAG_SET_STA_TLC_RTS_MSK BIT(0)
/* Link quality command flags bit fields */
/* Bit 0: (0) Don't use RTS (1) Use RTS */
#define LQ_FLAG_USE_RTS_POS 0
#define LQ_FLAG_USE_RTS_MSK (1 << LQ_FLAG_USE_RTS_POS)
/* Bit 1-3: LQ command color. Used to match responses to LQ commands */
#define LQ_FLAG_COLOR_POS 1
#define LQ_FLAG_COLOR_MSK (7 << LQ_FLAG_COLOR_POS)
/* Bit 4-5: Tx RTS BW Signalling
* (0) No RTS BW signalling
* (1) Static BW signalling
* (2) Dynamic BW signalling
*/
#define LQ_FLAG_RTS_BW_SIG_POS 4
#define LQ_FLAG_RTS_BW_SIG_NONE (0 << LQ_FLAG_RTS_BW_SIG_POS)
#define LQ_FLAG_RTS_BW_SIG_STATIC (1 << LQ_FLAG_RTS_BW_SIG_POS)
#define LQ_FLAG_RTS_BW_SIG_DYNAMIC (2 << LQ_FLAG_RTS_BW_SIG_POS)
/* Bit 6: (0) No dynamic BW selection (1) Allow dynamic BW selection
* Dyanmic BW selection allows Tx with narrower BW then requested in rates
*/
#define LQ_FLAG_DYNAMIC_BW_POS 6
#define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS)
/**
* struct iwl_lq_cmd - link quality command

View File

@ -530,14 +530,13 @@ struct iwl_scan_offload_schedule {
/*
* iwl_scan_offload_flags
*
* IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID: filter mode - upload every beacon or match
* ssid list.
* IWL_SCAN_OFFLOAD_FLAG_PASS_ALL: pass all results - no filtering.
* IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan.
* IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan
* on A band.
*/
enum iwl_scan_offload_flags {
IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID = BIT(0),
IWL_SCAN_OFFLOAD_FLAG_PASS_ALL = BIT(0),
IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2),
IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN = BIT(3),
};

View File

@ -138,7 +138,14 @@ enum iwl_sta_flags {
/**
* enum iwl_sta_key_flag - key flags for the ADD_STA host command
* @STA_KEY_FLG_EN_MSK: mask for encryption algorithm
* @STA_KEY_FLG_NO_ENC: no encryption
* @STA_KEY_FLG_WEP: WEP encryption algorithm
* @STA_KEY_FLG_CCM: CCMP encryption algorithm
* @STA_KEY_FLG_TKIP: TKIP encryption algorithm
* @STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support)
* @STA_KEY_FLG_CMAC: CMAC encryption algorithm
* @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm
* @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value
* @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from
* station info array (1 - n 1X mode)
* @STA_KEY_FLG_KEYID_MSK: the index of the key
@ -152,6 +159,7 @@ enum iwl_sta_key_flag {
STA_KEY_FLG_WEP = (1 << 0),
STA_KEY_FLG_CCM = (2 << 0),
STA_KEY_FLG_TKIP = (3 << 0),
STA_KEY_FLG_EXT = (4 << 0),
STA_KEY_FLG_CMAC = (6 << 0),
STA_KEY_FLG_ENC_UNKNOWN = (7 << 0),
STA_KEY_FLG_EN_MSK = (7 << 0),

View File

@ -132,6 +132,7 @@ enum iwl_tx_flags {
#define TX_CMD_SEC_WEP 0x01
#define TX_CMD_SEC_CCM 0x02
#define TX_CMD_SEC_TKIP 0x03
#define TX_CMD_SEC_EXT 0x04
#define TX_CMD_SEC_MSK 0x07
#define TX_CMD_SEC_WEP_KEY_IDX_POS 6
#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0

View File

@ -141,6 +141,7 @@ enum {
/* Power - legacy power table command */
POWER_TABLE_CMD = 0x77,
PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,
/* Thermal Throttling*/
REPLY_THERMAL_MNG_BACKOFF = 0x7e,
@ -183,6 +184,7 @@ enum {
BT_PROFILE_NOTIFICATION = 0xce,
BT_COEX_CI = 0x5d,
REPLY_SF_CFG_CMD = 0xd1,
REPLY_BEACON_FILTERING_CMD = 0xd2,
REPLY_DEBUG_CMD = 0xf0,
@ -1052,6 +1054,7 @@ enum iwl_mvm_rx_status {
RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8),
RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8),
RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8),
RX_MPDU_RES_STATUS_SEC_EXT_ENC = (4 << 8),
RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8),
RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8),
RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8),
@ -1131,6 +1134,7 @@ struct iwl_set_calib_default_cmd {
} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
#define MAX_PORT_ID_NUM 2
#define MAX_MCAST_FILTERING_ADDRESSES 256
/**
* struct iwl_mcast_filter_cmd - configure multicast filter.
@ -1363,4 +1367,65 @@ struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */
struct mvm_statistics_general general;
} __packed;
/***********************************
* Smart Fifo API
***********************************/
/* Smart Fifo state */
enum iwl_sf_state {
SF_LONG_DELAY_ON = 0, /* should never be called by driver */
SF_FULL_ON,
SF_UNINIT,
SF_INIT_OFF,
SF_HW_NUM_STATES
};
/* Smart Fifo possible scenario */
enum iwl_sf_scenario {
SF_SCENARIO_SINGLE_UNICAST,
SF_SCENARIO_AGG_UNICAST,
SF_SCENARIO_MULTICAST,
SF_SCENARIO_BA_RESP,
SF_SCENARIO_TX_RESP,
SF_NUM_SCENARIO
};
#define SF_TRANSIENT_STATES_NUMBER 2 /* SF_LONG_DELAY_ON and SF_FULL_ON */
#define SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */
/* smart FIFO default values */
#define SF_W_MARK_SISO 4096
#define SF_W_MARK_MIMO2 8192
#define SF_W_MARK_MIMO3 6144
#define SF_W_MARK_LEGACY 4096
#define SF_W_MARK_SCAN 4096
/* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */
#define SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */
#define SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */
#define SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */
#define SF_AGG_UNICAST_AGING_TIMER 2016 /* 2 mSec */
#define SF_MCAST_IDLE_TIMER 2016 /* 2 mSec */
#define SF_MCAST_AGING_TIMER 10016 /* 10 mSec */
#define SF_BA_IDLE_TIMER 320 /* 300 uSec */
#define SF_BA_AGING_TIMER 2016 /* 2 mSec */
#define SF_TX_RE_IDLE_TIMER 320 /* 300 uSec */
#define SF_TX_RE_AGING_TIMER 2016 /* 2 mSec */
#define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */
/**
* Smart Fifo configuration command.
* @state: smart fifo state, types listed in iwl_sf_sate.
* @watermark: Minimum allowed availabe free space in RXF for transient state.
* @long_delay_timeouts: aging and idle timer values for each scenario
* in long delay state.
* @full_on_timeouts: timer values for each scenario in full on state.
*/
struct iwl_sf_cfg_cmd {
enum iwl_sf_state state;
__le32 watermark[SF_TRANSIENT_STATES_NUMBER];
__le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
__le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
} __packed; /* SF_CFG_API_S_VER_2 */
#endif /* __fw_api_h__ */

View File

@ -241,7 +241,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
lockdep_assert_held(&mvm->mutex);
if (mvm->init_ucode_complete)
if (WARN_ON_ONCE(mvm->init_ucode_complete))
return 0;
iwl_init_notification_wait(&mvm->notif_wait,
@ -287,7 +287,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
IWL_DEBUG_RF_KILL(mvm,
"jump over all phy activities due to RF kill\n");
iwl_remove_notification(&mvm->notif_wait, &calib_wait);
return 1;
ret = 1;
goto out;
}
/* Send TX valid antennas before triggering calibrations */
@ -319,9 +320,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
error:
iwl_remove_notification(&mvm->notif_wait, &calib_wait);
out:
if (!iwlmvm_mod_params.init_dbg) {
iwl_trans_stop_device(mvm->trans);
} else if (!mvm->nvm_data) {
if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) {
/* we want to debug INIT and we have no NVM - fake */
mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) +
sizeof(struct ieee80211_channel) +
@ -370,11 +369,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
ret = -ERFKILL;
goto error;
}
/* should stop & start HW since that INIT image just loaded */
iwl_trans_stop_hw(mvm->trans, false);
ret = iwl_trans_start_hw(mvm->trans);
if (ret)
return ret;
if (!iwlmvm_mod_params.init_dbg) {
/*
* should stop and start HW since that INIT
* image just loaded
*/
iwl_trans_stop_device(mvm->trans);
ret = iwl_trans_start_hw(mvm->trans);
if (ret)
return ret;
}
}
if (iwlmvm_mod_params.init_dbg)
@ -386,6 +390,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
ret = iwl_mvm_sf_update(mvm, NULL, false);
if (ret)
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
if (ret)
goto error;

View File

@ -488,6 +488,40 @@ static void iwl_mvm_ack_rates(struct iwl_mvm *mvm,
*ofdm_rates = ofdm;
}
static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_ctx_cmd *cmd)
{
/* for both sta and ap, ht_operation_mode hold the protection_mode */
u8 protection_mode = vif->bss_conf.ht_operation_mode &
IEEE80211_HT_OP_MODE_PROTECTION;
/* The fw does not distinguish between ht and fat */
u32 ht_flag = MAC_PROT_FLG_HT_PROT | MAC_PROT_FLG_FAT_PROT;
IWL_DEBUG_RATE(mvm, "protection mode set to %d\n", protection_mode);
/*
* See section 9.23.3.1 of IEEE 80211-2012.
* Nongreenfield HT STAs Present is not supported.
*/
switch (protection_mode) {
case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
break;
case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
cmd->protection_flags |= cpu_to_le32(ht_flag);
break;
case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
/* Protect when channel wider than 20MHz */
if (vif->bss_conf.chandef.width > NL80211_CHAN_WIDTH_20)
cmd->protection_flags |= cpu_to_le32(ht_flag);
break;
default:
IWL_ERR(mvm, "Illegal protection mode %d\n",
protection_mode);
break;
}
}
static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_ctx_cmd *cmd,
@ -495,6 +529,8 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_chanctx_conf *chanctx;
bool ht_enabled = !!(vif->bss_conf.ht_operation_mode &
IEEE80211_HT_OP_MODE_PROTECTION);
u8 cck_ack_rates, ofdm_ack_rates;
int i;
@ -573,16 +609,13 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->protection_flags |=
cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN);
}
/*
* I think that we should enable these 2 flags regardless the HT PROT
* fields in the HT IE, but I am not sure. Someone knows whom to ask?...
*/
if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
IWL_DEBUG_RATE(mvm, "use_cts_prot %d, ht_operation_mode %d\n",
vif->bss_conf.use_cts_prot,
vif->bss_conf.ht_operation_mode);
if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN);
cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_HT_PROT |
MAC_PROT_FLG_FAT_PROT);
}
if (ht_enabled)
iwl_mvm_mac_ctxt_set_ht_flags(mvm, vif, cmd);
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
}

View File

@ -256,10 +256,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
}
hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
NL80211_FEATURE_P2P_GO_OPPPS;
NL80211_FEATURE_P2P_GO_OPPPS |
NL80211_FEATURE_LOW_PRIORITY_SCAN;
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
/* currently FW API supports only one optional cipher scheme */
if (mvm->fw->cs && mvm->fw->cs->cipher) {
mvm->hw->n_cipher_schemes = 1;
mvm->hw->cipher_schemes = mvm->fw->cs;
}
#ifdef CONFIG_PM_SLEEP
if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
mvm->trans->ops->d3_suspend &&
@ -398,7 +405,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{
iwl_trans_stop_device(mvm->trans);
iwl_trans_stop_hw(mvm->trans, false);
mvm->scan_status = IWL_MVM_SCAN_NONE;
@ -470,7 +476,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
cancel_work_sync(&mvm->roc_done_wk);
iwl_trans_stop_device(mvm->trans);
iwl_trans_stop_hw(mvm->trans, false);
iwl_mvm_async_handlers_purge(mvm);
/* async_handlers_list is empty and will stay empty: HW is stopped */
@ -487,17 +492,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
cancel_work_sync(&mvm->async_handlers_wk);
}
static void iwl_mvm_pm_disable_iterator(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm *mvm = data;
int ret;
ret = iwl_mvm_power_disable(mvm, vif);
if (ret)
IWL_ERR(mvm, "failed to disable power management\n");
}
static void iwl_mvm_power_update_iterator(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
@ -520,6 +514,20 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
return NULL;
}
static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
s8 tx_power)
{
/* FW is in charge of regulatory enforcement */
struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = {
.mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id,
.pwr_restriction = cpu_to_le16(tx_power),
};
return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, CMD_SYNC,
sizeof(reduce_txpwr_cmd),
&reduce_txpwr_cmd);
}
static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@ -540,26 +548,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out_unlock;
/*
* TODO: remove this temporary code.
* Currently MVM FW supports power management only on single MAC.
* If new interface added, disable PM on existing interface.
* P2P device is a special case, since it is handled by FW similary to
* scan. If P2P deviced is added, PM remains enabled on existing
* interface.
* Note: the method below does not count the new interface being added
* at this moment.
*/
/* Counting number of interfaces is needed for legacy PM */
if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count++;
if (mvm->vif_count > 1) {
IWL_DEBUG_MAC80211(mvm,
"Disable power on existing interfaces\n");
ieee80211_iterate_active_interfaces_atomic(
mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_pm_disable_iterator, mvm);
}
/*
* The AP binding flow can be done only after the beacon
@ -590,11 +581,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out_release;
/*
* Update power state on the new interface. Admittedly, based on
* mac80211 logics this power update will disable power management
*/
iwl_mvm_power_update_mode(mvm, vif);
iwl_mvm_power_disable(mvm, vif);
/* beacon filtering */
ret = iwl_mvm_disable_beacon_filter(mvm, vif);
@ -655,9 +642,12 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
out_release:
if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--;
/* TODO: remove this when legacy PM will be discarded */
ieee80211_iterate_active_interfaces(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_power_update_iterator, mvm);
iwl_mvm_mac_ctxt_release(mvm, vif);
out_unlock:
mutex_unlock(&mvm->mutex);
@ -743,21 +733,13 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mvmvif->phy_ctxt = NULL;
}
/*
* TODO: remove this temporary code.
* Currently MVM FW supports power management only on single MAC.
* Check if only one additional interface remains after removing
* current one. Update power mode on the remaining interface.
*/
if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--;
IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
mvm->vif_count);
if (mvm->vif_count == 1) {
ieee80211_iterate_active_interfaces(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_power_update_iterator, mvm);
}
/* TODO: remove this when legacy PM will be discarded */
ieee80211_iterate_active_interfaces(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_power_update_iterator, mvm);
iwl_mvm_mac_ctxt_remove(mvm, vif);
@ -766,47 +748,116 @@ out_release:
mutex_unlock(&mvm->mutex);
}
static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
s8 tx_power)
{
/* FW is in charge of regulatory enforcement */
struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = {
.mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id,
.pwr_restriction = cpu_to_le16(tx_power),
};
return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, CMD_SYNC,
sizeof(reduce_txpwr_cmd),
&reduce_txpwr_cmd);
}
static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed)
{
return 0;
}
struct iwl_mvm_mc_iter_data {
struct iwl_mvm *mvm;
int port_id;
};
static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_mc_iter_data *data = _data;
struct iwl_mvm *mvm = data->mvm;
struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd;
int ret, len;
/* if we don't have free ports, mcast frames will be dropped */
if (WARN_ON_ONCE(data->port_id >= MAX_PORT_ID_NUM))
return;
if (vif->type != NL80211_IFTYPE_STATION ||
!vif->bss_conf.assoc)
return;
cmd->port_id = data->port_id++;
memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);
len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4);
ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC, len, cmd);
if (ret)
IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);
}
static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm)
{
struct iwl_mvm_mc_iter_data iter_data = {
.mvm = mvm,
};
lockdep_assert_held(&mvm->mutex);
if (WARN_ON_ONCE(!mvm->mcast_filter_cmd))
return;
ieee80211_iterate_active_interfaces(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_mc_iface_iterator, &iter_data);
}
static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mcast_filter_cmd *cmd;
struct netdev_hw_addr *addr;
int addr_count = netdev_hw_addr_list_count(mc_list);
bool pass_all = false;
int len;
if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) {
pass_all = true;
addr_count = 0;
}
len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);
cmd = kzalloc(len, GFP_ATOMIC);
if (!cmd)
return 0;
if (pass_all) {
cmd->pass_all = 1;
return (u64)(unsigned long)cmd;
}
netdev_hw_addr_list_for_each(addr, mc_list) {
IWL_DEBUG_MAC80211(mvm, "mcast addr (%d): %pM\n",
cmd->count, addr->addr);
memcpy(&cmd->addr_list[cmd->count * ETH_ALEN],
addr->addr, ETH_ALEN);
cmd->count++;
}
return (u64)(unsigned long)cmd;
}
static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mcast_filter_cmd *cmd = (void *)(unsigned long)multicast;
mutex_lock(&mvm->mutex);
/* replace previous configuration */
kfree(mvm->mcast_filter_cmd);
mvm->mcast_filter_cmd = cmd;
if (!cmd)
goto out;
iwl_mvm_recalc_multicast(mvm);
out:
mutex_unlock(&mvm->mutex);
*total_flags = 0;
}
static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_mcast_filter_cmd mcast_filter_cmd = {
.pass_all = 1,
};
memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN);
return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC,
sizeof(mcast_filter_cmd),
&mcast_filter_cmd);
}
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@ -827,7 +878,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_ERR(mvm, "failed to update quotas\n");
return;
}
iwl_mvm_configure_mcast_filter(mvm, vif);
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
&mvm->status)) {
@ -849,7 +899,17 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
iwl_mvm_protect_session(mvm, vif, dur, dur,
5 * dur);
}
iwl_mvm_sf_update(mvm, vif, false);
iwl_mvm_power_vif_assoc(mvm, vif);
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
/*
* If update fails - SF might be running in associated
* mode while disassociated - which is forbidden.
*/
WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false),
"Failed to update SF upon disassociation\n");
/* remove AP station now that the MAC is unassoc */
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
if (ret)
@ -861,6 +921,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_ERR(mvm, "failed to update quotas\n");
}
iwl_mvm_recalc_multicast(mvm);
/* reset rssi values */
mvmvif->bf_data.ave_beacon_signal = 0;
@ -881,7 +943,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
*/
iwl_mvm_remove_time_event(mvm, mvmvif,
&mvmvif->time_event_data);
} else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_QOS)) {
} else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
BSS_CHANGED_QOS)) {
ret = iwl_mvm_power_update_mode(mvm, vif);
if (ret)
IWL_ERR(mvm, "failed to update power mode\n");
@ -990,6 +1053,22 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
struct ieee80211_bss_conf *bss_conf,
u32 changes)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
enum ieee80211_bss_change ht_change = BSS_CHANGED_ERP_CTS_PROT |
BSS_CHANGED_HT |
BSS_CHANGED_BANDWIDTH;
int ret;
/* Changes will be applied when the AP/IBSS is started */
if (!mvmvif->ap_ibss_active)
return;
if (changes & ht_change) {
ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
if (ret)
IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
}
/* Need to send a new beacon template to the FW */
if (changes & BSS_CHANGED_BEACON) {
if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
@ -1080,7 +1159,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
switch (cmd) {
case STA_NOTIFY_SLEEP:
@ -1102,6 +1181,28 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
}
}
static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
/*
* This is called before mac80211 does RCU synchronisation,
* so here we already invalidate our internal RCU-protected
* station pointer. The rest of the code will thus no longer
* be able to find the station this way, and we don't rely
* on further RCU synchronisation after the sta_state()
* callback deleted the station.
*/
mutex_lock(&mvm->mutex);
if (sta == rcu_access_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id]))
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
ERR_PTR(-ENOENT));
mutex_unlock(&mvm->mutex);
}
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@ -1149,7 +1250,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
ret = iwl_mvm_update_sta(mvm, vif, sta);
if (ret == 0)
iwl_mvm_rs_rate_init(mvm, sta,
mvmvif->phy_ctxt->channel->band);
mvmvif->phy_ctxt->channel->band,
true);
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTHORIZED) {
/* enable beacon filtering */
@ -1187,6 +1289,17 @@ static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return 0;
}
static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u32 changed)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (vif->type == NL80211_IFTYPE_STATION &&
changed & IEEE80211_RC_NSS_CHANGED)
iwl_mvm_sf_update(mvm, vif, false);
}
static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 ac,
const struct ieee80211_tx_queue_params *params)
@ -1309,7 +1422,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
*/
return 0;
default:
return -EOPNOTSUPP;
/* currently FW supports only one optional cipher scheme */
if (hw->n_cipher_schemes &&
hw->cipher_schemes->cipher == key->cipher)
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
else
return -EOPNOTSUPP;
}
mutex_lock(&mvm->mutex);
@ -1515,7 +1633,7 @@ static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,
goto out;
}
ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
ctx->rx_chains_static,
ctx->rx_chains_dynamic);
if (ret) {
@ -1559,7 +1677,7 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
return;
mutex_lock(&mvm->mutex);
iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
ctx->rx_chains_static,
ctx->rx_chains_dynamic);
iwl_mvm_bt_coex_vif_change(mvm);
@ -1602,7 +1720,13 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
goto out_unlock;
/*
* Setting the quota at this stage is only required for monitor
* Power state must be updated before quotas,
* otherwise fw will complain.
*/
mvm->bound_vif_cnt++;
iwl_mvm_power_update_binding(mvm, vif, true);
/* Setting the quota at this stage is only required for monitor
* interfaces. For the other types, the bss_info changed flow
* will handle quota settings.
*/
@ -1617,6 +1741,8 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
out_remove_binding:
iwl_mvm_binding_remove_vif(mvm, vif);
mvm->bound_vif_cnt--;
iwl_mvm_power_update_binding(mvm, vif, false);
out_unlock:
mutex_unlock(&mvm->mutex);
if (ret)
@ -1650,6 +1776,9 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
iwl_mvm_binding_remove_vif(mvm, vif);
out_unlock:
mvmvif->phy_ctxt = NULL;
mvm->bound_vif_cnt--;
iwl_mvm_power_update_binding(mvm, vif, false);
mutex_unlock(&mvm->mutex);
}
@ -1744,14 +1873,17 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.add_interface = iwl_mvm_mac_add_interface,
.remove_interface = iwl_mvm_mac_remove_interface,
.config = iwl_mvm_mac_config,
.prepare_multicast = iwl_mvm_prepare_multicast,
.configure_filter = iwl_mvm_configure_filter,
.bss_info_changed = iwl_mvm_bss_info_changed,
.hw_scan = iwl_mvm_mac_hw_scan,
.cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,
.sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove,
.sta_state = iwl_mvm_mac_sta_state,
.sta_notify = iwl_mvm_mac_sta_notify,
.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
.sta_rc_update = iwl_mvm_sta_rc_update,
.conf_tx = iwl_mvm_mac_conf_tx,
.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
.sched_scan_start = iwl_mvm_mac_sched_scan_start,

View File

@ -163,6 +163,8 @@ struct iwl_mvm_power_ops {
struct ieee80211_vif *vif);
int (*power_update_device_mode)(struct iwl_mvm *mvm);
int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void (*power_update_binding)(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, bool assign);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
char *buf, int bufsz);
@ -181,6 +183,7 @@ enum iwl_dbgfs_pm_mask {
MVM_DEBUGFS_PM_LPRX_ENA = BIT(6),
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9),
};
struct iwl_dbgfs_pm {
@ -193,6 +196,7 @@ struct iwl_dbgfs_pm {
bool lprx_ena;
u32 lprx_rssi_threshold;
bool snooze_ena;
bool uapsd_misbehaving;
int mask;
};
@ -269,8 +273,8 @@ struct iwl_mvm_vif_bf_data {
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
* @beacon_skb: the skb used to hold the AP/GO beacon template
* @smps_requests: the requests of of differents parts of the driver, regard
the desired smps mode.
* @smps_requests: the SMPS requests of differents parts of the driver,
* combined on update to yield the overall request to mac80211.
*/
struct iwl_mvm_vif {
u16 id;
@ -323,14 +327,19 @@ struct iwl_mvm_vif {
#endif
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_mvm *mvm;
struct dentry *dbgfs_dir;
struct dentry *dbgfs_slink;
void *dbgfs_data;
struct iwl_dbgfs_pm dbgfs_pm;
struct iwl_dbgfs_bf dbgfs_bf;
#endif
enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
/* FW identified misbehaving AP */
u8 uapsd_misbehaving_bssid[ETH_ALEN];
bool pm_prevented;
};
static inline struct iwl_mvm_vif *
@ -479,6 +488,7 @@ struct iwl_mvm {
/* Scan status, cmd (pre-allocated) and auxiliary station */
enum iwl_scan_status scan_status;
struct iwl_scan_cmd *scan_cmd;
struct iwl_mcast_filter_cmd *mcast_filter_cmd;
/* rx chain antennas set through debugfs for the scan command */
u8 scan_rx_ant;
@ -489,11 +499,19 @@ struct iwl_mvm {
u8 scan_last_antenna_idx; /* to toggle TX between antennas */
u8 mgmt_last_antenna_idx;
/* last smart fifo state that was successfully sent to firmware */
enum iwl_sf_state sf_state;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct dentry *debugfs_dir;
u32 dbgfs_sram_offset, dbgfs_sram_len;
bool disable_power_off;
bool disable_power_off_d3;
struct debugfs_blob_wrapper nvm_hw_blob;
struct debugfs_blob_wrapper nvm_sw_blob;
struct debugfs_blob_wrapper nvm_calib_blob;
struct debugfs_blob_wrapper nvm_prod_blob;
#endif
struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
@ -507,12 +525,6 @@ struct iwl_mvm {
*/
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
/*
* This counter of created interfaces is referenced only in conjunction
* with FW limitation related to power management. Currently PM is
* supported only on a single interface.
* IMPORTANT: this variable counts all interfaces except P2P device.
*/
u8 vif_count;
/* -1 for always, 0 for never, >0 for that many times */
@ -531,6 +543,7 @@ struct iwl_mvm {
bool store_d3_resume_sram;
void *d3_resume_sram;
u32 d3_test_pme_ptr;
struct ieee80211_vif *keep_vif;
#endif
#endif
@ -554,6 +567,11 @@ struct iwl_mvm {
u8 aux_queue;
u8 first_agg_queue;
u8 last_agg_queue;
u8 bound_vif_cnt;
/* Indicate if device power save is allowed */
bool ps_prevented;
};
/* Extract MVM priv from op_mode and _hw */
@ -750,8 +768,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
#endif /* CONFIG_IWLWIFI_DEBUGFS */
/* rate scaling */
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
u8 flags, bool init);
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
/* power managment */
static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm,
@ -773,6 +790,19 @@ static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
return 0;
}
static inline void iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
bool assign)
{
if (mvm->pm_ops->power_update_binding)
mvm->pm_ops->power_update_binding(mvm, vif, assign);
}
void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS
static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
@ -864,4 +894,8 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm);
void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
/* smart fifo */
int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool added_vif);
#endif /* __IWL_MVM_H__ */

View File

@ -443,6 +443,29 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
}
mvm->nvm_sections[section].data = temp;
mvm->nvm_sections[section].length = ret;
#ifdef CONFIG_IWLWIFI_DEBUGFS
switch (section) {
case NVM_SECTION_TYPE_HW:
mvm->nvm_hw_blob.data = temp;
mvm->nvm_hw_blob.size = ret;
break;
case NVM_SECTION_TYPE_SW:
mvm->nvm_sw_blob.data = temp;
mvm->nvm_sw_blob.size = ret;
break;
case NVM_SECTION_TYPE_CALIBRATION:
mvm->nvm_calib_blob.data = temp;
mvm->nvm_calib_blob.size = ret;
break;
case NVM_SECTION_TYPE_PRODUCTION:
mvm->nvm_prod_blob.data = temp;
mvm->nvm_prod_blob.size = ret;
break;
default:
WARN(1, "section: %d", section);
}
#endif
}
kfree(nvm_buffer);
if (ret < 0)

View File

@ -236,6 +236,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
false),
RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION,
iwl_mvm_power_uapsd_misbehaving_ap_notif, false),
};
#undef RX_HANDLER
#define CMD(x) [x] = #x
@ -311,6 +313,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(REPLY_THERMAL_MNG_BACKOFF),
CMD(MAC_PM_POWER_TABLE),
CMD(BT_COEX_CI),
CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
};
#undef CMD
@ -341,7 +344,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
op_mode = hw->priv;
op_mode->ops = &iwl_mvm_ops;
op_mode->trans = trans;
mvm = IWL_OP_MODE_GET_MVM(op_mode);
mvm->dev = trans->dev;
@ -359,6 +361,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->aux_queue = 11;
mvm->first_agg_queue = 12;
}
mvm->sf_state = SF_UNINIT;
mutex_init(&mvm->mutex);
spin_lock_init(&mvm->async_handlers_lock);
@ -424,7 +427,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
* there is no need to unnecessarily power up the NIC at driver load
*/
if (iwlwifi_mod_params.nvm_file) {
iwl_nvm_init(mvm);
err = iwl_nvm_init(mvm);
if (err)
goto out_free;
} else {
err = iwl_trans_start_hw(mvm->trans);
if (err)
@ -432,16 +437,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_lock(&mvm->mutex);
err = iwl_run_init_mvm_ucode(mvm, true);
iwl_trans_stop_device(trans);
mutex_unlock(&mvm->mutex);
/* returns 0 if successful, 1 if success but in rfkill */
if (err < 0 && !iwlmvm_mod_params.init_dbg) {
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
goto out_free;
}
/* Stop the hw after the ALIVE and NVM has been read */
if (!iwlmvm_mod_params.init_dbg)
iwl_trans_stop_hw(mvm->trans, false);
}
scan_size = sizeof(struct iwl_scan_cmd) +
@ -474,7 +476,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_phy_db_free(mvm->phy_db);
kfree(mvm->scan_cmd);
if (!iwlwifi_mod_params.nvm_file)
iwl_trans_stop_hw(trans, true);
iwl_trans_op_mode_leave(trans);
ieee80211_free_hw(mvm->hw);
return NULL;
}
@ -491,12 +493,14 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
ieee80211_unregister_hw(mvm->hw);
kfree(mvm->scan_cmd);
kfree(mvm->mcast_filter_cmd);
mvm->mcast_filter_cmd = NULL;
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
kfree(mvm->d3_resume_sram);
#endif
iwl_trans_stop_hw(mvm->trans, true);
iwl_trans_op_mode_leave(mvm->trans);
iwl_phy_db_free(mvm->phy_db);
mvm->phy_db = NULL;

View File

@ -186,6 +186,92 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm,
}
}
static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_power_cmd *cmd)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
enum ieee80211_ac_numbers ac;
bool tid_found = false;
for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
if (!mvmvif->queue_params[ac].uapsd)
continue;
if (mvm->cur_ucode != IWL_UCODE_WOWLAN)
cmd->flags |=
cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
cmd->uapsd_ac_flags |= BIT(ac);
/* QNDP TID - the highest TID with no admission control */
if (!tid_found && !mvmvif->queue_params[ac].acm) {
tid_found = true;
switch (ac) {
case IEEE80211_AC_VO:
cmd->qndp_tid = 6;
break;
case IEEE80211_AC_VI:
cmd->qndp_tid = 5;
break;
case IEEE80211_AC_BE:
cmd->qndp_tid = 0;
break;
case IEEE80211_AC_BK:
cmd->qndp_tid = 1;
break;
}
}
}
if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
BIT(IEEE80211_AC_VI) |
BIT(IEEE80211_AC_BE) |
BIT(IEEE80211_AC_BK))) {
cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
cmd->snooze_interval = cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
cmd->snooze_window = (mvm->cur_ucode == IWL_UCODE_WOWLAN) ?
cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
}
cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP;
if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags &
cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
cmd->rx_data_timeout_uapsd =
cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
cmd->tx_data_timeout_uapsd =
cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
} else {
cmd->rx_data_timeout_uapsd =
cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
cmd->tx_data_timeout_uapsd =
cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
}
if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
cmd->heavy_tx_thld_packets =
IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
cmd->heavy_rx_thld_packets =
IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
} else {
cmd->heavy_tx_thld_packets =
IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
cmd->heavy_rx_thld_packets =
IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
}
cmd->heavy_tx_thld_percentage =
IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
cmd->heavy_rx_thld_percentage =
IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
}
static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_power_cmd *cmd)
@ -198,8 +284,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
bool radar_detect = false;
struct iwl_mvm_vif *mvmvif __maybe_unused =
iwl_mvm_vif_from_mac80211(vif);
enum ieee80211_ac_numbers ac;
bool tid_found = false;
bool allow_uapsd = true;
cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
mvmvif->color));
@ -217,7 +302,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
mvm->ps_prevented)
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
@ -227,7 +313,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
mvmvif->dbgfs_pm.disable_power_off)
cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
#endif
if (!vif->bss_conf.ps)
if (!vif->bss_conf.ps || mvmvif->pm_prevented)
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@ -269,81 +355,24 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
}
for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
if (!mvmvif->queue_params[ac].uapsd)
continue;
if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
ETH_ALEN))
allow_uapsd = false;
if (mvm->cur_ucode != IWL_UCODE_WOWLAN)
cmd->flags |=
cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
if (vif->p2p &&
!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD))
allow_uapsd = false;
/*
* Avoid using uAPSD if P2P client is associated to GO that uses
* opportunistic power save. This is due to current FW limitation.
*/
if (vif->p2p &&
vif->bss_conf.p2p_noa_attr.oppps_ctwindow &
IEEE80211_P2P_OPPPS_ENABLE_BIT)
allow_uapsd = false;
cmd->uapsd_ac_flags |= BIT(ac);
/* QNDP TID - the highest TID with no admission control */
if (!tid_found && !mvmvif->queue_params[ac].acm) {
tid_found = true;
switch (ac) {
case IEEE80211_AC_VO:
cmd->qndp_tid = 6;
break;
case IEEE80211_AC_VI:
cmd->qndp_tid = 5;
break;
case IEEE80211_AC_BE:
cmd->qndp_tid = 0;
break;
case IEEE80211_AC_BK:
cmd->qndp_tid = 1;
break;
}
}
}
if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
BIT(IEEE80211_AC_VI) |
BIT(IEEE80211_AC_BE) |
BIT(IEEE80211_AC_BK))) {
cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
cmd->snooze_interval =
cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
cmd->snooze_window =
(mvm->cur_ucode == IWL_UCODE_WOWLAN) ?
cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
}
cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP;
if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags &
cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
cmd->rx_data_timeout_uapsd =
cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
cmd->tx_data_timeout_uapsd =
cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
} else {
cmd->rx_data_timeout_uapsd =
cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
cmd->tx_data_timeout_uapsd =
cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
}
if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
cmd->heavy_tx_thld_packets =
IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
cmd->heavy_rx_thld_packets =
IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
} else {
cmd->heavy_tx_thld_packets =
IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
cmd->heavy_rx_thld_packets =
IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
}
cmd->heavy_tx_thld_percentage =
IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
cmd->heavy_rx_thld_percentage =
IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
}
if (allow_uapsd)
iwl_mvm_power_configure_uapsd(mvm, vif, cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE)
@ -381,6 +410,13 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cmd->flags &=
cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK);
}
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_UAPSD_MISBEHAVING) {
u16 flag = POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK;
if (mvmvif->dbgfs_pm.uapsd_misbehaving)
cmd->flags |= cpu_to_le16(flag);
else
cmd->flags &= cpu_to_le16(flag);
}
#endif /* CONFIG_IWLWIFI_DEBUGFS */
}
@ -391,18 +427,11 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
bool ba_enable;
struct iwl_mac_power_cmd cmd = {};
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
if (vif->type != NL80211_IFTYPE_STATION)
return 0;
/*
* TODO: The following vif_count verification is temporary condition.
* Avoid power mode update if more than one interface is currently
* active. Remove this condition when FW will support power management
* on multiple MACs.
*/
IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n",
mvm->vif_count);
if (mvm->vif_count > 1)
if (vif->p2p &&
!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS))
return 0;
iwl_mvm_power_build_cmd(mvm, vif, &cmd);
@ -446,7 +475,7 @@ static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm,
sizeof(cmd), &cmd);
}
static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
{
struct iwl_device_power_cmd cmd = {
.flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
@ -455,7 +484,8 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
return 0;
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
force_disable)
cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK);
#ifdef CONFIG_IWLWIFI_DEBUGFS
@ -472,6 +502,78 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
&cmd);
}
static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
{
return _iwl_mvm_power_update_device(mvm, false);
}
void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid,
ETH_ALEN))
memset(mvmvif->uapsd_misbehaving_bssid, 0, ETH_ALEN);
}
static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
u8 *ap_sta_id = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
/* The ap_sta_id is not expected to change during current association
* so no explicit protection is needed
*/
if (mvmvif->ap_sta_id == *ap_sta_id)
memcpy(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
ETH_ALEN);
}
int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data;
u8 ap_sta_id = le32_to_cpu(notif->sta_id);
ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id);
return 0;
}
static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = _data;
int ret;
mvmvif->pm_prevented = (mvm->bound_vif_cnt <= 1) ? false : true;
ret = iwl_mvm_power_mac_update_mode(mvm, vif);
WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n");
}
static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
bool assign)
{
if (vif->type == NL80211_IFTYPE_MONITOR) {
int ret = _iwl_mvm_power_update_device(mvm, assign);
mvm->ps_prevented = assign;
WARN_ONCE(ret, "Failed to update power device state\n");
}
ieee80211_iterate_active_interfaces(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_power_binding_iterator,
mvm);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, char *buf,
@ -494,70 +596,58 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
le16_to_cpu(cmd.keep_alive_seconds));
if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
(cmd.flags &
cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ?
1 : 0);
pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
cmd.skip_dtim_periods);
if (!(cmd.flags &
cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
pos += scnprintf(buf+pos, bufsz-pos,
"rx_data_timeout = %d\n",
le32_to_cpu(cmd.rx_data_timeout));
pos += scnprintf(buf+pos, bufsz-pos,
"tx_data_timeout = %d\n",
le32_to_cpu(cmd.tx_data_timeout));
}
if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
pos += scnprintf(buf+pos, bufsz-pos,
"lprx_rssi_threshold = %d\n",
cmd.lprx_rssi_threshold);
if (cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
pos +=
scnprintf(buf+pos, bufsz-pos,
"rx_data_timeout_uapsd = %d\n",
le32_to_cpu(cmd.rx_data_timeout_uapsd));
pos +=
scnprintf(buf+pos, bufsz-pos,
"tx_data_timeout_uapsd = %d\n",
le32_to_cpu(cmd.tx_data_timeout_uapsd));
pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n",
cmd.qndp_tid);
pos += scnprintf(buf+pos, bufsz-pos,
"uapsd_ac_flags = 0x%x\n",
cmd.uapsd_ac_flags);
pos += scnprintf(buf+pos, bufsz-pos,
"uapsd_max_sp = %d\n",
cmd.uapsd_max_sp);
pos += scnprintf(buf+pos, bufsz-pos,
"heavy_tx_thld_packets = %d\n",
cmd.heavy_tx_thld_packets);
pos += scnprintf(buf+pos, bufsz-pos,
"heavy_rx_thld_packets = %d\n",
cmd.heavy_rx_thld_packets);
pos += scnprintf(buf+pos, bufsz-pos,
"heavy_tx_thld_percentage = %d\n",
cmd.heavy_tx_thld_percentage);
pos += scnprintf(buf+pos, bufsz-pos,
"heavy_rx_thld_percentage = %d\n",
cmd.heavy_rx_thld_percentage);
pos +=
scnprintf(buf+pos, bufsz-pos, "snooze_enable = %d\n",
(cmd.flags &
cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) ?
1 : 0);
}
if (cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
pos += scnprintf(buf+pos, bufsz-pos,
"snooze_interval = %d\n",
cmd.snooze_interval);
pos += scnprintf(buf+pos, bufsz-pos,
"snooze_window = %d\n",
cmd.snooze_window);
}
if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)))
return pos;
pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
(cmd.flags &
cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? 1 : 0);
pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
cmd.skip_dtim_periods);
if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",
le32_to_cpu(cmd.rx_data_timeout));
pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
le32_to_cpu(cmd.tx_data_timeout));
}
if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
pos += scnprintf(buf+pos, bufsz-pos,
"lprx_rssi_threshold = %d\n",
cmd.lprx_rssi_threshold);
if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
return pos;
pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout_uapsd = %d\n",
le32_to_cpu(cmd.rx_data_timeout_uapsd));
pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout_uapsd = %d\n",
le32_to_cpu(cmd.tx_data_timeout_uapsd));
pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", cmd.qndp_tid);
pos += scnprintf(buf+pos, bufsz-pos, "uapsd_ac_flags = 0x%x\n",
cmd.uapsd_ac_flags);
pos += scnprintf(buf+pos, bufsz-pos, "uapsd_max_sp = %d\n",
cmd.uapsd_max_sp);
pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_packets = %d\n",
cmd.heavy_tx_thld_packets);
pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_packets = %d\n",
cmd.heavy_rx_thld_packets);
pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_percentage = %d\n",
cmd.heavy_tx_thld_percentage);
pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_percentage = %d\n",
cmd.heavy_rx_thld_percentage);
pos += scnprintf(buf+pos, bufsz-pos, "uapsd_misbehaving_enable = %d\n",
(cmd.flags &
cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK)) ?
1 : 0);
if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)))
return pos;
pos += scnprintf(buf+pos, bufsz-pos, "snooze_interval = %d\n",
cmd.snooze_interval);
pos += scnprintf(buf+pos, bufsz-pos, "snooze_window = %d\n",
cmd.snooze_window);
return pos;
}
@ -654,6 +744,7 @@ const struct iwl_mvm_power_ops pm_mac_ops = {
.power_update_mode = iwl_mvm_power_mac_update_mode,
.power_update_device_mode = iwl_mvm_power_update_device,
.power_disable = iwl_mvm_power_mac_disable,
.power_update_binding = _iwl_mvm_power_update_binding,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read,
#endif

View File

@ -217,8 +217,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
} else {
cmd.quotas[idx].quota =
cpu_to_le32(quota * data.n_interfaces[i]);
cmd.quotas[idx].max_duration =
cpu_to_le32(IWL_MVM_MAX_QUOTA);
cmd.quotas[idx].max_duration = cpu_to_le32(0);
}
idx++;
}

File diff suppressed because it is too large Load Diff

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