mirror of https://gitee.com/openkylin/linux.git
Merge branch 'master' of ssh://master.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
8571a19c4a
|
@ -1945,7 +1945,8 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
|||
static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
{
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
|
|
|
@ -108,12 +108,14 @@ enum ath_cipher {
|
|||
* struct ath_ops - Register read/write operations
|
||||
*
|
||||
* @read: Register read
|
||||
* @multi_read: Multiple register read
|
||||
* @write: Register write
|
||||
* @enable_write_buffer: Enable multiple register writes
|
||||
* @write_flush: flush buffered register writes and disable buffering
|
||||
*/
|
||||
struct ath_ops {
|
||||
unsigned int (*read)(void *, u32 reg_offset);
|
||||
void (*multi_read)(void *, u32 *addr, u32 *val, u16 count);
|
||||
void (*write)(void *, u32 val, u32 reg_offset);
|
||||
void (*enable_write_buffer)(void *);
|
||||
void (*write_flush) (void *);
|
||||
|
|
|
@ -31,7 +31,8 @@ static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz)
|
|||
*csz = L1_CACHE_BYTES >> 2;
|
||||
}
|
||||
|
||||
bool ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
|
||||
static bool
|
||||
ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
|
||||
{
|
||||
struct ath5k_softc *sc = common->priv;
|
||||
struct platform_device *pdev = to_platform_device(sc->dev);
|
||||
|
@ -46,10 +47,10 @@ bool ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
|
|||
|
||||
eeprom += off;
|
||||
if (eeprom > eeprom_end)
|
||||
return -EINVAL;
|
||||
return false;
|
||||
|
||||
*data = *eeprom;
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int ath5k_hw_read_srev(struct ath5k_hw *ah)
|
||||
|
|
|
@ -241,74 +241,69 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re
|
|||
* Channel/mode setup *
|
||||
\********************/
|
||||
|
||||
/*
|
||||
* Convert IEEE channel number to MHz frequency.
|
||||
*/
|
||||
static inline short
|
||||
ath5k_ieee2mhz(short chan)
|
||||
{
|
||||
if (chan <= 14 || chan >= 27)
|
||||
return ieee80211chan2mhz(chan);
|
||||
else
|
||||
return 2212 + chan * 20;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true for the channel numbers used without all_channels modparam.
|
||||
*/
|
||||
static bool ath5k_is_standard_channel(short chan)
|
||||
static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band)
|
||||
{
|
||||
return ((chan <= 14) ||
|
||||
/* UNII 1,2 */
|
||||
((chan & 3) == 0 && chan >= 36 && chan <= 64) ||
|
||||
if (band == IEEE80211_BAND_2GHZ && chan <= 14)
|
||||
return true;
|
||||
|
||||
return /* UNII 1,2 */
|
||||
(((chan & 3) == 0 && chan >= 36 && chan <= 64) ||
|
||||
/* midband */
|
||||
((chan & 3) == 0 && chan >= 100 && chan <= 140) ||
|
||||
/* UNII-3 */
|
||||
((chan & 3) == 1 && chan >= 149 && chan <= 165));
|
||||
((chan & 3) == 1 && chan >= 149 && chan <= 165) ||
|
||||
/* 802.11j 5.030-5.080 GHz (20MHz) */
|
||||
(chan == 8 || chan == 12 || chan == 16) ||
|
||||
/* 802.11j 4.9GHz (20MHz) */
|
||||
(chan == 184 || chan == 188 || chan == 192 || chan == 196));
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
ath5k_copy_channels(struct ath5k_hw *ah,
|
||||
struct ieee80211_channel *channels,
|
||||
unsigned int mode,
|
||||
unsigned int max)
|
||||
ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
|
||||
unsigned int mode, unsigned int max)
|
||||
{
|
||||
unsigned int i, count, size, chfreq, freq, ch;
|
||||
|
||||
if (!test_bit(mode, ah->ah_modes))
|
||||
return 0;
|
||||
unsigned int count, size, chfreq, freq, ch;
|
||||
enum ieee80211_band band;
|
||||
|
||||
switch (mode) {
|
||||
case AR5K_MODE_11A:
|
||||
/* 1..220, but 2GHz frequencies are filtered by check_channel */
|
||||
size = 220 ;
|
||||
size = 220;
|
||||
chfreq = CHANNEL_5GHZ;
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
break;
|
||||
case AR5K_MODE_11B:
|
||||
case AR5K_MODE_11G:
|
||||
size = 26;
|
||||
chfreq = CHANNEL_2GHZ;
|
||||
band = IEEE80211_BAND_2GHZ;
|
||||
break;
|
||||
default:
|
||||
ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0, count = 0; i < size && max > 0; i++) {
|
||||
ch = i + 1 ;
|
||||
freq = ath5k_ieee2mhz(ch);
|
||||
count = 0;
|
||||
for (ch = 1; ch <= size && count < max; ch++) {
|
||||
freq = ieee80211_channel_to_frequency(ch, band);
|
||||
|
||||
if (freq == 0) /* mapping failed - not a standard channel */
|
||||
continue;
|
||||
|
||||
/* Check if channel is supported by the chipset */
|
||||
if (!ath5k_channel_ok(ah, freq, chfreq))
|
||||
continue;
|
||||
|
||||
if (!modparam_all_channels && !ath5k_is_standard_channel(ch))
|
||||
if (!modparam_all_channels &&
|
||||
!ath5k_is_standard_channel(ch, band))
|
||||
continue;
|
||||
|
||||
/* Write channel info and increment counter */
|
||||
channels[count].center_freq = freq;
|
||||
channels[count].band = (chfreq == CHANNEL_2GHZ) ?
|
||||
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
|
||||
channels[count].band = band;
|
||||
switch (mode) {
|
||||
case AR5K_MODE_11A:
|
||||
case AR5K_MODE_11G:
|
||||
|
@ -319,7 +314,6 @@ ath5k_copy_channels(struct ath5k_hw *ah,
|
|||
}
|
||||
|
||||
count++;
|
||||
max--;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -364,7 +358,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw)
|
|||
sband->n_bitrates = 12;
|
||||
|
||||
sband->channels = sc->channels;
|
||||
sband->n_channels = ath5k_copy_channels(ah, sband->channels,
|
||||
sband->n_channels = ath5k_setup_channels(ah, sband->channels,
|
||||
AR5K_MODE_11G, max_c);
|
||||
|
||||
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
|
||||
|
@ -390,7 +384,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw)
|
|||
}
|
||||
|
||||
sband->channels = sc->channels;
|
||||
sband->n_channels = ath5k_copy_channels(ah, sband->channels,
|
||||
sband->n_channels = ath5k_setup_channels(ah, sband->channels,
|
||||
AR5K_MODE_11B, max_c);
|
||||
|
||||
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
|
||||
|
@ -410,7 +404,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw)
|
|||
sband->n_bitrates = 8;
|
||||
|
||||
sband->channels = &sc->channels[count_c];
|
||||
sband->n_channels = ath5k_copy_channels(ah, sband->channels,
|
||||
sband->n_channels = ath5k_setup_channels(ah, sband->channels,
|
||||
AR5K_MODE_11A, max_c);
|
||||
|
||||
hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
|
||||
|
@ -445,18 +439,6 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
|
|||
return ath5k_reset(sc, chan, true);
|
||||
}
|
||||
|
||||
static void
|
||||
ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
|
||||
{
|
||||
sc->curmode = mode;
|
||||
|
||||
if (mode == AR5K_MODE_11A) {
|
||||
sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ];
|
||||
} else {
|
||||
sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ];
|
||||
}
|
||||
}
|
||||
|
||||
struct ath_vif_iter_data {
|
||||
const u8 *hw_macaddr;
|
||||
u8 mask[ETH_ALEN];
|
||||
|
@ -569,7 +551,7 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix)
|
|||
"hw_rix out of bounds: %x\n", hw_rix))
|
||||
return 0;
|
||||
|
||||
rix = sc->rate_idx[sc->curband->band][hw_rix];
|
||||
rix = sc->rate_idx[sc->curchan->band][hw_rix];
|
||||
if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix))
|
||||
rix = 0;
|
||||
|
||||
|
@ -1379,7 +1361,7 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
|
|||
rxs->flag |= RX_FLAG_TSFT;
|
||||
|
||||
rxs->freq = sc->curchan->center_freq;
|
||||
rxs->band = sc->curband->band;
|
||||
rxs->band = sc->curchan->band;
|
||||
|
||||
rxs->signal = sc->ah->ah_noise_floor + rs->rs_rssi;
|
||||
|
||||
|
@ -1394,7 +1376,7 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
|
|||
rxs->flag |= ath5k_rx_decrypted(sc, skb, rs);
|
||||
|
||||
if (rxs->rate_idx >= 0 && rs->rs_rate ==
|
||||
sc->curband->bitrates[rxs->rate_idx].hw_value_short)
|
||||
sc->sbands[sc->curchan->band].bitrates[rxs->rate_idx].hw_value_short)
|
||||
rxs->flag |= RX_FLAG_SHORTPRE;
|
||||
|
||||
ath5k_debug_dump_skb(sc, skb, "RX ", 0);
|
||||
|
@ -2554,7 +2536,6 @@ ath5k_init_hw(struct ath5k_softc *sc)
|
|||
* and then setup of the interrupt mask.
|
||||
*/
|
||||
sc->curchan = sc->hw->conf.channel;
|
||||
sc->curband = &sc->sbands[sc->curchan->band];
|
||||
sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
|
||||
AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
|
||||
AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
|
||||
|
@ -2681,10 +2662,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
|
|||
* so we should also free any remaining
|
||||
* tx buffers */
|
||||
ath5k_drain_tx_buffs(sc);
|
||||
if (chan) {
|
||||
if (chan)
|
||||
sc->curchan = chan;
|
||||
sc->curband = &sc->sbands[chan->band];
|
||||
}
|
||||
ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL,
|
||||
skip_pcu);
|
||||
if (ret) {
|
||||
|
@ -2782,12 +2761,6 @@ ath5k_init(struct ieee80211_hw *hw)
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* NB: setup here so ath5k_rate_update is happy */
|
||||
if (test_bit(AR5K_MODE_11A, ah->ah_modes))
|
||||
ath5k_setcurmode(sc, AR5K_MODE_11A);
|
||||
else
|
||||
ath5k_setcurmode(sc, AR5K_MODE_11B);
|
||||
|
||||
/*
|
||||
* Allocate tx+rx descriptors and populate the lists.
|
||||
*/
|
||||
|
|
|
@ -183,8 +183,6 @@ struct ath5k_softc {
|
|||
enum nl80211_iftype opmode;
|
||||
struct ath5k_hw *ah; /* Atheros HW */
|
||||
|
||||
struct ieee80211_supported_band *curband;
|
||||
|
||||
#ifdef CONFIG_ATH5K_DEBUG
|
||||
struct ath5k_dbg_info debug; /* debug info */
|
||||
#endif /* CONFIG_ATH5K_DEBUG */
|
||||
|
@ -202,7 +200,6 @@ struct ath5k_softc {
|
|||
#define ATH_STAT_STARTED 4 /* opened & irqs enabled */
|
||||
|
||||
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
|
||||
unsigned int curmode; /* current phy mode */
|
||||
struct ieee80211_channel *curchan; /* current h/w channel */
|
||||
|
||||
u16 nvifs;
|
||||
|
|
|
@ -72,7 +72,6 @@ static int
|
|||
ath5k_eeprom_init_header(struct ath5k_hw *ah)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
int ret;
|
||||
u16 val;
|
||||
u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX;
|
||||
|
||||
|
@ -192,7 +191,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
|
|||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
u32 o = *offset;
|
||||
u16 val;
|
||||
int ret, i = 0;
|
||||
int i = 0;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_switch_settling[mode] = (val >> 8) & 0x7f;
|
||||
|
@ -252,7 +251,6 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
|
|||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
u32 o = *offset;
|
||||
u16 val;
|
||||
int ret;
|
||||
|
||||
ee->ee_n_piers[mode] = 0;
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
|
@ -515,7 +513,6 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
|
|||
int o = *offset;
|
||||
int i = 0;
|
||||
u8 freq1, freq2;
|
||||
int ret;
|
||||
u16 val;
|
||||
|
||||
ee->ee_n_piers[mode] = 0;
|
||||
|
@ -551,7 +548,7 @@ ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
|
|||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;
|
||||
int i, ret;
|
||||
int i;
|
||||
u16 val;
|
||||
u8 mask;
|
||||
|
||||
|
@ -970,7 +967,6 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
|
|||
u32 offset;
|
||||
u8 i, c;
|
||||
u16 val;
|
||||
int ret;
|
||||
u8 pd_gains = 0;
|
||||
|
||||
/* Count how many curves we have and
|
||||
|
@ -1228,7 +1224,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
|||
struct ath5k_chan_pcal_info *chinfo;
|
||||
u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
|
||||
u32 offset;
|
||||
int idx, i, ret;
|
||||
int idx, i;
|
||||
u16 val;
|
||||
u8 pd_gains = 0;
|
||||
|
||||
|
@ -1419,7 +1415,7 @@ ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
|
|||
u8 *rate_target_pwr_num;
|
||||
u32 offset;
|
||||
u16 val;
|
||||
int ret, i;
|
||||
int i;
|
||||
|
||||
offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);
|
||||
rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];
|
||||
|
@ -1593,7 +1589,7 @@ ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
|
|||
struct ath5k_edge_power *rep;
|
||||
unsigned int fmask, pmask;
|
||||
unsigned int ctl_mode;
|
||||
int ret, i, j;
|
||||
int i, j;
|
||||
u32 offset;
|
||||
u16 val;
|
||||
|
||||
|
@ -1733,16 +1729,12 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
|
|||
u8 mac_d[ETH_ALEN] = {};
|
||||
u32 total, offset;
|
||||
u16 data;
|
||||
int octet, ret;
|
||||
int octet;
|
||||
|
||||
ret = ath5k_hw_nvram_read(ah, 0x20, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
AR5K_EEPROM_READ(0x20, data);
|
||||
|
||||
for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
|
||||
ret = ath5k_hw_nvram_read(ah, offset, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
AR5K_EEPROM_READ(offset, data);
|
||||
|
||||
total += data;
|
||||
mac_d[octet + 1] = data & 0xff;
|
||||
|
|
|
@ -241,9 +241,8 @@ enum ath5k_eeprom_freq_bands{
|
|||
#define AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz 6250
|
||||
|
||||
#define AR5K_EEPROM_READ(_o, _v) do { \
|
||||
ret = ath5k_hw_nvram_read(ah, (_o), &(_v)); \
|
||||
if (ret) \
|
||||
return ret; \
|
||||
if (!ath5k_hw_nvram_read(ah, (_o), &(_v))) \
|
||||
return -EIO; \
|
||||
} while (0)
|
||||
|
||||
#define AR5K_EEPROM_READ_HDR(_o, _v) \
|
||||
|
@ -269,29 +268,6 @@ enum ath5k_ctl_mode {
|
|||
AR5K_CTL_MODE_M = 15,
|
||||
};
|
||||
|
||||
/* Default CTL ids for the 3 main reg domains.
|
||||
* Atheros only uses these by default but vendors
|
||||
* can have up to 32 different CTLs for different
|
||||
* scenarios. Note that theese values are ORed with
|
||||
* the mode id (above) so we can have up to 24 CTL
|
||||
* datasets out of these 3 main regdomains. That leaves
|
||||
* 8 ids that can be used by vendors and since 0x20 is
|
||||
* missing from HAL sources i guess this is the set of
|
||||
* custom CTLs vendors can use. */
|
||||
#define AR5K_CTL_FCC 0x10
|
||||
#define AR5K_CTL_CUSTOM 0x20
|
||||
#define AR5K_CTL_ETSI 0x30
|
||||
#define AR5K_CTL_MKK 0x40
|
||||
|
||||
/* Indicates a CTL with only mode set and
|
||||
* no reg domain mapping, such CTLs are used
|
||||
* for world roaming domains or simply when
|
||||
* a reg domain is not set */
|
||||
#define AR5K_CTL_NO_REGDOMAIN 0xf0
|
||||
|
||||
/* Indicates an empty (invalid) CTL */
|
||||
#define AR5K_CTL_NO_CTL 0xff
|
||||
|
||||
/* Per channel calibration data, used for power table setup */
|
||||
struct ath5k_chan_pcal_info_rf5111 {
|
||||
/* Power levels in half dbm units
|
||||
|
|
|
@ -69,7 +69,8 @@ static void ath5k_pci_read_cachesize(struct ath_common *common, int *csz)
|
|||
/*
|
||||
* Read from eeprom
|
||||
*/
|
||||
bool ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
|
||||
static bool
|
||||
ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
|
||||
{
|
||||
struct ath5k_hw *ah = (struct ath5k_hw *) common->ah;
|
||||
u32 status, timeout;
|
||||
|
@ -90,15 +91,15 @@ bool ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
|
|||
status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
|
||||
if (status & AR5K_EEPROM_STAT_RDDONE) {
|
||||
if (status & AR5K_EEPROM_STAT_RDERR)
|
||||
return -EIO;
|
||||
return false;
|
||||
*data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
|
||||
0xffff);
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
udelay(15);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
return false;
|
||||
}
|
||||
|
||||
int ath5k_hw_read_srev(struct ath5k_hw *ah)
|
||||
|
|
|
@ -805,7 +805,10 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
|
||||
if (AR_SREV_9271(ah)) {
|
||||
if (!ar9285_hw_cl_cal(ah, chan))
|
||||
return false;
|
||||
} else if (AR_SREV_9285_12_OR_LATER(ah)) {
|
||||
if (!ar9285_hw_clc(ah, chan))
|
||||
return false;
|
||||
} else {
|
||||
|
|
|
@ -3959,19 +3959,19 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
{
|
||||
#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s))
|
||||
/* make sure forced gain is not set */
|
||||
REG_WRITE(ah, 0xa458, 0);
|
||||
REG_WRITE(ah, AR_PHY_TX_FORCED_GAIN, 0);
|
||||
|
||||
/* Write the OFDM power per rate set */
|
||||
|
||||
/* 6 (LSB), 9, 12, 18 (MSB) */
|
||||
REG_WRITE(ah, 0xa3c0,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(0),
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 0));
|
||||
|
||||
/* 24 (LSB), 36, 48, 54 (MSB) */
|
||||
REG_WRITE(ah, 0xa3c4,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(1),
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_54], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_48], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_36], 8) |
|
||||
|
@ -3980,14 +3980,14 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
/* Write the CCK power per rate set */
|
||||
|
||||
/* 1L (LSB), reserved, 2L, 2S (MSB) */
|
||||
REG_WRITE(ah, 0xa3c8,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(2),
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
|
||||
/* POW_SM(txPowerTimes2, 8) | this is reserved for AR9003 */
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0));
|
||||
|
||||
/* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */
|
||||
REG_WRITE(ah, 0xa3cc,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(3),
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_11S], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_11L], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_5S], 8) |
|
||||
|
@ -3997,7 +3997,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
/* Write the HT20 power per rate set */
|
||||
|
||||
/* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */
|
||||
REG_WRITE(ah, 0xa3d0,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(4),
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_5], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_4], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_1_3_9_11_17_19], 8) |
|
||||
|
@ -4005,7 +4005,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
);
|
||||
|
||||
/* 6 (LSB), 7, 12, 13 (MSB) */
|
||||
REG_WRITE(ah, 0xa3d4,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(5),
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_13], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_12], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_7], 8) |
|
||||
|
@ -4013,7 +4013,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
);
|
||||
|
||||
/* 14 (LSB), 15, 20, 21 */
|
||||
REG_WRITE(ah, 0xa3e4,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(9),
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_21], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_20], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_15], 8) |
|
||||
|
@ -4023,7 +4023,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
/* Mixed HT20 and HT40 rates */
|
||||
|
||||
/* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */
|
||||
REG_WRITE(ah, 0xa3e8,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(10),
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_23], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_22], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT20_23], 8) |
|
||||
|
@ -4035,7 +4035,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
* correct PAR difference between HT40 and HT20/LEGACY
|
||||
* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB)
|
||||
*/
|
||||
REG_WRITE(ah, 0xa3d8,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(6),
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_5], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_4], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_1_3_9_11_17_19], 8) |
|
||||
|
@ -4043,7 +4043,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
);
|
||||
|
||||
/* 6 (LSB), 7, 12, 13 (MSB) */
|
||||
REG_WRITE(ah, 0xa3dc,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(7),
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_13], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_12], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_7], 8) |
|
||||
|
@ -4051,7 +4051,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
);
|
||||
|
||||
/* 14 (LSB), 15, 20, 21 */
|
||||
REG_WRITE(ah, 0xa3ec,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(11),
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_21], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_20], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_HT40_15], 8) |
|
||||
|
|
|
@ -615,7 +615,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
|
|||
*/
|
||||
if (rxsp->status11 & AR_CRCErr)
|
||||
rxs->rs_status |= ATH9K_RXERR_CRC;
|
||||
if (rxsp->status11 & AR_PHYErr) {
|
||||
else if (rxsp->status11 & AR_PHYErr) {
|
||||
phyerr = MS(rxsp->status11, AR_PHYErrCode);
|
||||
/*
|
||||
* If we reach a point here where AR_PostDelimCRCErr is
|
||||
|
@ -638,11 +638,11 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
|
|||
rxs->rs_phyerr = phyerr;
|
||||
}
|
||||
|
||||
}
|
||||
if (rxsp->status11 & AR_DecryptCRCErr)
|
||||
} else if (rxsp->status11 & AR_DecryptCRCErr)
|
||||
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
|
||||
if (rxsp->status11 & AR_MichaelErr)
|
||||
else if (rxsp->status11 & AR_MichaelErr)
|
||||
rxs->rs_status |= ATH9K_RXERR_MIC;
|
||||
|
||||
if (rxsp->status11 & AR_KeyMiss)
|
||||
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
|
||||
}
|
||||
|
|
|
@ -486,6 +486,8 @@
|
|||
#define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac)
|
||||
#define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0)
|
||||
|
||||
#define AR_PHY_POWER_TX_RATE(_d) (AR_SM_BASE + 0x1c0 + ((_d) << 2))
|
||||
|
||||
#define AR_PHY_PWRTX_MAX (AR_SM_BASE + 0x1f0)
|
||||
#define AR_PHY_POWER_TX_SUB (AR_SM_BASE + 0x1f4)
|
||||
|
||||
|
|
|
@ -95,9 +95,9 @@ struct ath_config {
|
|||
* @BUF_XRETRY: To denote excessive retries of the buffer
|
||||
*/
|
||||
enum buffer_type {
|
||||
BUF_AMPDU = BIT(2),
|
||||
BUF_AGGR = BIT(3),
|
||||
BUF_XRETRY = BIT(5),
|
||||
BUF_AMPDU = BIT(0),
|
||||
BUF_AGGR = BIT(1),
|
||||
BUF_XRETRY = BIT(2),
|
||||
};
|
||||
|
||||
#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU)
|
||||
|
@ -137,7 +137,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
(((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
|
||||
WME_AC_VO)
|
||||
|
||||
#define ADDBA_EXCHANGE_ATTEMPTS 10
|
||||
#define ATH_AGGR_DELIM_SZ 4
|
||||
#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
|
||||
/* number of delimiters for encryption padding */
|
||||
|
@ -184,7 +183,8 @@ enum ATH_AGGR_STATUS {
|
|||
|
||||
#define ATH_TXFIFO_DEPTH 8
|
||||
struct ath_txq {
|
||||
u32 axq_qnum;
|
||||
int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
|
||||
u32 axq_qnum; /* ath9k hardware queue number */
|
||||
u32 *axq_link;
|
||||
struct list_head axq_q;
|
||||
spinlock_t axq_lock;
|
||||
|
@ -254,7 +254,10 @@ struct ath_atx_tid {
|
|||
};
|
||||
|
||||
struct ath_node {
|
||||
struct ath_common *common;
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
struct list_head list; /* for sc->nodes */
|
||||
struct ieee80211_sta *sta; /* station struct we're part of */
|
||||
#endif
|
||||
struct ath_atx_tid tid[WME_NUM_TID];
|
||||
struct ath_atx_ac ac[WME_NUM_AC];
|
||||
u16 maxampdu;
|
||||
|
@ -277,6 +280,11 @@ struct ath_tx_control {
|
|||
#define ATH_TX_XRETRY 0x02
|
||||
#define ATH_TX_BAR 0x04
|
||||
|
||||
/**
|
||||
* @txq_map: Index is mac80211 queue number. This is
|
||||
* not necessarily the same as the hardware queue number
|
||||
* (axq_qnum).
|
||||
*/
|
||||
struct ath_tx {
|
||||
u16 seq_no;
|
||||
u32 txqsetup;
|
||||
|
@ -342,7 +350,6 @@ struct ath_vif {
|
|||
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
|
||||
enum nl80211_iftype av_opmode;
|
||||
struct ath_buf *av_bcbuf;
|
||||
struct ath_tx_control av_btxctl;
|
||||
u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */
|
||||
};
|
||||
|
||||
|
@ -560,6 +567,20 @@ struct ath_ant_comb {
|
|||
struct ath_wiphy;
|
||||
struct ath_rate_table;
|
||||
|
||||
struct ath9k_vif_iter_data {
|
||||
const u8 *hw_macaddr; /* phy's hardware address, set
|
||||
* before starting iteration for
|
||||
* valid bssid mask.
|
||||
*/
|
||||
u8 mask[ETH_ALEN]; /* bssid mask */
|
||||
int naps; /* number of AP vifs */
|
||||
int nmeshes; /* number of mesh vifs */
|
||||
int nstations; /* number of station vifs */
|
||||
int nwds; /* number of nwd vifs */
|
||||
int nadhocs; /* number of adhoc vifs */
|
||||
int nothers; /* number of vifs not specified above. */
|
||||
};
|
||||
|
||||
struct ath_softc {
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
|
@ -599,10 +620,10 @@ struct ath_softc {
|
|||
u32 sc_flags; /* SC_OP_* */
|
||||
u16 ps_flags; /* PS_* */
|
||||
u16 curtxpow;
|
||||
u8 nbcnvifs;
|
||||
u16 nvifs;
|
||||
bool ps_enabled;
|
||||
bool ps_idle;
|
||||
short nbcnvifs;
|
||||
short nvifs;
|
||||
unsigned long ps_usecount;
|
||||
|
||||
struct ath_config config;
|
||||
|
@ -625,6 +646,9 @@ struct ath_softc {
|
|||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
struct ath9k_debug debug;
|
||||
spinlock_t nodes_lock;
|
||||
struct list_head nodes; /* basically, stations */
|
||||
unsigned int tx_complete_poll_work_seen;
|
||||
#endif
|
||||
struct ath_beacon_config cur_beacon_conf;
|
||||
struct delayed_work tx_complete_work;
|
||||
|
@ -683,6 +707,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
|||
void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||
bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
|
||||
bool ath9k_uses_beacons(int type);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
int ath_pci_init(void);
|
||||
|
@ -727,5 +752,9 @@ bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
|
|||
|
||||
void ath_start_rfkill_poll(struct ath_softc *sc);
|
||||
extern 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 */
|
||||
|
|
|
@ -244,9 +244,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
|
|||
struct ath_buf, list);
|
||||
list_del(&avp->av_bcbuf->list);
|
||||
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
|
||||
sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC ||
|
||||
sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) {
|
||||
if (ath9k_uses_beacons(vif->type)) {
|
||||
int slot;
|
||||
/*
|
||||
* Assign the vif to a beacon xmit slot. As
|
||||
|
@ -281,10 +279,8 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
|
|||
|
||||
/* NB: the beacon data buffer must be 32-bit aligned. */
|
||||
skb = ieee80211_beacon_get(sc->hw, vif);
|
||||
if (skb == NULL) {
|
||||
ath_dbg(common, ATH_DBG_BEACON, "cannot get skb\n");
|
||||
if (skb == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
|
||||
sc->beacon.bc_tstamp = le64_to_cpu(tstamp);
|
||||
|
@ -720,10 +716,10 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|||
iftype = sc->sc_ah->opmode;
|
||||
}
|
||||
|
||||
cur_conf->listen_interval = 1;
|
||||
cur_conf->dtim_count = 1;
|
||||
cur_conf->bmiss_timeout =
|
||||
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
|
||||
cur_conf->listen_interval = 1;
|
||||
cur_conf->dtim_count = 1;
|
||||
cur_conf->bmiss_timeout =
|
||||
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
|
||||
|
||||
/*
|
||||
* It looks like mac80211 may end up using beacon interval of zero in
|
||||
|
|
|
@ -382,9 +382,8 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
|
|||
s16 default_nf;
|
||||
int i, j;
|
||||
|
||||
if (!ah->caldata)
|
||||
return;
|
||||
|
||||
ah->caldata->channel = chan->channel;
|
||||
ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT;
|
||||
h = ah->caldata->nfCalHist;
|
||||
default_nf = ath9k_hw_get_default_nf(ah, chan);
|
||||
for (i = 0; i < NUM_NF_READINGS; i++) {
|
||||
|
|
|
@ -587,26 +587,60 @@ static const struct file_operations fops_wiphy = {
|
|||
sc->debug.stats.txstats[WME_AC_BK].elem, \
|
||||
sc->debug.stats.txstats[WME_AC_VI].elem, \
|
||||
sc->debug.stats.txstats[WME_AC_VO].elem); \
|
||||
if (len >= size) \
|
||||
goto done; \
|
||||
} while(0)
|
||||
|
||||
#define PRX(str, elem) \
|
||||
do { \
|
||||
len += snprintf(buf + len, size - len, \
|
||||
"%s%13u%11u%10u%10u\n", str, \
|
||||
(unsigned int)(sc->tx.txq[ATH_TXQ_AC_BE].elem), \
|
||||
(unsigned int)(sc->tx.txq[ATH_TXQ_AC_BK].elem), \
|
||||
(unsigned int)(sc->tx.txq[ATH_TXQ_AC_VI].elem), \
|
||||
(unsigned int)(sc->tx.txq[ATH_TXQ_AC_VO].elem)); \
|
||||
if (len >= size) \
|
||||
goto done; \
|
||||
} while(0)
|
||||
|
||||
#define PRQLE(str, elem) \
|
||||
do { \
|
||||
len += snprintf(buf + len, size - len, \
|
||||
"%s%13i%11i%10i%10i\n", str, \
|
||||
list_empty(&sc->tx.txq[ATH_TXQ_AC_BE].elem), \
|
||||
list_empty(&sc->tx.txq[ATH_TXQ_AC_BK].elem), \
|
||||
list_empty(&sc->tx.txq[ATH_TXQ_AC_VI].elem), \
|
||||
list_empty(&sc->tx.txq[ATH_TXQ_AC_VO].elem)); \
|
||||
if (len >= size) \
|
||||
goto done; \
|
||||
} while (0)
|
||||
|
||||
static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
char *buf;
|
||||
unsigned int len = 0, size = 2048;
|
||||
unsigned int len = 0, size = 8000;
|
||||
int i;
|
||||
ssize_t retval = 0;
|
||||
char tmp[32];
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
|
||||
len += sprintf(buf, "Num-Tx-Queues: %i tx-queues-setup: 0x%x"
|
||||
" poll-work-seen: %u\n"
|
||||
"%30s %10s%10s%10s\n\n",
|
||||
ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup,
|
||||
sc->tx_complete_poll_work_seen,
|
||||
"BE", "BK", "VI", "VO");
|
||||
|
||||
PR("MPDUs Queued: ", queued);
|
||||
PR("MPDUs Completed: ", completed);
|
||||
PR("Aggregates: ", a_aggr);
|
||||
PR("AMPDUs Queued: ", a_queued);
|
||||
PR("AMPDUs Queued HW:", a_queued_hw);
|
||||
PR("AMPDUs Queued SW:", a_queued_sw);
|
||||
PR("AMPDUs Completed:", a_completed);
|
||||
PR("AMPDUs Retried: ", a_retries);
|
||||
PR("AMPDUs XRetried: ", a_xretries);
|
||||
|
@ -618,6 +652,223 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
|
|||
PR("DELIM Underrun: ", delim_underrun);
|
||||
PR("TX-Pkts-All: ", tx_pkts_all);
|
||||
PR("TX-Bytes-All: ", tx_bytes_all);
|
||||
PR("hw-put-tx-buf: ", puttxbuf);
|
||||
PR("hw-tx-start: ", txstart);
|
||||
PR("hw-tx-proc-desc: ", txprocdesc);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%s%11p%11p%10p%10p\n", "txq-memory-address:",
|
||||
&(sc->tx.txq[ATH_TXQ_AC_BE]),
|
||||
&(sc->tx.txq[ATH_TXQ_AC_BK]),
|
||||
&(sc->tx.txq[ATH_TXQ_AC_VI]),
|
||||
&(sc->tx.txq[ATH_TXQ_AC_VO]));
|
||||
if (len >= size)
|
||||
goto done;
|
||||
|
||||
PRX("axq-qnum: ", axq_qnum);
|
||||
PRX("axq-depth: ", axq_depth);
|
||||
PRX("axq-ampdu_depth: ", axq_ampdu_depth);
|
||||
PRX("axq-stopped ", stopped);
|
||||
PRX("tx-in-progress ", axq_tx_inprogress);
|
||||
PRX("pending-frames ", pending_frames);
|
||||
PRX("txq_headidx: ", txq_headidx);
|
||||
PRX("txq_tailidx: ", txq_headidx);
|
||||
|
||||
PRQLE("axq_q empty: ", axq_q);
|
||||
PRQLE("axq_acq empty: ", axq_acq);
|
||||
PRQLE("txq_fifo_pending: ", txq_fifo_pending);
|
||||
for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
|
||||
snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
|
||||
PRQLE(tmp, txq_fifo[i]);
|
||||
}
|
||||
|
||||
/* Print out more detailed queue-info */
|
||||
for (i = 0; i <= WME_AC_BK; i++) {
|
||||
struct ath_txq *txq = &(sc->tx.txq[i]);
|
||||
struct ath_atx_ac *ac;
|
||||
struct ath_atx_tid *tid;
|
||||
if (len >= size)
|
||||
goto done;
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
if (!list_empty(&txq->axq_acq)) {
|
||||
ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac,
|
||||
list);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"txq[%i] first-ac: %p sched: %i\n",
|
||||
i, ac, ac->sched);
|
||||
if (list_empty(&ac->tid_q) || (len >= size))
|
||||
goto done_for;
|
||||
tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
|
||||
list);
|
||||
len += snprintf(buf + len, size - len,
|
||||
" first-tid: %p sched: %i paused: %i\n",
|
||||
tid, tid->sched, tid->paused);
|
||||
}
|
||||
done_for:
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
}
|
||||
|
||||
done:
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t read_file_stations(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
char *buf;
|
||||
unsigned int len = 0, size = 64000;
|
||||
struct ath_node *an = NULL;
|
||||
ssize_t retval = 0;
|
||||
int q;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"Stations:\n"
|
||||
" tid: addr sched paused buf_q-empty an ac\n"
|
||||
" ac: addr sched tid_q-empty txq\n");
|
||||
|
||||
spin_lock(&sc->nodes_lock);
|
||||
list_for_each_entry(an, &sc->nodes, list) {
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%pM\n", an->sta->addr);
|
||||
if (len >= size)
|
||||
goto done;
|
||||
|
||||
for (q = 0; q < WME_NUM_TID; q++) {
|
||||
struct ath_atx_tid *tid = &(an->tid[q]);
|
||||
len += snprintf(buf + len, size - len,
|
||||
" tid: %p %s %s %i %p %p\n",
|
||||
tid, tid->sched ? "sched" : "idle",
|
||||
tid->paused ? "paused" : "running",
|
||||
list_empty(&tid->buf_q),
|
||||
tid->an, tid->ac);
|
||||
if (len >= size)
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (q = 0; q < WME_NUM_AC; q++) {
|
||||
struct ath_atx_ac *ac = &(an->ac[q]);
|
||||
len += snprintf(buf + len, size - len,
|
||||
" ac: %p %s %i %p\n",
|
||||
ac, ac->sched ? "sched" : "idle",
|
||||
list_empty(&ac->tid_q), ac->txq);
|
||||
if (len >= size)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
spin_unlock(&sc->nodes_lock);
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t read_file_misc(struct file *file, 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);
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
char *buf;
|
||||
unsigned int len = 0, size = 8000;
|
||||
ssize_t retval = 0;
|
||||
const char *tmp;
|
||||
unsigned int reg;
|
||||
struct ath9k_vif_iter_data iter_data;
|
||||
|
||||
ath9k_calculate_iter_data(hw, NULL, &iter_data);
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (sc->sc_ah->opmode) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
tmp = "ADHOC";
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
tmp = "MESH";
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
tmp = "AP";
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
tmp = "STATION";
|
||||
break;
|
||||
default:
|
||||
tmp = "???";
|
||||
break;
|
||||
}
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"curbssid: %pM\n"
|
||||
"OP-Mode: %s(%i)\n"
|
||||
"Beacon-Timer-Register: 0x%x\n",
|
||||
common->curbssid,
|
||||
tmp, (int)(sc->sc_ah->opmode),
|
||||
REG_READ(ah, AR_BEACON_PERIOD));
|
||||
|
||||
reg = REG_READ(ah, AR_TIMER_MODE);
|
||||
len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (",
|
||||
reg);
|
||||
if (reg & AR_TBTT_TIMER_EN)
|
||||
len += snprintf(buf + len, size - len, "TBTT ");
|
||||
if (reg & AR_DBA_TIMER_EN)
|
||||
len += snprintf(buf + len, size - len, "DBA ");
|
||||
if (reg & AR_SWBA_TIMER_EN)
|
||||
len += snprintf(buf + len, size - len, "SWBA ");
|
||||
if (reg & AR_HCF_TIMER_EN)
|
||||
len += snprintf(buf + len, size - len, "HCF ");
|
||||
if (reg & AR_TIM_TIMER_EN)
|
||||
len += snprintf(buf + len, size - len, "TIM ");
|
||||
if (reg & AR_DTIM_TIMER_EN)
|
||||
len += snprintf(buf + len, size - len, "DTIM ");
|
||||
len += snprintf(buf + len, size - len, ")\n");
|
||||
|
||||
reg = sc->sc_ah->imask;
|
||||
len += snprintf(buf + len, size - len, "imask: 0x%x (", reg);
|
||||
if (reg & ATH9K_INT_SWBA)
|
||||
len += snprintf(buf + len, size - len, "SWBA ");
|
||||
if (reg & ATH9K_INT_BMISS)
|
||||
len += snprintf(buf + len, size - len, "BMISS ");
|
||||
if (reg & ATH9K_INT_CST)
|
||||
len += snprintf(buf + len, size - len, "CST ");
|
||||
if (reg & ATH9K_INT_RX)
|
||||
len += snprintf(buf + len, size - len, "RX ");
|
||||
if (reg & ATH9K_INT_RXHP)
|
||||
len += snprintf(buf + len, size - len, "RXHP ");
|
||||
if (reg & ATH9K_INT_RXLP)
|
||||
len += snprintf(buf + len, size - len, "RXLP ");
|
||||
if (reg & ATH9K_INT_BB_WATCHDOG)
|
||||
len += snprintf(buf + len, size - len, "BB_WATCHDOG ");
|
||||
/* there are other IRQs if one wanted to add them. */
|
||||
len += snprintf(buf + len, size - len, ")\n");
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"VIF Counts: AP: %i STA: %i MESH: %i WDS: %i"
|
||||
" ADHOC: %i OTHER: %i nvifs: %hi beacon-vifs: %hi\n",
|
||||
iter_data.naps, iter_data.nstations, iter_data.nmeshes,
|
||||
iter_data.nwds, iter_data.nadhocs, iter_data.nothers,
|
||||
sc->nvifs, sc->nbcnvifs);
|
||||
|
||||
len += snprintf(buf + len, size - len,
|
||||
"Calculated-BSSID-Mask: %pM\n",
|
||||
iter_data.mask);
|
||||
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
@ -666,6 +917,20 @@ static const struct file_operations fops_xmit = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static const struct file_operations fops_stations = {
|
||||
.read = read_file_stations,
|
||||
.open = ath9k_debugfs_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static const struct file_operations fops_misc = {
|
||||
.read = read_file_misc,
|
||||
.open = ath9k_debugfs_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -903,6 +1168,14 @@ int ath9k_init_debug(struct ath_hw *ah)
|
|||
sc, &fops_xmit))
|
||||
goto err;
|
||||
|
||||
if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy,
|
||||
sc, &fops_stations))
|
||||
goto err;
|
||||
|
||||
if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy,
|
||||
sc, &fops_misc))
|
||||
goto err;
|
||||
|
||||
if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
|
||||
sc, &fops_recv))
|
||||
goto err;
|
||||
|
|
|
@ -89,7 +89,8 @@ struct ath_interrupt_stats {
|
|||
* @queued: Total MPDUs (non-aggr) queued
|
||||
* @completed: Total MPDUs (non-aggr) completed
|
||||
* @a_aggr: Total no. of aggregates queued
|
||||
* @a_queued: Total AMPDUs queued
|
||||
* @a_queued_hw: Total AMPDUs queued to hardware
|
||||
* @a_queued_sw: Total AMPDUs queued to software queues
|
||||
* @a_completed: Total AMPDUs completed
|
||||
* @a_retries: No. of AMPDUs retried (SW)
|
||||
* @a_xretries: No. of AMPDUs dropped due to xretries
|
||||
|
@ -102,6 +103,9 @@ struct ath_interrupt_stats {
|
|||
* @desc_cfg_err: Descriptor configuration errors
|
||||
* @data_urn: TX data underrun errors
|
||||
* @delim_urn: TX delimiter underrun errors
|
||||
* @puttxbuf: Number of times hardware was given txbuf to write.
|
||||
* @txstart: Number of times hardware was told to start tx.
|
||||
* @txprocdesc: Number of times tx descriptor was processed
|
||||
*/
|
||||
struct ath_tx_stats {
|
||||
u32 tx_pkts_all;
|
||||
|
@ -109,7 +113,8 @@ struct ath_tx_stats {
|
|||
u32 queued;
|
||||
u32 completed;
|
||||
u32 a_aggr;
|
||||
u32 a_queued;
|
||||
u32 a_queued_hw;
|
||||
u32 a_queued_sw;
|
||||
u32 a_completed;
|
||||
u32 a_retries;
|
||||
u32 a_xretries;
|
||||
|
@ -119,6 +124,9 @@ struct ath_tx_stats {
|
|||
u32 desc_cfg_err;
|
||||
u32 data_underrun;
|
||||
u32 delim_underrun;
|
||||
u32 puttxbuf;
|
||||
u32 txstart;
|
||||
u32 txprocdesc;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -89,6 +89,38 @@ bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
|
|||
return false;
|
||||
}
|
||||
|
||||
void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
|
||||
int eep_start_loc, int size)
|
||||
{
|
||||
int i = 0, j, addr;
|
||||
u32 addrdata[8];
|
||||
u32 data[8];
|
||||
|
||||
for (addr = 0; addr < size; addr++) {
|
||||
addrdata[i] = AR5416_EEPROM_OFFSET +
|
||||
((addr + eep_start_loc) << AR5416_EEPROM_S);
|
||||
i++;
|
||||
if (i == 8) {
|
||||
REG_READ_MULTI(ah, addrdata, data, i);
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
*eep_data = data[j];
|
||||
eep_data++;
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
REG_READ_MULTI(ah, addrdata, data, i);
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
*eep_data = data[j];
|
||||
eep_data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data)
|
||||
{
|
||||
return common->bus_ops->eeprom_read(common, off, data);
|
||||
|
|
|
@ -665,6 +665,8 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
|
|||
bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
|
||||
u16 *indexL, u16 *indexR);
|
||||
bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data);
|
||||
void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
|
||||
int eep_start_loc, int size);
|
||||
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
|
||||
u8 *pVpdList, u16 numIntercepts,
|
||||
u8 *pRetVpdList);
|
||||
|
|
|
@ -27,19 +27,13 @@ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
|
|||
return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF);
|
||||
}
|
||||
|
||||
static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
|
||||
|
||||
static bool __ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u16 *eep_data = (u16 *)&ah->eeprom.map4k;
|
||||
int addr, eep_start_loc = 0;
|
||||
|
||||
eep_start_loc = 64;
|
||||
|
||||
if (!ath9k_hw_use_flash(ah)) {
|
||||
ath_dbg(common, ATH_DBG_EEPROM,
|
||||
"Reading from EEPROM, not flash\n");
|
||||
}
|
||||
int addr, eep_start_loc = 64;
|
||||
|
||||
for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
|
||||
if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) {
|
||||
|
@ -51,9 +45,34 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
|
|||
}
|
||||
|
||||
return true;
|
||||
#undef SIZE_EEPROM_4K
|
||||
}
|
||||
|
||||
static bool __ath9k_hw_usb_4k_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
u16 *eep_data = (u16 *)&ah->eeprom.map4k;
|
||||
|
||||
ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, 64, SIZE_EEPROM_4K);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (!ath9k_hw_use_flash(ah)) {
|
||||
ath_dbg(common, ATH_DBG_EEPROM,
|
||||
"Reading from EEPROM, not flash\n");
|
||||
}
|
||||
|
||||
if (common->bus_ops->ath_bus_type == ATH_USB)
|
||||
return __ath9k_hw_usb_4k_fill_eeprom(ah);
|
||||
else
|
||||
return __ath9k_hw_4k_fill_eeprom(ah);
|
||||
}
|
||||
|
||||
#undef SIZE_EEPROM_4K
|
||||
|
||||
static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "hw.h"
|
||||
#include "ar9002_phy.h"
|
||||
|
||||
#define NUM_EEP_WORDS (sizeof(struct ar9287_eeprom) / sizeof(u16))
|
||||
#define SIZE_EEPROM_AR9287 (sizeof(struct ar9287_eeprom) / sizeof(u16))
|
||||
|
||||
static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
|
||||
{
|
||||
|
@ -29,25 +29,15 @@ static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
|
|||
return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
|
||||
}
|
||||
|
||||
static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
|
||||
static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u16 *eep_data;
|
||||
int addr, eep_start_loc;
|
||||
int addr, eep_start_loc = AR9287_EEP_START_LOC;
|
||||
eep_data = (u16 *)eep;
|
||||
|
||||
if (common->bus_ops->ath_bus_type == ATH_USB)
|
||||
eep_start_loc = AR9287_HTC_EEP_START_LOC;
|
||||
else
|
||||
eep_start_loc = AR9287_EEP_START_LOC;
|
||||
|
||||
if (!ath9k_hw_use_flash(ah)) {
|
||||
ath_dbg(common, ATH_DBG_EEPROM,
|
||||
"Reading from EEPROM, not flash\n");
|
||||
}
|
||||
|
||||
for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
|
||||
for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
|
||||
if (!ath9k_hw_nvram_read(common, addr + eep_start_loc,
|
||||
eep_data)) {
|
||||
ath_dbg(common, ATH_DBG_EEPROM,
|
||||
|
@ -60,6 +50,31 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool __ath9k_hw_usb_ar9287_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
u16 *eep_data = (u16 *)&ah->eeprom.map9287;
|
||||
|
||||
ath9k_hw_usb_gen_fill_eeprom(ah, eep_data,
|
||||
AR9287_HTC_EEP_START_LOC,
|
||||
SIZE_EEPROM_AR9287);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (!ath9k_hw_use_flash(ah)) {
|
||||
ath_dbg(common, ATH_DBG_EEPROM,
|
||||
"Reading from EEPROM, not flash\n");
|
||||
}
|
||||
|
||||
if (common->bus_ops->ath_bus_type == ATH_USB)
|
||||
return __ath9k_hw_usb_ar9287_fill_eeprom(ah);
|
||||
else
|
||||
return __ath9k_hw_ar9287_fill_eeprom(ah);
|
||||
}
|
||||
|
||||
static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
u32 sum = 0, el, integer;
|
||||
|
@ -86,7 +101,7 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
|
|||
need_swap = true;
|
||||
eepdata = (u16 *)(&ah->eeprom);
|
||||
|
||||
for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
|
||||
for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
|
||||
temp = swab16(*eepdata);
|
||||
*eepdata = temp;
|
||||
eepdata++;
|
||||
|
|
|
@ -86,9 +86,10 @@ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah)
|
|||
return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF);
|
||||
}
|
||||
|
||||
static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
|
||||
|
||||
static bool __ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u16 *eep_data = (u16 *)&ah->eeprom.def;
|
||||
int addr, ar5416_eep_start_loc = 0x100;
|
||||
|
@ -103,9 +104,34 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
|
|||
eep_data++;
|
||||
}
|
||||
return true;
|
||||
#undef SIZE_EEPROM_DEF
|
||||
}
|
||||
|
||||
static bool __ath9k_hw_usb_def_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
u16 *eep_data = (u16 *)&ah->eeprom.def;
|
||||
|
||||
ath9k_hw_usb_gen_fill_eeprom(ah, eep_data,
|
||||
0x100, SIZE_EEPROM_DEF);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (!ath9k_hw_use_flash(ah)) {
|
||||
ath_dbg(common, ATH_DBG_EEPROM,
|
||||
"Reading from EEPROM, not flash\n");
|
||||
}
|
||||
|
||||
if (common->bus_ops->ath_bus_type == ATH_USB)
|
||||
return __ath9k_hw_usb_def_fill_eeprom(ah);
|
||||
else
|
||||
return __ath9k_hw_def_fill_eeprom(ah);
|
||||
}
|
||||
|
||||
#undef SIZE_EEPROM_DEF
|
||||
|
||||
static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
struct ar5416_eeprom_def *eep =
|
||||
|
|
|
@ -366,7 +366,7 @@ struct ath9k_htc_priv {
|
|||
u16 seq_no;
|
||||
u32 bmiss_cnt;
|
||||
|
||||
struct ath9k_hw_cal_data caldata[ATH9K_NUM_CHANNELS];
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
|
||||
spinlock_t beacon_lock;
|
||||
|
||||
|
|
|
@ -297,6 +297,34 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
|
|||
return be32_to_cpu(val);
|
||||
}
|
||||
|
||||
static void ath9k_multi_regread(void *hw_priv, u32 *addr,
|
||||
u32 *val, u16 count)
|
||||
{
|
||||
struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
__be32 tmpaddr[8];
|
||||
__be32 tmpval[8];
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
tmpaddr[i] = cpu_to_be32(addr[i]);
|
||||
}
|
||||
|
||||
ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
|
||||
(u8 *)tmpaddr , sizeof(u32) * count,
|
||||
(u8 *)tmpval, sizeof(u32) * count,
|
||||
100);
|
||||
if (unlikely(ret)) {
|
||||
ath_dbg(common, ATH_DBG_WMI,
|
||||
"Multiple REGISTER READ FAILED (count: %d)\n", count);
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
val[i] = be32_to_cpu(tmpval[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
|
||||
{
|
||||
struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
|
@ -407,6 +435,7 @@ static void ath9k_regwrite_flush(void *hw_priv)
|
|||
|
||||
static const struct ath_ops ath9k_common_ops = {
|
||||
.read = ath9k_regread,
|
||||
.multi_read = ath9k_multi_regread,
|
||||
.write = ath9k_regwrite,
|
||||
.enable_write_buffer = ath9k_enable_regwrite_buffer,
|
||||
.write_flush = ath9k_regwrite_flush,
|
||||
|
|
|
@ -121,7 +121,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
|
|||
struct ath_hw *ah = priv->ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_channel *channel = priv->hw->conf.channel;
|
||||
struct ath9k_hw_cal_data *caldata;
|
||||
struct ath9k_hw_cal_data *caldata = NULL;
|
||||
enum htc_phymode mode;
|
||||
__be16 htc_mode;
|
||||
u8 cmd_rsp;
|
||||
|
@ -139,7 +139,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
|
|||
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
|
||||
WMI_CMD(WMI_STOP_RECV_CMDID);
|
||||
|
||||
caldata = &priv->caldata[channel->hw_value];
|
||||
caldata = &priv->caldata;
|
||||
ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
|
||||
if (ret) {
|
||||
ath_err(common,
|
||||
|
@ -202,7 +202,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
|
|||
channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
|
||||
fastcc);
|
||||
|
||||
caldata = &priv->caldata[channel->hw_value];
|
||||
if (!fastcc)
|
||||
caldata = &priv->caldata;
|
||||
ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
|
||||
if (ret) {
|
||||
ath_err(common,
|
||||
|
@ -1548,7 +1549,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
u16 tid, u16 *ssn, u8 buf_size)
|
||||
{
|
||||
struct ath9k_htc_priv *priv = hw->priv;
|
||||
struct ath9k_htc_sta *ista;
|
||||
|
|
|
@ -495,6 +495,17 @@ static int __ath9k_hw_init(struct ath_hw *ah)
|
|||
if (ah->hw_version.devid == AR5416_AR9100_DEVID)
|
||||
ah->hw_version.macVersion = AR_SREV_VERSION_9100;
|
||||
|
||||
ath9k_hw_read_revisions(ah);
|
||||
|
||||
/*
|
||||
* Read back AR_WA into a permanent copy and set bits 14 and 17.
|
||||
* We need to do this to avoid RMW of this register. We cannot
|
||||
* read the reg when chip is asleep.
|
||||
*/
|
||||
ah->WARegVal = REG_READ(ah, AR_WA);
|
||||
ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
|
||||
AR_WA_ASPM_TIMER_BASED_DISABLE);
|
||||
|
||||
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
|
||||
ath_err(common, "Couldn't reset chip\n");
|
||||
return -EIO;
|
||||
|
@ -563,14 +574,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
|
|||
|
||||
ath9k_hw_init_mode_regs(ah);
|
||||
|
||||
/*
|
||||
* Read back AR_WA into a permanent copy and set bits 14 and 17.
|
||||
* We need to do this to avoid RMW of this register. We cannot
|
||||
* read the reg when chip is asleep.
|
||||
*/
|
||||
ah->WARegVal = REG_READ(ah, AR_WA);
|
||||
ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
|
||||
AR_WA_ASPM_TIMER_BASED_DISABLE);
|
||||
|
||||
if (ah->is_pciexpress)
|
||||
ath9k_hw_configpcipowersave(ah, 0, 0);
|
||||
|
@ -1082,8 +1085,6 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
|
|||
return false;
|
||||
}
|
||||
|
||||
ath9k_hw_read_revisions(ah);
|
||||
|
||||
return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@
|
|||
#define REG_READ(_ah, _reg) \
|
||||
ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
|
||||
|
||||
#define REG_READ_MULTI(_ah, _addr, _val, _cnt) \
|
||||
ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt))
|
||||
|
||||
#define ENABLE_REGWRITE_BUFFER(_ah) \
|
||||
do { \
|
||||
if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \
|
||||
|
|
|
@ -442,9 +442,10 @@ static int ath9k_init_queues(struct ath_softc *sc)
|
|||
sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
|
||||
ath_cabq_update(sc);
|
||||
|
||||
for (i = 0; i < WME_NUM_AC; i++)
|
||||
for (i = 0; i < WME_NUM_AC; i++) {
|
||||
sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
|
||||
|
||||
sc->tx.txq_map[i]->mac80211_qnum = i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -537,6 +538,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
|
|||
if (!ah)
|
||||
return -ENOMEM;
|
||||
|
||||
ah->hw = sc->hw;
|
||||
ah->hw_version.devid = devid;
|
||||
ah->hw_version.subsysid = subsysid;
|
||||
sc->sc_ah = ah;
|
||||
|
@ -558,6 +560,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
|
|||
spin_lock_init(&sc->sc_serial_rw);
|
||||
spin_lock_init(&sc->sc_pm_lock);
|
||||
mutex_init(&sc->mutex);
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
spin_lock_init(&sc->nodes_lock);
|
||||
INIT_LIST_HEAD(&sc->nodes);
|
||||
#endif
|
||||
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
|
||||
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
|
||||
(unsigned long)sc);
|
||||
|
|
|
@ -690,17 +690,23 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
|
|||
rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
|
||||
|
||||
if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
|
||||
/*
|
||||
* Treat these errors as mutually exclusive to avoid spurious
|
||||
* extra error reports from the hardware. If a CRC error is
|
||||
* reported, then decryption and MIC errors are irrelevant,
|
||||
* the frame is going to be dropped either way
|
||||
*/
|
||||
if (ads.ds_rxstatus8 & AR_CRCErr)
|
||||
rs->rs_status |= ATH9K_RXERR_CRC;
|
||||
if (ads.ds_rxstatus8 & AR_PHYErr) {
|
||||
else if (ads.ds_rxstatus8 & AR_PHYErr) {
|
||||
rs->rs_status |= ATH9K_RXERR_PHY;
|
||||
phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
|
||||
rs->rs_phyerr = phyerr;
|
||||
}
|
||||
if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
|
||||
} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
|
||||
rs->rs_status |= ATH9K_RXERR_DECRYPT;
|
||||
if (ads.ds_rxstatus8 & AR_MichaelErr)
|
||||
else if (ads.ds_rxstatus8 & AR_MichaelErr)
|
||||
rs->rs_status |= ATH9K_RXERR_MIC;
|
||||
|
||||
if (ads.ds_rxstatus8 & AR_KeyMiss)
|
||||
rs->rs_status |= ATH9K_RXERR_DECRYPT;
|
||||
}
|
||||
|
|
|
@ -251,6 +251,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
|||
if (!ath_stoprecv(sc))
|
||||
stopped = false;
|
||||
|
||||
if (!ath9k_hw_check_alive(ah))
|
||||
stopped = false;
|
||||
|
||||
/* XXX: do not flush receive queue here. We don't want
|
||||
* to flush data frames already in queue because of
|
||||
* changing channel. */
|
||||
|
@ -545,6 +548,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
|
|||
struct ath_hw *ah = sc->sc_ah;
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
spin_lock(&sc->nodes_lock);
|
||||
list_add(&an->list, &sc->nodes);
|
||||
spin_unlock(&sc->nodes_lock);
|
||||
an->sta = sta;
|
||||
#endif
|
||||
if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM)
|
||||
sc->sc_flags |= SC_OP_ENABLE_APM;
|
||||
|
||||
|
@ -560,6 +569,13 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
|
|||
{
|
||||
struct ath_node *an = (struct ath_node *)sta->drv_priv;
|
||||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
spin_lock(&sc->nodes_lock);
|
||||
list_del(&an->list);
|
||||
spin_unlock(&sc->nodes_lock);
|
||||
an->sta = NULL;
|
||||
#endif
|
||||
|
||||
if (sc->sc_flags & SC_OP_TXAGGR)
|
||||
ath_tx_node_cleanup(sc, an);
|
||||
}
|
||||
|
@ -600,7 +616,15 @@ void ath9k_tasklet(unsigned long data)
|
|||
ath9k_ps_wakeup(sc);
|
||||
spin_lock(&sc->sc_pcu_lock);
|
||||
|
||||
if (!ath9k_hw_check_alive(ah))
|
||||
/*
|
||||
* Only run the baseband hang check if beacons stop working in AP or
|
||||
* IBSS mode, because it has a high false positive rate. For station
|
||||
* mode it should not be necessary, since the upper layers will detect
|
||||
* this through a beacon miss automatically and the following channel
|
||||
* change will trigger a hardware reset anyway
|
||||
*/
|
||||
if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 &&
|
||||
!ath9k_hw_check_alive(ah))
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
|
||||
|
@ -1341,87 +1365,16 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
|||
ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
|
||||
}
|
||||
|
||||
static int ath9k_add_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
bool ath9k_uses_beacons(int type)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ic_opmode = NL80211_IFTYPE_STATION;
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
ic_opmode = NL80211_IFTYPE_WDS;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (sc->nbcnvifs >= ATH_BCBUF) {
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
ic_opmode = vif->type;
|
||||
break;
|
||||
return true;
|
||||
default:
|
||||
ath_err(common, "Interface type %d not yet supported\n",
|
||||
vif->type);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
return false;
|
||||
}
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Attach a VIF of type: %d\n", ic_opmode);
|
||||
|
||||
/* Set the VIF opmode */
|
||||
avp->av_opmode = ic_opmode;
|
||||
avp->av_bslot = -1;
|
||||
|
||||
sc->nvifs++;
|
||||
|
||||
ath9k_set_bssid_mask(hw, vif);
|
||||
|
||||
if (sc->nvifs > 1)
|
||||
goto out; /* skip global settings for secondary vif */
|
||||
|
||||
if (ic_opmode == NL80211_IFTYPE_AP) {
|
||||
ath9k_hw_set_tsfadjust(ah, 1);
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
}
|
||||
|
||||
/* Set the device opmode */
|
||||
ah->opmode = ic_opmode;
|
||||
|
||||
/*
|
||||
* Enable MIB interrupts when there are hardware phy counters.
|
||||
* Note we only do this (at the moment) for station mode.
|
||||
*/
|
||||
if ((vif->type == NL80211_IFTYPE_STATION) ||
|
||||
(vif->type == NL80211_IFTYPE_ADHOC) ||
|
||||
(vif->type == NL80211_IFTYPE_MESH_POINT)) {
|
||||
if (ah->config.enable_ani)
|
||||
ah->imask |= ATH9K_INT_MIB;
|
||||
ah->imask |= ATH9K_INT_TSFOOR;
|
||||
}
|
||||
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_ADHOC) {
|
||||
sc->sc_flags |= SC_OP_ANI_RUN;
|
||||
ath_start_ani(common);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&sc->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath9k_reclaim_beacon(struct ath_softc *sc,
|
||||
|
@ -1449,6 +1402,216 @@ static void ath9k_reclaim_beacon(struct ath_softc *sc,
|
|||
}
|
||||
}
|
||||
|
||||
static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath9k_vif_iter_data *iter_data = data;
|
||||
int i;
|
||||
|
||||
if (iter_data->hw_macaddr)
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
iter_data->mask[i] &=
|
||||
~(iter_data->hw_macaddr[i] ^ mac[i]);
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
iter_data->naps++;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
iter_data->nstations++;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
iter_data->nadhocs++;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
iter_data->nmeshes++;
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
iter_data->nwds++;
|
||||
break;
|
||||
default:
|
||||
iter_data->nothers++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Called with sc->mutex held. */
|
||||
void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ath9k_vif_iter_data *iter_data)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Use the hardware MAC address as reference, the hardware uses it
|
||||
* together with the BSSID mask when matching addresses.
|
||||
*/
|
||||
memset(iter_data, 0, sizeof(*iter_data));
|
||||
iter_data->hw_macaddr = common->macaddr;
|
||||
memset(&iter_data->mask, 0xff, ETH_ALEN);
|
||||
|
||||
if (vif)
|
||||
ath9k_vif_iter(iter_data, vif->addr, vif);
|
||||
|
||||
/* Get list of all active MAC addresses */
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
|
||||
iter_data);
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] == NULL)
|
||||
continue;
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
sc->sec_wiphy[i]->hw, ath9k_vif_iter, iter_data);
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
}
|
||||
|
||||
/* Called with sc->mutex held. */
|
||||
static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_vif_iter_data iter_data;
|
||||
|
||||
ath9k_calculate_iter_data(hw, vif, &iter_data);
|
||||
|
||||
/* Set BSSID mask. */
|
||||
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
|
||||
ath_hw_setbssidmask(common);
|
||||
|
||||
/* Set op-mode & TSF */
|
||||
if (iter_data.naps > 0) {
|
||||
ath9k_hw_set_tsfadjust(ah, 1);
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
ah->opmode = NL80211_IFTYPE_AP;
|
||||
} else {
|
||||
ath9k_hw_set_tsfadjust(ah, 0);
|
||||
sc->sc_flags &= ~SC_OP_TSF_RESET;
|
||||
|
||||
if (iter_data.nwds + iter_data.nmeshes)
|
||||
ah->opmode = NL80211_IFTYPE_AP;
|
||||
else if (iter_data.nadhocs)
|
||||
ah->opmode = NL80211_IFTYPE_ADHOC;
|
||||
else
|
||||
ah->opmode = NL80211_IFTYPE_STATION;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable MIB interrupts when there are hardware phy counters.
|
||||
*/
|
||||
if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) {
|
||||
if (ah->config.enable_ani)
|
||||
ah->imask |= ATH9K_INT_MIB;
|
||||
ah->imask |= ATH9K_INT_TSFOOR;
|
||||
} else {
|
||||
ah->imask &= ~ATH9K_INT_MIB;
|
||||
ah->imask &= ~ATH9K_INT_TSFOOR;
|
||||
}
|
||||
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
|
||||
/* Set up ANI */
|
||||
if ((iter_data.naps + iter_data.nadhocs) > 0) {
|
||||
sc->sc_flags |= SC_OP_ANI_RUN;
|
||||
ath_start_ani(common);
|
||||
} else {
|
||||
sc->sc_flags &= ~SC_OP_ANI_RUN;
|
||||
del_timer_sync(&common->ani.timer);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called with sc->mutex held, vif counts set up properly. */
|
||||
static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
|
||||
ath9k_calculate_summary_state(hw, vif);
|
||||
|
||||
if (ath9k_uses_beacons(vif->type)) {
|
||||
int error;
|
||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||
/* This may fail because upper levels do not have beacons
|
||||
* properly configured yet. That's OK, we assume it
|
||||
* will be properly configured and then we will be notified
|
||||
* in the info_changed method and set up beacons properly
|
||||
* there.
|
||||
*/
|
||||
error = ath_beacon_alloc(aphy, vif);
|
||||
if (error)
|
||||
ath9k_reclaim_beacon(sc, vif);
|
||||
else
|
||||
ath_beacon_config(sc, vif);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ath9k_add_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
break;
|
||||
default:
|
||||
ath_err(common, "Interface type %d not yet supported\n",
|
||||
vif->type);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ath9k_uses_beacons(vif->type)) {
|
||||
if (sc->nbcnvifs >= ATH_BCBUF) {
|
||||
ath_err(common, "Not enough beacon buffers when adding"
|
||||
" new interface of type: %i\n",
|
||||
vif->type);
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if ((vif->type == NL80211_IFTYPE_ADHOC) &&
|
||||
sc->nvifs > 0) {
|
||||
ath_err(common, "Cannot create ADHOC interface when other"
|
||||
" interfaces already exist.\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Attach a VIF of type: %d\n", vif->type);
|
||||
|
||||
/* Set the VIF opmode */
|
||||
avp->av_opmode = vif->type;
|
||||
avp->av_bslot = -1;
|
||||
|
||||
sc->nvifs++;
|
||||
|
||||
ath9k_do_vif_add_setup(hw, vif);
|
||||
out:
|
||||
mutex_unlock(&sc->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath9k_change_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum nl80211_iftype new_type,
|
||||
|
@ -1462,32 +1625,33 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
|
|||
ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n");
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
switch (new_type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
/* See if new interface type is valid. */
|
||||
if ((new_type == NL80211_IFTYPE_ADHOC) &&
|
||||
(sc->nvifs > 1)) {
|
||||
ath_err(common, "When using ADHOC, it must be the only"
|
||||
" interface.\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ath9k_uses_beacons(new_type) &&
|
||||
!ath9k_uses_beacons(vif->type)) {
|
||||
if (sc->nbcnvifs >= ATH_BCBUF) {
|
||||
ath_err(common, "No beacon slot available\n");
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/* Stop ANI */
|
||||
sc->sc_flags &= ~SC_OP_ANI_RUN;
|
||||
del_timer_sync(&common->ani.timer);
|
||||
if ((vif->type == NL80211_IFTYPE_AP) ||
|
||||
(vif->type == NL80211_IFTYPE_ADHOC))
|
||||
ath9k_reclaim_beacon(sc, vif);
|
||||
break;
|
||||
default:
|
||||
ath_err(common, "Interface type %d not yet supported\n",
|
||||
vif->type);
|
||||
ret = -ENOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Clean up old vif stuff */
|
||||
if (ath9k_uses_beacons(vif->type))
|
||||
ath9k_reclaim_beacon(sc, vif);
|
||||
|
||||
/* Add new settings */
|
||||
vif->type = new_type;
|
||||
vif->p2p = p2p;
|
||||
|
||||
ath9k_do_vif_add_setup(hw, vif);
|
||||
out:
|
||||
mutex_unlock(&sc->mutex);
|
||||
return ret;
|
||||
|
@ -1504,17 +1668,13 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
/* Stop ANI */
|
||||
sc->sc_flags &= ~SC_OP_ANI_RUN;
|
||||
del_timer_sync(&common->ani.timer);
|
||||
sc->nvifs--;
|
||||
|
||||
/* Reclaim beacon resources */
|
||||
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
|
||||
(sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
|
||||
(sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT))
|
||||
if (ath9k_uses_beacons(vif->type))
|
||||
ath9k_reclaim_beacon(sc, vif);
|
||||
|
||||
sc->nvifs--;
|
||||
ath9k_calculate_summary_state(hw, NULL);
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
@ -2020,7 +2180,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
u16 tid, u16 *ssn, u8 buf_size)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
|
|
|
@ -588,8 +588,14 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
|
|||
return;
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0)
|
||||
if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) {
|
||||
/* TODO: This doesn't work well if you have stations
|
||||
* associated to two different APs because curbssid
|
||||
* is just the last AP that any of the stations associated
|
||||
* with.
|
||||
*/
|
||||
return; /* not from our current AP */
|
||||
}
|
||||
|
||||
sc->ps_flags &= ~PS_WAIT_FOR_BEACON;
|
||||
|
||||
|
@ -984,8 +990,14 @@ static void ath9k_process_rssi(struct ath_common *common,
|
|||
|
||||
fc = hdr->frame_control;
|
||||
if (!ieee80211_is_beacon(fc) ||
|
||||
compare_ether_addr(hdr->addr3, common->curbssid))
|
||||
compare_ether_addr(hdr->addr3, common->curbssid)) {
|
||||
/* TODO: This doesn't work well if you have stations
|
||||
* associated to two different APs because curbssid
|
||||
* is just the last AP that any of the stations associated
|
||||
* with.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr)
|
||||
ATH_RSSI_LPF(aphy->last_rssi, rx_stats->rs_rssi);
|
||||
|
|
|
@ -18,54 +18,6 @@
|
|||
|
||||
#include "ath9k.h"
|
||||
|
||||
struct ath9k_vif_iter_data {
|
||||
const u8 *hw_macaddr;
|
||||
u8 mask[ETH_ALEN];
|
||||
};
|
||||
|
||||
static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath9k_vif_iter_data *iter_data = data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
|
||||
}
|
||||
|
||||
void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath9k_vif_iter_data iter_data;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Use the hardware MAC address as reference, the hardware uses it
|
||||
* together with the BSSID mask when matching addresses.
|
||||
*/
|
||||
iter_data.hw_macaddr = common->macaddr;
|
||||
memset(&iter_data.mask, 0xff, ETH_ALEN);
|
||||
|
||||
if (vif)
|
||||
ath9k_vif_iter(&iter_data, vif->addr, vif);
|
||||
|
||||
/* Get list of all active MAC addresses */
|
||||
spin_lock_bh(&sc->wiphy_lock);
|
||||
ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
|
||||
&iter_data);
|
||||
for (i = 0; i < sc->num_sec_wiphy; i++) {
|
||||
if (sc->sec_wiphy[i] == NULL)
|
||||
continue;
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data);
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
|
||||
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
|
||||
ath_hw_setbssidmask(common);
|
||||
}
|
||||
|
||||
int ath9k_wiphy_add(struct ath_softc *sc)
|
||||
{
|
||||
int i, error;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#define BITS_PER_BYTE 8
|
||||
#define OFDM_PLCP_BITS 22
|
||||
#define HT_RC_2_MCS(_rc) ((_rc) & 0x1f)
|
||||
#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
|
||||
#define L_STF 8
|
||||
#define L_LTF 8
|
||||
|
@ -32,7 +31,6 @@
|
|||
#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
|
||||
#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
|
||||
|
||||
#define OFDM_SIFS_TIME 16
|
||||
|
||||
static u16 bits_per_symbol[][2] = {
|
||||
/* 20MHz 40MHz */
|
||||
|
@ -169,7 +167,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
|||
ath_tx_update_baw(sc, tid, fi->seqno);
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
|
||||
} else {
|
||||
ath_tx_send_normal(sc, txq, tid, &bf_head);
|
||||
ath_tx_send_normal(sc, txq, NULL, &bf_head);
|
||||
}
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
}
|
||||
|
@ -429,7 +427,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
|
||||
ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
|
||||
while (bf) {
|
||||
txfail = txpending = 0;
|
||||
txfail = txpending = sendbar = 0;
|
||||
bf_next = bf->bf_next;
|
||||
|
||||
skb = bf->bf_mpdu;
|
||||
|
@ -856,7 +854,10 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
|||
|
||||
txtid->state |= AGGR_ADDBA_PROGRESS;
|
||||
txtid->paused = true;
|
||||
*ssn = txtid->seq_start;
|
||||
*ssn = txtid->seq_start = txtid->seq_next;
|
||||
|
||||
memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
|
||||
txtid->baw_head = txtid->baw_tail = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -942,7 +943,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
|
|||
[WME_AC_VI] = ATH_TXQ_AC_VI,
|
||||
[WME_AC_VO] = ATH_TXQ_AC_VO,
|
||||
};
|
||||
int qnum, i;
|
||||
int axq_qnum, i;
|
||||
|
||||
memset(&qi, 0, sizeof(qi));
|
||||
qi.tqi_subtype = subtype_txq_to_hwq[subtype];
|
||||
|
@ -976,24 +977,25 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
|
|||
qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
|
||||
TXQ_FLAG_TXDESCINT_ENABLE;
|
||||
}
|
||||
qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
|
||||
if (qnum == -1) {
|
||||
axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
|
||||
if (axq_qnum == -1) {
|
||||
/*
|
||||
* NB: don't print a message, this happens
|
||||
* normally on parts with too few tx queues
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
|
||||
if (axq_qnum >= ARRAY_SIZE(sc->tx.txq)) {
|
||||
ath_err(common, "qnum %u out of range, max %zu!\n",
|
||||
qnum, ARRAY_SIZE(sc->tx.txq));
|
||||
ath9k_hw_releasetxqueue(ah, qnum);
|
||||
axq_qnum, ARRAY_SIZE(sc->tx.txq));
|
||||
ath9k_hw_releasetxqueue(ah, axq_qnum);
|
||||
return NULL;
|
||||
}
|
||||
if (!ATH_TXQ_SETUP(sc, qnum)) {
|
||||
struct ath_txq *txq = &sc->tx.txq[qnum];
|
||||
if (!ATH_TXQ_SETUP(sc, axq_qnum)) {
|
||||
struct ath_txq *txq = &sc->tx.txq[axq_qnum];
|
||||
|
||||
txq->axq_qnum = qnum;
|
||||
txq->axq_qnum = axq_qnum;
|
||||
txq->mac80211_qnum = -1;
|
||||
txq->axq_link = NULL;
|
||||
INIT_LIST_HEAD(&txq->axq_q);
|
||||
INIT_LIST_HEAD(&txq->axq_acq);
|
||||
|
@ -1001,14 +1003,14 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
|
|||
txq->axq_depth = 0;
|
||||
txq->axq_ampdu_depth = 0;
|
||||
txq->axq_tx_inprogress = false;
|
||||
sc->tx.txqsetup |= 1<<qnum;
|
||||
sc->tx.txqsetup |= 1<<axq_qnum;
|
||||
|
||||
txq->txq_headidx = txq->txq_tailidx = 0;
|
||||
for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
|
||||
INIT_LIST_HEAD(&txq->txq_fifo[i]);
|
||||
INIT_LIST_HEAD(&txq->txq_fifo_pending);
|
||||
}
|
||||
return &sc->tx.txq[qnum];
|
||||
return &sc->tx.txq[axq_qnum];
|
||||
}
|
||||
|
||||
int ath_txq_update(struct ath_softc *sc, int qnum,
|
||||
|
@ -1218,46 +1220,59 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
|
||||
}
|
||||
|
||||
/* For each axq_acq entry, for each tid, try to schedule packets
|
||||
* for transmit until ampdu_depth has reached min Q depth.
|
||||
*/
|
||||
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
||||
{
|
||||
struct ath_atx_ac *ac;
|
||||
struct ath_atx_tid *tid;
|
||||
struct ath_atx_ac *ac, *ac_tmp, *last_ac;
|
||||
struct ath_atx_tid *tid, *last_tid;
|
||||
|
||||
if (list_empty(&txq->axq_acq))
|
||||
if (list_empty(&txq->axq_acq) ||
|
||||
txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
|
||||
return;
|
||||
|
||||
ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
|
||||
list_del(&ac->list);
|
||||
ac->sched = false;
|
||||
last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);
|
||||
|
||||
do {
|
||||
if (list_empty(&ac->tid_q))
|
||||
return;
|
||||
list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
|
||||
last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
|
||||
list_del(&ac->list);
|
||||
ac->sched = false;
|
||||
|
||||
tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
|
||||
list_del(&tid->list);
|
||||
tid->sched = false;
|
||||
while (!list_empty(&ac->tid_q)) {
|
||||
tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
|
||||
list);
|
||||
list_del(&tid->list);
|
||||
tid->sched = false;
|
||||
|
||||
if (tid->paused)
|
||||
continue;
|
||||
if (tid->paused)
|
||||
continue;
|
||||
|
||||
ath_tx_sched_aggr(sc, txq, tid);
|
||||
ath_tx_sched_aggr(sc, txq, tid);
|
||||
|
||||
/*
|
||||
* add tid to round-robin queue if more frames
|
||||
* are pending for the tid
|
||||
*/
|
||||
if (!list_empty(&tid->buf_q))
|
||||
ath_tx_queue_tid(txq, tid);
|
||||
/*
|
||||
* add tid to round-robin queue if more frames
|
||||
* are pending for the tid
|
||||
*/
|
||||
if (!list_empty(&tid->buf_q))
|
||||
ath_tx_queue_tid(txq, tid);
|
||||
|
||||
break;
|
||||
} while (!list_empty(&ac->tid_q));
|
||||
|
||||
if (!list_empty(&ac->tid_q)) {
|
||||
if (!ac->sched) {
|
||||
ac->sched = true;
|
||||
list_add_tail(&ac->list, &txq->axq_acq);
|
||||
if (tid == last_tid ||
|
||||
txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!list_empty(&ac->tid_q)) {
|
||||
if (!ac->sched) {
|
||||
ac->sched = true;
|
||||
list_add_tail(&ac->list, &txq->axq_acq);
|
||||
}
|
||||
}
|
||||
|
||||
if (ac == last_ac ||
|
||||
txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1301,6 +1316,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
|
|||
INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
|
||||
list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
|
||||
INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
|
||||
TX_STAT_INC(txq->axq_qnum, puttxbuf);
|
||||
ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
|
||||
ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
|
||||
txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
|
||||
|
@ -1308,6 +1324,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
|
|||
list_splice_tail_init(head, &txq->axq_q);
|
||||
|
||||
if (txq->axq_link == NULL) {
|
||||
TX_STAT_INC(txq->axq_qnum, puttxbuf);
|
||||
ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
|
||||
ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
|
||||
txq->axq_qnum, ito64(bf->bf_daddr),
|
||||
|
@ -1321,6 +1338,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
|
|||
}
|
||||
ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
|
||||
&txq->axq_link);
|
||||
TX_STAT_INC(txq->axq_qnum, txstart);
|
||||
ath9k_hw_txstart(ah, txq->axq_qnum);
|
||||
}
|
||||
txq->axq_depth++;
|
||||
|
@ -1335,7 +1353,6 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
|
|||
struct list_head bf_head;
|
||||
|
||||
bf->bf_state.bf_type |= BUF_AMPDU;
|
||||
TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
|
||||
|
||||
/*
|
||||
* Do not queue to h/w when any of the following conditions is true:
|
||||
|
@ -1351,6 +1368,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
|
|||
* Add this frame to software queue for scheduling later
|
||||
* for aggregation.
|
||||
*/
|
||||
TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw);
|
||||
list_add_tail(&bf->list, &tid->buf_q);
|
||||
ath_tx_queue_tid(txctl->txq, tid);
|
||||
return;
|
||||
|
@ -1364,6 +1382,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
|
|||
ath_tx_addto_baw(sc, tid, fi->seqno);
|
||||
|
||||
/* Queue to h/w without aggregation */
|
||||
TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
|
||||
bf->bf_lastbf = bf;
|
||||
ath_buf_set_rate(sc, bf, fi->framelen);
|
||||
ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
|
||||
|
@ -1966,17 +1985,16 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
|
|||
tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
|
||||
}
|
||||
|
||||
static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
|
||||
/* Has no locking. Must hold spin_lock_bh(&txq->axq_lock)
|
||||
* before calling this.
|
||||
*/
|
||||
static void __ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
|
||||
{
|
||||
struct ath_txq *txq;
|
||||
|
||||
txq = sc->tx.txq_map[qnum];
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
|
||||
if (ath_mac80211_start_queue(sc, qnum))
|
||||
if (txq->mac80211_qnum >= 0 &&
|
||||
txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
|
||||
if (ath_mac80211_start_queue(sc, txq->mac80211_qnum))
|
||||
txq->stopped = 0;
|
||||
}
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
}
|
||||
|
||||
static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
|
@ -1999,6 +2017,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
spin_lock_bh(&txq->axq_lock);
|
||||
if (list_empty(&txq->axq_q)) {
|
||||
txq->axq_link = NULL;
|
||||
if (sc->sc_flags & SC_OP_TXAGGR)
|
||||
ath_txq_schedule(sc, txq);
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
break;
|
||||
}
|
||||
|
@ -2033,6 +2053,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
spin_unlock_bh(&txq->axq_lock);
|
||||
break;
|
||||
}
|
||||
TX_STAT_INC(txq->axq_qnum, txprocdesc);
|
||||
|
||||
/*
|
||||
* Remove ath_buf's of the same transmit unit from txq,
|
||||
|
@ -2076,10 +2097,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
else
|
||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
|
||||
|
||||
if (txq == sc->tx.txq_map[qnum])
|
||||
ath_wake_mac80211_queue(sc, qnum);
|
||||
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
__ath_wake_mac80211_queue(sc, txq);
|
||||
|
||||
if (sc->sc_flags & SC_OP_TXAGGR)
|
||||
ath_txq_schedule(sc, txq);
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
|
@ -2093,6 +2113,9 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
|
|||
struct ath_txq *txq;
|
||||
int i;
|
||||
bool needreset = false;
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
sc->tx_complete_poll_work_seen++;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
|
||||
if (ATH_TXQ_SETUP(sc, i)) {
|
||||
|
@ -2106,6 +2129,34 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
|
|||
} else {
|
||||
txq->axq_tx_inprogress = true;
|
||||
}
|
||||
} else {
|
||||
/* If the queue has pending buffers, then it
|
||||
* should be doing tx work (and have axq_depth).
|
||||
* Shouldn't get to this state I think..but
|
||||
* we do.
|
||||
*/
|
||||
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) &&
|
||||
(txq->pending_frames > 0 ||
|
||||
!list_empty(&txq->axq_acq) ||
|
||||
txq->stopped)) {
|
||||
ath_err(ath9k_hw_common(sc->sc_ah),
|
||||
"txq: %p axq_qnum: %u,"
|
||||
" mac80211_qnum: %i"
|
||||
" axq_link: %p"
|
||||
" pending frames: %i"
|
||||
" axq_acq empty: %i"
|
||||
" stopped: %i"
|
||||
" axq_depth: 0 Attempting to"
|
||||
" restart tx logic.\n",
|
||||
txq, txq->axq_qnum,
|
||||
txq->mac80211_qnum,
|
||||
txq->axq_link,
|
||||
txq->pending_frames,
|
||||
list_empty(&txq->axq_acq),
|
||||
txq->stopped);
|
||||
__ath_wake_mac80211_queue(sc, txq);
|
||||
ath_txq_schedule(sc, txq);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
}
|
||||
|
@ -2200,10 +2251,9 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
|
|||
ath_tx_complete_buf(sc, bf, txq, &bf_head,
|
||||
&txs, txok, 0);
|
||||
|
||||
if (txq == sc->tx.txq_map[qnum])
|
||||
ath_wake_mac80211_queue(sc, qnum);
|
||||
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
__ath_wake_mac80211_queue(sc, txq);
|
||||
|
||||
if (!list_empty(&txq->txq_fifo_pending)) {
|
||||
INIT_LIST_HEAD(&bf_head);
|
||||
bf = list_first_entry(&txq->txq_fifo_pending,
|
||||
|
|
|
@ -283,6 +283,7 @@ struct ar9170 {
|
|||
unsigned int mem_blocks;
|
||||
unsigned int mem_block_size;
|
||||
unsigned int rx_size;
|
||||
unsigned int tx_seq_table;
|
||||
} fw;
|
||||
|
||||
/* reset / stuck frames/queue detection */
|
||||
|
|
|
@ -150,6 +150,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
|||
const struct carl9170fw_otus_desc *otus_desc;
|
||||
const struct carl9170fw_chk_desc *chk_desc;
|
||||
const struct carl9170fw_last_desc *last_desc;
|
||||
const struct carl9170fw_txsq_desc *txsq_desc;
|
||||
|
||||
last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC,
|
||||
sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER);
|
||||
|
@ -264,6 +265,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
|||
FIF_PROMISC_IN_BSS;
|
||||
}
|
||||
|
||||
if (SUPP(CARL9170FW_WOL))
|
||||
device_set_wakeup_enable(&ar->udev->dev, true);
|
||||
|
||||
ar->fw.vif_num = otus_desc->vif_num;
|
||||
ar->fw.cmd_bufs = otus_desc->cmd_bufs;
|
||||
ar->fw.address = le32_to_cpu(otus_desc->fw_address);
|
||||
|
@ -296,6 +300,17 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC,
|
||||
sizeof(*txsq_desc), CARL9170FW_TXSQ_DESC_CUR_VER);
|
||||
|
||||
if (txsq_desc) {
|
||||
ar->fw.tx_seq_table = le32_to_cpu(txsq_desc->seq_table_addr);
|
||||
if (!valid_cpu_addr(ar->fw.tx_seq_table))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
ar->fw.tx_seq_table = 0;
|
||||
}
|
||||
|
||||
#undef SUPPORTED
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -167,6 +167,7 @@ struct carl9170_rx_filter_cmd {
|
|||
#define CARL9170_RX_FILTER_CTL_BACKR 0x20
|
||||
#define CARL9170_RX_FILTER_MGMT 0x40
|
||||
#define CARL9170_RX_FILTER_DATA 0x80
|
||||
#define CARL9170_RX_FILTER_EVERYTHING (~0)
|
||||
|
||||
struct carl9170_bcn_ctrl_cmd {
|
||||
__le32 vif_id;
|
||||
|
|
|
@ -69,6 +69,9 @@ enum carl9170fw_feature_list {
|
|||
/* Firmware RX filter | CARL9170_CMD_RX_FILTER */
|
||||
CARL9170FW_RX_FILTER,
|
||||
|
||||
/* Wake up on WLAN */
|
||||
CARL9170FW_WOL,
|
||||
|
||||
/* KEEP LAST */
|
||||
__CARL9170FW_FEATURE_NUM
|
||||
};
|
||||
|
@ -78,6 +81,7 @@ enum carl9170fw_feature_list {
|
|||
#define FIX_MAGIC "FIX\0"
|
||||
#define DBG_MAGIC "DBG\0"
|
||||
#define CHK_MAGIC "CHK\0"
|
||||
#define TXSQ_MAGIC "TXSQ"
|
||||
#define LAST_MAGIC "LAST"
|
||||
|
||||
#define CARL9170FW_SET_DAY(d) (((d) - 1) % 31)
|
||||
|
@ -88,8 +92,10 @@ enum carl9170fw_feature_list {
|
|||
#define CARL9170FW_GET_MONTH(m) ((((m) / 31) % 12) + 1)
|
||||
#define CARL9170FW_GET_YEAR(y) ((y) / 372 + 10)
|
||||
|
||||
#define CARL9170FW_MAGIC_SIZE 4
|
||||
|
||||
struct carl9170fw_desc_head {
|
||||
u8 magic[4];
|
||||
u8 magic[CARL9170FW_MAGIC_SIZE];
|
||||
__le16 length;
|
||||
u8 min_ver;
|
||||
u8 cur_ver;
|
||||
|
@ -170,6 +176,16 @@ struct carl9170fw_chk_desc {
|
|||
#define CARL9170FW_CHK_DESC_SIZE \
|
||||
(sizeof(struct carl9170fw_chk_desc))
|
||||
|
||||
#define CARL9170FW_TXSQ_DESC_MIN_VER 1
|
||||
#define CARL9170FW_TXSQ_DESC_CUR_VER 1
|
||||
struct carl9170fw_txsq_desc {
|
||||
struct carl9170fw_desc_head head;
|
||||
|
||||
__le32 seq_table_addr;
|
||||
} __packed;
|
||||
#define CARL9170FW_TXSQ_DESC_SIZE \
|
||||
(sizeof(struct carl9170fw_txsq_desc))
|
||||
|
||||
#define CARL9170FW_LAST_DESC_MIN_VER 1
|
||||
#define CARL9170FW_LAST_DESC_CUR_VER 2
|
||||
struct carl9170fw_last_desc {
|
||||
|
@ -189,8 +205,8 @@ struct carl9170fw_last_desc {
|
|||
}
|
||||
|
||||
static inline void carl9170fw_fill_desc(struct carl9170fw_desc_head *head,
|
||||
u8 magic[4], __le16 length,
|
||||
u8 min_ver, u8 cur_ver)
|
||||
u8 magic[CARL9170FW_MAGIC_SIZE],
|
||||
__le16 length, u8 min_ver, u8 cur_ver)
|
||||
{
|
||||
head->magic[0] = magic[0];
|
||||
head->magic[1] = magic[1];
|
||||
|
@ -204,7 +220,7 @@ static inline void carl9170fw_fill_desc(struct carl9170fw_desc_head *head,
|
|||
|
||||
#define carl9170fw_for_each_hdr(desc, fw_desc) \
|
||||
for (desc = fw_desc; \
|
||||
memcmp(desc->magic, LAST_MAGIC, 4) && \
|
||||
memcmp(desc->magic, LAST_MAGIC, CARL9170FW_MAGIC_SIZE) && \
|
||||
le16_to_cpu(desc->length) >= CARL9170FW_DESC_HEAD_SIZE && \
|
||||
le16_to_cpu(desc->length) < CARL9170FW_DESC_MAX_LENGTH; \
|
||||
desc = (void *)((unsigned long)desc + le16_to_cpu(desc->length)))
|
||||
|
@ -218,8 +234,8 @@ static inline bool carl9170fw_supports(__le32 list, u8 feature)
|
|||
}
|
||||
|
||||
static inline bool carl9170fw_desc_cmp(const struct carl9170fw_desc_head *head,
|
||||
const u8 descid[4], u16 min_len,
|
||||
u8 compatible_revision)
|
||||
const u8 descid[CARL9170FW_MAGIC_SIZE],
|
||||
u16 min_len, u8 compatible_revision)
|
||||
{
|
||||
if (descid[0] == head->magic[0] && descid[1] == head->magic[1] &&
|
||||
descid[2] == head->magic[2] && descid[3] == head->magic[3] &&
|
||||
|
|
|
@ -463,6 +463,8 @@
|
|||
|
||||
#define AR9170_PWR_REG_CHIP_REVISION (AR9170_PWR_REG_BASE + 0x010)
|
||||
#define AR9170_PWR_REG_PLL_ADDAC (AR9170_PWR_REG_BASE + 0x014)
|
||||
#define AR9170_PWR_PLL_ADDAC_DIV_S 2
|
||||
#define AR9170_PWR_PLL_ADDAC_DIV 0xffc
|
||||
#define AR9170_PWR_REG_WATCH_DOG_MAGIC (AR9170_PWR_REG_BASE + 0x020)
|
||||
|
||||
/* Faraday USB Controller */
|
||||
|
@ -471,6 +473,9 @@
|
|||
#define AR9170_USB_REG_MAIN_CTRL (AR9170_USB_REG_BASE + 0x000)
|
||||
#define AR9170_USB_MAIN_CTRL_REMOTE_WAKEUP BIT(0)
|
||||
#define AR9170_USB_MAIN_CTRL_ENABLE_GLOBAL_INT BIT(2)
|
||||
#define AR9170_USB_MAIN_CTRL_GO_TO_SUSPEND BIT(3)
|
||||
#define AR9170_USB_MAIN_CTRL_RESET BIT(4)
|
||||
#define AR9170_USB_MAIN_CTRL_CHIP_ENABLE BIT(5)
|
||||
#define AR9170_USB_MAIN_CTRL_HIGHSPEED BIT(6)
|
||||
|
||||
#define AR9170_USB_REG_DEVICE_ADDRESS (AR9170_USB_REG_BASE + 0x001)
|
||||
|
@ -499,6 +504,13 @@
|
|||
#define AR9170_USB_REG_INTR_GROUP (AR9170_USB_REG_BASE + 0x020)
|
||||
|
||||
#define AR9170_USB_REG_INTR_SOURCE_0 (AR9170_USB_REG_BASE + 0x021)
|
||||
#define AR9170_USB_INTR_SRC0_SETUP BIT(0)
|
||||
#define AR9170_USB_INTR_SRC0_IN BIT(1)
|
||||
#define AR9170_USB_INTR_SRC0_OUT BIT(2)
|
||||
#define AR9170_USB_INTR_SRC0_FAIL BIT(3) /* ??? */
|
||||
#define AR9170_USB_INTR_SRC0_END BIT(4) /* ??? */
|
||||
#define AR9170_USB_INTR_SRC0_ABORT BIT(7)
|
||||
|
||||
#define AR9170_USB_REG_INTR_SOURCE_1 (AR9170_USB_REG_BASE + 0x022)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_2 (AR9170_USB_REG_BASE + 0x023)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_3 (AR9170_USB_REG_BASE + 0x024)
|
||||
|
@ -506,6 +518,15 @@
|
|||
#define AR9170_USB_REG_INTR_SOURCE_5 (AR9170_USB_REG_BASE + 0x026)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_6 (AR9170_USB_REG_BASE + 0x027)
|
||||
#define AR9170_USB_REG_INTR_SOURCE_7 (AR9170_USB_REG_BASE + 0x028)
|
||||
#define AR9170_USB_INTR_SRC7_USB_RESET BIT(1)
|
||||
#define AR9170_USB_INTR_SRC7_USB_SUSPEND BIT(2)
|
||||
#define AR9170_USB_INTR_SRC7_USB_RESUME BIT(3)
|
||||
#define AR9170_USB_INTR_SRC7_ISO_SEQ_ERR BIT(4)
|
||||
#define AR9170_USB_INTR_SRC7_ISO_SEQ_ABORT BIT(5)
|
||||
#define AR9170_USB_INTR_SRC7_TX0BYTE BIT(6)
|
||||
#define AR9170_USB_INTR_SRC7_RX0BYTE BIT(7)
|
||||
|
||||
#define AR9170_USB_REG_IDLE_COUNT (AR9170_USB_REG_BASE + 0x02f)
|
||||
|
||||
#define AR9170_USB_REG_EP_MAP (AR9170_USB_REG_BASE + 0x030)
|
||||
#define AR9170_USB_REG_EP1_MAP (AR9170_USB_REG_BASE + 0x030)
|
||||
|
@ -581,6 +602,10 @@
|
|||
|
||||
#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110)
|
||||
#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114)
|
||||
|
||||
#define AR9170_USB_REG_WAKE_UP (AR9170_USB_REG_BASE + 0x120)
|
||||
#define AR9170_USB_WAKE_UP_WAKE BIT(0)
|
||||
|
||||
#define AR9170_USB_REG_CBUS_CTRL (AR9170_USB_REG_BASE + 0x1f0)
|
||||
#define AR9170_USB_CBUS_CTRL_BUFFER_END (BIT(1))
|
||||
|
||||
|
|
|
@ -662,6 +662,13 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
if (ar->fw.tx_seq_table) {
|
||||
err = carl9170_write_reg(ar, ar->fw.tx_seq_table + vif_id * 4,
|
||||
0);
|
||||
if (err)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
unlock:
|
||||
if (err && (vif_id >= 0)) {
|
||||
vif_priv->active = false;
|
||||
|
@ -1279,7 +1286,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
u16 tid, u16 *ssn, u8 buf_size)
|
||||
{
|
||||
struct ar9170 *ar = hw->priv;
|
||||
struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
|
||||
|
|
|
@ -862,6 +862,9 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
|
|||
if (unlikely(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM))
|
||||
txc->s.misc |= CARL9170_TX_SUPER_MISC_CAB;
|
||||
|
||||
if (unlikely(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
|
||||
txc->s.misc |= CARL9170_TX_SUPER_MISC_ASSIGN_SEQ;
|
||||
|
||||
if (unlikely(ieee80211_is_probe_resp(hdr->frame_control)))
|
||||
txc->s.misc |= CARL9170_TX_SUPER_MISC_FILL_IN_TSF;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __CARL9170_SHARED_VERSION_H
|
||||
#define __CARL9170_SHARED_VERSION_H
|
||||
#define CARL9170FW_VERSION_YEAR 10
|
||||
#define CARL9170FW_VERSION_MONTH 10
|
||||
#define CARL9170FW_VERSION_DAY 29
|
||||
#define CARL9170FW_VERSION_GIT "1.9.0"
|
||||
#define CARL9170FW_VERSION_YEAR 11
|
||||
#define CARL9170FW_VERSION_MONTH 1
|
||||
#define CARL9170FW_VERSION_DAY 22
|
||||
#define CARL9170FW_VERSION_GIT "1.9.2"
|
||||
#endif /* __CARL9170_SHARED_VERSION_H */
|
||||
|
|
|
@ -251,7 +251,7 @@ struct carl9170_tx_superdesc {
|
|||
u8 ampdu_commit_factor:1;
|
||||
u8 ampdu_unused_bit:1;
|
||||
u8 queue:2;
|
||||
u8 reserved:1;
|
||||
u8 assign_seq:1;
|
||||
u8 vif_id:3;
|
||||
u8 fill_in_tsf:1;
|
||||
u8 cab:1;
|
||||
|
@ -299,6 +299,7 @@ struct _ar9170_tx_hwdesc {
|
|||
|
||||
#define CARL9170_TX_SUPER_MISC_QUEUE 0x3
|
||||
#define CARL9170_TX_SUPER_MISC_QUEUE_S 0
|
||||
#define CARL9170_TX_SUPER_MISC_ASSIGN_SEQ 0x4
|
||||
#define CARL9170_TX_SUPER_MISC_VIF_ID 0x38
|
||||
#define CARL9170_TX_SUPER_MISC_VIF_ID_S 3
|
||||
#define CARL9170_TX_SUPER_MISC_FILL_IN_TSF 0x40
|
||||
|
@ -413,6 +414,23 @@ enum ar9170_txq {
|
|||
__AR9170_NUM_TXQ,
|
||||
};
|
||||
|
||||
/*
|
||||
* This is an workaround for several undocumented bugs.
|
||||
* Don't mess with the QoS/AC <-> HW Queue map, if you don't
|
||||
* know what you are doing.
|
||||
*
|
||||
* Known problems [hardware]:
|
||||
* * The MAC does not aggregate frames on anything other
|
||||
* than the first HW queue.
|
||||
* * when an AMPDU is placed [in the first hw queue] and
|
||||
* additional frames are already queued on a different
|
||||
* hw queue, the MAC will ALWAYS freeze.
|
||||
*
|
||||
* In a nutshell: The hardware can either do QoS or
|
||||
* Aggregation but not both at the same time. As a
|
||||
* result, this makes the device pretty much useless
|
||||
* for any serious 802.11n setup.
|
||||
*/
|
||||
static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 2, 1, 0, 3 };
|
||||
|
||||
#define AR9170_TXQ_DEPTH 32
|
||||
|
|
|
@ -2,6 +2,10 @@ config IWLWIFI
|
|||
tristate "Intel Wireless Wifi"
|
||||
depends on PCI && MAC80211
|
||||
select FW_LOADER
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
select LEDS_TRIGGERS
|
||||
select MAC80211_LEDS
|
||||
|
||||
menu "Debugging Options"
|
||||
depends on IWLWIFI
|
||||
|
@ -106,9 +110,27 @@ config IWL5000
|
|||
Intel WiFi Link 1000BGN
|
||||
Intel Wireless WiFi 5150AGN
|
||||
Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN
|
||||
Intel 6000 Gen 2 Series Wi-Fi Adapters (6000G2A and 6000G2B)
|
||||
Intel WIreless WiFi Link 6050BGN Gen 2 Adapter
|
||||
Intel 6005 Series Wi-Fi Adapters
|
||||
Intel 6030 Series Wi-Fi Adapters
|
||||
Intel Wireless WiFi Link 6150BGN 2 Adapter
|
||||
Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN)
|
||||
Intel 2000 Series Wi-Fi Adapters
|
||||
|
||||
config IWL_P2P
|
||||
bool "iwlwifi experimental P2P support"
|
||||
depends on IWL5000
|
||||
help
|
||||
This option enables experimental P2P support for some devices
|
||||
based on microcode support. Since P2P support is still under
|
||||
development, this option may even enable it for some devices
|
||||
now that turn out to not support it in the future due to
|
||||
microcode restrictions.
|
||||
|
||||
To determine if your microcode supports the experimental P2P
|
||||
offered by this option, check if the driver advertises AP
|
||||
support when it is loaded.
|
||||
|
||||
Say Y only if you want to experiment with P2P.
|
||||
|
||||
config IWL3945
|
||||
tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"
|
||||
|
|
|
@ -26,6 +26,7 @@ iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o iwl-agn-hcmd.o iwl-agn-ict.o
|
|||
iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
|
||||
iwlagn-$(CONFIG_IWL5000) += iwl-6000.o
|
||||
iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
|
||||
iwlagn-$(CONFIG_IWL5000) += iwl-2000.o
|
||||
|
||||
# 3945
|
||||
obj-$(CONFIG_IWL3945) += iwl3945.o
|
||||
|
|
|
@ -270,6 +270,7 @@ static struct iwl_base_params iwl1000_base_params = {
|
|||
.ucode_tracing = true,
|
||||
.sensitivity_calib_by_driver = true,
|
||||
.chain_noise_calib_by_driver = true,
|
||||
.supports_idle = true,
|
||||
};
|
||||
static struct iwl_ht_params iwl1000_ht_params = {
|
||||
.ht_greenfield_support = true,
|
||||
|
|
|
@ -0,0 +1,556 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2008 - 2010 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 LICENSE.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-sta.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-helpers.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-6000-hw.h"
|
||||
#include "iwl-agn-led.h"
|
||||
#include "iwl-agn-debugfs.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL2030_UCODE_API_MAX 5
|
||||
#define IWL2000_UCODE_API_MAX 5
|
||||
#define IWL200_UCODE_API_MAX 5
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL2030_UCODE_API_MIN 5
|
||||
#define IWL2000_UCODE_API_MIN 5
|
||||
#define IWL200_UCODE_API_MIN 5
|
||||
|
||||
#define IWL2030_FW_PRE "iwlwifi-2030-"
|
||||
#define _IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode"
|
||||
#define IWL2030_MODULE_FIRMWARE(api) _IWL2030_MODULE_FIRMWARE(api)
|
||||
|
||||
#define IWL2000_FW_PRE "iwlwifi-2000-"
|
||||
#define _IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode"
|
||||
#define IWL2000_MODULE_FIRMWARE(api) _IWL2000_MODULE_FIRMWARE(api)
|
||||
|
||||
#define IWL200_FW_PRE "iwlwifi-200-"
|
||||
#define _IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode"
|
||||
#define IWL200_MODULE_FIRMWARE(api) _IWL200_MODULE_FIRMWARE(api)
|
||||
|
||||
static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
/* want Celsius */
|
||||
priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
|
||||
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
|
||||
}
|
||||
|
||||
/* NIC configuration for 2000 series */
|
||||
static void iwl2000_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
u16 radio_cfg;
|
||||
|
||||
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
|
||||
|
||||
/* write radio config values to register */
|
||||
if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX)
|
||||
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
|
||||
EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
|
||||
EEPROM_RF_CFG_DASH_MSK(radio_cfg));
|
||||
|
||||
/* set CSR_HW_CONFIG_REG for uCode use */
|
||||
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
|
||||
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
|
||||
|
||||
}
|
||||
|
||||
static struct iwl_sensitivity_ranges iwl2000_sensitivity = {
|
||||
.min_nrg_cck = 97,
|
||||
.max_nrg_cck = 0, /* not used, set to 0 */
|
||||
.auto_corr_min_ofdm = 80,
|
||||
.auto_corr_min_ofdm_mrc = 128,
|
||||
.auto_corr_min_ofdm_x1 = 105,
|
||||
.auto_corr_min_ofdm_mrc_x1 = 192,
|
||||
|
||||
.auto_corr_max_ofdm = 145,
|
||||
.auto_corr_max_ofdm_mrc = 232,
|
||||
.auto_corr_max_ofdm_x1 = 110,
|
||||
.auto_corr_max_ofdm_mrc_x1 = 232,
|
||||
|
||||
.auto_corr_min_cck = 125,
|
||||
.auto_corr_max_cck = 175,
|
||||
.auto_corr_min_cck_mrc = 160,
|
||||
.auto_corr_max_cck_mrc = 310,
|
||||
.nrg_th_cck = 97,
|
||||
.nrg_th_ofdm = 100,
|
||||
|
||||
.barker_corr_th_min = 190,
|
||||
.barker_corr_th_min_mrc = 390,
|
||||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
|
||||
priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
|
||||
priv->cfg->base_params->num_of_queues =
|
||||
priv->cfg->mod_params->num_of_queues;
|
||||
|
||||
priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
|
||||
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
|
||||
priv->hw_params.scd_bc_tbls_size =
|
||||
priv->cfg->base_params->num_of_queues *
|
||||
sizeof(struct iwlagn_scd_bc_tbl);
|
||||
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
|
||||
priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
|
||||
priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
|
||||
|
||||
priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
|
||||
priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
|
||||
|
||||
priv->hw_params.max_bsm_size = 0;
|
||||
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
|
||||
BIT(IEEE80211_BAND_5GHZ);
|
||||
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
|
||||
|
||||
priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
|
||||
if (priv->cfg->rx_with_siso_diversity)
|
||||
priv->hw_params.rx_chains_num = 1;
|
||||
else
|
||||
priv->hw_params.rx_chains_num =
|
||||
num_of_ant(priv->cfg->valid_rx_ant);
|
||||
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
|
||||
priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
|
||||
|
||||
iwl2000_set_ct_threshold(priv);
|
||||
|
||||
/* Set initial sensitivity parameters */
|
||||
/* Set initial calibration set */
|
||||
priv->hw_params.sens = &iwl2000_sensitivity;
|
||||
priv->hw_params.calib_init_cfg =
|
||||
BIT(IWL_CALIB_XTAL) |
|
||||
BIT(IWL_CALIB_LO) |
|
||||
BIT(IWL_CALIB_TX_IQ) |
|
||||
BIT(IWL_CALIB_BASE_BAND);
|
||||
if (priv->cfg->need_dc_calib)
|
||||
priv->hw_params.calib_rt_cfg |= BIT(IWL_CALIB_CFG_DC_IDX);
|
||||
if (priv->cfg->need_temp_offset_calib)
|
||||
priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET);
|
||||
|
||||
priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl2030_hw_channel_switch(struct iwl_priv *priv,
|
||||
struct ieee80211_channel_switch *ch_switch)
|
||||
{
|
||||
/*
|
||||
* MULTI-FIXME
|
||||
* See iwl_mac_channel_switch.
|
||||
*/
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
struct iwl6000_channel_switch_cmd cmd;
|
||||
const struct iwl_channel_info *ch_info;
|
||||
u32 switch_time_in_usec, ucode_switch_time;
|
||||
u16 ch;
|
||||
u32 tsf_low;
|
||||
u8 switch_count;
|
||||
u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
|
||||
struct ieee80211_vif *vif = ctx->vif;
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = REPLY_CHANNEL_SWITCH,
|
||||
.len = sizeof(cmd),
|
||||
.flags = CMD_SYNC,
|
||||
.data = &cmd,
|
||||
};
|
||||
|
||||
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
|
||||
ch = ch_switch->channel->hw_value;
|
||||
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
cmd.channel = cpu_to_le16(ch);
|
||||
cmd.rxon_flags = ctx->staging.flags;
|
||||
cmd.rxon_filter_flags = ctx->staging.filter_flags;
|
||||
switch_count = ch_switch->count;
|
||||
tsf_low = ch_switch->timestamp & 0x0ffffffff;
|
||||
/*
|
||||
* calculate the ucode channel switch time
|
||||
* adding TSF as one of the factor for when to switch
|
||||
*/
|
||||
if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
|
||||
if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
|
||||
beacon_interval)) {
|
||||
switch_count -= (priv->ucode_beacon_time -
|
||||
tsf_low) / beacon_interval;
|
||||
} else
|
||||
switch_count = 0;
|
||||
}
|
||||
if (switch_count <= 1)
|
||||
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
|
||||
else {
|
||||
switch_time_in_usec =
|
||||
vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
|
||||
ucode_switch_time = iwl_usecs_to_beacons(priv,
|
||||
switch_time_in_usec,
|
||||
beacon_interval);
|
||||
cmd.switch_time = iwl_add_beacon_time(priv,
|
||||
priv->ucode_beacon_time,
|
||||
ucode_switch_time,
|
||||
beacon_interval);
|
||||
}
|
||||
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
|
||||
cmd.switch_time);
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, ch);
|
||||
if (ch_info)
|
||||
cmd.expect_beacon = is_channel_radar(ch_info);
|
||||
else {
|
||||
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
|
||||
ctx->active.channel, ch);
|
||||
return -EFAULT;
|
||||
}
|
||||
priv->switch_rxon.channel = cmd.channel;
|
||||
priv->switch_rxon.switch_in_progress = true;
|
||||
|
||||
return iwl_send_cmd_sync(priv, &hcmd);
|
||||
}
|
||||
|
||||
static struct iwl_lib_ops iwl2000_lib = {
|
||||
.set_hw_params = iwl2000_hw_set_hw_params,
|
||||
.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
|
||||
.txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
|
||||
.txq_set_sched = iwlagn_txq_set_sched,
|
||||
.txq_agg_enable = iwlagn_txq_agg_enable,
|
||||
.txq_agg_disable = iwlagn_txq_agg_disable,
|
||||
.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
|
||||
.txq_free_tfd = iwl_hw_txq_free_tfd,
|
||||
.txq_init = iwl_hw_tx_queue_init,
|
||||
.rx_handler_setup = iwlagn_rx_handler_setup,
|
||||
.setup_deferred_work = iwlagn_setup_deferred_work,
|
||||
.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
|
||||
.load_ucode = iwlagn_load_ucode,
|
||||
.dump_nic_event_log = iwl_dump_nic_event_log,
|
||||
.dump_nic_error_log = iwl_dump_nic_error_log,
|
||||
.dump_csr = iwl_dump_csr,
|
||||
.dump_fh = iwl_dump_fh,
|
||||
.init_alive_start = iwlagn_init_alive_start,
|
||||
.alive_notify = iwlagn_alive_notify,
|
||||
.send_tx_power = iwlagn_send_tx_power,
|
||||
.update_chain_flags = iwl_update_chain_flags,
|
||||
.set_channel_switch = iwl2030_hw_channel_switch,
|
||||
.apm_ops = {
|
||||
.init = iwl_apm_init,
|
||||
.config = iwl2000_nic_config,
|
||||
},
|
||||
.eeprom_ops = {
|
||||
.regulatory_bands = {
|
||||
EEPROM_REG_BAND_1_CHANNELS,
|
||||
EEPROM_REG_BAND_2_CHANNELS,
|
||||
EEPROM_REG_BAND_3_CHANNELS,
|
||||
EEPROM_REG_BAND_4_CHANNELS,
|
||||
EEPROM_REG_BAND_5_CHANNELS,
|
||||
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
|
||||
EEPROM_REG_BAND_52_HT40_CHANNELS
|
||||
},
|
||||
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
|
||||
.release_semaphore = iwlcore_eeprom_release_semaphore,
|
||||
.calib_version = iwlagn_eeprom_calib_version,
|
||||
.query_addr = iwlagn_eeprom_query_addr,
|
||||
.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
|
||||
},
|
||||
.isr_ops = {
|
||||
.isr = iwl_isr_ict,
|
||||
.free = iwl_free_isr_ict,
|
||||
.alloc = iwl_alloc_isr_ict,
|
||||
.reset = iwl_reset_ict,
|
||||
.disable = iwl_disable_ict,
|
||||
},
|
||||
.temp_ops = {
|
||||
.temperature = iwlagn_temperature,
|
||||
},
|
||||
.debugfs_ops = {
|
||||
.rx_stats_read = iwl_ucode_rx_stats_read,
|
||||
.tx_stats_read = iwl_ucode_tx_stats_read,
|
||||
.general_stats_read = iwl_ucode_general_stats_read,
|
||||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
.check_ack_health = iwl_good_ack_health,
|
||||
.txfifo_flush = iwlagn_txfifo_flush,
|
||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||
.tt_ops = {
|
||||
.lower_power_detection = iwl_tt_is_low_power_state,
|
||||
.tt_power_mode = iwl_tt_current_power_mode,
|
||||
.ct_kill_check = iwl_check_for_ct_kill,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct iwl_ops iwl2000_ops = {
|
||||
.lib = &iwl2000_lib,
|
||||
.hcmd = &iwlagn_hcmd,
|
||||
.utils = &iwlagn_hcmd_utils,
|
||||
.led = &iwlagn_led_ops,
|
||||
.ieee80211_ops = &iwlagn_hw_ops,
|
||||
};
|
||||
|
||||
static const struct iwl_ops iwl2030_ops = {
|
||||
.lib = &iwl2000_lib,
|
||||
.hcmd = &iwlagn_bt_hcmd,
|
||||
.utils = &iwlagn_hcmd_utils,
|
||||
.led = &iwlagn_led_ops,
|
||||
.ieee80211_ops = &iwlagn_hw_ops,
|
||||
};
|
||||
|
||||
static const struct iwl_ops iwl200_ops = {
|
||||
.lib = &iwl2000_lib,
|
||||
.hcmd = &iwlagn_hcmd,
|
||||
.utils = &iwlagn_hcmd_utils,
|
||||
.led = &iwlagn_led_ops,
|
||||
.ieee80211_ops = &iwlagn_hw_ops,
|
||||
};
|
||||
|
||||
static const struct iwl_ops iwl230_ops = {
|
||||
.lib = &iwl2000_lib,
|
||||
.hcmd = &iwlagn_bt_hcmd,
|
||||
.utils = &iwlagn_hcmd_utils,
|
||||
.led = &iwlagn_led_ops,
|
||||
.ieee80211_ops = &iwlagn_hw_ops,
|
||||
};
|
||||
|
||||
static struct iwl_base_params iwl2000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
|
||||
.pll_cfg_val = 0,
|
||||
.set_l0s = true,
|
||||
.use_bsm = false,
|
||||
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
.wd_timeout = IWL_DEF_WD_TIMEOUT,
|
||||
.max_event_log_size = 512,
|
||||
.ucode_tracing = true,
|
||||
.sensitivity_calib_by_driver = true,
|
||||
.chain_noise_calib_by_driver = true,
|
||||
.shadow_reg_enable = true,
|
||||
};
|
||||
|
||||
|
||||
static struct iwl_base_params iwl2030_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
|
||||
.pll_cfg_val = 0,
|
||||
.set_l0s = true,
|
||||
.use_bsm = false,
|
||||
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 57,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
|
||||
.chain_noise_scale = 1000,
|
||||
.wd_timeout = IWL_LONG_WD_TIMEOUT,
|
||||
.max_event_log_size = 512,
|
||||
.ucode_tracing = true,
|
||||
.sensitivity_calib_by_driver = true,
|
||||
.chain_noise_calib_by_driver = true,
|
||||
.shadow_reg_enable = true,
|
||||
};
|
||||
|
||||
static struct iwl_ht_params iwl2000_ht_params = {
|
||||
.ht_greenfield_support = true,
|
||||
.use_rts_for_aggregation = true, /* use rts/cts protection */
|
||||
};
|
||||
|
||||
static struct iwl_bt_params iwl2030_bt_params = {
|
||||
.bt_statistics = true,
|
||||
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
|
||||
.advanced_bt_coexist = true,
|
||||
.agg_time_limit = BT_AGG_THRESHOLD_DEF,
|
||||
.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
|
||||
.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
|
||||
.bt_sco_disable = true,
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_2000 \
|
||||
.fw_name_pre = IWL2000_FW_PRE, \
|
||||
.ucode_api_max = IWL2000_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL2000_UCODE_API_MIN, \
|
||||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.ops = &iwl2000_ops, \
|
||||
.mod_params = &iwlagn_mod_params, \
|
||||
.base_params = &iwl2000_base_params, \
|
||||
.need_dc_calib = true, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.led_mode = IWL_LED_RF_STATE \
|
||||
|
||||
struct iwl_cfg iwl2000_2bgn_cfg = {
|
||||
.name = "2000 Series 2x2 BGN",
|
||||
IWL_DEVICE_2000,
|
||||
.ht_params = &iwl2000_ht_params,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl2000_2bg_cfg = {
|
||||
.name = "2000 Series 2x2 BG",
|
||||
IWL_DEVICE_2000,
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_2030 \
|
||||
.fw_name_pre = IWL2030_FW_PRE, \
|
||||
.ucode_api_max = IWL2030_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL2030_UCODE_API_MIN, \
|
||||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.ops = &iwl2030_ops, \
|
||||
.mod_params = &iwlagn_mod_params, \
|
||||
.base_params = &iwl2030_base_params, \
|
||||
.bt_params = &iwl2030_bt_params, \
|
||||
.need_dc_calib = true, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.adv_pm = true \
|
||||
|
||||
struct iwl_cfg iwl2030_2bgn_cfg = {
|
||||
.name = "2000 Series 2x2 BGN/BT",
|
||||
IWL_DEVICE_2000,
|
||||
.ht_params = &iwl2000_ht_params,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl2030_2bg_cfg = {
|
||||
.name = "2000 Series 2x2 BG/BT",
|
||||
IWL_DEVICE_2000,
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_6035 \
|
||||
.fw_name_pre = IWL2030_FW_PRE, \
|
||||
.ucode_api_max = IWL2030_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL2030_UCODE_API_MIN, \
|
||||
.eeprom_ver = EEPROM_6035_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6035_TX_POWER_VERSION, \
|
||||
.ops = &iwl2030_ops, \
|
||||
.mod_params = &iwlagn_mod_params, \
|
||||
.base_params = &iwl2030_base_params, \
|
||||
.bt_params = &iwl2030_bt_params, \
|
||||
.need_dc_calib = true, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.adv_pm = true \
|
||||
|
||||
struct iwl_cfg iwl6035_2agn_cfg = {
|
||||
.name = "2000 Series 2x2 AGN/BT",
|
||||
IWL_DEVICE_6035,
|
||||
.ht_params = &iwl2000_ht_params,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl6035_2abg_cfg = {
|
||||
.name = "2000 Series 2x2 ABG/BT",
|
||||
IWL_DEVICE_6035,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl6035_2bg_cfg = {
|
||||
.name = "2000 Series 2x2 BG/BT",
|
||||
IWL_DEVICE_6035,
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_200 \
|
||||
.fw_name_pre = IWL200_FW_PRE, \
|
||||
.ucode_api_max = IWL200_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL200_UCODE_API_MIN, \
|
||||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.ops = &iwl200_ops, \
|
||||
.mod_params = &iwlagn_mod_params, \
|
||||
.base_params = &iwl2000_base_params, \
|
||||
.need_dc_calib = true, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.adv_pm = true, \
|
||||
.rx_with_siso_diversity = true \
|
||||
|
||||
struct iwl_cfg iwl200_bg_cfg = {
|
||||
.name = "200 Series 1x1 BG",
|
||||
IWL_DEVICE_200,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl200_bgn_cfg = {
|
||||
.name = "200 Series 1x1 BGN",
|
||||
IWL_DEVICE_200,
|
||||
.ht_params = &iwl2000_ht_params,
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_230 \
|
||||
.fw_name_pre = IWL200_FW_PRE, \
|
||||
.ucode_api_max = IWL200_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL200_UCODE_API_MIN, \
|
||||
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.ops = &iwl230_ops, \
|
||||
.mod_params = &iwlagn_mod_params, \
|
||||
.base_params = &iwl2030_base_params, \
|
||||
.bt_params = &iwl2030_bt_params, \
|
||||
.need_dc_calib = true, \
|
||||
.need_temp_offset_calib = true, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.adv_pm = true, \
|
||||
.rx_with_siso_diversity = true \
|
||||
|
||||
struct iwl_cfg iwl230_bg_cfg = {
|
||||
.name = "200 Series 1x1 BG/BT",
|
||||
IWL_DEVICE_230,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl230_bgn_cfg = {
|
||||
.name = "200 Series 1x1 BGN/BT",
|
||||
IWL_DEVICE_230,
|
||||
.ht_params = &iwl2000_ht_params,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL200_MODULE_FIRMWARE(IWL200_UCODE_API_MAX));
|
|
@ -59,33 +59,6 @@ static int iwl3945_send_led_cmd(struct iwl_priv *priv,
|
|||
return iwl_send_cmd(priv, &cmd);
|
||||
}
|
||||
|
||||
/* Set led on command */
|
||||
static int iwl3945_led_on(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_led_cmd led_cmd = {
|
||||
.id = IWL_LED_LINK,
|
||||
.on = IWL_LED_SOLID,
|
||||
.off = 0,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
return iwl3945_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
/* Set led off command */
|
||||
static int iwl3945_led_off(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_led_cmd led_cmd = {
|
||||
.id = IWL_LED_LINK,
|
||||
.on = 0,
|
||||
.off = 0,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
IWL_DEBUG_LED(priv, "led off\n");
|
||||
return iwl3945_send_led_cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
const struct iwl_led_ops iwl3945_led_ops = {
|
||||
.cmd = iwl3945_send_led_cmd,
|
||||
.on = iwl3945_led_on,
|
||||
.off = iwl3945_led_off,
|
||||
};
|
||||
|
|
|
@ -594,10 +594,11 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
|
|||
|
||||
rx_status.flag = 0;
|
||||
rx_status.mactime = le64_to_cpu(rx_end->timestamp);
|
||||
rx_status.freq =
|
||||
ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel));
|
||||
rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
|
||||
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
|
||||
rx_status.freq =
|
||||
ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel),
|
||||
rx_status.band);
|
||||
|
||||
rx_status.rate_idx = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate);
|
||||
if (rx_status.band == IEEE80211_BAND_5GHZ)
|
||||
|
|
|
@ -2316,6 +2316,11 @@ static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
|
|||
priv->rx_handlers[REPLY_RX] = iwlagn_rx_reply_rx;
|
||||
/* Tx response */
|
||||
priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
|
||||
|
||||
/* set up notification wait support */
|
||||
spin_lock_init(&priv->_agn.notif_wait_lock);
|
||||
INIT_LIST_HEAD(&priv->_agn.notif_waits);
|
||||
init_waitqueue_head(&priv->_agn.notif_waitq);
|
||||
}
|
||||
|
||||
static void iwl4965_setup_deferred_work(struct iwl_priv *priv)
|
||||
|
|
|
@ -67,13 +67,13 @@
|
|||
#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
|
||||
#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
|
||||
|
||||
#define IWL6000G2A_FW_PRE "iwlwifi-6000g2a-"
|
||||
#define _IWL6000G2A_MODULE_FIRMWARE(api) IWL6000G2A_FW_PRE #api ".ucode"
|
||||
#define IWL6000G2A_MODULE_FIRMWARE(api) _IWL6000G2A_MODULE_FIRMWARE(api)
|
||||
#define IWL6005_FW_PRE "iwlwifi-6000g2a-"
|
||||
#define _IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode"
|
||||
#define IWL6005_MODULE_FIRMWARE(api) _IWL6005_MODULE_FIRMWARE(api)
|
||||
|
||||
#define IWL6000G2B_FW_PRE "iwlwifi-6000g2b-"
|
||||
#define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode"
|
||||
#define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api)
|
||||
#define IWL6030_FW_PRE "iwlwifi-6000g2b-"
|
||||
#define _IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode"
|
||||
#define IWL6030_MODULE_FIRMWARE(api) _IWL6030_MODULE_FIRMWARE(api)
|
||||
|
||||
static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
|
||||
{
|
||||
|
@ -90,7 +90,7 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv)
|
|||
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
|
||||
}
|
||||
|
||||
static void iwl6050g2_additional_nic_config(struct iwl_priv *priv)
|
||||
static void iwl6150_additional_nic_config(struct iwl_priv *priv)
|
||||
{
|
||||
/* Indicate calibration version to uCode. */
|
||||
if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
|
||||
|
@ -354,7 +354,7 @@ static struct iwl_lib_ops iwl6000_lib = {
|
|||
}
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl6000g2b_lib = {
|
||||
static struct iwl_lib_ops iwl6030_lib = {
|
||||
.set_hw_params = iwl6000_hw_set_hw_params,
|
||||
.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
|
||||
.txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
|
||||
|
@ -430,8 +430,8 @@ static struct iwl_nic_ops iwl6050_nic_ops = {
|
|||
.additional_nic_config = &iwl6050_additional_nic_config,
|
||||
};
|
||||
|
||||
static struct iwl_nic_ops iwl6050g2_nic_ops = {
|
||||
.additional_nic_config = &iwl6050g2_additional_nic_config,
|
||||
static struct iwl_nic_ops iwl6150_nic_ops = {
|
||||
.additional_nic_config = &iwl6150_additional_nic_config,
|
||||
};
|
||||
|
||||
static const struct iwl_ops iwl6000_ops = {
|
||||
|
@ -451,17 +451,17 @@ static const struct iwl_ops iwl6050_ops = {
|
|||
.ieee80211_ops = &iwlagn_hw_ops,
|
||||
};
|
||||
|
||||
static const struct iwl_ops iwl6050g2_ops = {
|
||||
static const struct iwl_ops iwl6150_ops = {
|
||||
.lib = &iwl6000_lib,
|
||||
.hcmd = &iwlagn_hcmd,
|
||||
.utils = &iwlagn_hcmd_utils,
|
||||
.led = &iwlagn_led_ops,
|
||||
.nic = &iwl6050g2_nic_ops,
|
||||
.nic = &iwl6150_nic_ops,
|
||||
.ieee80211_ops = &iwlagn_hw_ops,
|
||||
};
|
||||
|
||||
static const struct iwl_ops iwl6000g2b_ops = {
|
||||
.lib = &iwl6000g2b_lib,
|
||||
static const struct iwl_ops iwl6030_ops = {
|
||||
.lib = &iwl6030_lib,
|
||||
.hcmd = &iwlagn_bt_hcmd,
|
||||
.utils = &iwlagn_hcmd_utils,
|
||||
.led = &iwlagn_led_ops,
|
||||
|
@ -555,11 +555,11 @@ static struct iwl_bt_params iwl6000_bt_params = {
|
|||
};
|
||||
|
||||
#define IWL_DEVICE_6005 \
|
||||
.fw_name_pre = IWL6000G2A_FW_PRE, \
|
||||
.fw_name_pre = IWL6005_FW_PRE, \
|
||||
.ucode_api_max = IWL6000G2_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL6000G2_UCODE_API_MIN, \
|
||||
.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, \
|
||||
.eeprom_ver = EEPROM_6005_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \
|
||||
.ops = &iwl6000_ops, \
|
||||
.mod_params = &iwlagn_mod_params, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
|
@ -584,12 +584,12 @@ struct iwl_cfg iwl6005_2bg_cfg = {
|
|||
};
|
||||
|
||||
#define IWL_DEVICE_6030 \
|
||||
.fw_name_pre = IWL6000G2B_FW_PRE, \
|
||||
.fw_name_pre = IWL6030_FW_PRE, \
|
||||
.ucode_api_max = IWL6000G2_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL6000G2_UCODE_API_MIN, \
|
||||
.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, \
|
||||
.ops = &iwl6000g2b_ops, \
|
||||
.eeprom_ver = EEPROM_6030_EEPROM_VERSION, \
|
||||
.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
|
||||
.ops = &iwl6030_ops, \
|
||||
.mod_params = &iwlagn_mod_params, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
.bt_params = &iwl6000_bt_params, \
|
||||
|
@ -706,9 +706,9 @@ struct iwl_cfg iwl6150_bgn_cfg = {
|
|||
.fw_name_pre = IWL6050_FW_PRE,
|
||||
.ucode_api_max = IWL6050_UCODE_API_MAX,
|
||||
.ucode_api_min = IWL6050_UCODE_API_MIN,
|
||||
.eeprom_ver = EEPROM_6050G2_EEPROM_VERSION,
|
||||
.eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION,
|
||||
.ops = &iwl6050g2_ops,
|
||||
.eeprom_ver = EEPROM_6150_EEPROM_VERSION,
|
||||
.eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,
|
||||
.ops = &iwl6150_ops,
|
||||
.mod_params = &iwlagn_mod_params,
|
||||
.base_params = &iwl6050_base_params,
|
||||
.ht_params = &iwl6000_ht_params,
|
||||
|
@ -734,5 +734,5 @@ struct iwl_cfg iwl6000_3agn_cfg = {
|
|||
|
||||
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
|
||||
MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
|
||||
|
|
|
@ -305,7 +305,11 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
|
|||
cmd.slots[0].type = 0; /* BSS */
|
||||
cmd.slots[1].type = 1; /* PAN */
|
||||
|
||||
if (ctx_bss->vif && ctx_pan->vif) {
|
||||
if (priv->_agn.hw_roc_channel) {
|
||||
/* both contexts must be used for this to happen */
|
||||
slot1 = priv->_agn.hw_roc_duration;
|
||||
slot0 = IWL_MIN_SLOT_TIME;
|
||||
} else if (ctx_bss->vif && ctx_pan->vif) {
|
||||
int bcnint = ctx_pan->vif->bss_conf.beacon_int;
|
||||
int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
|
||||
|
||||
|
@ -330,12 +334,12 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
|
|||
if (test_bit(STATUS_SCAN_HW, &priv->status) ||
|
||||
(!ctx_bss->vif->bss_conf.idle &&
|
||||
!ctx_bss->vif->bss_conf.assoc)) {
|
||||
slot0 = dtim * bcnint * 3 - 20;
|
||||
slot1 = 20;
|
||||
slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
|
||||
slot1 = IWL_MIN_SLOT_TIME;
|
||||
} else if (!ctx_pan->vif->bss_conf.idle &&
|
||||
!ctx_pan->vif->bss_conf.assoc) {
|
||||
slot1 = bcnint * 3 - 20;
|
||||
slot0 = 20;
|
||||
slot1 = bcnint * 3 - IWL_MIN_SLOT_TIME;
|
||||
slot0 = IWL_MIN_SLOT_TIME;
|
||||
}
|
||||
} else if (ctx_pan->vif) {
|
||||
slot0 = 0;
|
||||
|
@ -344,8 +348,8 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
|
|||
slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
|
||||
|
||||
if (test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
slot0 = slot1 * 3 - 20;
|
||||
slot1 = 20;
|
||||
slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME;
|
||||
slot1 = IWL_MIN_SLOT_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,23 +63,11 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
|
|||
}
|
||||
|
||||
/* Set led register off */
|
||||
static int iwl_led_on_reg(struct iwl_priv *priv)
|
||||
void iwlagn_led_enable(struct iwl_priv *priv)
|
||||
{
|
||||
IWL_DEBUG_LED(priv, "led on\n");
|
||||
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set led register off */
|
||||
static int iwl_led_off_reg(struct iwl_priv *priv)
|
||||
{
|
||||
IWL_DEBUG_LED(priv, "LED Reg off\n");
|
||||
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct iwl_led_ops iwlagn_led_ops = {
|
||||
.cmd = iwl_send_led_cmd,
|
||||
.on = iwl_led_on_reg,
|
||||
.off = iwl_led_off_reg,
|
||||
};
|
||||
|
|
|
@ -28,5 +28,6 @@
|
|||
#define __iwl_agn_led_h__
|
||||
|
||||
extern const struct iwl_led_ops iwlagn_led_ops;
|
||||
void iwlagn_led_enable(struct iwl_priv *priv);
|
||||
|
||||
#endif /* __iwl_agn_led_h__ */
|
||||
|
|
|
@ -473,6 +473,11 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
|
|||
priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
|
||||
iwlagn_rx_calib_complete;
|
||||
priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
|
||||
|
||||
/* set up notification wait support */
|
||||
spin_lock_init(&priv->_agn.notif_wait_lock);
|
||||
INIT_LIST_HEAD(&priv->_agn.notif_waits);
|
||||
init_waitqueue_head(&priv->_agn.notif_waitq);
|
||||
}
|
||||
|
||||
void iwlagn_setup_deferred_work(struct iwl_priv *priv)
|
||||
|
@ -1157,10 +1162,11 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv,
|
|||
|
||||
/* rx_status carries information about the packet to mac80211 */
|
||||
rx_status.mactime = le64_to_cpu(phy_res->timestamp);
|
||||
rx_status.freq =
|
||||
ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel));
|
||||
rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
|
||||
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
|
||||
rx_status.freq =
|
||||
ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel),
|
||||
rx_status.band);
|
||||
rx_status.rate_idx =
|
||||
iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
|
||||
rx_status.flag = 0;
|
||||
|
@ -2389,3 +2395,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* notification wait support */
|
||||
void iwlagn_init_notification_wait(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
void (*fn)(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt),
|
||||
u8 cmd)
|
||||
{
|
||||
wait_entry->fn = fn;
|
||||
wait_entry->cmd = cmd;
|
||||
wait_entry->triggered = false;
|
||||
|
||||
spin_lock_bh(&priv->_agn.notif_wait_lock);
|
||||
list_add(&wait_entry->list, &priv->_agn.notif_waits);
|
||||
spin_unlock_bh(&priv->_agn.notif_wait_lock);
|
||||
}
|
||||
|
||||
signed long iwlagn_wait_notification(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
unsigned long timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wait_event_timeout(priv->_agn.notif_waitq,
|
||||
&wait_entry->triggered,
|
||||
timeout);
|
||||
|
||||
spin_lock_bh(&priv->_agn.notif_wait_lock);
|
||||
list_del(&wait_entry->list);
|
||||
spin_unlock_bh(&priv->_agn.notif_wait_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwlagn_remove_notification(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry)
|
||||
{
|
||||
spin_lock_bh(&priv->_agn.notif_wait_lock);
|
||||
list_del(&wait_entry->list);
|
||||
spin_unlock_bh(&priv->_agn.notif_wait_lock);
|
||||
}
|
||||
|
|
|
@ -52,10 +52,14 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
|
|||
struct iwl_rxon_context *ctx,
|
||||
struct iwl_rxon_cmd *send)
|
||||
{
|
||||
struct iwl_notification_wait disable_wait;
|
||||
__le32 old_filter = send->filter_flags;
|
||||
u8 old_dev_type = send->dev_type;
|
||||
int ret;
|
||||
|
||||
iwlagn_init_notification_wait(priv, &disable_wait, NULL,
|
||||
REPLY_WIPAN_DEACTIVATION_COMPLETE);
|
||||
|
||||
send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||
send->dev_type = RXON_DEV_TYPE_P2P;
|
||||
ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
|
||||
|
@ -63,11 +67,18 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
|
|||
send->filter_flags = old_filter;
|
||||
send->dev_type = old_dev_type;
|
||||
|
||||
if (ret)
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
|
||||
iwlagn_remove_notification(priv, &disable_wait);
|
||||
} else {
|
||||
signed long wait_res;
|
||||
|
||||
/* FIXME: WAIT FOR PAN DISABLE */
|
||||
msleep(300);
|
||||
wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ);
|
||||
if (wait_res == 0) {
|
||||
IWL_ERR(priv, "Timed out waiting for PAN disable\n");
|
||||
ret = -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -145,6 +156,23 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
/* always get timestamp with Rx frame */
|
||||
ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
|
||||
|
||||
if (ctx->ctxid == IWL_RXON_CTX_PAN && priv->_agn.hw_roc_channel) {
|
||||
struct ieee80211_channel *chan = priv->_agn.hw_roc_channel;
|
||||
|
||||
iwl_set_rxon_channel(priv, chan, ctx);
|
||||
iwl_set_flags_for_band(priv, ctx, chan->band, NULL);
|
||||
ctx->staging.filter_flags |=
|
||||
RXON_FILTER_ASSOC_MSK |
|
||||
RXON_FILTER_PROMISC_MSK |
|
||||
RXON_FILTER_CTL2HOST_MSK;
|
||||
ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
|
||||
new_assoc = true;
|
||||
|
||||
if (memcmp(&ctx->staging, &ctx->active,
|
||||
sizeof(ctx->staging)) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
|
||||
!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
|
||||
ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
|
||||
|
@ -546,12 +574,10 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
|
|||
|
||||
if (changes & BSS_CHANGED_ASSOC) {
|
||||
if (bss_conf->assoc) {
|
||||
iwl_led_associate(priv);
|
||||
priv->timestamp = bss_conf->timestamp;
|
||||
ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
|
||||
} else {
|
||||
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||
iwl_led_disassociate(priv);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -539,7 +539,14 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
unsigned long flags;
|
||||
bool is_agg = false;
|
||||
|
||||
if (info->control.vif)
|
||||
/*
|
||||
* If the frame needs to go out off-channel, then
|
||||
* we'll have put the PAN context to that channel,
|
||||
* so make the frame go out there.
|
||||
*/
|
||||
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
|
||||
ctx = &priv->contexts[IWL_RXON_CTX_PAN];
|
||||
else if (info->control.vif)
|
||||
ctx = iwl_rxon_ctx_from_vif(info->control.vif);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "iwl-sta.h"
|
||||
#include "iwl-agn-calib.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-agn-led.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -846,7 +847,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
|
|||
* the appropriate handlers, including command responses,
|
||||
* frame-received notifications, and other notifications.
|
||||
*/
|
||||
void iwl_rx_handle(struct iwl_priv *priv)
|
||||
static void iwl_rx_handle(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_rx_mem_buffer *rxb;
|
||||
struct iwl_rx_packet *pkt;
|
||||
|
@ -910,6 +911,27 @@ void iwl_rx_handle(struct iwl_priv *priv)
|
|||
(pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
|
||||
(pkt->hdr.cmd != REPLY_TX);
|
||||
|
||||
/*
|
||||
* Do the notification wait before RX handlers so
|
||||
* even if the RX handler consumes the RXB we have
|
||||
* access to it in the notification wait entry.
|
||||
*/
|
||||
if (!list_empty(&priv->_agn.notif_waits)) {
|
||||
struct iwl_notification_wait *w;
|
||||
|
||||
spin_lock(&priv->_agn.notif_wait_lock);
|
||||
list_for_each_entry(w, &priv->_agn.notif_waits, list) {
|
||||
if (w->cmd == pkt->hdr.cmd) {
|
||||
w->triggered = true;
|
||||
if (w->fn)
|
||||
w->fn(priv, pkt);
|
||||
}
|
||||
}
|
||||
spin_unlock(&priv->_agn.notif_wait_lock);
|
||||
|
||||
wake_up_all(&priv->_agn.notif_waitq);
|
||||
}
|
||||
|
||||
/* Based on type of command response or notification,
|
||||
* handle those that need handling via function in
|
||||
* rx_handlers table. See iwl_setup_rx_handlers() */
|
||||
|
@ -2720,8 +2742,6 @@ static void iwl_alive_start(struct iwl_priv *priv)
|
|||
/* At this point, the NIC is initialized and operational */
|
||||
iwl_rf_kill_ct_config(priv);
|
||||
|
||||
iwl_leds_init(priv);
|
||||
|
||||
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
|
||||
|
@ -3188,6 +3208,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
|
|||
hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
|
||||
}
|
||||
|
||||
hw->wiphy->max_remain_on_channel_duration = 1000;
|
||||
|
||||
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
|
||||
WIPHY_FLAG_DISABLE_BEACON_HINTS;
|
||||
|
||||
|
@ -3213,6 +3235,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
|
|||
priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
|
||||
&priv->bands[IEEE80211_BAND_5GHZ];
|
||||
|
||||
iwl_leds_init(priv);
|
||||
|
||||
ret = ieee80211_register_hw(priv->hw);
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
|
||||
|
@ -3257,7 +3281,7 @@ int iwlagn_mac_start(struct ieee80211_hw *hw)
|
|||
}
|
||||
}
|
||||
|
||||
iwl_led_start(priv);
|
||||
iwlagn_led_enable(priv);
|
||||
|
||||
out:
|
||||
priv->is_open = 1;
|
||||
|
@ -3393,7 +3417,8 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
int ret = -EINVAL;
|
||||
|
@ -3703,6 +3728,95 @@ void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
|
|||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
}
|
||||
|
||||
static void iwlagn_disable_roc(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
|
||||
struct ieee80211_channel *chan = ACCESS_ONCE(priv->hw->conf.channel);
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (!ctx->is_active)
|
||||
return;
|
||||
|
||||
ctx->staging.dev_type = RXON_DEV_TYPE_2STA;
|
||||
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||
iwl_set_rxon_channel(priv, chan, ctx);
|
||||
iwl_set_flags_for_band(priv, ctx, chan->band, NULL);
|
||||
|
||||
priv->_agn.hw_roc_channel = NULL;
|
||||
|
||||
iwlagn_commit_rxon(priv, ctx);
|
||||
|
||||
ctx->is_active = false;
|
||||
}
|
||||
|
||||
static void iwlagn_bg_roc_done(struct work_struct *work)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(work, struct iwl_priv,
|
||||
_agn.hw_roc_work.work);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
ieee80211_remain_on_channel_expired(priv->hw);
|
||||
iwlagn_disable_roc(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
|
||||
struct ieee80211_channel *channel,
|
||||
enum nl80211_channel_type channel_type,
|
||||
int duration)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
int err = 0;
|
||||
|
||||
if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes &
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (priv->contexts[IWL_RXON_CTX_PAN].is_active ||
|
||||
test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
priv->contexts[IWL_RXON_CTX_PAN].is_active = true;
|
||||
priv->_agn.hw_roc_channel = channel;
|
||||
priv->_agn.hw_roc_chantype = channel_type;
|
||||
priv->_agn.hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024);
|
||||
iwlagn_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]);
|
||||
queue_delayed_work(priv->workqueue, &priv->_agn.hw_roc_work,
|
||||
msecs_to_jiffies(duration + 20));
|
||||
|
||||
msleep(IWL_MIN_SLOT_TIME); /* TU is almost ms */
|
||||
ieee80211_ready_on_channel(priv->hw);
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
|
||||
if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
cancel_delayed_work_sync(&priv->_agn.hw_roc_work);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
iwlagn_disable_roc(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* driver setup and teardown
|
||||
|
@ -3724,6 +3838,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
|||
INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
|
||||
INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
|
||||
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
|
||||
INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done);
|
||||
|
||||
iwl_setup_scan_deferred_work(priv);
|
||||
|
||||
|
@ -3892,6 +4007,8 @@ struct ieee80211_ops iwlagn_hw_ops = {
|
|||
.channel_switch = iwlagn_mac_channel_switch,
|
||||
.flush = iwlagn_mac_flush,
|
||||
.tx_last_beacon = iwl_mac_tx_last_beacon,
|
||||
.remain_on_channel = iwl_mac_remain_on_channel,
|
||||
.cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -4019,6 +4136,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
|
||||
priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
|
||||
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
|
||||
#ifdef CONFIG_IWL_P2P
|
||||
priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
|
||||
#endif
|
||||
priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
|
||||
priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
|
||||
priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
|
||||
|
@ -4266,6 +4387,9 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
|
|||
* we need to set STATUS_EXIT_PENDING bit.
|
||||
*/
|
||||
set_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
|
||||
iwl_leds_exit(priv);
|
||||
|
||||
if (priv->mac80211_registered) {
|
||||
ieee80211_unregister_hw(priv->hw);
|
||||
priv->mac80211_registered = 0;
|
||||
|
@ -4486,6 +4610,49 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
|
|||
{IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)},
|
||||
|
||||
/* 2x00 Series */
|
||||
{IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)},
|
||||
|
||||
/* 2x30 Series */
|
||||
{IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0887, 0x4066, iwl2030_2bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0888, 0x4266, iwl2030_2bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0887, 0x4466, iwl2030_2bg_cfg)},
|
||||
|
||||
/* 6x35 Series */
|
||||
{IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x088E, 0x4064, iwl6035_2abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x088F, 0x4264, iwl6035_2abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x088E, 0x4464, iwl6035_2abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x088E, 0x4066, iwl6035_2bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)},
|
||||
|
||||
/* 200 Series */
|
||||
{IWL_PCI_DEVICE(0x0894, 0x0022, iwl200_bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0895, 0x0222, iwl200_bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0894, 0x0422, iwl200_bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0894, 0x0026, iwl200_bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0895, 0x0226, iwl200_bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0894, 0x0426, iwl200_bg_cfg)},
|
||||
|
||||
/* 230 Series */
|
||||
{IWL_PCI_DEVICE(0x0892, 0x0062, iwl230_bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0893, 0x0262, iwl230_bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0892, 0x0462, iwl230_bgn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0892, 0x0066, iwl230_bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)},
|
||||
|
||||
#endif /* CONFIG_IWL5000 */
|
||||
|
||||
{0}
|
||||
|
|
|
@ -96,6 +96,17 @@ extern struct iwl_cfg iwl100_bgn_cfg;
|
|||
extern struct iwl_cfg iwl100_bg_cfg;
|
||||
extern struct iwl_cfg iwl130_bgn_cfg;
|
||||
extern struct iwl_cfg iwl130_bg_cfg;
|
||||
extern struct iwl_cfg iwl2000_2bgn_cfg;
|
||||
extern struct iwl_cfg iwl2000_2bg_cfg;
|
||||
extern struct iwl_cfg iwl2030_2bgn_cfg;
|
||||
extern struct iwl_cfg iwl2030_2bg_cfg;
|
||||
extern struct iwl_cfg iwl6035_2agn_cfg;
|
||||
extern struct iwl_cfg iwl6035_2abg_cfg;
|
||||
extern struct iwl_cfg iwl6035_2bg_cfg;
|
||||
extern struct iwl_cfg iwl200_bg_cfg;
|
||||
extern struct iwl_cfg iwl200_bgn_cfg;
|
||||
extern struct iwl_cfg iwl230_bg_cfg;
|
||||
extern struct iwl_cfg iwl230_bgn_cfg;
|
||||
|
||||
extern struct iwl_mod_params iwlagn_mod_params;
|
||||
extern struct iwl_hcmd_ops iwlagn_hcmd;
|
||||
|
@ -185,7 +196,6 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv,
|
|||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl_rx_handle(struct iwl_priv *priv);
|
||||
|
||||
/* tx */
|
||||
void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
|
||||
|
@ -330,6 +340,21 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
|
|||
int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
|
||||
void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
|
||||
|
||||
/* notification wait support */
|
||||
void __acquires(wait_entry)
|
||||
iwlagn_init_notification_wait(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
void (*fn)(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt),
|
||||
u8 cmd);
|
||||
signed long __releases(wait_entry)
|
||||
iwlagn_wait_notification(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
unsigned long timeout);
|
||||
void __releases(wait_entry)
|
||||
iwlagn_remove_notification(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry);
|
||||
|
||||
/* mac80211 handlers (for 4965) */
|
||||
int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
int iwlagn_mac_start(struct ieee80211_hw *hw);
|
||||
|
@ -349,7 +374,8 @@ void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
|
|||
int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size);
|
||||
int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
|
|
|
@ -189,6 +189,7 @@ enum {
|
|||
REPLY_WIPAN_WEPKEY = 0xb8, /* use REPLY_WEPKEY structure */
|
||||
REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9,
|
||||
REPLY_WIPAN_NOA_NOTIFICATION = 0xbc,
|
||||
REPLY_WIPAN_DEACTIVATION_COMPLETE = 0xbd,
|
||||
|
||||
REPLY_MAX = 0xff
|
||||
};
|
||||
|
@ -4369,6 +4370,11 @@ int iwl_agn_check_rxon_cmd(struct iwl_priv *priv);
|
|||
* REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minimum slot time in TU
|
||||
*/
|
||||
#define IWL_MIN_SLOT_TIME 20
|
||||
|
||||
/**
|
||||
* struct iwl_wipan_slot
|
||||
* @width: Time in TU
|
||||
|
|
|
@ -227,7 +227,8 @@ int iwlcore_init_geos(struct iwl_priv *priv)
|
|||
geo_ch = &sband->channels[sband->n_channels++];
|
||||
|
||||
geo_ch->center_freq =
|
||||
ieee80211_channel_to_frequency(ch->channel);
|
||||
ieee80211_channel_to_frequency(ch->channel,
|
||||
sband->band);
|
||||
geo_ch->max_power = ch->max_power_avg;
|
||||
geo_ch->max_antenna_gain = 0xff;
|
||||
geo_ch->hw_value = ch->channel;
|
||||
|
@ -1403,9 +1404,10 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
|
||||
struct iwl_rxon_context *tmp, *ctx = NULL;
|
||||
int err;
|
||||
enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
|
||||
vif->type, vif->addr);
|
||||
viftype, vif->addr);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
|
@ -1429,7 +1431,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!(possible_modes & BIT(vif->type)))
|
||||
if (!(possible_modes & BIT(viftype)))
|
||||
continue;
|
||||
|
||||
/* have maybe usable context w/o interface */
|
||||
|
@ -1675,7 +1677,6 @@ void iwl_clear_traffic_stats(struct iwl_priv *priv)
|
|||
{
|
||||
memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
|
||||
memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
|
||||
priv->led_tpt = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1768,7 +1769,6 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
|
|||
stats->data_cnt++;
|
||||
stats->data_bytes += len;
|
||||
}
|
||||
iwl_leds_background(priv);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_update_stats);
|
||||
#endif
|
||||
|
|
|
@ -227,8 +227,6 @@ struct iwl_lib_ops {
|
|||
|
||||
struct iwl_led_ops {
|
||||
int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd);
|
||||
int (*on)(struct iwl_priv *priv);
|
||||
int (*off)(struct iwl_priv *priv);
|
||||
};
|
||||
|
||||
/* NIC specific ops */
|
||||
|
@ -494,18 +492,6 @@ static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
|
|||
static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
|
||||
__le16 fc, u16 len)
|
||||
{
|
||||
struct traffic_stats *stats;
|
||||
|
||||
if (is_tx)
|
||||
stats = &priv->tx_stats;
|
||||
else
|
||||
stats = &priv->rx_stats;
|
||||
|
||||
if (ieee80211_is_data(fc)) {
|
||||
/* data */
|
||||
stats->data_bytes += len;
|
||||
}
|
||||
iwl_leds_background(priv);
|
||||
}
|
||||
#endif
|
||||
/*****************************************************
|
||||
|
|
|
@ -290,7 +290,7 @@
|
|||
|
||||
|
||||
/* HW REV */
|
||||
#define CSR_HW_REV_TYPE_MSK (0x00000F0)
|
||||
#define CSR_HW_REV_TYPE_MSK (0x00001F0)
|
||||
#define CSR_HW_REV_TYPE_3945 (0x00000D0)
|
||||
#define CSR_HW_REV_TYPE_4965 (0x0000000)
|
||||
#define CSR_HW_REV_TYPE_5300 (0x0000020)
|
||||
|
@ -300,9 +300,15 @@
|
|||
#define CSR_HW_REV_TYPE_1000 (0x0000060)
|
||||
#define CSR_HW_REV_TYPE_6x00 (0x0000070)
|
||||
#define CSR_HW_REV_TYPE_6x50 (0x0000080)
|
||||
#define CSR_HW_REV_TYPE_6x50g2 (0x0000084)
|
||||
#define CSR_HW_REV_TYPE_6x00g2 (0x00000B0)
|
||||
#define CSR_HW_REV_TYPE_NONE (0x00000F0)
|
||||
#define CSR_HW_REV_TYPE_6150 (0x0000084)
|
||||
#define CSR_HW_REV_TYPE_6x05 (0x00000B0)
|
||||
#define CSR_HW_REV_TYPE_6x30 CSR_HW_REV_TYPE_6x05
|
||||
#define CSR_HW_REV_TYPE_6x35 CSR_HW_REV_TYPE_6x05
|
||||
#define CSR_HW_REV_TYPE_2x30 (0x00000C0)
|
||||
#define CSR_HW_REV_TYPE_2x00 (0x0000100)
|
||||
#define CSR_HW_REV_TYPE_200 (0x0000110)
|
||||
#define CSR_HW_REV_TYPE_230 (0x0000120)
|
||||
#define CSR_HW_REV_TYPE_NONE (0x00001F0)
|
||||
|
||||
/* EEPROM REG */
|
||||
#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
|
||||
|
|
|
@ -207,18 +207,19 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define BYTE1_MASK 0x000000ff;
|
||||
#define BYTE2_MASK 0x0000ffff;
|
||||
#define BYTE3_MASK 0x00ffffff;
|
||||
static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
u32 val;
|
||||
u32 val = 0;
|
||||
char *buf;
|
||||
ssize_t ret;
|
||||
int i;
|
||||
int i = 0;
|
||||
bool device_format = false;
|
||||
int offset = 0;
|
||||
int len = 0;
|
||||
int pos = 0;
|
||||
int sram;
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
size_t bufsz;
|
||||
|
||||
|
@ -230,35 +231,62 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
|||
else
|
||||
priv->dbgfs_sram_len = priv->ucode_data.len;
|
||||
}
|
||||
bufsz = 30 + priv->dbgfs_sram_len * sizeof(char) * 10;
|
||||
len = priv->dbgfs_sram_len;
|
||||
|
||||
if (len == -4) {
|
||||
device_format = true;
|
||||
len = 4;
|
||||
}
|
||||
|
||||
bufsz = 50 + len * 4;
|
||||
buf = kmalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
|
||||
priv->dbgfs_sram_len);
|
||||
len);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
|
||||
priv->dbgfs_sram_offset);
|
||||
for (i = priv->dbgfs_sram_len; i > 0; i -= 4) {
|
||||
val = iwl_read_targ_mem(priv, priv->dbgfs_sram_offset + \
|
||||
priv->dbgfs_sram_len - i);
|
||||
if (i < 4) {
|
||||
switch (i) {
|
||||
case 1:
|
||||
val &= BYTE1_MASK;
|
||||
break;
|
||||
case 2:
|
||||
val &= BYTE2_MASK;
|
||||
break;
|
||||
case 3:
|
||||
val &= BYTE3_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
/* adjust sram address since reads are only on even u32 boundaries */
|
||||
offset = priv->dbgfs_sram_offset & 0x3;
|
||||
sram = priv->dbgfs_sram_offset & ~0x3;
|
||||
|
||||
/* read the first u32 from sram */
|
||||
val = iwl_read_targ_mem(priv, sram);
|
||||
|
||||
for (; len; len--) {
|
||||
/* put the address at the start of every line */
|
||||
if (i == 0)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"%08X: ", sram + offset);
|
||||
|
||||
if (device_format)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"%02x", (val >> (8 * (3 - offset))) & 0xff);
|
||||
else
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"%02x ", (val >> (8 * offset)) & 0xff);
|
||||
|
||||
/* if all bytes processed, read the next u32 from sram */
|
||||
if (++offset == 4) {
|
||||
sram += 4;
|
||||
offset = 0;
|
||||
val = iwl_read_targ_mem(priv, sram);
|
||||
}
|
||||
if (!(i % 16))
|
||||
|
||||
/* put in extra spaces and split lines for human readability */
|
||||
if (++i == 16) {
|
||||
i = 0;
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
|
||||
} else if (!(i & 7)) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos, " ");
|
||||
} else if (!(i & 3)) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos, " ");
|
||||
}
|
||||
}
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
if (i)
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
|
@ -282,6 +310,9 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file,
|
|||
if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
|
||||
priv->dbgfs_sram_offset = offset;
|
||||
priv->dbgfs_sram_len = len;
|
||||
} else if (sscanf(buf, "%x", &offset) == 1) {
|
||||
priv->dbgfs_sram_offset = offset;
|
||||
priv->dbgfs_sram_len = -4;
|
||||
} else {
|
||||
priv->dbgfs_sram_offset = 0;
|
||||
priv->dbgfs_sram_len = 0;
|
||||
|
@ -668,29 +699,6 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
|
|||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
char buf[256];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"allow blinking: %s\n",
|
||||
(priv->allow_blinking) ? "True" : "False");
|
||||
if (priv->allow_blinking) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"Led blinking rate: %u\n",
|
||||
priv->last_blink_rate);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"Last blink time: %lu\n",
|
||||
priv->last_blink_time);
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
|
@ -856,7 +864,6 @@ DEBUGFS_READ_FILE_OPS(channels);
|
|||
DEBUGFS_READ_FILE_OPS(status);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
|
||||
DEBUGFS_READ_FILE_OPS(qos);
|
||||
DEBUGFS_READ_FILE_OPS(led);
|
||||
DEBUGFS_READ_FILE_OPS(thermal_throttling);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
|
||||
|
@ -1725,7 +1732,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
|
|||
DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR);
|
||||
if (!priv->cfg->base_params->broken_powersave) {
|
||||
DEBUGFS_ADD_FILE(sleep_level_override, dir_data,
|
||||
S_IWUSR | S_IRUSR);
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
#include <linux/pci.h> /* for struct pci_device_id */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/leds.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
|
@ -995,7 +997,6 @@ struct reply_agg_tx_error_statistics {
|
|||
u32 unknown;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
/* management statistics */
|
||||
enum iwl_mgmt_stats {
|
||||
MANAGEMENT_ASSOC_REQ = 0,
|
||||
|
@ -1026,16 +1027,13 @@ enum iwl_ctrl_stats {
|
|||
};
|
||||
|
||||
struct traffic_stats {
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
u32 mgmt[MANAGEMENT_MAX];
|
||||
u32 ctrl[CONTROL_MAX];
|
||||
u32 data_cnt;
|
||||
u64 data_bytes;
|
||||
};
|
||||
#else
|
||||
struct traffic_stats {
|
||||
u64 data_bytes;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* iwl_switch_rxon: "channel switch" structure
|
||||
|
@ -1139,6 +1137,33 @@ struct iwl_force_reset {
|
|||
*/
|
||||
#define IWLAGN_EXT_BEACON_TIME_POS 22
|
||||
|
||||
/**
|
||||
* struct iwl_notification_wait - notification wait entry
|
||||
* @list: list head for global list
|
||||
* @fn: function called with the notification
|
||||
* @cmd: command ID
|
||||
*
|
||||
* This structure is not used directly, to wait for a
|
||||
* notification declare it on the stack, and call
|
||||
* iwlagn_init_notification_wait() with appropriate
|
||||
* parameters. Then do whatever will cause the ucode
|
||||
* to notify the driver, and to wait for that then
|
||||
* call iwlagn_wait_notification().
|
||||
*
|
||||
* Each notification is one-shot. If at some point we
|
||||
* need to support multi-shot notifications (which
|
||||
* can't be allocated on the stack) we need to modify
|
||||
* the code for them.
|
||||
*/
|
||||
struct iwl_notification_wait {
|
||||
struct list_head list;
|
||||
|
||||
void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt);
|
||||
|
||||
u8 cmd;
|
||||
bool triggered;
|
||||
};
|
||||
|
||||
enum iwl_rxon_context_id {
|
||||
IWL_RXON_CTX_BSS,
|
||||
IWL_RXON_CTX_PAN,
|
||||
|
@ -1310,11 +1335,6 @@ struct iwl_priv {
|
|||
struct iwl_init_alive_resp card_alive_init;
|
||||
struct iwl_alive_resp card_alive;
|
||||
|
||||
unsigned long last_blink_time;
|
||||
u8 last_blink_rate;
|
||||
u8 allow_blinking;
|
||||
u64 led_tpt;
|
||||
|
||||
u16 active_rate;
|
||||
|
||||
u8 start_calib;
|
||||
|
@ -1463,6 +1483,17 @@ struct iwl_priv {
|
|||
struct iwl_bt_notif_statistics delta_statistics_bt;
|
||||
struct iwl_bt_notif_statistics max_delta_bt;
|
||||
#endif
|
||||
|
||||
/* notification wait support */
|
||||
struct list_head notif_waits;
|
||||
spinlock_t notif_wait_lock;
|
||||
wait_queue_head_t notif_waitq;
|
||||
|
||||
/* remain-on-channel offload support */
|
||||
struct ieee80211_channel *hw_roc_channel;
|
||||
struct delayed_work hw_roc_work;
|
||||
enum nl80211_channel_type hw_roc_chantype;
|
||||
int hw_roc_duration;
|
||||
} _agn;
|
||||
#endif
|
||||
};
|
||||
|
@ -1547,6 +1578,10 @@ struct iwl_priv {
|
|||
bool hw_ready;
|
||||
|
||||
struct iwl_event_log event_log;
|
||||
|
||||
struct led_classdev led;
|
||||
unsigned long blink_on, blink_off;
|
||||
bool led_registered;
|
||||
}; /*iwl_priv */
|
||||
|
||||
static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
|
||||
|
|
|
@ -247,13 +247,26 @@ struct iwl_eeprom_enhanced_txpwr {
|
|||
#define EEPROM_6050_TX_POWER_VERSION (4)
|
||||
#define EEPROM_6050_EEPROM_VERSION (0x532)
|
||||
|
||||
/* 6x50g2 Specific */
|
||||
#define EEPROM_6050G2_TX_POWER_VERSION (6)
|
||||
#define EEPROM_6050G2_EEPROM_VERSION (0x553)
|
||||
/* 6150 Specific */
|
||||
#define EEPROM_6150_TX_POWER_VERSION (6)
|
||||
#define EEPROM_6150_EEPROM_VERSION (0x553)
|
||||
|
||||
/* 6x05 Specific */
|
||||
#define EEPROM_6005_TX_POWER_VERSION (6)
|
||||
#define EEPROM_6005_EEPROM_VERSION (0x709)
|
||||
|
||||
/* 6x30 Specific */
|
||||
#define EEPROM_6030_TX_POWER_VERSION (6)
|
||||
#define EEPROM_6030_EEPROM_VERSION (0x709)
|
||||
|
||||
/* 2x00 Specific */
|
||||
#define EEPROM_2000_TX_POWER_VERSION (6)
|
||||
#define EEPROM_2000_EEPROM_VERSION (0x805)
|
||||
|
||||
/* 6x35 Specific */
|
||||
#define EEPROM_6035_TX_POWER_VERSION (6)
|
||||
#define EEPROM_6035_EEPROM_VERSION (0x753)
|
||||
|
||||
/* 6x00g2 Specific */
|
||||
#define EEPROM_6000G2_TX_POWER_VERSION (6)
|
||||
#define EEPROM_6000G2_EEPROM_VERSION (0x709)
|
||||
|
||||
/* OTP */
|
||||
/* lower blocks contain EEPROM image and calibration data */
|
||||
|
@ -264,6 +277,7 @@ struct iwl_eeprom_enhanced_txpwr {
|
|||
#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */
|
||||
#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */
|
||||
#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */
|
||||
#define OTP_MAX_LL_ITEMS_2x00 (4) /* OTP blocks for 2x00 */
|
||||
|
||||
/* 2.4 GHz */
|
||||
extern const u8 iwl_eeprom_band_1[14];
|
||||
|
|
|
@ -108,6 +108,7 @@ const char *get_cmd_string(u8 cmd)
|
|||
IWL_CMD(REPLY_WIPAN_WEPKEY);
|
||||
IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH);
|
||||
IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION);
|
||||
IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
|
||||
|
|
|
@ -48,31 +48,19 @@ module_param(led_mode, int, S_IRUGO);
|
|||
MODULE_PARM_DESC(led_mode, "0=system default, "
|
||||
"1=On(RF On)/Off(RF Off), 2=blinking");
|
||||
|
||||
static const struct {
|
||||
u16 tpt; /* Mb/s */
|
||||
u8 on_time;
|
||||
u8 off_time;
|
||||
} blink_tbl[] =
|
||||
{
|
||||
{300, 25, 25},
|
||||
{200, 40, 40},
|
||||
{100, 55, 55},
|
||||
{70, 65, 65},
|
||||
{50, 75, 75},
|
||||
{20, 85, 85},
|
||||
{10, 95, 95},
|
||||
{5, 110, 110},
|
||||
{1, 130, 130},
|
||||
{0, 167, 167},
|
||||
/* SOLID_ON */
|
||||
{-1, IWL_LED_SOLID, 0}
|
||||
static const struct ieee80211_tpt_blink iwl_blink[] = {
|
||||
{ .throughput = 0 * 1024 - 1, .blink_time = 334 },
|
||||
{ .throughput = 1 * 1024 - 1, .blink_time = 260 },
|
||||
{ .throughput = 5 * 1024 - 1, .blink_time = 220 },
|
||||
{ .throughput = 10 * 1024 - 1, .blink_time = 190 },
|
||||
{ .throughput = 20 * 1024 - 1, .blink_time = 170 },
|
||||
{ .throughput = 50 * 1024 - 1, .blink_time = 150 },
|
||||
{ .throughput = 70 * 1024 - 1, .blink_time = 130 },
|
||||
{ .throughput = 100 * 1024 - 1, .blink_time = 110 },
|
||||
{ .throughput = 200 * 1024 - 1, .blink_time = 80 },
|
||||
{ .throughput = 300 * 1024 - 1, .blink_time = 50 },
|
||||
};
|
||||
|
||||
#define IWL_1MB_RATE (128 * 1024)
|
||||
#define IWL_LED_THRESHOLD (16)
|
||||
#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */
|
||||
#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
|
||||
|
||||
/*
|
||||
* Adjust led blink rate to compensate on a MAC Clock difference on every HW
|
||||
* Led blink rate analysis showed an average deviation of 0% on 3945,
|
||||
|
@ -97,133 +85,104 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
|
|||
}
|
||||
|
||||
/* Set led pattern command */
|
||||
static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx)
|
||||
static int iwl_led_cmd(struct iwl_priv *priv,
|
||||
unsigned long on,
|
||||
unsigned long off)
|
||||
{
|
||||
struct iwl_led_cmd led_cmd = {
|
||||
.id = IWL_LED_LINK,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
int ret;
|
||||
|
||||
BUG_ON(idx > IWL_MAX_BLINK_TBL);
|
||||
if (!test_bit(STATUS_READY, &priv->status))
|
||||
return -EBUSY;
|
||||
|
||||
IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n",
|
||||
if (priv->blink_on == on && priv->blink_off == off)
|
||||
return 0;
|
||||
|
||||
IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n",
|
||||
priv->cfg->base_params->led_compensation);
|
||||
led_cmd.on =
|
||||
iwl_blink_compensation(priv, blink_tbl[idx].on_time,
|
||||
led_cmd.on = iwl_blink_compensation(priv, on,
|
||||
priv->cfg->base_params->led_compensation);
|
||||
led_cmd.off =
|
||||
iwl_blink_compensation(priv, blink_tbl[idx].off_time,
|
||||
led_cmd.off = iwl_blink_compensation(priv, off,
|
||||
priv->cfg->base_params->led_compensation);
|
||||
|
||||
return priv->cfg->ops->led->cmd(priv, &led_cmd);
|
||||
}
|
||||
|
||||
int iwl_led_start(struct iwl_priv *priv)
|
||||
{
|
||||
return priv->cfg->ops->led->on(priv);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_led_start);
|
||||
|
||||
int iwl_led_associate(struct iwl_priv *priv)
|
||||
{
|
||||
IWL_DEBUG_LED(priv, "Associated\n");
|
||||
if (priv->cfg->led_mode == IWL_LED_BLINK)
|
||||
priv->allow_blinking = 1;
|
||||
priv->last_blink_time = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_led_associate);
|
||||
|
||||
int iwl_led_disassociate(struct iwl_priv *priv)
|
||||
{
|
||||
priv->allow_blinking = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_led_disassociate);
|
||||
|
||||
/*
|
||||
* calculate blink rate according to last second Tx/Rx activities
|
||||
*/
|
||||
static int iwl_get_blink_rate(struct iwl_priv *priv)
|
||||
{
|
||||
int i;
|
||||
/* count both tx and rx traffic to be able to
|
||||
* handle traffic in either direction
|
||||
*/
|
||||
u64 current_tpt = priv->tx_stats.data_bytes +
|
||||
priv->rx_stats.data_bytes;
|
||||
s64 tpt = current_tpt - priv->led_tpt;
|
||||
|
||||
if (tpt < 0) /* wraparound */
|
||||
tpt = -tpt;
|
||||
|
||||
IWL_DEBUG_LED(priv, "tpt %lld current_tpt %llu\n",
|
||||
(long long)tpt,
|
||||
(unsigned long long)current_tpt);
|
||||
priv->led_tpt = current_tpt;
|
||||
|
||||
if (!priv->allow_blinking)
|
||||
i = IWL_MAX_BLINK_TBL;
|
||||
else
|
||||
for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
|
||||
if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
|
||||
break;
|
||||
|
||||
IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i);
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function called from handler. Since setting Led command can
|
||||
* happen very frequent we postpone led command to be called from
|
||||
* REPLY handler so we know ucode is up
|
||||
*/
|
||||
void iwl_leds_background(struct iwl_priv *priv)
|
||||
{
|
||||
u8 blink_idx;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
||||
priv->last_blink_time = 0;
|
||||
return;
|
||||
ret = priv->cfg->ops->led->cmd(priv, &led_cmd);
|
||||
if (!ret) {
|
||||
priv->blink_on = on;
|
||||
priv->blink_off = off;
|
||||
}
|
||||
if (iwl_is_rfkill(priv)) {
|
||||
priv->last_blink_time = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!priv->allow_blinking) {
|
||||
priv->last_blink_time = 0;
|
||||
if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
|
||||
priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
|
||||
iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!priv->last_blink_time ||
|
||||
!time_after(jiffies, priv->last_blink_time +
|
||||
msecs_to_jiffies(1000)))
|
||||
return;
|
||||
|
||||
blink_idx = iwl_get_blink_rate(priv);
|
||||
|
||||
/* call only if blink rate change */
|
||||
if (blink_idx != priv->last_blink_rate)
|
||||
iwl_led_pattern(priv, blink_idx);
|
||||
|
||||
priv->last_blink_time = jiffies;
|
||||
priv->last_blink_rate = blink_idx;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_led_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
|
||||
unsigned long on = 0;
|
||||
|
||||
if (brightness > 0)
|
||||
on = IWL_LED_SOLID;
|
||||
|
||||
iwl_led_cmd(priv, on, 0);
|
||||
}
|
||||
|
||||
static int iwl_led_blink_set(struct led_classdev *led_cdev,
|
||||
unsigned long *delay_on,
|
||||
unsigned long *delay_off)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
|
||||
|
||||
return iwl_led_cmd(priv, *delay_on, *delay_off);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_leds_background);
|
||||
|
||||
void iwl_leds_init(struct iwl_priv *priv)
|
||||
{
|
||||
priv->last_blink_rate = 0;
|
||||
priv->last_blink_time = 0;
|
||||
priv->allow_blinking = 0;
|
||||
if (led_mode != IWL_LED_DEFAULT &&
|
||||
led_mode != priv->cfg->led_mode)
|
||||
priv->cfg->led_mode = led_mode;
|
||||
int mode = led_mode;
|
||||
int ret;
|
||||
|
||||
if (mode == IWL_LED_DEFAULT)
|
||||
mode = priv->cfg->led_mode;
|
||||
|
||||
priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
priv->led.brightness_set = iwl_led_brightness_set;
|
||||
priv->led.blink_set = iwl_led_blink_set;
|
||||
priv->led.max_brightness = 1;
|
||||
|
||||
switch (mode) {
|
||||
case IWL_LED_DEFAULT:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
case IWL_LED_BLINK:
|
||||
priv->led.default_trigger =
|
||||
ieee80211_create_tpt_led_trigger(priv->hw,
|
||||
IEEE80211_TPT_LEDTRIG_FL_CONNECTED,
|
||||
iwl_blink, ARRAY_SIZE(iwl_blink));
|
||||
break;
|
||||
case IWL_LED_RF_STATE:
|
||||
priv->led.default_trigger =
|
||||
ieee80211_get_radio_led_name(priv->hw);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = led_classdev_register(&priv->pci_dev->dev, &priv->led);
|
||||
if (ret) {
|
||||
kfree(priv->led.name);
|
||||
return;
|
||||
}
|
||||
|
||||
priv->led_registered = true;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_leds_init);
|
||||
|
||||
void iwl_leds_exit(struct iwl_priv *priv)
|
||||
{
|
||||
if (!priv->led_registered)
|
||||
return;
|
||||
|
||||
led_classdev_unregister(&priv->led);
|
||||
kfree(priv->led.name);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_leds_exit);
|
||||
|
|
|
@ -31,23 +31,14 @@
|
|||
struct iwl_priv;
|
||||
|
||||
#define IWL_LED_SOLID 11
|
||||
#define IWL_LED_NAME_LEN 31
|
||||
#define IWL_DEF_LED_INTRVL cpu_to_le32(1000)
|
||||
|
||||
#define IWL_LED_ACTIVITY (0<<1)
|
||||
#define IWL_LED_LINK (1<<1)
|
||||
|
||||
enum led_type {
|
||||
IWL_LED_TRG_TX,
|
||||
IWL_LED_TRG_RX,
|
||||
IWL_LED_TRG_ASSOC,
|
||||
IWL_LED_TRG_RADIO,
|
||||
IWL_LED_TRG_MAX,
|
||||
};
|
||||
|
||||
/*
|
||||
* LED mode
|
||||
* IWL_LED_DEFAULT: use system default
|
||||
* IWL_LED_DEFAULT: use device default
|
||||
* IWL_LED_RF_STATE: turn LED on/off based on RF state
|
||||
* LED ON = RF ON
|
||||
* LED OFF = RF OFF
|
||||
|
@ -60,9 +51,6 @@ enum iwl_led_mode {
|
|||
};
|
||||
|
||||
void iwl_leds_init(struct iwl_priv *priv);
|
||||
void iwl_leds_background(struct iwl_priv *priv);
|
||||
int iwl_led_start(struct iwl_priv *priv);
|
||||
int iwl_led_associate(struct iwl_priv *priv);
|
||||
int iwl_led_disassociate(struct iwl_priv *priv);
|
||||
void iwl_leds_exit(struct iwl_priv *priv);
|
||||
|
||||
#endif /* __iwl_leds_h__ */
|
||||
|
|
|
@ -332,7 +332,6 @@ static inline void iwl_set_no_assoc(struct iwl_priv *priv,
|
|||
{
|
||||
struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
|
||||
|
||||
iwl_led_disassociate(priv);
|
||||
/*
|
||||
* inform the ucode that there is no longer an
|
||||
* association and that no more packets should be
|
||||
|
@ -520,8 +519,6 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
|
|||
if (bss_conf->assoc) {
|
||||
priv->timestamp = bss_conf->timestamp;
|
||||
|
||||
iwl_led_associate(priv);
|
||||
|
||||
if (!iwl_is_rfkill(priv))
|
||||
priv->cfg->ops->legacy->post_associate(priv);
|
||||
} else
|
||||
|
@ -545,7 +542,6 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
|
|||
memcpy(ctx->staging.bssid_addr,
|
||||
bss_conf->bssid, ETH_ALEN);
|
||||
memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
|
||||
iwl_led_associate(priv);
|
||||
priv->cfg->ops->legacy->config_ap(priv);
|
||||
} else
|
||||
iwl_set_no_assoc(priv, vif);
|
||||
|
|
|
@ -2540,8 +2540,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
|
|||
|
||||
iwl3945_reg_txpower_periodic(priv);
|
||||
|
||||
iwl_leds_init(priv);
|
||||
|
||||
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
|
||||
set_bit(STATUS_READY, &priv->status);
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
|
@ -3170,8 +3168,6 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
|
|||
* no need to poll the killswitch state anymore */
|
||||
cancel_delayed_work(&priv->_3945.rfkill_poll);
|
||||
|
||||
iwl_led_start(priv);
|
||||
|
||||
priv->is_open = 1;
|
||||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
return 0;
|
||||
|
@ -3935,6 +3931,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
|
|||
priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
|
||||
&priv->bands[IEEE80211_BAND_5GHZ];
|
||||
|
||||
iwl_leds_init(priv);
|
||||
|
||||
ret = ieee80211_register_hw(priv->hw);
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
|
||||
|
@ -4194,6 +4192,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
|
|||
|
||||
set_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
|
||||
iwl_leds_exit(priv);
|
||||
|
||||
if (priv->mac80211_registered) {
|
||||
ieee80211_unregister_hw(priv->hw);
|
||||
priv->mac80211_registered = 0;
|
||||
|
|
|
@ -287,7 +287,8 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq = ieee80211_channel_to_frequency(umac_bss->channel);
|
||||
freq = ieee80211_channel_to_frequency(umac_bss->channel,
|
||||
band->band);
|
||||
channel = ieee80211_get_channel(wiphy, freq);
|
||||
signal = umac_bss->rssi * 100;
|
||||
|
||||
|
|
|
@ -543,7 +543,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
|
|||
switch (le32_to_cpu(complete->status)) {
|
||||
case UMAC_ASSOC_COMPLETE_SUCCESS:
|
||||
chan = ieee80211_get_channel(wiphy,
|
||||
ieee80211_channel_to_frequency(complete->channel));
|
||||
ieee80211_channel_to_frequency(complete->channel,
|
||||
complete->band == UMAC_BAND_2GHZ ?
|
||||
IEEE80211_BAND_2GHZ :
|
||||
IEEE80211_BAND_5GHZ));
|
||||
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
|
||||
/* Associated to a unallowed channel, disassociate. */
|
||||
__iwm_invalidate_mlme_profile(iwm);
|
||||
|
@ -841,7 +844,7 @@ static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
|
|||
goto err;
|
||||
}
|
||||
|
||||
freq = ieee80211_channel_to_frequency(umac_bss->channel);
|
||||
freq = ieee80211_channel_to_frequency(umac_bss->channel, band->band);
|
||||
channel = ieee80211_get_channel(wiphy, freq);
|
||||
signal = umac_bss->rssi * 100;
|
||||
|
||||
|
|
|
@ -607,7 +607,8 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
|||
/* No channel, no luck */
|
||||
if (chan_no != -1) {
|
||||
struct wiphy *wiphy = priv->wdev->wiphy;
|
||||
int freq = ieee80211_channel_to_frequency(chan_no);
|
||||
int freq = ieee80211_channel_to_frequency(chan_no,
|
||||
IEEE80211_BAND_2GHZ);
|
||||
struct ieee80211_channel *channel =
|
||||
ieee80211_get_channel(wiphy, freq);
|
||||
|
||||
|
@ -1597,7 +1598,8 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
|
|||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
survey->channel = ieee80211_get_channel(wiphy,
|
||||
ieee80211_channel_to_frequency(priv->channel));
|
||||
ieee80211_channel_to_frequency(priv->channel,
|
||||
IEEE80211_BAND_2GHZ));
|
||||
|
||||
ret = lbs_get_rssi(priv, &signal, &noise);
|
||||
if (ret == 0) {
|
||||
|
|
|
@ -943,7 +943,8 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
|
|||
static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
{
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
|
|
|
@ -232,6 +232,9 @@ struct mwl8k_priv {
|
|||
struct completion firmware_loading_complete;
|
||||
};
|
||||
|
||||
#define MAX_WEP_KEY_LEN 13
|
||||
#define NUM_WEP_KEYS 4
|
||||
|
||||
/* Per interface specific private data */
|
||||
struct mwl8k_vif {
|
||||
struct list_head list;
|
||||
|
@ -242,8 +245,21 @@ struct mwl8k_vif {
|
|||
|
||||
/* Non AMPDU sequence number assigned by driver. */
|
||||
u16 seqno;
|
||||
|
||||
/* Saved WEP keys */
|
||||
struct {
|
||||
u8 enabled;
|
||||
u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN];
|
||||
} wep_key_conf[NUM_WEP_KEYS];
|
||||
|
||||
/* BSSID */
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
||||
/* A flag to indicate is HW crypto is enabled for this bssid */
|
||||
bool is_hw_crypto_enabled;
|
||||
};
|
||||
#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
|
||||
#define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8))
|
||||
|
||||
struct mwl8k_sta {
|
||||
/* Index into station database. Returned by UPDATE_STADB. */
|
||||
|
@ -337,6 +353,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
|
|||
#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203
|
||||
#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */
|
||||
#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */
|
||||
#define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */
|
||||
#define MWL8K_CMD_UPDATE_STADB 0x1123
|
||||
|
||||
static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
|
||||
|
@ -375,6 +392,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
|
|||
MWL8K_CMDNAME(SET_RATEADAPT_MODE);
|
||||
MWL8K_CMDNAME(BSS_START);
|
||||
MWL8K_CMDNAME(SET_NEW_STN);
|
||||
MWL8K_CMDNAME(UPDATE_ENCRYPTION);
|
||||
MWL8K_CMDNAME(UPDATE_STADB);
|
||||
default:
|
||||
snprintf(buf, bufsize, "0x%x", cmd);
|
||||
|
@ -715,10 +733,12 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos)
|
|||
skb_pull(skb, sizeof(*tr) - hdrlen);
|
||||
}
|
||||
|
||||
static inline void mwl8k_add_dma_header(struct sk_buff *skb)
|
||||
static void
|
||||
mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad)
|
||||
{
|
||||
struct ieee80211_hdr *wh;
|
||||
int hdrlen;
|
||||
int reqd_hdrlen;
|
||||
struct mwl8k_dma_data *tr;
|
||||
|
||||
/*
|
||||
|
@ -730,11 +750,13 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
|
|||
wh = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(wh->frame_control);
|
||||
if (hdrlen != sizeof(*tr))
|
||||
skb_push(skb, sizeof(*tr) - hdrlen);
|
||||
reqd_hdrlen = sizeof(*tr);
|
||||
|
||||
if (hdrlen != reqd_hdrlen)
|
||||
skb_push(skb, reqd_hdrlen - hdrlen);
|
||||
|
||||
if (ieee80211_is_data_qos(wh->frame_control))
|
||||
hdrlen -= 2;
|
||||
hdrlen -= IEEE80211_QOS_CTL_LEN;
|
||||
|
||||
tr = (struct mwl8k_dma_data *)skb->data;
|
||||
if (wh != &tr->wh)
|
||||
|
@ -747,9 +769,52 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
|
|||
* payload". That is, everything except for the 802.11 header.
|
||||
* This includes all crypto material including the MIC.
|
||||
*/
|
||||
tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr));
|
||||
tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad);
|
||||
}
|
||||
|
||||
static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *wh;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct ieee80211_key_conf *key_conf;
|
||||
int data_pad;
|
||||
|
||||
wh = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
key_conf = NULL;
|
||||
if (ieee80211_is_data(wh->frame_control))
|
||||
key_conf = tx_info->control.hw_key;
|
||||
|
||||
/*
|
||||
* Make sure the packet header is in the DMA header format (4-address
|
||||
* without QoS), the necessary crypto padding between the header and the
|
||||
* payload has already been provided by mac80211, but it doesn't add tail
|
||||
* padding when HW crypto is enabled.
|
||||
*
|
||||
* We have the following trailer padding requirements:
|
||||
* - WEP: 4 trailer bytes (ICV)
|
||||
* - TKIP: 12 trailer bytes (8 MIC + 4 ICV)
|
||||
* - CCMP: 8 trailer bytes (MIC)
|
||||
*/
|
||||
data_pad = 0;
|
||||
if (key_conf != NULL) {
|
||||
switch (key_conf->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
data_pad = 4;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
data_pad = 12;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
data_pad = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mwl8k_add_dma_header(skb, data_pad);
|
||||
}
|
||||
|
||||
/*
|
||||
* Packet reception for 88w8366 AP firmware.
|
||||
|
@ -778,6 +843,13 @@ struct mwl8k_rxd_8366_ap {
|
|||
|
||||
#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80
|
||||
|
||||
/* 8366 AP rx_status bits */
|
||||
#define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK 0x80
|
||||
#define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR 0xFF
|
||||
#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR 0x02
|
||||
#define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR 0x04
|
||||
#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR 0x08
|
||||
|
||||
static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr)
|
||||
{
|
||||
struct mwl8k_rxd_8366_ap *rxd = _rxd;
|
||||
|
@ -834,10 +906,16 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
|
|||
} else {
|
||||
status->band = IEEE80211_BAND_2GHZ;
|
||||
}
|
||||
status->freq = ieee80211_channel_to_frequency(rxd->channel);
|
||||
status->freq = ieee80211_channel_to_frequency(rxd->channel,
|
||||
status->band);
|
||||
|
||||
*qos = rxd->qos_control;
|
||||
|
||||
if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) &&
|
||||
(rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) &&
|
||||
(rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR))
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
return le16_to_cpu(rxd->pkt_len);
|
||||
}
|
||||
|
||||
|
@ -876,6 +954,11 @@ struct mwl8k_rxd_sta {
|
|||
#define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001
|
||||
|
||||
#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02
|
||||
#define MWL8K_STA_RX_CTRL_DECRYPT_ERROR 0x04
|
||||
/* ICV=0 or MIC=1 */
|
||||
#define MWL8K_STA_RX_CTRL_DEC_ERR_TYPE 0x08
|
||||
/* Key is uploaded only in failure case */
|
||||
#define MWL8K_STA_RX_CTRL_KEY_INDEX 0x30
|
||||
|
||||
static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr)
|
||||
{
|
||||
|
@ -931,9 +1014,13 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
|
|||
} else {
|
||||
status->band = IEEE80211_BAND_2GHZ;
|
||||
}
|
||||
status->freq = ieee80211_channel_to_frequency(rxd->channel);
|
||||
status->freq = ieee80211_channel_to_frequency(rxd->channel,
|
||||
status->band);
|
||||
|
||||
*qos = rxd->qos_control;
|
||||
if ((rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DECRYPT_ERROR) &&
|
||||
(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DEC_ERR_TYPE))
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
return le16_to_cpu(rxd->pkt_len);
|
||||
}
|
||||
|
@ -1092,9 +1179,25 @@ static inline void mwl8k_save_beacon(struct ieee80211_hw *hw,
|
|||
ieee80211_queue_work(hw, &priv->finalize_join_worker);
|
||||
}
|
||||
|
||||
static inline struct mwl8k_vif *mwl8k_find_vif_bss(struct list_head *vif_list,
|
||||
u8 *bssid)
|
||||
{
|
||||
struct mwl8k_vif *mwl8k_vif;
|
||||
|
||||
list_for_each_entry(mwl8k_vif,
|
||||
vif_list, list) {
|
||||
if (memcmp(bssid, mwl8k_vif->bssid,
|
||||
ETH_ALEN) == 0)
|
||||
return mwl8k_vif;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
|
||||
{
|
||||
struct mwl8k_priv *priv = hw->priv;
|
||||
struct mwl8k_vif *mwl8k_vif = NULL;
|
||||
struct mwl8k_rx_queue *rxq = priv->rxq + index;
|
||||
int processed;
|
||||
|
||||
|
@ -1104,6 +1207,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
|
|||
void *rxd;
|
||||
int pkt_len;
|
||||
struct ieee80211_rx_status status;
|
||||
struct ieee80211_hdr *wh;
|
||||
__le16 qos;
|
||||
|
||||
skb = rxq->buf[rxq->head].skb;
|
||||
|
@ -1130,8 +1234,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
|
|||
|
||||
rxq->rxd_count--;
|
||||
|
||||
skb_put(skb, pkt_len);
|
||||
mwl8k_remove_dma_header(skb, qos);
|
||||
wh = &((struct mwl8k_dma_data *)skb->data)->wh;
|
||||
|
||||
/*
|
||||
* Check for a pending join operation. Save a
|
||||
|
@ -1141,6 +1244,46 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
|
|||
if (mwl8k_capture_bssid(priv, (void *)skb->data))
|
||||
mwl8k_save_beacon(hw, skb);
|
||||
|
||||
if (ieee80211_has_protected(wh->frame_control)) {
|
||||
|
||||
/* Check if hw crypto has been enabled for
|
||||
* this bss. If yes, set the status flags
|
||||
* accordingly
|
||||
*/
|
||||
mwl8k_vif = mwl8k_find_vif_bss(&priv->vif_list,
|
||||
wh->addr1);
|
||||
|
||||
if (mwl8k_vif != NULL &&
|
||||
mwl8k_vif->is_hw_crypto_enabled == true) {
|
||||
/*
|
||||
* When MMIC ERROR is encountered
|
||||
* by the firmware, payload is
|
||||
* dropped and only 32 bytes of
|
||||
* mwl8k Firmware header is sent
|
||||
* to the host.
|
||||
*
|
||||
* We need to add four bytes of
|
||||
* key information. In it
|
||||
* MAC80211 expects keyidx set to
|
||||
* 0 for triggering Counter
|
||||
* Measure of MMIC failure.
|
||||
*/
|
||||
if (status.flag & RX_FLAG_MMIC_ERROR) {
|
||||
struct mwl8k_dma_data *tr;
|
||||
tr = (struct mwl8k_dma_data *)skb->data;
|
||||
memset((void *)&(tr->data), 0, 4);
|
||||
pkt_len += 4;
|
||||
}
|
||||
|
||||
if (!ieee80211_is_auth(wh->frame_control))
|
||||
status.flag |= RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_DECRYPTED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
}
|
||||
}
|
||||
|
||||
skb_put(skb, pkt_len);
|
||||
mwl8k_remove_dma_header(skb, qos);
|
||||
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
|
||||
ieee80211_rx_irqsafe(hw, skb);
|
||||
|
||||
|
@ -1443,7 +1586,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
|
|||
else
|
||||
qos = 0;
|
||||
|
||||
mwl8k_add_dma_header(skb);
|
||||
if (priv->ap_fw)
|
||||
mwl8k_encapsulate_tx_frame(skb);
|
||||
else
|
||||
mwl8k_add_dma_header(skb, 0);
|
||||
|
||||
wh = &((struct mwl8k_dma_data *)skb->data)->wh;
|
||||
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
|
@ -3098,6 +3245,274 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw,
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* CMD_UPDATE_ENCRYPTION.
|
||||
*/
|
||||
|
||||
#define MAX_ENCR_KEY_LENGTH 16
|
||||
#define MIC_KEY_LENGTH 8
|
||||
|
||||
struct mwl8k_cmd_update_encryption {
|
||||
struct mwl8k_cmd_pkt header;
|
||||
|
||||
__le32 action;
|
||||
__le32 reserved;
|
||||
__u8 mac_addr[6];
|
||||
__u8 encr_type;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
struct mwl8k_cmd_set_key {
|
||||
struct mwl8k_cmd_pkt header;
|
||||
|
||||
__le32 action;
|
||||
__le32 reserved;
|
||||
__le16 length;
|
||||
__le16 key_type_id;
|
||||
__le32 key_info;
|
||||
__le32 key_id;
|
||||
__le16 key_len;
|
||||
__u8 key_material[MAX_ENCR_KEY_LENGTH];
|
||||
__u8 tkip_tx_mic_key[MIC_KEY_LENGTH];
|
||||
__u8 tkip_rx_mic_key[MIC_KEY_LENGTH];
|
||||
__le16 tkip_rsc_low;
|
||||
__le32 tkip_rsc_high;
|
||||
__le16 tkip_tsc_low;
|
||||
__le32 tkip_tsc_high;
|
||||
__u8 mac_addr[6];
|
||||
} __attribute__((packed));
|
||||
|
||||
enum {
|
||||
MWL8K_ENCR_ENABLE,
|
||||
MWL8K_ENCR_SET_KEY,
|
||||
MWL8K_ENCR_REMOVE_KEY,
|
||||
MWL8K_ENCR_SET_GROUP_KEY,
|
||||
};
|
||||
|
||||
#define MWL8K_UPDATE_ENCRYPTION_TYPE_WEP 0
|
||||
#define MWL8K_UPDATE_ENCRYPTION_TYPE_DISABLE 1
|
||||
#define MWL8K_UPDATE_ENCRYPTION_TYPE_TKIP 4
|
||||
#define MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED 7
|
||||
#define MWL8K_UPDATE_ENCRYPTION_TYPE_AES 8
|
||||
|
||||
enum {
|
||||
MWL8K_ALG_WEP,
|
||||
MWL8K_ALG_TKIP,
|
||||
MWL8K_ALG_CCMP,
|
||||
};
|
||||
|
||||
#define MWL8K_KEY_FLAG_TXGROUPKEY 0x00000004
|
||||
#define MWL8K_KEY_FLAG_PAIRWISE 0x00000008
|
||||
#define MWL8K_KEY_FLAG_TSC_VALID 0x00000040
|
||||
#define MWL8K_KEY_FLAG_WEP_TXKEY 0x01000000
|
||||
#define MWL8K_KEY_FLAG_MICKEY_VALID 0x02000000
|
||||
|
||||
static int mwl8k_cmd_update_encryption_enable(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u8 *addr,
|
||||
u8 encr_type)
|
||||
{
|
||||
struct mwl8k_cmd_update_encryption *cmd;
|
||||
int rc;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (cmd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION);
|
||||
cmd->header.length = cpu_to_le16(sizeof(*cmd));
|
||||
cmd->action = cpu_to_le32(MWL8K_ENCR_ENABLE);
|
||||
memcpy(cmd->mac_addr, addr, ETH_ALEN);
|
||||
cmd->encr_type = encr_type;
|
||||
|
||||
rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
|
||||
kfree(cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mwl8k_encryption_set_cmd_info(struct mwl8k_cmd_set_key *cmd,
|
||||
u8 *addr,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION);
|
||||
cmd->header.length = cpu_to_le16(sizeof(*cmd));
|
||||
cmd->length = cpu_to_le16(sizeof(*cmd) -
|
||||
offsetof(struct mwl8k_cmd_set_key, length));
|
||||
cmd->key_id = cpu_to_le32(key->keyidx);
|
||||
cmd->key_len = cpu_to_le16(key->keylen);
|
||||
memcpy(cmd->mac_addr, addr, ETH_ALEN);
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
cmd->key_type_id = cpu_to_le16(MWL8K_ALG_WEP);
|
||||
if (key->keyidx == 0)
|
||||
cmd->key_info = cpu_to_le32(MWL8K_KEY_FLAG_WEP_TXKEY);
|
||||
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
cmd->key_type_id = cpu_to_le16(MWL8K_ALG_TKIP);
|
||||
cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
|
||||
? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE)
|
||||
: cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY);
|
||||
cmd->key_info |= cpu_to_le32(MWL8K_KEY_FLAG_MICKEY_VALID
|
||||
| MWL8K_KEY_FLAG_TSC_VALID);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
cmd->key_type_id = cpu_to_le16(MWL8K_ALG_CCMP);
|
||||
cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
|
||||
? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE)
|
||||
: cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u8 *addr,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct mwl8k_cmd_set_key *cmd;
|
||||
int rc;
|
||||
int keymlen;
|
||||
u32 action;
|
||||
u8 idx;
|
||||
struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (cmd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = mwl8k_encryption_set_cmd_info(cmd, addr, key);
|
||||
if (rc < 0)
|
||||
goto done;
|
||||
|
||||
idx = key->keyidx;
|
||||
|
||||
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
|
||||
action = MWL8K_ENCR_SET_KEY;
|
||||
else
|
||||
action = MWL8K_ENCR_SET_GROUP_KEY;
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
if (!mwl8k_vif->wep_key_conf[idx].enabled) {
|
||||
memcpy(mwl8k_vif->wep_key_conf[idx].key, key,
|
||||
sizeof(*key) + key->keylen);
|
||||
mwl8k_vif->wep_key_conf[idx].enabled = 1;
|
||||
}
|
||||
|
||||
keymlen = 0;
|
||||
action = MWL8K_ENCR_SET_KEY;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
keymlen = MAX_ENCR_KEY_LENGTH + 2 * MIC_KEY_LENGTH;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
keymlen = key->keylen;
|
||||
break;
|
||||
default:
|
||||
rc = -ENOTSUPP;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(cmd->key_material, key->key, keymlen);
|
||||
cmd->action = cpu_to_le32(action);
|
||||
|
||||
rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
|
||||
done:
|
||||
kfree(cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mwl8k_cmd_encryption_remove_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u8 *addr,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct mwl8k_cmd_set_key *cmd;
|
||||
int rc;
|
||||
struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (cmd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = mwl8k_encryption_set_cmd_info(cmd, addr, key);
|
||||
if (rc < 0)
|
||||
goto done;
|
||||
|
||||
if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
||||
WLAN_CIPHER_SUITE_WEP104)
|
||||
mwl8k_vif->wep_key_conf[key->keyidx].enabled = 0;
|
||||
|
||||
cmd->action = cpu_to_le32(MWL8K_ENCR_REMOVE_KEY);
|
||||
|
||||
rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
|
||||
done:
|
||||
kfree(cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mwl8k_set_key(struct ieee80211_hw *hw,
|
||||
enum set_key_cmd cmd_param,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
int rc = 0;
|
||||
u8 encr_type;
|
||||
u8 *addr;
|
||||
struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (sta == NULL)
|
||||
addr = hw->wiphy->perm_addr;
|
||||
else
|
||||
addr = sta->addr;
|
||||
|
||||
if (cmd_param == SET_KEY) {
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if ((key->cipher == WLAN_CIPHER_SUITE_WEP40)
|
||||
|| (key->cipher == WLAN_CIPHER_SUITE_WEP104))
|
||||
encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_WEP;
|
||||
else
|
||||
encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED;
|
||||
|
||||
rc = mwl8k_cmd_update_encryption_enable(hw, vif, addr,
|
||||
encr_type);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
mwl8k_vif->is_hw_crypto_enabled = true;
|
||||
|
||||
} else {
|
||||
rc = mwl8k_cmd_encryption_remove_key(hw, vif, addr, key);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
mwl8k_vif->is_hw_crypto_enabled = false;
|
||||
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* CMD_UPDATE_STADB.
|
||||
*/
|
||||
|
@ -3469,6 +3884,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
|
|||
mwl8k_vif->vif = vif;
|
||||
mwl8k_vif->macid = macid;
|
||||
mwl8k_vif->seqno = 0;
|
||||
memcpy(mwl8k_vif->bssid, vif->addr, ETH_ALEN);
|
||||
mwl8k_vif->is_hw_crypto_enabled = false;
|
||||
|
||||
/* Set the mac address. */
|
||||
mwl8k_cmd_set_mac_addr(hw, vif, vif->addr);
|
||||
|
@ -3866,18 +4283,27 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct mwl8k_priv *priv = hw->priv;
|
||||
int ret;
|
||||
int i;
|
||||
struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
|
||||
struct ieee80211_key_conf *key;
|
||||
|
||||
if (!priv->ap_fw) {
|
||||
ret = mwl8k_cmd_update_stadb_add(hw, vif, sta);
|
||||
if (ret >= 0) {
|
||||
MWL8K_STA(sta)->peer_id = ret;
|
||||
return 0;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta);
|
||||
}
|
||||
|
||||
return mwl8k_cmd_set_new_stn_add(hw, vif, sta);
|
||||
for (i = 0; i < NUM_WEP_KEYS; i++) {
|
||||
key = IEEE80211_KEY_CONF(mwl8k_vif->wep_key_conf[i].key);
|
||||
if (mwl8k_vif->wep_key_conf[i].enabled)
|
||||
mwl8k_set_key(hw, SET_KEY, vif, sta, key);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||
|
@ -3932,7 +4358,8 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
|
|||
static int
|
||||
mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
{
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
|
@ -3955,6 +4382,7 @@ static const struct ieee80211_ops mwl8k_ops = {
|
|||
.bss_info_changed = mwl8k_bss_info_changed,
|
||||
.prepare_multicast = mwl8k_prepare_multicast,
|
||||
.configure_filter = mwl8k_configure_filter,
|
||||
.set_key = mwl8k_set_key,
|
||||
.set_rts_threshold = mwl8k_set_rts_threshold,
|
||||
.sta_add = mwl8k_sta_add,
|
||||
.sta_remove = mwl8k_sta_remove,
|
||||
|
|
|
@ -1804,6 +1804,12 @@ struct mac_iveiv_entry {
|
|||
*/
|
||||
#define RFCSR30_RF_CALIBRATION FIELD8(0x80)
|
||||
|
||||
/*
|
||||
* RFCSR 31:
|
||||
*/
|
||||
#define RFCSR31_RX_AGC_FC FIELD8(0x1f)
|
||||
#define RFCSR31_RX_H20M FIELD8(0x20)
|
||||
|
||||
/*
|
||||
* RF registers
|
||||
*/
|
||||
|
|
|
@ -2436,6 +2436,10 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
|
|||
rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40);
|
||||
rt2800_bbp_write(rt2x00dev, 4, bbp);
|
||||
|
||||
rt2800_rfcsr_read(rt2x00dev, 31, &rfcsr);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR31_RX_H20M, bw40);
|
||||
rt2800_rfcsr_write(rt2x00dev, 31, rfcsr);
|
||||
|
||||
rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1);
|
||||
rt2800_rfcsr_write(rt2x00dev, 22, rfcsr);
|
||||
|
@ -2510,7 +2514,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
|
|||
rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
|
||||
rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
|
||||
rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
|
||||
rt2800_rfcsr_write(rt2x00dev, 7, 0x70);
|
||||
rt2800_rfcsr_write(rt2x00dev, 7, 0x60);
|
||||
rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
|
||||
rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
|
||||
rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
|
||||
|
@ -2602,12 +2606,12 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
|
|||
rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
|
||||
} else if (rt2x00_rt(rt2x00dev, RT3071) ||
|
||||
rt2x00_rt(rt2x00dev, RT3090)) {
|
||||
rt2800_rfcsr_write(rt2x00dev, 31, 0x14);
|
||||
|
||||
rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
|
||||
rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
|
||||
|
||||
rt2800_rfcsr_write(rt2x00dev, 31, 0x14);
|
||||
|
||||
rt2800_register_read(rt2x00dev, LDO_CFG0, ®);
|
||||
rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1);
|
||||
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
|
||||
|
@ -2619,6 +2623,10 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
|
|||
rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 0);
|
||||
}
|
||||
rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
|
||||
|
||||
rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®);
|
||||
rt2x00_set_field32(®, GPIO_SWITCH_5, 0);
|
||||
rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
|
||||
} else if (rt2x00_rt(rt2x00dev, RT3390)) {
|
||||
rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®);
|
||||
rt2x00_set_field32(®, GPIO_SWITCH_5, 0);
|
||||
|
@ -2670,10 +2678,11 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
|
|||
|
||||
rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
|
||||
rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0);
|
||||
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
|
||||
if (rt2x00_rt(rt2x00dev, RT3070) ||
|
||||
rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
|
||||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
|
||||
rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
|
||||
if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
|
||||
if (!test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
|
||||
rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
|
||||
}
|
||||
rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom);
|
||||
|
@ -2686,6 +2695,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
|
|||
if (rt2x00_rt(rt2x00dev, RT3090)) {
|
||||
rt2800_bbp_read(rt2x00dev, 138, &bbp);
|
||||
|
||||
/* Turn off unused DAC1 and ADC1 to reduce power consumption */
|
||||
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
|
||||
if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
|
||||
rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
|
||||
|
@ -2719,10 +2729,9 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
|
|||
rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
|
||||
}
|
||||
|
||||
if (rt2x00_rt(rt2x00dev, RT3070) || rt2x00_rt(rt2x00dev, RT3071)) {
|
||||
if (rt2x00_rt(rt2x00dev, RT3070)) {
|
||||
rt2800_rfcsr_read(rt2x00dev, 27, &rfcsr);
|
||||
if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F) ||
|
||||
rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E))
|
||||
if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F))
|
||||
rt2x00_set_field8(&rfcsr, RFCSR27_R1, 3);
|
||||
else
|
||||
rt2x00_set_field8(&rfcsr, RFCSR27_R1, 0);
|
||||
|
@ -2810,10 +2819,7 @@ void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev)
|
|||
|
||||
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
|
||||
rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
|
||||
|
||||
/* Wait for DMA, ignore error */
|
||||
|
@ -2823,9 +2829,6 @@ void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev)
|
|||
rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 0);
|
||||
rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0);
|
||||
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
|
||||
|
||||
rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
|
||||
rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2800_disable_radio);
|
||||
|
||||
|
@ -3530,7 +3533,8 @@ EXPORT_SYMBOL_GPL(rt2800_get_tsf);
|
|||
|
||||
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
|
|
@ -198,7 +198,8 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
|
|||
u64 rt2800_get_tsf(struct ieee80211_hw *hw);
|
||||
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size);
|
||||
int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey);
|
||||
|
||||
|
|
|
@ -475,39 +475,23 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
|
|||
|
||||
static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
rt2800_disable_radio(rt2x00dev);
|
||||
|
||||
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280);
|
||||
|
||||
rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®);
|
||||
rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1);
|
||||
rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1);
|
||||
rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1);
|
||||
rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, 1);
|
||||
rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1);
|
||||
rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1);
|
||||
rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1);
|
||||
rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
|
||||
|
||||
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
|
||||
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
|
||||
if (rt2x00_is_soc(rt2x00dev)) {
|
||||
rt2800_disable_radio(rt2x00dev);
|
||||
rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
|
||||
rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
|
||||
enum dev_state state)
|
||||
{
|
||||
/*
|
||||
* Always put the device to sleep (even when we intend to wakeup!)
|
||||
* if the device is booting and wasn't asleep it will return
|
||||
* failure when attempting to wakeup.
|
||||
*/
|
||||
rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0xff, 2);
|
||||
|
||||
if (state == STATE_AWAKE) {
|
||||
rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0);
|
||||
rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02);
|
||||
rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP);
|
||||
} else if (state == STATE_SLEEP) {
|
||||
rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, 0xffffffff);
|
||||
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, 0xffffffff);
|
||||
rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -649,7 +649,10 @@ static void rt2x00lib_channel(struct ieee80211_channel *entry,
|
|||
const int channel, const int tx_power,
|
||||
const int value)
|
||||
{
|
||||
entry->center_freq = ieee80211_channel_to_frequency(channel);
|
||||
/* XXX: this assumption about the band is wrong for 802.11j */
|
||||
entry->band = channel <= 14 ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
|
||||
entry->center_freq = ieee80211_channel_to_frequency(channel,
|
||||
entry->band);
|
||||
entry->hw_value = value;
|
||||
entry->max_power = tx_power;
|
||||
entry->max_antenna_gain = 0xff;
|
||||
|
|
|
@ -748,7 +748,8 @@ static void rtl_op_sta_notify(struct ieee80211_hw *hw,
|
|||
static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 * ssn)
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
|
||||
|
|
|
@ -78,7 +78,8 @@ static void wl1251_rx_status(struct wl1251 *wl,
|
|||
*/
|
||||
wl->noise = desc->rssi - desc->snr / 2;
|
||||
|
||||
status->freq = ieee80211_channel_to_frequency(desc->channel);
|
||||
status->freq = ieee80211_channel_to_frequency(desc->channel,
|
||||
status->band);
|
||||
|
||||
status->flag |= RX_FLAG_TSFT;
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ static void wl1271_rx_status(struct wl1271 *wl,
|
|||
*/
|
||||
wl->noise = desc->rssi - (desc->snr >> 1);
|
||||
|
||||
status->freq = ieee80211_channel_to_frequency(desc->channel);
|
||||
status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band);
|
||||
|
||||
if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
|
||||
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
|
||||
|
|
|
@ -1790,8 +1790,9 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
|
|||
/**
|
||||
* ieee80211_channel_to_frequency - convert channel number to frequency
|
||||
* @chan: channel number
|
||||
* @band: band, necessary due to channel number overlap
|
||||
*/
|
||||
extern int ieee80211_channel_to_frequency(int chan);
|
||||
extern int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band);
|
||||
|
||||
/**
|
||||
* ieee80211_frequency_to_channel - convert frequency to channel number
|
||||
|
|
|
@ -1147,6 +1147,17 @@ enum ieee80211_hw_flags {
|
|||
* @napi_weight: weight used for NAPI polling. You must specify an
|
||||
* appropriate value here if a napi_poll operation is provided
|
||||
* by your driver.
|
||||
|
||||
* @max_rx_aggregation_subframes: maximum buffer size (number of
|
||||
* sub-frames) to be used for A-MPDU block ack receiver
|
||||
* aggregation.
|
||||
* This is only relevant if the device has restrictions on the
|
||||
* number of subframes, if it relies on mac80211 to do reordering
|
||||
* it shouldn't be set.
|
||||
*
|
||||
* @max_tx_aggregation_subframes: maximum number of subframes in an
|
||||
* aggregate an HT driver will transmit, used by the peer as a
|
||||
* hint to size its reorder buffer.
|
||||
*/
|
||||
struct ieee80211_hw {
|
||||
struct ieee80211_conf conf;
|
||||
|
@ -1165,6 +1176,8 @@ struct ieee80211_hw {
|
|||
u8 max_rates;
|
||||
u8 max_report_rates;
|
||||
u8 max_rate_tries;
|
||||
u8 max_rx_aggregation_subframes;
|
||||
u8 max_tx_aggregation_subframes;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1723,6 +1736,10 @@ enum ieee80211_ampdu_mlme_action {
|
|||
* ieee80211_ampdu_mlme_action. Starting sequence number (@ssn)
|
||||
* is the first frame we expect to perform the action on. Notice
|
||||
* that TX/RX_STOP can pass NULL for this parameter.
|
||||
* The @buf_size parameter is only valid when the action is set to
|
||||
* %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's reorder
|
||||
* buffer size (number of subframes) for this session -- aggregates
|
||||
* containing more subframes than this may not be transmitted to the peer.
|
||||
* Returns a negative error code on failure.
|
||||
* The callback can sleep.
|
||||
*
|
||||
|
@ -1825,7 +1842,8 @@ struct ieee80211_ops {
|
|||
int (*ampdu_action)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size);
|
||||
int (*get_survey)(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey);
|
||||
void (*rfkill_poll)(struct ieee80211_hw *hw);
|
||||
|
|
|
@ -76,7 +76,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
|||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL))
|
||||
&sta->sta, tid, NULL, 0))
|
||||
printk(KERN_DEBUG "HW problem - can not stop rx "
|
||||
"aggregation for tid %d\n", tid);
|
||||
|
||||
|
@ -232,6 +232,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|||
if (buf_size == 0)
|
||||
buf_size = IEEE80211_MAX_AMPDU_BUF;
|
||||
|
||||
/* make sure the size doesn't exceed the maximum supported by the hw */
|
||||
if (buf_size > local->hw.max_rx_aggregation_subframes)
|
||||
buf_size = local->hw.max_rx_aggregation_subframes;
|
||||
|
||||
/* examine state machine */
|
||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||
|
@ -287,7 +290,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|||
}
|
||||
|
||||
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
&sta->sta, tid, &start_seq_num, 0);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
|
|
@ -190,7 +190,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
|||
|
||||
ret = drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_STOP,
|
||||
&sta->sta, tid, NULL);
|
||||
&sta->sta, tid, NULL, 0);
|
||||
|
||||
/* HW shall not deny going back to legacy */
|
||||
if (WARN_ON(ret)) {
|
||||
|
@ -311,7 +311,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
|||
start_seq_num = sta->tid_seq[tid] >> 4;
|
||||
|
||||
ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
&sta->sta, tid, &start_seq_num, 0);
|
||||
if (ret) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - HW unavailable for"
|
||||
|
@ -342,7 +342,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
|||
/* send AddBA request */
|
||||
ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
|
||||
tid_tx->dialog_token, start_seq_num,
|
||||
0x40, tid_tx->timeout);
|
||||
local->hw.max_tx_aggregation_subframes,
|
||||
tid_tx->timeout);
|
||||
}
|
||||
|
||||
int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
||||
|
@ -487,7 +488,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
|||
|
||||
drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
&sta->sta, tid, NULL);
|
||||
&sta->sta, tid, NULL,
|
||||
sta->ampdu_mlme.tid_tx[tid]->buf_size);
|
||||
|
||||
/*
|
||||
* synchronize with TX path, while splicing the TX path
|
||||
|
@ -742,9 +744,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
|||
{
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
u16 capab, tid;
|
||||
u8 buf_size;
|
||||
|
||||
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
|
||||
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
|
||||
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
|
||||
|
||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||
|
||||
|
@ -767,12 +771,23 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
|||
|
||||
if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
|
||||
== WLAN_STATUS_SUCCESS) {
|
||||
/*
|
||||
* IEEE 802.11-2007 7.3.1.14:
|
||||
* In an ADDBA Response frame, when the Status Code field
|
||||
* is set to 0, the Buffer Size subfield is set to a value
|
||||
* of at least 1.
|
||||
*/
|
||||
if (!buf_size)
|
||||
goto out;
|
||||
|
||||
if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED,
|
||||
&tid_tx->state)) {
|
||||
/* ignore duplicate response */
|
||||
goto out;
|
||||
}
|
||||
|
||||
tid_tx->buf_size = buf_size;
|
||||
|
||||
if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))
|
||||
ieee80211_agg_tx_operational(local, sta, tid);
|
||||
|
||||
|
|
|
@ -382,17 +382,17 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
|
|||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn)
|
||||
u16 *ssn, u8 buf_size)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
might_sleep();
|
||||
|
||||
trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn);
|
||||
trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
|
||||
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
|
||||
sta, tid, ssn);
|
||||
sta, tid, ssn, buf_size);
|
||||
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
#undef TRACE_EVENT
|
||||
#define TRACE_EVENT(name, proto, ...) \
|
||||
static inline void trace_ ## name(proto) {}
|
||||
#undef DECLARE_EVENT_CLASS
|
||||
#define DECLARE_EVENT_CLASS(...)
|
||||
#undef DEFINE_EVENT
|
||||
#define DEFINE_EVENT(evt_class, name, proto, ...) \
|
||||
static inline void trace_ ## name(proto) {}
|
||||
#endif
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
|
@ -38,7 +43,7 @@ static inline void trace_ ## name(proto) {}
|
|||
* Tracing for driver callbacks.
|
||||
*/
|
||||
|
||||
TRACE_EVENT(drv_return_void,
|
||||
DECLARE_EVENT_CLASS(local_only_evt,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
TP_ARGS(local),
|
||||
TP_STRUCT__entry(
|
||||
|
@ -50,6 +55,11 @@ TRACE_EVENT(drv_return_void,
|
|||
TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(local_only_evt, drv_return_void,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_return_int,
|
||||
TP_PROTO(struct ieee80211_local *local, int ret),
|
||||
TP_ARGS(local, ret),
|
||||
|
@ -78,40 +88,14 @@ TRACE_EVENT(drv_return_u64,
|
|||
TP_printk(LOCAL_PR_FMT " - %llu", LOCAL_PR_ARG, __entry->ret)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_start,
|
||||
DEFINE_EVENT(local_only_evt, drv_start,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_stop,
|
||||
DEFINE_EVENT(local_only_evt, drv_stop,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_add_interface,
|
||||
|
@ -439,40 +423,14 @@ TRACE_EVENT(drv_hw_scan,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_sw_scan_start,
|
||||
DEFINE_EVENT(local_only_evt, drv_sw_scan_start,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_sw_scan_complete,
|
||||
DEFINE_EVENT(local_only_evt, drv_sw_scan_complete,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_get_stats,
|
||||
|
@ -702,23 +660,9 @@ TRACE_EVENT(drv_conf_tx,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_get_tsf,
|
||||
DEFINE_EVENT(local_only_evt, drv_get_tsf,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT,
|
||||
LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_set_tsf,
|
||||
|
@ -742,41 +686,14 @@ TRACE_EVENT(drv_set_tsf,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_reset_tsf,
|
||||
DEFINE_EVENT(local_only_evt, drv_reset_tsf,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_tx_last_beacon,
|
||||
DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT,
|
||||
LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_ampdu_action,
|
||||
|
@ -784,9 +701,9 @@ TRACE_EVENT(drv_ampdu_action,
|
|||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn),
|
||||
u16 *ssn, u8 buf_size),
|
||||
|
||||
TP_ARGS(local, sdata, action, sta, tid, ssn),
|
||||
TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
|
@ -794,6 +711,7 @@ TRACE_EVENT(drv_ampdu_action,
|
|||
__field(u32, action)
|
||||
__field(u16, tid)
|
||||
__field(u16, ssn)
|
||||
__field(u8, buf_size)
|
||||
VIF_ENTRY
|
||||
),
|
||||
|
||||
|
@ -804,11 +722,13 @@ TRACE_EVENT(drv_ampdu_action,
|
|||
__entry->action = action;
|
||||
__entry->tid = tid;
|
||||
__entry->ssn = ssn ? *ssn : 0;
|
||||
__entry->buf_size = buf_size;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
|
||||
__entry->tid, __entry->buf_size
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -959,22 +879,9 @@ TRACE_EVENT(drv_remain_on_channel,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_cancel_remain_on_channel,
|
||||
DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
/*
|
||||
|
@ -1069,23 +976,9 @@ TRACE_EVENT(api_stop_tx_ba_cb,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(api_restart_hw,
|
||||
DEFINE_EVENT(local_only_evt, api_restart_hw,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT,
|
||||
LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(api_beacon_loss,
|
||||
|
@ -1214,40 +1107,14 @@ TRACE_EVENT(api_chswitch_done,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(api_ready_on_channel,
|
||||
DEFINE_EVENT(local_only_evt, api_ready_on_channel,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
TRACE_EVENT(api_remain_on_channel_expired,
|
||||
DEFINE_EVENT(local_only_evt, api_remain_on_channel_expired,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
/*
|
||||
|
|
|
@ -270,7 +270,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
enum ieee80211_band band = rx_status->band;
|
||||
|
||||
if (elems->ds_params && elems->ds_params_len == 1)
|
||||
freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
|
||||
freq = ieee80211_channel_to_frequency(elems->ds_params[0],
|
||||
band);
|
||||
else
|
||||
freq = rx_status->freq;
|
||||
|
||||
|
|
|
@ -554,6 +554,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
local->hw.queues = 1;
|
||||
local->hw.max_rates = 1;
|
||||
local->hw.max_report_rates = 0;
|
||||
local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
|
||||
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
|
||||
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
|
||||
local->user_power_level = -1;
|
||||
|
|
|
@ -574,7 +574,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
|||
&elems);
|
||||
|
||||
if (elems.ds_params && elems.ds_params_len == 1)
|
||||
freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
|
||||
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
|
||||
else
|
||||
freq = rx_status->freq;
|
||||
|
||||
|
@ -645,7 +645,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
|||
if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
|
||||
mesh_mpath_table_grow();
|
||||
|
||||
if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
|
||||
if (test_and_clear_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags))
|
||||
mesh_mpp_table_grow();
|
||||
|
||||
if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
|
||||
|
|
|
@ -176,7 +176,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* check that channel matches the right operating channel */
|
||||
if (local->hw.conf.channel->center_freq !=
|
||||
ieee80211_channel_to_frequency(hti->control_chan))
|
||||
ieee80211_channel_to_frequency(hti->control_chan, sband->band))
|
||||
enable_ht = false;
|
||||
|
||||
if (enable_ht) {
|
||||
|
@ -429,7 +429,8 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
container_of((void *)bss, struct cfg80211_bss, priv);
|
||||
struct ieee80211_channel *new_ch;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
|
||||
int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num,
|
||||
cbss->channel->band);
|
||||
|
||||
ASSERT_MGD_MTX(ifmgd);
|
||||
|
||||
|
@ -1519,7 +1520,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
if (elems->ds_params && elems->ds_params_len == 1)
|
||||
freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
|
||||
freq = ieee80211_channel_to_frequency(elems->ds_params[0],
|
||||
rx_status->band);
|
||||
else
|
||||
freq = rx_status->freq;
|
||||
|
||||
|
@ -1972,9 +1974,9 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
|||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"%s: No ack for nullfunc frame to"
|
||||
" AP %pM, try %d\n",
|
||||
" AP %pM, try %d/%i\n",
|
||||
sdata->name, bssid,
|
||||
ifmgd->probe_send_count);
|
||||
ifmgd->probe_send_count, max_tries);
|
||||
#endif
|
||||
ieee80211_mgd_probe_ap_send(sdata);
|
||||
} else {
|
||||
|
@ -2001,10 +2003,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
|||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"%s: No probe response from AP %pM"
|
||||
" after %dms, try %d\n",
|
||||
" after %dms, try %d/%i\n",
|
||||
sdata->name,
|
||||
bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ,
|
||||
ifmgd->probe_send_count);
|
||||
ifmgd->probe_send_count, max_tries);
|
||||
#endif
|
||||
ieee80211_mgd_probe_ap_send(sdata);
|
||||
} else {
|
||||
|
|
|
@ -1556,17 +1556,36 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
bool check_port_control = false;
|
||||
struct ethhdr *ehdr;
|
||||
int ret;
|
||||
|
||||
if (ieee80211_has_a4(hdr->frame_control) &&
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
|
||||
return -1;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!!sdata->u.mgd.use_4addr != !!ieee80211_has_a4(hdr->frame_control)) {
|
||||
|
||||
if (!sdata->u.mgd.use_4addr)
|
||||
return -1;
|
||||
else
|
||||
check_port_control = true;
|
||||
}
|
||||
|
||||
if (is_multicast_ether_addr(hdr->addr1) &&
|
||||
((sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta) ||
|
||||
(sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr)))
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta)
|
||||
return -1;
|
||||
|
||||
return ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
|
||||
ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
|
||||
if (ret < 0 || !check_port_control)
|
||||
return ret;
|
||||
|
||||
ehdr = (struct ethhdr *) rx->skb->data;
|
||||
if (ehdr->h_proto != rx->sdata->control_port_protocol)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2692,7 +2711,7 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
|
|||
if (!skb) {
|
||||
if (net_ratelimit())
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"failed to copy multicast frame for %s\n",
|
||||
"failed to copy skb for %s\n",
|
||||
sdata->name);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -196,7 +196,8 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
|||
ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
|
||||
|
||||
if (elems.ds_params && elems.ds_params_len == 1)
|
||||
freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
|
||||
freq = ieee80211_channel_to_frequency(elems.ds_params[0],
|
||||
rx_status->band);
|
||||
else
|
||||
freq = rx_status->freq;
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ enum ieee80211_sta_info_flags {
|
|||
* @state: session state (see above)
|
||||
* @stop_initiator: initiator of a session stop
|
||||
* @tx_stop: TX DelBA frame when stopping
|
||||
* @buf_size: reorder buffer size at receiver
|
||||
*
|
||||
* This structure's lifetime is managed by RCU, assignments to
|
||||
* the array holding it must hold the aggregation mutex.
|
||||
|
@ -101,6 +102,7 @@ struct tid_ampdu_tx {
|
|||
u8 dialog_token;
|
||||
u8 stop_initiator;
|
||||
bool tx_stop;
|
||||
u8 buf_size;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1750,7 +1750,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
__le16 fc;
|
||||
struct ieee80211_hdr hdr;
|
||||
struct ieee80211s_hdr mesh_hdr __maybe_unused;
|
||||
struct mesh_path *mppath = NULL;
|
||||
struct mesh_path __maybe_unused *mppath = NULL;
|
||||
const u8 *encaps_data;
|
||||
int encaps_len, skip_header_bytes;
|
||||
int nh_pos, h_pos;
|
||||
|
@ -1815,19 +1815,19 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
mppath = mpp_path_lookup(skb->data, sdata);
|
||||
|
||||
/*
|
||||
* Do not use address extension, if it is a packet from
|
||||
* the same interface and the destination is not being
|
||||
* proxied by any other mest point.
|
||||
* Use address extension if it is a packet from
|
||||
* another interface or if we know the destination
|
||||
* is being proxied by a portal (i.e. portal address
|
||||
* differs from proxied address)
|
||||
*/
|
||||
if (compare_ether_addr(sdata->vif.addr,
|
||||
skb->data + ETH_ALEN) == 0 &&
|
||||
(!mppath || !compare_ether_addr(mppath->mpp, skb->data))) {
|
||||
!(mppath && compare_ether_addr(mppath->mpp, skb->data))) {
|
||||
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
|
||||
skb->data, skb->data + ETH_ALEN);
|
||||
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
|
||||
sdata, NULL, NULL);
|
||||
} else {
|
||||
/* packet from other interface */
|
||||
int is_mesh_mcast = 1;
|
||||
const u8 *mesh_da;
|
||||
|
||||
|
@ -2302,6 +2302,11 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
|||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *pos;
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
if (!sdata->u.mesh.mesh_id_len)
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
/* headroom, head length, tail length and maximum TIM length */
|
||||
skb = dev_alloc_skb(local->tx_headroom + 400 +
|
||||
sdata->u.mesh.vendor_ie_len);
|
||||
|
|
|
@ -1801,9 +1801,9 @@ void regulatory_hint_disconnect(void)
|
|||
|
||||
static bool freq_is_chan_12_13_14(u16 freq)
|
||||
{
|
||||
if (freq == ieee80211_channel_to_frequency(12) ||
|
||||
freq == ieee80211_channel_to_frequency(13) ||
|
||||
freq == ieee80211_channel_to_frequency(14))
|
||||
if (freq == ieee80211_channel_to_frequency(12, IEEE80211_BAND_2GHZ) ||
|
||||
freq == ieee80211_channel_to_frequency(13, IEEE80211_BAND_2GHZ) ||
|
||||
freq == ieee80211_channel_to_frequency(14, IEEE80211_BAND_2GHZ))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -29,29 +29,37 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_get_response_rate);
|
||||
|
||||
int ieee80211_channel_to_frequency(int chan)
|
||||
int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band)
|
||||
{
|
||||
if (chan < 14)
|
||||
return 2407 + chan * 5;
|
||||
|
||||
if (chan == 14)
|
||||
return 2484;
|
||||
|
||||
/* FIXME: 802.11j 17.3.8.3.2 */
|
||||
return (chan + 1000) * 5;
|
||||
/* see 802.11 17.3.8.3.2 and Annex J
|
||||
* there are overlapping channel numbers in 5GHz and 2GHz bands */
|
||||
if (band == IEEE80211_BAND_5GHZ) {
|
||||
if (chan >= 182 && chan <= 196)
|
||||
return 4000 + chan * 5;
|
||||
else
|
||||
return 5000 + chan * 5;
|
||||
} else { /* IEEE80211_BAND_2GHZ */
|
||||
if (chan == 14)
|
||||
return 2484;
|
||||
else if (chan < 14)
|
||||
return 2407 + chan * 5;
|
||||
else
|
||||
return 0; /* not supported */
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_channel_to_frequency);
|
||||
|
||||
int ieee80211_frequency_to_channel(int freq)
|
||||
{
|
||||
/* see 802.11 17.3.8.3.2 and Annex J */
|
||||
if (freq == 2484)
|
||||
return 14;
|
||||
|
||||
if (freq < 2484)
|
||||
else if (freq < 2484)
|
||||
return (freq - 2407) / 5;
|
||||
|
||||
/* FIXME: 802.11j 17.3.8.3.2 */
|
||||
return freq/5 - 1000;
|
||||
else if (freq >= 4910 && freq <= 4980)
|
||||
return (freq - 4000) / 5;
|
||||
else
|
||||
return (freq - 5000) / 5;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_frequency_to_channel);
|
||||
|
||||
|
|
|
@ -267,9 +267,12 @@ int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq)
|
|||
* -EINVAL for impossible things.
|
||||
*/
|
||||
if (freq->e == 0) {
|
||||
enum ieee80211_band band = IEEE80211_BAND_2GHZ;
|
||||
if (freq->m < 0)
|
||||
return 0;
|
||||
return ieee80211_channel_to_frequency(freq->m);
|
||||
if (freq->m > 14)
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
return ieee80211_channel_to_frequency(freq->m, band);
|
||||
} else {
|
||||
int i, div = 1000000;
|
||||
for (i = 0; i < freq->e; i++)
|
||||
|
|
Loading…
Reference in New Issue