mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-08 20:57:29 +02:00
442b9d46bb
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@31326 3c298f89-4303-0410-b956-a3cf2f4a3e73
880 lines
29 KiB
Diff
880 lines
29 KiB
Diff
--- a/drivers/net/wireless/ath/ath5k/base.c
|
|
+++ b/drivers/net/wireless/ath/ath5k/base.c
|
|
@@ -1171,7 +1171,7 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah
|
|
|
|
if (ieee80211_is_beacon(mgmt->frame_control) &&
|
|
le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
|
|
- memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) {
|
|
+ compare_ether_addr(mgmt->bssid, common->curbssid) == 0) {
|
|
/*
|
|
* Received an IBSS beacon with the same BSSID. Hardware *must*
|
|
* have updated the local TSF. We have to work around various
|
|
@@ -1235,7 +1235,7 @@ ath5k_update_beacon_rssi(struct ath5k_hw
|
|
|
|
/* only beacons from our BSSID */
|
|
if (!ieee80211_is_beacon(mgmt->frame_control) ||
|
|
- memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0)
|
|
+ compare_ether_addr(mgmt->bssid, common->curbssid) != 0)
|
|
return;
|
|
|
|
ewma_add(&ah->ah_beacon_rssi_avg, rssi);
|
|
@@ -2416,6 +2416,22 @@ ath5k_tx_complete_poll_work(struct work_
|
|
* Initialization routines *
|
|
\*************************/
|
|
|
|
+static const struct ieee80211_iface_limit if_limits[] = {
|
|
+ { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) },
|
|
+ { .max = 4, .types =
|
|
+#ifdef CONFIG_MAC80211_MESH
|
|
+ BIT(NL80211_IFTYPE_MESH_POINT) |
|
|
+#endif
|
|
+ BIT(NL80211_IFTYPE_AP) },
|
|
+};
|
|
+
|
|
+static const struct ieee80211_iface_combination if_comb = {
|
|
+ .limits = if_limits,
|
|
+ .n_limits = ARRAY_SIZE(if_limits),
|
|
+ .max_interfaces = 2048,
|
|
+ .num_different_channels = 1,
|
|
+};
|
|
+
|
|
int __devinit
|
|
ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
|
|
{
|
|
@@ -2437,6 +2453,9 @@ ath5k_init_ah(struct ath5k_hw *ah, const
|
|
BIT(NL80211_IFTYPE_ADHOC) |
|
|
BIT(NL80211_IFTYPE_MESH_POINT);
|
|
|
|
+ hw->wiphy->iface_combinations = &if_comb;
|
|
+ hw->wiphy->n_iface_combinations = 1;
|
|
+
|
|
/* SW support for IBSS_RSN is provided by mac80211 */
|
|
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
|
|
|
|
--- a/drivers/net/wireless/ath/ath9k/ani.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/ani.c
|
|
@@ -274,7 +274,9 @@ static void ath9k_hw_set_ofdm_nil(struct
|
|
aniState->rssiThrLow, aniState->rssiThrHigh);
|
|
|
|
if (aniState->update_ani)
|
|
- aniState->ofdmNoiseImmunityLevel = immunityLevel;
|
|
+ aniState->ofdmNoiseImmunityLevel =
|
|
+ (immunityLevel > ATH9K_ANI_OFDM_DEF_LEVEL) ?
|
|
+ immunityLevel : ATH9K_ANI_OFDM_DEF_LEVEL;
|
|
|
|
entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
|
|
entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
|
|
@@ -340,7 +342,9 @@ static void ath9k_hw_set_cck_nil(struct
|
|
immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
|
|
|
|
if (aniState->update_ani)
|
|
- aniState->cckNoiseImmunityLevel = immunityLevel;
|
|
+ aniState->cckNoiseImmunityLevel =
|
|
+ (immunityLevel > ATH9K_ANI_CCK_DEF_LEVEL) ?
|
|
+ immunityLevel : ATH9K_ANI_CCK_DEF_LEVEL;
|
|
|
|
entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
|
|
entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
|
|
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
|
|
@@ -618,19 +618,10 @@ static void ar5008_hw_init_bb(struct ath
|
|
u32 synthDelay;
|
|
|
|
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
|
|
- if (IS_CHAN_B(chan))
|
|
- synthDelay = (4 * synthDelay) / 22;
|
|
- else
|
|
- synthDelay /= 10;
|
|
-
|
|
- if (IS_CHAN_HALF_RATE(chan))
|
|
- synthDelay *= 2;
|
|
- else if (IS_CHAN_QUARTER_RATE(chan))
|
|
- synthDelay *= 4;
|
|
|
|
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
|
|
|
|
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
|
|
+ ath9k_hw_synth_delay(ah, chan, synthDelay);
|
|
}
|
|
|
|
static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
|
|
@@ -868,7 +859,7 @@ static int ar5008_hw_process_ini(struct
|
|
ar5008_hw_set_channel_regs(ah, chan);
|
|
ar5008_hw_init_chain_masks(ah);
|
|
ath9k_olc_init(ah);
|
|
- ath9k_hw_apply_txpower(ah, chan);
|
|
+ ath9k_hw_apply_txpower(ah, chan, false);
|
|
|
|
/* Write analog registers */
|
|
if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
|
|
@@ -948,12 +939,8 @@ static bool ar5008_hw_rfbus_req(struct a
|
|
static void ar5008_hw_rfbus_done(struct ath_hw *ah)
|
|
{
|
|
u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
|
|
- if (IS_CHAN_B(ah->curchan))
|
|
- synthDelay = (4 * synthDelay) / 22;
|
|
- else
|
|
- synthDelay /= 10;
|
|
|
|
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
|
|
+ ath9k_hw_synth_delay(ah, ah->curchan, synthDelay);
|
|
|
|
REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
|
|
}
|
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
|
@@ -1000,10 +1000,12 @@ static bool ar9003_hw_init_cal(struct at
|
|
if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
|
|
ar9003_mci_init_cal_req(ah, &is_reusable);
|
|
|
|
- txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
|
|
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
|
|
- udelay(5);
|
|
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
|
|
+ if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
|
|
+ txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
|
|
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
|
|
+ udelay(5);
|
|
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
|
|
+ }
|
|
|
|
skip_tx_iqcal:
|
|
if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
|
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
|
|
@@ -54,7 +54,7 @@ void ar9003_paprd_enable(struct ath_hw *
|
|
|
|
if (val) {
|
|
ah->paprd_table_write_done = true;
|
|
- ath9k_hw_apply_txpower(ah, chan);
|
|
+ ath9k_hw_apply_txpower(ah, chan, false);
|
|
}
|
|
|
|
REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
|
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
|
@@ -524,22 +524,10 @@ static void ar9003_hw_init_bb(struct ath
|
|
* Value is in 100ns increments.
|
|
*/
|
|
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
|
|
- if (IS_CHAN_B(chan))
|
|
- synthDelay = (4 * synthDelay) / 22;
|
|
- else
|
|
- synthDelay /= 10;
|
|
|
|
/* Activate the PHY (includes baseband activate + synthesizer on) */
|
|
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
|
|
-
|
|
- /*
|
|
- * There is an issue if the AP starts the calibration before
|
|
- * the base band timeout completes. This could result in the
|
|
- * rx_clear false triggering. As a workaround we add delay an
|
|
- * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
|
|
- * does not happen.
|
|
- */
|
|
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
|
|
+ ath9k_hw_synth_delay(ah, chan, synthDelay);
|
|
}
|
|
|
|
static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
|
|
@@ -690,7 +678,7 @@ static int ar9003_hw_process_ini(struct
|
|
ar9003_hw_override_ini(ah);
|
|
ar9003_hw_set_channel_regs(ah, chan);
|
|
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
|
|
- ath9k_hw_apply_txpower(ah, chan);
|
|
+ ath9k_hw_apply_txpower(ah, chan, false);
|
|
|
|
if (AR_SREV_9462(ah)) {
|
|
if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
|
|
@@ -721,6 +709,14 @@ static void ar9003_hw_set_rfmode(struct
|
|
|
|
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
|
|
rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
|
|
+ if (IS_CHAN_QUARTER_RATE(chan))
|
|
+ rfMode |= AR_PHY_MODE_QUARTER;
|
|
+ if (IS_CHAN_HALF_RATE(chan))
|
|
+ rfMode |= AR_PHY_MODE_HALF;
|
|
+
|
|
+ if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
|
|
+ REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
|
|
+ AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 3);
|
|
|
|
REG_WRITE(ah, AR_PHY_MODE, rfMode);
|
|
}
|
|
@@ -791,12 +787,8 @@ static bool ar9003_hw_rfbus_req(struct a
|
|
static void ar9003_hw_rfbus_done(struct ath_hw *ah)
|
|
{
|
|
u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
|
|
- if (IS_CHAN_B(ah->curchan))
|
|
- synthDelay = (4 * synthDelay) / 22;
|
|
- else
|
|
- synthDelay /= 10;
|
|
|
|
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
|
|
+ ath9k_hw_synth_delay(ah, ah->curchan, synthDelay);
|
|
|
|
REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
|
|
}
|
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
|
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
|
|
@@ -468,6 +468,9 @@
|
|
#define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150)
|
|
#define AR_PHY_XPA_CFG (AR_SM_BASE + 0x158)
|
|
|
|
+#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW 3
|
|
+#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW_S 0
|
|
+
|
|
#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A 0x0001FC00
|
|
#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A_S 10
|
|
#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF
|
|
--- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
|
|
+++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
|
|
@@ -1115,9 +1115,9 @@ static const u32 ar9462_2p0_mac_core[][2
|
|
{0x000081f8, 0x00000000},
|
|
{0x000081fc, 0x00000000},
|
|
{0x00008240, 0x00100000},
|
|
- {0x00008244, 0x0010f400},
|
|
+ {0x00008244, 0x0010f424},
|
|
{0x00008248, 0x00000800},
|
|
- {0x0000824c, 0x0001e800},
|
|
+ {0x0000824c, 0x0001e848},
|
|
{0x00008250, 0x00000000},
|
|
{0x00008254, 0x00000000},
|
|
{0x00008258, 0x00000000},
|
|
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
@@ -370,7 +370,7 @@ struct ath_vif {
|
|
* number of beacon intervals, the game's up.
|
|
*/
|
|
#define BSTUCK_THRESH 9
|
|
-#define ATH_BCBUF 4
|
|
+#define ATH_BCBUF 8
|
|
#define ATH_DEFAULT_BINTVAL 100 /* TU */
|
|
#define ATH_DEFAULT_BMISS_LIMIT 10
|
|
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
|
|
--- a/drivers/net/wireless/ath/ath9k/beacon.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
|
|
@@ -91,7 +91,7 @@ static void ath_beacon_setup(struct ath_
|
|
info.txpower = MAX_RATE_POWER;
|
|
info.keyix = ATH9K_TXKEYIX_INVALID;
|
|
info.keytype = ATH9K_KEY_TYPE_CLEAR;
|
|
- info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_INTREQ;
|
|
+ info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK;
|
|
|
|
info.buf_addr[0] = bf->bf_buf_addr;
|
|
info.buf_len[0] = roundup(skb->len, 4);
|
|
@@ -359,6 +359,11 @@ void ath_beacon_tasklet(unsigned long da
|
|
int slot;
|
|
u32 bfaddr, bc = 0;
|
|
|
|
+ if (work_pending(&sc->hw_reset_work)) {
|
|
+ ath_dbg(common, RESET,
|
|
+ "reset work is pending, skip beaconing now\n");
|
|
+ return;
|
|
+ }
|
|
/*
|
|
* Check if the previous beacon has gone out. If
|
|
* not don't try to post another, skip this period
|
|
@@ -369,6 +374,9 @@ void ath_beacon_tasklet(unsigned long da
|
|
if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
|
|
sc->beacon.bmisscnt++;
|
|
|
|
+ if (!ath9k_hw_check_alive(ah))
|
|
+ ieee80211_queue_work(sc->hw, &sc->hw_check_work);
|
|
+
|
|
if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
|
|
ath_dbg(common, BSTUCK,
|
|
"missed %u consecutive beacons\n",
|
|
@@ -378,6 +386,7 @@ void ath_beacon_tasklet(unsigned long da
|
|
ath9k_hw_bstuck_nfcal(ah);
|
|
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
|
|
ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
|
|
+ sc->beacon.bmisscnt = 0;
|
|
sc->sc_flags |= SC_OP_TSF_RESET;
|
|
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
|
}
|
|
@@ -650,6 +659,8 @@ static void ath_beacon_config_adhoc(stru
|
|
u32 tsf, intval, nexttbtt;
|
|
|
|
ath9k_reset_beacon_status(sc);
|
|
+ if (!(sc->sc_flags & SC_OP_BEACONS))
|
|
+ ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
|
|
|
|
intval = TU_TO_USEC(conf->beacon_interval);
|
|
tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval);
|
|
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
|
|
@@ -824,6 +824,8 @@ static void ath9k_hw_ar9287_set_txpower(
|
|
regulatory->max_power_level = ratesArray[i];
|
|
}
|
|
|
|
+ ath9k_hw_update_regulatory_maxpower(ah);
|
|
+
|
|
if (test)
|
|
return;
|
|
|
|
--- a/drivers/net/wireless/ath/ath9k/gpio.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
|
|
@@ -41,6 +41,9 @@ void ath_init_leds(struct ath_softc *sc)
|
|
{
|
|
int ret;
|
|
|
|
+ if (AR_SREV_9100(sc->sc_ah))
|
|
+ return;
|
|
+
|
|
if (sc->sc_ah->led_pin < 0) {
|
|
if (AR_SREV_9287(sc->sc_ah))
|
|
sc->sc_ah->led_pin = ATH_LED_PIN_9287;
|
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
|
@@ -142,6 +142,22 @@ bool ath9k_hw_wait(struct ath_hw *ah, u3
|
|
}
|
|
EXPORT_SYMBOL(ath9k_hw_wait);
|
|
|
|
+void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
|
|
+ int hw_delay)
|
|
+{
|
|
+ if (IS_CHAN_B(chan))
|
|
+ hw_delay = (4 * hw_delay) / 22;
|
|
+ else
|
|
+ hw_delay /= 10;
|
|
+
|
|
+ if (IS_CHAN_HALF_RATE(chan))
|
|
+ hw_delay *= 2;
|
|
+ else if (IS_CHAN_QUARTER_RATE(chan))
|
|
+ hw_delay *= 4;
|
|
+
|
|
+ udelay(hw_delay + BASE_ACTIVATE_DELAY);
|
|
+}
|
|
+
|
|
void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
|
|
int column, unsigned int *writecnt)
|
|
{
|
|
@@ -388,8 +404,8 @@ static void ath9k_hw_init_config(struct
|
|
{
|
|
int i;
|
|
|
|
- ah->config.dma_beacon_response_time = 2;
|
|
- ah->config.sw_beacon_response_time = 10;
|
|
+ ah->config.dma_beacon_response_time = 1;
|
|
+ ah->config.sw_beacon_response_time = 6;
|
|
ah->config.additional_swba_backoff = 0;
|
|
ah->config.ack_6mb = 0x0;
|
|
ah->config.cwm_ignore_extcca = 0;
|
|
@@ -971,7 +987,7 @@ void ath9k_hw_init_global_settings(struc
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
struct ieee80211_conf *conf = &common->hw->conf;
|
|
const struct ath9k_channel *chan = ah->curchan;
|
|
- int acktimeout, ctstimeout;
|
|
+ int acktimeout, ctstimeout, ack_offset = 0;
|
|
int slottime;
|
|
int sifstime;
|
|
int rx_lat = 0, tx_lat = 0, eifs = 0;
|
|
@@ -992,6 +1008,11 @@ void ath9k_hw_init_global_settings(struc
|
|
rx_lat = 37;
|
|
tx_lat = 54;
|
|
|
|
+ if (IS_CHAN_5GHZ(chan))
|
|
+ sifstime = 16;
|
|
+ else
|
|
+ sifstime = 10;
|
|
+
|
|
if (IS_CHAN_HALF_RATE(chan)) {
|
|
eifs = 175;
|
|
rx_lat *= 2;
|
|
@@ -999,8 +1020,9 @@ void ath9k_hw_init_global_settings(struc
|
|
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
|
|
tx_lat += 11;
|
|
|
|
+ sifstime *= 2;
|
|
+ ack_offset = 16;
|
|
slottime = 13;
|
|
- sifstime = 32;
|
|
} else if (IS_CHAN_QUARTER_RATE(chan)) {
|
|
eifs = 340;
|
|
rx_lat = (rx_lat * 4) - 1;
|
|
@@ -1008,8 +1030,9 @@ void ath9k_hw_init_global_settings(struc
|
|
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
|
|
tx_lat += 22;
|
|
|
|
+ sifstime *= 4;
|
|
+ ack_offset = 32;
|
|
slottime = 21;
|
|
- sifstime = 64;
|
|
} else {
|
|
if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) {
|
|
eifs = AR_D_GBL_IFS_EIFS_ASYNC_FIFO;
|
|
@@ -1023,14 +1046,10 @@ void ath9k_hw_init_global_settings(struc
|
|
tx_lat = MS(reg, AR_USEC_TX_LAT);
|
|
|
|
slottime = ah->slottime;
|
|
- if (IS_CHAN_5GHZ(chan))
|
|
- sifstime = 16;
|
|
- else
|
|
- sifstime = 10;
|
|
}
|
|
|
|
/* As defined by IEEE 802.11-2007 17.3.8.6 */
|
|
- acktimeout = slottime + sifstime + 3 * ah->coverage_class;
|
|
+ acktimeout = slottime + sifstime + 3 * ah->coverage_class + ack_offset;
|
|
ctstimeout = acktimeout;
|
|
|
|
/*
|
|
@@ -1040,7 +1059,8 @@ void ath9k_hw_init_global_settings(struc
|
|
* BA frames in some implementations, but it has been found to fix ACK
|
|
* timeout issues in other cases as well.
|
|
*/
|
|
- if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) {
|
|
+ if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ &&
|
|
+ !IS_CHAN_HALF_RATE(chan) && !IS_CHAN_QUARTER_RATE(chan)) {
|
|
acktimeout += 64 - sifstime - ah->slottime;
|
|
ctstimeout += 48 - sifstime - ah->slottime;
|
|
}
|
|
@@ -1420,6 +1440,10 @@ static bool ath9k_hw_channel_change(stru
|
|
CHANNEL_5GHZ));
|
|
mode_diff = (chan->chanmode != ah->curchan->chanmode);
|
|
|
|
+ if ((ah->curchan->channelFlags | chan->channelFlags) &
|
|
+ (CHANNEL_HALF | CHANNEL_QUARTER))
|
|
+ return false;
|
|
+
|
|
for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
|
|
if (ath9k_hw_numtxpending(ah, qnum)) {
|
|
ath_dbg(common, QUEUE,
|
|
@@ -1453,7 +1477,7 @@ static bool ath9k_hw_channel_change(stru
|
|
return false;
|
|
}
|
|
ath9k_hw_set_clockrate(ah);
|
|
- ath9k_hw_apply_txpower(ah, chan);
|
|
+ ath9k_hw_apply_txpower(ah, chan, false);
|
|
ath9k_hw_rfbus_done(ah);
|
|
|
|
if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
|
|
@@ -2724,7 +2748,8 @@ static int get_antenna_gain(struct ath_h
|
|
return ah->eep_ops->get_eeprom(ah, gain_param);
|
|
}
|
|
|
|
-void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan)
|
|
+void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan,
|
|
+ bool test)
|
|
{
|
|
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
|
|
struct ieee80211_channel *channel;
|
|
@@ -2745,7 +2770,7 @@ void ath9k_hw_apply_txpower(struct ath_h
|
|
|
|
ah->eep_ops->set_txpower(ah, chan,
|
|
ath9k_regd_get_ctl(reg, chan),
|
|
- ant_reduction, new_pwr, false);
|
|
+ ant_reduction, new_pwr, test);
|
|
}
|
|
|
|
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
|
|
@@ -2758,7 +2783,7 @@ void ath9k_hw_set_txpowerlimit(struct at
|
|
if (test)
|
|
channel->max_power = MAX_RATE_POWER / 2;
|
|
|
|
- ath9k_hw_apply_txpower(ah, chan);
|
|
+ ath9k_hw_apply_txpower(ah, chan, test);
|
|
|
|
if (test)
|
|
channel->max_power = DIV_ROUND_UP(reg->max_power_level, 2);
|
|
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
|
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
|
@@ -923,6 +923,8 @@ void ath9k_hw_set_gpio(struct ath_hw *ah
|
|
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
|
|
|
|
/* General Operation */
|
|
+void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
|
|
+ int hw_delay);
|
|
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
|
|
void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
|
|
int column, unsigned int *writecnt);
|
|
@@ -976,7 +978,8 @@ void ath9k_hw_name(struct ath_hw *ah, ch
|
|
/* PHY */
|
|
void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
|
|
u32 *coef_mantissa, u32 *coef_exponent);
|
|
-void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan);
|
|
+void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan,
|
|
+ bool test);
|
|
|
|
/*
|
|
* Code Specific to AR5008, AR9001 or AR9002,
|
|
--- a/drivers/net/wireless/ath/ath9k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/mac.c
|
|
@@ -133,8 +133,16 @@ EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel
|
|
|
|
void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
|
|
{
|
|
+ int maxdelay = 1000;
|
|
int i, q;
|
|
|
|
+ if (ah->curchan) {
|
|
+ if (IS_CHAN_HALF_RATE(ah->curchan))
|
|
+ maxdelay *= 2;
|
|
+ else if (IS_CHAN_QUARTER_RATE(ah->curchan))
|
|
+ maxdelay *= 4;
|
|
+ }
|
|
+
|
|
REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
|
|
|
|
REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
|
|
@@ -142,7 +150,7 @@ void ath9k_hw_abort_tx_dma(struct ath_hw
|
|
REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
|
|
|
|
for (q = 0; q < AR_NUM_QCU; q++) {
|
|
- for (i = 0; i < 1000; i++) {
|
|
+ for (i = 0; i < maxdelay; i++) {
|
|
if (i)
|
|
udelay(5);
|
|
|
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
@@ -692,17 +692,6 @@ void ath9k_tasklet(unsigned long data)
|
|
goto out;
|
|
}
|
|
|
|
- /*
|
|
- * 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 ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
|
|
/*
|
|
* TSF sync does not look correct; remain awake to sync with
|
|
--- a/net/mac80211/agg-rx.c
|
|
+++ b/net/mac80211/agg-rx.c
|
|
@@ -200,6 +200,8 @@ static void ieee80211_send_addba_resp(st
|
|
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
|
else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
|
memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
|
|
+ else if (sdata->vif.type == NL80211_IFTYPE_WDS)
|
|
+ memcpy(mgmt->bssid, da, ETH_ALEN);
|
|
|
|
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
|
IEEE80211_STYPE_ACTION);
|
|
--- a/net/mac80211/agg-tx.c
|
|
+++ b/net/mac80211/agg-tx.c
|
|
@@ -81,7 +81,8 @@ static void ieee80211_send_addba_request
|
|
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
|
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
|
sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
|
- sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
|
+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
|
|
+ sdata->vif.type == NL80211_IFTYPE_WDS)
|
|
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
|
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
|
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
|
@@ -484,6 +485,7 @@ int ieee80211_start_tx_ba_session(struct
|
|
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
|
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
|
sdata->vif.type != NL80211_IFTYPE_AP &&
|
|
+ sdata->vif.type != NL80211_IFTYPE_WDS &&
|
|
sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
|
return -EINVAL;
|
|
|
|
--- a/net/mac80211/debugfs_sta.c
|
|
+++ b/net/mac80211/debugfs_sta.c
|
|
@@ -63,11 +63,11 @@ static ssize_t sta_flags_read(struct fil
|
|
test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
|
|
|
|
int res = scnprintf(buf, sizeof(buf),
|
|
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
|
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
|
TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
|
|
TEST(PS_DRIVER), TEST(AUTHORIZED),
|
|
TEST(SHORT_PREAMBLE),
|
|
- TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
|
|
+ TEST(WME), TEST(CLEAR_PS_FILT),
|
|
TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
|
|
TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
|
|
TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
|
|
--- a/net/mac80211/iface.c
|
|
+++ b/net/mac80211/iface.c
|
|
@@ -163,7 +163,8 @@ static int ieee80211_check_queues(struct
|
|
return -EINVAL;
|
|
}
|
|
|
|
- if (sdata->vif.type != NL80211_IFTYPE_AP) {
|
|
+ if ((sdata->vif.type != NL80211_IFTYPE_AP) ||
|
|
+ !(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) {
|
|
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
|
|
return 0;
|
|
}
|
|
@@ -281,7 +282,6 @@ static int ieee80211_do_open(struct net_
|
|
{
|
|
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
struct ieee80211_local *local = sdata->local;
|
|
- struct sta_info *sta;
|
|
u32 changed = 0;
|
|
int res;
|
|
u32 hw_reconf_flags = 0;
|
|
@@ -427,28 +427,6 @@ static int ieee80211_do_open(struct net_
|
|
|
|
set_bit(SDATA_STATE_RUNNING, &sdata->state);
|
|
|
|
- if (sdata->vif.type == NL80211_IFTYPE_WDS) {
|
|
- /* Create STA entry for the WDS peer */
|
|
- sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
|
|
- GFP_KERNEL);
|
|
- if (!sta) {
|
|
- res = -ENOMEM;
|
|
- goto err_del_interface;
|
|
- }
|
|
-
|
|
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
|
- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
|
|
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
|
-
|
|
- res = sta_info_insert(sta);
|
|
- if (res) {
|
|
- /* STA has been freed */
|
|
- goto err_del_interface;
|
|
- }
|
|
-
|
|
- rate_control_rate_init(sta);
|
|
- }
|
|
-
|
|
/*
|
|
* set_multicast_list will be invoked by the networking core
|
|
* which will check whether any increments here were done in
|
|
@@ -845,6 +823,70 @@ static void ieee80211_if_setup(struct ne
|
|
dev->destructor = free_netdev;
|
|
}
|
|
|
|
+static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|
+ struct sk_buff *skb)
|
|
+{
|
|
+ struct ieee80211_local *local = sdata->local;
|
|
+ struct ieee80211_rx_status *rx_status;
|
|
+ struct ieee802_11_elems elems;
|
|
+ struct ieee80211_mgmt *mgmt;
|
|
+ struct sta_info *sta;
|
|
+ size_t baselen;
|
|
+ u32 rates = 0;
|
|
+ u16 stype;
|
|
+ bool new = false;
|
|
+ enum ieee80211_band band = local->hw.conf.channel->band;
|
|
+ struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
|
|
+
|
|
+ rx_status = IEEE80211_SKB_RXCB(skb);
|
|
+ mgmt = (struct ieee80211_mgmt *) skb->data;
|
|
+ stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
|
|
+
|
|
+ if (stype != IEEE80211_STYPE_BEACON)
|
|
+ return;
|
|
+
|
|
+ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
|
|
+ if (baselen > skb->len)
|
|
+ return;
|
|
+
|
|
+ ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
|
|
+ skb->len - baselen, &elems);
|
|
+
|
|
+ rates = ieee80211_sta_get_rates(local, &elems, band, NULL);
|
|
+
|
|
+ rcu_read_lock();
|
|
+
|
|
+ sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
|
|
+
|
|
+ if (!sta) {
|
|
+ rcu_read_unlock();
|
|
+ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
|
|
+ GFP_KERNEL);
|
|
+ if (!sta)
|
|
+ return;
|
|
+
|
|
+ new = true;
|
|
+ }
|
|
+
|
|
+ sta->last_rx = jiffies;
|
|
+ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
|
|
+
|
|
+ if (elems.ht_cap_elem)
|
|
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
|
+ elems.ht_cap_elem, &sta->sta.ht_cap);
|
|
+
|
|
+ if (elems.wmm_param)
|
|
+ set_sta_flag(sta, WLAN_STA_WME);
|
|
+
|
|
+ if (new) {
|
|
+ set_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
|
+ rate_control_rate_init(sta);
|
|
+ sta_info_insert_rcu(sta);
|
|
+ }
|
|
+
|
|
+ rcu_read_unlock();
|
|
+}
|
|
+
|
|
static void ieee80211_iface_work(struct work_struct *work)
|
|
{
|
|
struct ieee80211_sub_if_data *sdata =
|
|
@@ -949,6 +991,9 @@ static void ieee80211_iface_work(struct
|
|
break;
|
|
ieee80211_mesh_rx_queued_mgmt(sdata, skb);
|
|
break;
|
|
+ case NL80211_IFTYPE_WDS:
|
|
+ ieee80211_wds_rx_queued_mgmt(sdata, skb);
|
|
+ break;
|
|
default:
|
|
WARN(1, "frame for unexpected interface type");
|
|
break;
|
|
--- a/net/mac80211/rx.c
|
|
+++ b/net/mac80211/rx.c
|
|
@@ -103,7 +103,7 @@ static void
|
|
ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
|
struct sk_buff *skb,
|
|
struct ieee80211_rate *rate,
|
|
- int rtap_len)
|
|
+ int rtap_len, bool has_fcs)
|
|
{
|
|
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
|
struct ieee80211_radiotap_header *rthdr;
|
|
@@ -134,7 +134,7 @@ ieee80211_add_rx_radiotap_header(struct
|
|
}
|
|
|
|
/* IEEE80211_RADIOTAP_FLAGS */
|
|
- if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
|
|
+ if (has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))
|
|
*pos |= IEEE80211_RADIOTAP_F_FCS;
|
|
if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
|
|
*pos |= IEEE80211_RADIOTAP_F_BADFCS;
|
|
@@ -294,7 +294,8 @@ ieee80211_rx_monitor(struct ieee80211_lo
|
|
}
|
|
|
|
/* prepend radiotap information */
|
|
- ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom);
|
|
+ ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
|
|
+ true);
|
|
|
|
skb_reset_mac_header(skb);
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
@@ -2282,6 +2283,7 @@ ieee80211_rx_h_action(struct ieee80211_r
|
|
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
|
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
|
sdata->vif.type != NL80211_IFTYPE_AP &&
|
|
+ sdata->vif.type != NL80211_IFTYPE_WDS &&
|
|
sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
|
break;
|
|
|
|
@@ -2496,14 +2498,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
|
|
|
|
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
|
|
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
|
- sdata->vif.type != NL80211_IFTYPE_STATION)
|
|
+ sdata->vif.type != NL80211_IFTYPE_STATION &&
|
|
+ sdata->vif.type != NL80211_IFTYPE_WDS)
|
|
return RX_DROP_MONITOR;
|
|
|
|
switch (stype) {
|
|
case cpu_to_le16(IEEE80211_STYPE_AUTH):
|
|
case cpu_to_le16(IEEE80211_STYPE_BEACON):
|
|
case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
|
|
- /* process for all: mesh, mlme, ibss */
|
|
+ /* process for all: mesh, mlme, ibss, wds */
|
|
break;
|
|
case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
|
|
case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
|
|
@@ -2567,7 +2570,8 @@ static void ieee80211_rx_cooked_monitor(
|
|
goto out_free_skb;
|
|
|
|
/* prepend radiotap information */
|
|
- ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom);
|
|
+ ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
|
|
+ false);
|
|
|
|
skb_set_mac_header(skb, 0);
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
@@ -2836,10 +2840,16 @@ static int prepare_for_handlers(struct i
|
|
}
|
|
break;
|
|
case NL80211_IFTYPE_WDS:
|
|
- if (bssid || !ieee80211_is_data(hdr->frame_control))
|
|
- return 0;
|
|
if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
|
|
return 0;
|
|
+
|
|
+ if (ieee80211_is_data(hdr->frame_control) ||
|
|
+ ieee80211_is_action(hdr->frame_control)) {
|
|
+ if (compare_ether_addr(sdata->vif.addr, hdr->addr1))
|
|
+ return 0;
|
|
+ } else if (!ieee80211_is_beacon(hdr->frame_control))
|
|
+ return 0;
|
|
+
|
|
break;
|
|
default:
|
|
/* should never get here */
|
|
--- a/net/mac80211/sta_info.h
|
|
+++ b/net/mac80211/sta_info.h
|
|
@@ -32,7 +32,6 @@
|
|
* @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
|
|
* frames.
|
|
* @WLAN_STA_WME: Station is a QoS-STA.
|
|
- * @WLAN_STA_WDS: Station is one of our WDS peers.
|
|
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
|
|
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
|
|
* frame to this station is transmitted.
|
|
@@ -64,7 +63,6 @@ enum ieee80211_sta_info_flags {
|
|
WLAN_STA_AUTHORIZED,
|
|
WLAN_STA_SHORT_PREAMBLE,
|
|
WLAN_STA_WME,
|
|
- WLAN_STA_WDS,
|
|
WLAN_STA_CLEAR_PS_FILT,
|
|
WLAN_STA_MFP,
|
|
WLAN_STA_BLOCK_BA,
|
|
--- a/drivers/net/wireless/ath/ath9k/init.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
|
@@ -647,6 +647,24 @@ void ath9k_reload_chainmask_settings(str
|
|
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
|
|
}
|
|
|
|
+static const struct ieee80211_iface_limit if_limits[] = {
|
|
+ { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
|
|
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
|
+ BIT(NL80211_IFTYPE_WDS) },
|
|
+ { .max = 8, .types =
|
|
+#ifdef CONFIG_MAC80211_MESH
|
|
+ BIT(NL80211_IFTYPE_MESH_POINT) |
|
|
+#endif
|
|
+ BIT(NL80211_IFTYPE_AP) |
|
|
+ BIT(NL80211_IFTYPE_P2P_GO) },
|
|
+};
|
|
+
|
|
+static const struct ieee80211_iface_combination if_comb = {
|
|
+ .limits = if_limits,
|
|
+ .n_limits = ARRAY_SIZE(if_limits),
|
|
+ .max_interfaces = 2048,
|
|
+ .num_different_channels = 1,
|
|
+};
|
|
|
|
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|
{
|
|
@@ -676,6 +694,9 @@ void ath9k_set_hw_capab(struct ath_softc
|
|
BIT(NL80211_IFTYPE_ADHOC) |
|
|
BIT(NL80211_IFTYPE_MESH_POINT);
|
|
|
|
+ hw->wiphy->iface_combinations = &if_comb;
|
|
+ hw->wiphy->n_iface_combinations = 1;
|
|
+
|
|
if (AR_SREV_5416(sc->sc_ah))
|
|
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
|
|
|
--- a/net/mac80211/ibss.c
|
|
+++ b/net/mac80211/ibss.c
|
|
@@ -455,8 +455,8 @@ static void ieee80211_rx_bss_info(struct
|
|
* fall back to HT20 if we don't use or use
|
|
* the other extension channel
|
|
*/
|
|
- if ((channel_type == NL80211_CHAN_HT40MINUS ||
|
|
- channel_type == NL80211_CHAN_HT40PLUS) &&
|
|
+ if (!(channel_type == NL80211_CHAN_HT40MINUS ||
|
|
+ channel_type == NL80211_CHAN_HT40PLUS) ||
|
|
channel_type != sdata->u.ibss.channel_type)
|
|
sta_ht_cap_new.cap &=
|
|
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|