Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2009-07-30 19:26:55 -07:00
commit 2f6d7c1b34
82 changed files with 5380 additions and 1158 deletions

View file

@ -1293,7 +1293,9 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
flush_workqueue(ar->hw->workqueue); flush_workqueue(ar->hw->workqueue);
cancel_delayed_work_sync(&ar->tx_janitor); cancel_delayed_work_sync(&ar->tx_janitor);
#ifdef CONFIG_AR9170_LEDS
cancel_delayed_work_sync(&ar->led_work); cancel_delayed_work_sync(&ar->led_work);
#endif
cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->filter_config_work);
cancel_work_sync(&ar->beacon_work); cancel_work_sync(&ar->beacon_work);
mutex_lock(&ar->mutex); mutex_lock(&ar->mutex);

View file

@ -18,6 +18,6 @@ config ATH9K_DEBUG
Say Y, if you need ath9k to display debug messages. Say Y, if you need ath9k to display debug messages.
Pass the debug mask as a module parameter: Pass the debug mask as a module parameter:
modprobe ath9k debug=0x00002000 modprobe ath9k debug=0x00000200
Look in ath9k/core.h for possible debug masks Look in ath9k/debug.h for possible debug masks

View file

@ -190,12 +190,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_AGGR_MIN_QDEPTH 2 #define ATH_AGGR_MIN_QDEPTH 2
#define ATH_AMPDU_SUBFRAME_DEFAULT 32 #define ATH_AMPDU_SUBFRAME_DEFAULT 32
#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) #define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1)
#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX
#define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_SEQ_SHIFT 4
#define IEEE80211_SEQ_MAX 4096 #define IEEE80211_SEQ_MAX 4096
#define IEEE80211_MIN_AMPDU_BUF 0x8
#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
#define IEEE80211_WEP_IVLEN 3 #define IEEE80211_WEP_IVLEN 3
#define IEEE80211_WEP_KIDLEN 1 #define IEEE80211_WEP_KIDLEN 1
#define IEEE80211_WEP_CRCLEN 4 #define IEEE80211_WEP_CRCLEN 4
@ -240,7 +237,6 @@ struct ath_txq {
spinlock_t axq_lock; spinlock_t axq_lock;
u32 axq_depth; u32 axq_depth;
u8 axq_aggr_depth; u8 axq_aggr_depth;
u32 axq_totalqueued;
bool stopped; bool stopped;
bool axq_tx_inprogress; bool axq_tx_inprogress;
struct ath_buf *axq_linkbuf; struct ath_buf *axq_linkbuf;
@ -365,9 +361,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
void ath_tx_tasklet(struct ath_softc *sc); void ath_tx_tasklet(struct ath_softc *sc);
void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn); u16 tid, u16 *ssn);
int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
/********/ /********/
@ -576,6 +572,7 @@ struct ath_softc {
u32 keymax; u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX); DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic; u8 splitmic;
bool ps_enabled;
unsigned long ps_usecount; unsigned long ps_usecount;
enum ath9k_int imask; enum ath9k_int imask;
enum ath9k_ht_extprotspacing ht_extprotspacing; enum ath9k_ht_extprotspacing ht_extprotspacing;

View file

@ -116,7 +116,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
"NF calibrated [ctl] [chain 1] is %d\n", nf); "NF calibrated [ctl] [chain 1] is %d\n", nf);
nfarray[1] = nf; nfarray[1] = nf;
if (!AR_SREV_9280(ah)) { if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
AR_PHY_CH2_MINCCA_PWR); AR_PHY_CH2_MINCCA_PWR);
if (nf & 0x100) if (nf & 0x100)
@ -154,7 +154,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
"NF calibrated [ext] [chain 1] is %d\n", nf); "NF calibrated [ext] [chain 1] is %d\n", nf);
nfarray[4] = nf; nfarray[4] = nf;
if (!AR_SREV_9280(ah)) { if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
AR_PHY_CH2_EXT_MINCCA_PWR); AR_PHY_CH2_EXT_MINCCA_PWR);
if (nf & 0x100) if (nf & 0x100)
@ -613,7 +613,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
if (AR_SREV_9285(ah)) if (AR_SREV_9285(ah))
chainmask = 0x9; chainmask = 0x9;
else if (AR_SREV_9280(ah)) else if (AR_SREV_9280(ah) || AR_SREV_9287(ah))
chainmask = 0x1B; chainmask = 0x1B;
else else
chainmask = 0x3F; chainmask = 0x3F;
@ -873,7 +873,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9285_11_OR_LATER(ah)) if (AR_SREV_9285_11_OR_LATER(ah))
ath9k_hw_9285_pa_cal(ah); ath9k_hw_9285_pa_cal(ah);
if (OLC_FOR_AR9280_20_LATER) if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
ath9k_olc_temp_compensation(ah); ath9k_olc_temp_compensation(ah);
ath9k_hw_getnf(ah, chan); ath9k_hw_getnf(ah, chan);
ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_loadnf(ah, ah->curchan);
@ -929,8 +929,11 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
return false; return false;
} else { } else {
if (AR_SREV_9280_10_OR_LATER(ah)) { if (AR_SREV_9280_10_OR_LATER(ah)) {
REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); if (!AR_SREV_9287_10_OR_LATER(ah))
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
AR_PHY_ADC_CTL_OFF_PWDADC);
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_FLTR_CAL);
} }
/* Calibrate the AGC */ /* Calibrate the AGC */
@ -948,8 +951,11 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
} }
if (AR_SREV_9280_10_OR_LATER(ah)) { if (AR_SREV_9280_10_OR_LATER(ah)) {
REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); if (!AR_SREV_9287_10_OR_LATER(ah))
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); REG_SET_BIT(ah, AR_PHY_ADC_CTL,
AR_PHY_ADC_CTL_OFF_PWDADC);
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_FLTR_CAL);
} }
} }

View file

@ -486,6 +486,83 @@ static const struct file_operations fops_wiphy = {
.owner = THIS_MODULE .owner = THIS_MODULE
}; };
#define PR(str, elem) \
do { \
len += snprintf(buf + len, size - len, \
"%s%13u%11u%10u%10u\n", str, \
sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BE]].elem, \
sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BK]].elem, \
sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VI]].elem, \
sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VO]].elem); \
} 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;
ssize_t retval = 0;
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
return 0;
len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
PR("MPDUs Queued: ", queued);
PR("MPDUs Completed: ", completed);
PR("Aggregates: ", a_aggr);
PR("AMPDUs Queued: ", a_queued);
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
PR("FIFO Underrun: ", fifo_underrun);
PR("TXOP Exceeded: ", xtxop);
PR("TXTIMER Expiry: ", timer_exp);
PR("DESC CFG Error: ", desc_cfg_err);
PR("DATA Underrun: ", data_underrun);
PR("DELIM Underrun: ", delim_underrun);
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return retval;
}
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf)
{
struct ath_desc *ds = bf->bf_desc;
if (bf_isampdu(bf)) {
if (bf_isxretried(bf))
TX_STAT_INC(txq->axq_qnum, a_xretries);
else
TX_STAT_INC(txq->axq_qnum, a_completed);
} else {
TX_STAT_INC(txq->axq_qnum, completed);
}
if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)
TX_STAT_INC(txq->axq_qnum, fifo_underrun);
if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP)
TX_STAT_INC(txq->axq_qnum, xtxop);
if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED)
TX_STAT_INC(txq->axq_qnum, timer_exp);
if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR)
TX_STAT_INC(txq->axq_qnum, desc_cfg_err);
if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN)
TX_STAT_INC(txq->axq_qnum, data_underrun);
if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN)
TX_STAT_INC(txq->axq_qnum, delim_underrun);
}
static const struct file_operations fops_xmit = {
.read = read_file_xmit,
.open = ath9k_debugfs_open,
.owner = THIS_MODULE
};
int ath9k_init_debug(struct ath_softc *sc) int ath9k_init_debug(struct ath_softc *sc)
{ {
@ -529,6 +606,13 @@ int ath9k_init_debug(struct ath_softc *sc)
if (!sc->debug.debugfs_wiphy) if (!sc->debug.debugfs_wiphy)
goto err; goto err;
sc->debug.debugfs_xmit = debugfs_create_file("xmit",
S_IRUSR,
sc->debug.debugfs_phy,
sc, &fops_xmit);
if (!sc->debug.debugfs_xmit)
goto err;
return 0; return 0;
err: err:
ath9k_exit_debug(sc); ath9k_exit_debug(sc);
@ -537,6 +621,7 @@ err:
void ath9k_exit_debug(struct ath_softc *sc) void ath9k_exit_debug(struct ath_softc *sc)
{ {
debugfs_remove(sc->debug.debugfs_xmit);
debugfs_remove(sc->debug.debugfs_wiphy); debugfs_remove(sc->debug.debugfs_wiphy);
debugfs_remove(sc->debug.debugfs_rcstat); debugfs_remove(sc->debug.debugfs_rcstat);
debugfs_remove(sc->debug.debugfs_interrupt); debugfs_remove(sc->debug.debugfs_interrupt);

View file

@ -35,6 +35,15 @@ enum ATH_DEBUG {
#define DBG_DEFAULT (ATH_DBG_FATAL) #define DBG_DEFAULT (ATH_DBG_FATAL)
struct ath_txq;
struct ath_buf;
#ifdef CONFIG_ATH9K_DEBUG
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
#else
#define TX_STAT_INC(q, c) do { } while (0)
#endif
#ifdef CONFIG_ATH9K_DEBUG #ifdef CONFIG_ATH9K_DEBUG
/** /**
@ -87,9 +96,45 @@ struct ath_rc_stats {
u8 per; u8 per;
}; };
/**
* struct ath_tx_stats - Statistics about TX
* @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_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
* @fifo_underrun: FIFO underrun occurrences
Valid only for:
- non-aggregate condition.
- first packet of aggregate.
* @xtxop: No. of frames filtered because of TXOP limit
* @timer_exp: Transmit timer expiry
* @desc_cfg_err: Descriptor configuration errors
* @data_urn: TX data underrun errors
* @delim_urn: TX delimiter underrun errors
*/
struct ath_tx_stats {
u32 queued;
u32 completed;
u32 a_aggr;
u32 a_queued;
u32 a_completed;
u32 a_retries;
u32 a_xretries;
u32 fifo_underrun;
u32 xtxop;
u32 timer_exp;
u32 desc_cfg_err;
u32 data_underrun;
u32 delim_underrun;
};
struct ath_stats { struct ath_stats {
struct ath_interrupt_stats istats; struct ath_interrupt_stats istats;
struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
}; };
struct ath9k_debug { struct ath9k_debug {
@ -100,6 +145,7 @@ struct ath9k_debug {
struct dentry *debugfs_interrupt; struct dentry *debugfs_interrupt;
struct dentry *debugfs_rcstat; struct dentry *debugfs_rcstat;
struct dentry *debugfs_wiphy; struct dentry *debugfs_wiphy;
struct dentry *debugfs_xmit;
struct ath_stats stats; struct ath_stats stats;
}; };
@ -110,6 +156,8 @@ int ath9k_debug_create_root(void);
void ath9k_debug_remove_root(void); void ath9k_debug_remove_root(void);
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb); void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf);
void ath_debug_stat_retries(struct ath_softc *sc, int rix, void ath_debug_stat_retries(struct ath_softc *sc, int rix,
int xretries, int retries, u8 per); int xretries, int retries, u8 per);
@ -148,6 +196,12 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc,
{ {
} }
static inline void ath_debug_stat_tx(struct ath_softc *sc,
struct ath_txq *txq,
struct ath_buf *bf)
{
}
static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
int xretries, int retries, u8 per) int xretries, int retries, u8 per)
{ {

File diff suppressed because it is too large Load diff

View file

@ -100,6 +100,8 @@
#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) #define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK)
#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ #define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \
ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_10_OR_LATER(ah) && \
ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 #define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
@ -176,6 +178,57 @@
#define AR9280_TX_GAIN_TABLE_SIZE 22 #define AR9280_TX_GAIN_TABLE_SIZE 22
#define AR9287_EEP_VER 0xE
#define AR9287_EEP_VER_MINOR_MASK 0xFFF
#define AR9287_EEP_MINOR_VER_1 0x1
#define AR9287_EEP_MINOR_VER_2 0x2
#define AR9287_EEP_MINOR_VER_3 0x3
#define AR9287_EEP_MINOR_VER AR9287_EEP_MINOR_VER_3
#define AR9287_EEP_MINOR_VER_b AR9287_EEP_MINOR_VER
#define AR9287_EEP_NO_BACK_VER AR9287_EEP_MINOR_VER_1
#define AR9287_EEP_START_LOC 128
#define AR9287_NUM_2G_CAL_PIERS 3
#define AR9287_NUM_2G_CCK_TARGET_POWERS 3
#define AR9287_NUM_2G_20_TARGET_POWERS 3
#define AR9287_NUM_2G_40_TARGET_POWERS 3
#define AR9287_NUM_CTLS 12
#define AR9287_NUM_BAND_EDGES 4
#define AR9287_NUM_PD_GAINS 4
#define AR9287_PD_GAINS_IN_MASK 4
#define AR9287_PD_GAIN_ICEPTS 1
#define AR9287_EEPROM_MODAL_SPURS 5
#define AR9287_MAX_RATE_POWER 63
#define AR9287_NUM_PDADC_VALUES 128
#define AR9287_NUM_RATES 16
#define AR9287_BCHAN_UNUSED 0xFF
#define AR9287_MAX_PWR_RANGE_IN_HALF_DB 64
#define AR9287_OPFLAGS_11A 0x01
#define AR9287_OPFLAGS_11G 0x02
#define AR9287_OPFLAGS_2G_HT40 0x08
#define AR9287_OPFLAGS_2G_HT20 0x20
#define AR9287_OPFLAGS_5G_HT40 0x04
#define AR9287_OPFLAGS_5G_HT20 0x10
#define AR9287_EEPMISC_BIG_ENDIAN 0x01
#define AR9287_EEPMISC_WOW 0x02
#define AR9287_MAX_CHAINS 2
#define AR9287_ANT_16S 32
#define AR9287_custdatasize 20
#define AR9287_NUM_ANT_CHAIN_FIELDS 6
#define AR9287_NUM_ANT_COMMON_FIELDS 4
#define AR9287_SIZE_ANT_CHAIN_FIELD 2
#define AR9287_SIZE_ANT_COMMON_FIELD 4
#define AR9287_ANT_CHAIN_MASK 0x3
#define AR9287_ANT_COMMON_MASK 0xf
#define AR9287_CHAIN_0_IDX 0
#define AR9287_CHAIN_1_IDX 1
#define AR9287_DATA_SZ 32
#define AR9287_PWR_TABLE_OFFSET_DB -5
#define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1)
enum eeprom_param { enum eeprom_param {
EEP_NFTHRESH_5, EEP_NFTHRESH_5,
EEP_NFTHRESH_2, EEP_NFTHRESH_2,
@ -199,7 +252,11 @@ enum eeprom_param {
EEP_OL_PWRCTRL, EEP_OL_PWRCTRL,
EEP_RC_CHAIN_MASK, EEP_RC_CHAIN_MASK,
EEP_DAC_HPWR_5G, EEP_DAC_HPWR_5G,
EEP_FRAC_N_5G EEP_FRAC_N_5G,
EEP_DEV_TYPE,
EEP_TEMPSENSE_SLOPE,
EEP_TEMPSENSE_SLOPE_PAL_ON,
EEP_PWR_TABLE_OFFSET
}; };
enum ar5416_rates { enum ar5416_rates {
@ -368,6 +425,65 @@ struct modal_eep_4k_header {
struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
} __packed; } __packed;
struct base_eep_ar9287_header {
u16 length;
u16 checksum;
u16 version;
u8 opCapFlags;
u8 eepMisc;
u16 regDmn[2];
u8 macAddr[6];
u8 rxMask;
u8 txMask;
u16 rfSilent;
u16 blueToothOptions;
u16 deviceCap;
u32 binBuildNumber;
u8 deviceType;
u8 openLoopPwrCntl;
int8_t pwrTableOffset;
int8_t tempSensSlope;
int8_t tempSensSlopePalOn;
u8 futureBase[29];
} __packed;
struct modal_eep_ar9287_header {
u32 antCtrlChain[AR9287_MAX_CHAINS];
u32 antCtrlCommon;
int8_t antennaGainCh[AR9287_MAX_CHAINS];
u8 switchSettling;
u8 txRxAttenCh[AR9287_MAX_CHAINS];
u8 rxTxMarginCh[AR9287_MAX_CHAINS];
int8_t adcDesiredSize;
u8 txEndToXpaOff;
u8 txEndToRxOn;
u8 txFrameToXpaOn;
u8 thresh62;
int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS];
u8 xpdGain;
u8 xpd;
int8_t iqCalICh[AR9287_MAX_CHAINS];
int8_t iqCalQCh[AR9287_MAX_CHAINS];
u8 pdGainOverlap;
u8 xpaBiasLvl;
u8 txFrameToDataStart;
u8 txFrameToPaOn;
u8 ht40PowerIncForPdadc;
u8 bswAtten[AR9287_MAX_CHAINS];
u8 bswMargin[AR9287_MAX_CHAINS];
u8 swSettleHt40;
u8 version;
u8 db1;
u8 db2;
u8 ob_cck;
u8 ob_psk;
u8 ob_qam;
u8 ob_pal_off;
u8 futureModal[30];
struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS];
} __packed;
struct cal_data_per_freq { struct cal_data_per_freq {
u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
@ -402,6 +518,29 @@ struct cal_ctl_edges {
} __packed; } __packed;
#endif #endif
struct cal_data_op_loop_ar9287 {
u8 pwrPdg[2][5];
u8 vpdPdg[2][5];
u8 pcdac[2][5];
u8 empty[2][5];
} __packed;
struct cal_data_per_freq_ar9287 {
u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
} __packed;
union cal_data_per_freq_ar9287_u {
struct cal_data_op_loop_ar9287 calDataOpen;
struct cal_data_per_freq_ar9287 calDataClose;
} __packed;
struct cal_ctl_data_ar9287 {
struct cal_ctl_edges
ctlEdges[AR9287_MAX_CHAINS][AR9287_NUM_BAND_EDGES];
} __packed;
struct cal_ctl_data { struct cal_ctl_data {
struct cal_ctl_edges struct cal_ctl_edges
ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
@ -461,6 +600,27 @@ struct ar5416_eeprom_4k {
u8 padding; u8 padding;
} __packed; } __packed;
struct ar9287_eeprom_t {
struct base_eep_ar9287_header baseEepHeader;
u8 custData[AR9287_DATA_SZ];
struct modal_eep_ar9287_header modalHeader;
u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS];
union cal_data_per_freq_ar9287_u
calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS];
struct cal_target_power_leg
calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS];
struct cal_target_power_leg
calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS];
struct cal_target_power_ht
calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS];
struct cal_target_power_ht
calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS];
u8 ctlIndex[AR9287_NUM_CTLS];
struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS];
u8 padding;
} __packed;
enum reg_ext_bitmap { enum reg_ext_bitmap {
REG_EXT_JAPAN_MIDBAND = 1, REG_EXT_JAPAN_MIDBAND = 1,
REG_EXT_FCC_DFS_HT40 = 2, REG_EXT_FCC_DFS_HT40 = 2,
@ -480,6 +640,7 @@ struct ath9k_country_entry {
enum ath9k_eep_map { enum ath9k_eep_map {
EEP_MAP_DEFAULT = 0x0, EEP_MAP_DEFAULT = 0x0,
EEP_MAP_4KBITS, EEP_MAP_4KBITS,
EEP_MAP_AR9287,
EEP_MAP_MAX EEP_MAP_MAX
}; };

View file

@ -380,6 +380,9 @@ static const char *ath9k_hw_devname(u16 devid)
return "Atheros 9280"; return "Atheros 9280";
case AR9285_DEVID_PCIE: case AR9285_DEVID_PCIE:
return "Atheros 9285"; return "Atheros 9285";
case AR5416_DEVID_AR9287_PCI:
case AR5416_DEVID_AR9287_PCIE:
return "Atheros 9287";
} }
return NULL; return NULL;
@ -475,6 +478,8 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
ah->gbeacon_rate = 0; ah->gbeacon_rate = 0;
ah->power_mode = ATH9K_PM_UNDEFINED;
return ah; return ah;
} }
@ -660,7 +665,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) &&
(ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
(ah->hw_version.macVersion != AR_SREV_VERSION_9160) && (ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
(!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) &&
(!AR_SREV_9285(ah)) && (!AR_SREV_9287(ah))) {
DPRINTF(sc, ATH_DBG_FATAL, DPRINTF(sc, ATH_DBG_FATAL,
"Mac Chip Rev 0x%02x.%x is not supported by " "Mac Chip Rev 0x%02x.%x is not supported by "
"this driver\n", ah->hw_version.macVersion, "this driver\n", ah->hw_version.macVersion,
@ -700,8 +706,37 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
ah->ani_function = ATH9K_ANI_ALL; ah->ani_function = ATH9K_ANI_ALL;
if (AR_SREV_9280_10_OR_LATER(ah)) if (AR_SREV_9280_10_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
ARRAY_SIZE(ar9287Common_9287_1_1), 2);
if (ah->config.pcie_clock_req)
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9287PciePhy_clkreq_off_L1_9287_1_1,
ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
else
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
2);
} else if (AR_SREV_9287_10_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0,
ARRAY_SIZE(ar9287Modes_9287_1_0), 6);
INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0,
ARRAY_SIZE(ar9287Common_9287_1_0), 2);
if (ah->config.pcie_clock_req)
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9287PciePhy_clkreq_off_L1_9287_1_0,
ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2);
else
INIT_INI_ARRAY(&ah->iniPcieSerdes,
ar9287PciePhy_clkreq_always_on_L1_9287_1_0,
ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0),
2);
} else if (AR_SREV_9285_12_OR_LATER(ah)) {
if (AR_SREV_9285_12_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
ARRAY_SIZE(ar9285Modes_9285_1_2), 6); ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
@ -842,7 +877,28 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
if (ecode != 0) if (ecode != 0)
goto bad; goto bad;
if (AR_SREV_9285_12_OR_LATER(ah)) { if (AR_SREV_9287_11(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9287Modes_rx_gain_9287_1_1,
ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
else if (AR_SREV_9287_10(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9287Modes_rx_gain_9287_1_0,
ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6);
else if (AR_SREV_9280_20(ah))
ath9k_hw_init_rxgain_ini(ah);
if (AR_SREV_9287_11(ah)) {
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9287Modes_tx_gain_9287_1_1,
ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
} else if (AR_SREV_9287_10(ah)) {
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9287Modes_tx_gain_9287_1_0,
ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6);
} else if (AR_SREV_9280_20(ah)) {
ath9k_hw_init_txgain_ini(ah);
} else if (AR_SREV_9285_12_OR_LATER(ah)) {
u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
/* txgain table */ /* txgain table */
@ -858,14 +914,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
} }
/* rxgain table */
if (AR_SREV_9280_20(ah))
ath9k_hw_init_rxgain_ini(ah);
/* txgain table */
if (AR_SREV_9280_20(ah))
ath9k_hw_init_txgain_ini(ah);
ath9k_hw_fill_cap_info(ah); ath9k_hw_fill_cap_info(ah);
if ((ah->hw_version.devid == AR9280_DEVID_PCI) && if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
@ -1165,6 +1213,8 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
case AR9280_DEVID_PCI: case AR9280_DEVID_PCI:
case AR9280_DEVID_PCIE: case AR9280_DEVID_PCIE:
case AR9285_DEVID_PCIE: case AR9285_DEVID_PCIE:
case AR5416_DEVID_AR9287_PCI:
case AR5416_DEVID_AR9287_PCIE:
ah = ath9k_hw_do_attach(devid, sc, error); ah = ath9k_hw_do_attach(devid, sc, error);
break; break;
default: default:
@ -1341,10 +1391,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
DO_DELAY(regWrites); DO_DELAY(regWrites);
} }
if (AR_SREV_9280(ah)) if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah)) if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) ||
AR_SREV_9287_10_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
for (i = 0; i < ah->iniCommon.ia_rows; i++) { for (i = 0; i < ah->iniCommon.ia_rows; i++) {
@ -2254,6 +2305,16 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9280_10_OR_LATER(ah)) if (AR_SREV_9280_10_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
if (AR_SREV_9287_10_OR_LATER(ah)) {
/* Enable ASYNC FIFO */
REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
}
r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width); r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width);
if (r) if (r)
return r; return r;
@ -2330,6 +2391,27 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_user_settings(ah); ath9k_hw_init_user_settings(ah);
if (AR_SREV_9287_10_OR_LATER(ah)) {
REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
}
if (AR_SREV_9287_10_OR_LATER(ah)) {
REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
}
REG_WRITE(ah, AR_STA_ID1, REG_WRITE(ah, AR_STA_ID1,
REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
@ -2739,6 +2821,9 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
"UNDEFINED" "UNDEFINED"
}; };
if (ah->power_mode == mode)
return status;
DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n", DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
modes[ah->power_mode], modes[mode]); modes[ah->power_mode], modes[mode]);
@ -2783,10 +2868,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
if (++sc->ps_usecount != 1) if (++sc->ps_usecount != 1)
goto unlock; goto unlock;
if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
}
unlock: unlock:
spin_unlock_irqrestore(&sc->sc_pm_lock, flags); spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
@ -2800,13 +2882,12 @@ void ath9k_ps_restore(struct ath_softc *sc)
if (--sc->ps_usecount != 0) if (--sc->ps_usecount != 0)
goto unlock; goto unlock;
if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && if (sc->ps_enabled &&
!(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_CAB |
SC_OP_WAIT_FOR_PSPOLL_DATA | SC_OP_WAIT_FOR_PSPOLL_DATA |
SC_OP_WAIT_FOR_TX_ACK))) SC_OP_WAIT_FOR_TX_ACK)))
ath9k_hw_setpower_nolock(sc->sc_ah, ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
sc->sc_ah->restore_mode);
unlock: unlock:
spin_unlock_irqrestore(&sc->sc_pm_lock, flags); spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
@ -3644,7 +3725,9 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
if (gpio >= ah->caps.num_gpio_pins) if (gpio >= ah->caps.num_gpio_pins)
return 0xffffffff; return 0xffffffff;
if (AR_SREV_9285_10_OR_LATER(ah)) if (AR_SREV_9287_10_OR_LATER(ah))
return MS_REG_READ(AR9287, gpio) != 0;
else if (AR_SREV_9285_10_OR_LATER(ah))
return MS_REG_READ(AR9285, gpio) != 0; return MS_REG_READ(AR9285, gpio) != 0;
else if (AR_SREV_9280_10_OR_LATER(ah)) else if (AR_SREV_9280_10_OR_LATER(ah))
return MS_REG_READ(AR928X, gpio) != 0; return MS_REG_READ(AR928X, gpio) != 0;

View file

@ -42,6 +42,9 @@
#define AR_SUBVENDOR_ID_NEW_A 0x7065 #define AR_SUBVENDOR_ID_NEW_A 0x7065
#define AR5416_MAGIC 0x19641014 #define AR5416_MAGIC 0x19641014
#define AR5416_DEVID_AR9287_PCI 0x002D
#define AR5416_DEVID_AR9287_PCIE 0x002E
/* Register read/write primitives */ /* Register read/write primitives */
#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) #define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val))
#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) #define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg))
@ -400,6 +403,7 @@ struct ath_hw {
union { union {
struct ar5416_eeprom_def def; struct ar5416_eeprom_def def;
struct ar5416_eeprom_4k map4k; struct ar5416_eeprom_4k map4k;
struct ar9287_eeprom_t map9287;
} eeprom; } eeprom;
const struct eeprom_ops *eep_ops; const struct eeprom_ops *eep_ops;
enum ath9k_eep_map eep_map; enum ath9k_eep_map eep_map;
@ -417,7 +421,6 @@ struct ath_hw {
enum nl80211_iftype opmode; enum nl80211_iftype opmode;
enum ath9k_power_mode power_mode; enum ath9k_power_mode power_mode;
enum ath9k_power_mode restore_mode;
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
struct ar5416Stats stats; struct ar5416Stats stats;

File diff suppressed because it is too large Load diff

View file

@ -17,8 +17,6 @@
#include <linux/nl80211.h> #include <linux/nl80211.h>
#include "ath9k.h" #include "ath9k.h"
#define ATH_PCI_VERSION "0.1"
static char *dev_info = "ath9k"; static char *dev_info = "ath9k";
MODULE_AUTHOR("Atheros Communications"); MODULE_AUTHOR("Atheros Communications");
@ -462,7 +460,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
if (sc->sc_flags & SC_OP_TXAGGR) { if (sc->sc_flags & SC_OP_TXAGGR) {
ath_tx_node_init(sc, an); ath_tx_node_init(sc, an);
an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor); sta->ht_cap.ampdu_factor);
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
an->last_rssi = ATH_RSSI_DUMMY_MARKER; an->last_rssi = ATH_RSSI_DUMMY_MARKER;
@ -499,8 +497,7 @@ static void ath9k_tasklet(unsigned long data)
if (status & ATH9K_INT_TX) if (status & ATH9K_INT_TX)
ath_tx_tasklet(sc); ath_tx_tasklet(sc);
if ((status & ATH9K_INT_TSFOOR) && if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
/* /*
* TSF sync does not look correct; remain awake to sync with * TSF sync does not look correct; remain awake to sync with
* the next Beacon. * the next Beacon.
@ -888,8 +885,6 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
static void setup_ht_cap(struct ath_softc *sc, static void setup_ht_cap(struct ath_softc *sc,
struct ieee80211_sta_ht_cap *ht_info) struct ieee80211_sta_ht_cap *ht_info)
{ {
#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */
#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */
u8 tx_streams, rx_streams; u8 tx_streams, rx_streams;
ht_info->ht_supported = true; ht_info->ht_supported = true;
@ -898,8 +893,8 @@ static void setup_ht_cap(struct ath_softc *sc,
IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_DSSSCCK40; IEEE80211_HT_CAP_DSSSCCK40;
ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
/* set up supported mcs set */ /* set up supported mcs set */
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
@ -2003,7 +1998,7 @@ static int ath9k_tx(struct ieee80211_hw *hw,
goto exit; goto exit;
} }
if (sc->hw->conf.flags & IEEE80211_CONF_PS) { if (sc->ps_enabled) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
/* /*
* mac80211 does not set PM field for normal data frames, so we * mac80211 does not set PM field for normal data frames, so we
@ -2291,8 +2286,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
} }
ath9k_hw_setrxabort(sc->sc_ah, 1); ath9k_hw_setrxabort(sc->sc_ah, 1);
} }
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); sc->ps_enabled = true;
} else { } else {
sc->ps_enabled = false;
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
if (!(ah->caps.hw_caps & if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) { ATH9K_HW_CAP_AUTOSLEEP)) {
@ -2671,19 +2667,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_STOP: case IEEE80211_AMPDU_RX_STOP:
break; break;
case IEEE80211_AMPDU_TX_START: case IEEE80211_AMPDU_TX_START:
ret = ath_tx_aggr_start(sc, sta, tid, ssn); ath_tx_aggr_start(sc, sta, tid, ssn);
if (ret < 0) ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to start TX aggregation\n");
else
ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
break; break;
case IEEE80211_AMPDU_TX_STOP: case IEEE80211_AMPDU_TX_STOP:
ret = ath_tx_aggr_stop(sc, sta, tid); ath_tx_aggr_stop(sc, sta, tid);
if (ret < 0)
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to stop TX aggregation\n");
ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
break; break;
case IEEE80211_AMPDU_TX_OPERATIONAL: case IEEE80211_AMPDU_TX_OPERATIONAL:
@ -2761,7 +2749,8 @@ static struct {
{ AR_SREV_VERSION_9100, "9100" }, { AR_SREV_VERSION_9100, "9100" },
{ AR_SREV_VERSION_9160, "9160" }, { AR_SREV_VERSION_9160, "9160" },
{ AR_SREV_VERSION_9280, "9280" }, { AR_SREV_VERSION_9280, "9280" },
{ AR_SREV_VERSION_9285, "9285" } { AR_SREV_VERSION_9285, "9285" },
{ AR_SREV_VERSION_9287, "9287" }
}; };
static struct { static struct {

View file

@ -25,6 +25,8 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = {
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
{ 0 } { 0 }
}; };

View file

@ -375,6 +375,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#define AR_PHY_CHAN_INFO_GAIN 0x9CFC #define AR_PHY_CHAN_INFO_GAIN 0x9CFC
#define AR_PHY_MODE 0xA200 #define AR_PHY_MODE 0xA200
#define AR_PHY_MODE_ASYNCFIFO 0x80
#define AR_PHY_MODE_AR2133 0x08 #define AR_PHY_MODE_AR2133 0x08
#define AR_PHY_MODE_AR5111 0x00 #define AR_PHY_MODE_AR5111 0x00
#define AR_PHY_MODE_AR5112 0x08 #define AR_PHY_MODE_AR5112 0x08

View file

@ -59,6 +59,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct ath_atx_tid *tid,
struct list_head *bf_head); struct list_head *bf_head);
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
struct ath_txq *txq,
struct list_head *bf_q, struct list_head *bf_q,
int txok, int sendbar); int txok, int sendbar);
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
@ -212,7 +213,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_update_baw(sc, tid, bf->bf_seqno); ath_tx_update_baw(sc, tid, bf->bf_seqno);
spin_unlock(&txq->axq_lock); spin_unlock(&txq->axq_lock);
ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
spin_lock(&txq->axq_lock); spin_lock(&txq->axq_lock);
} }
@ -220,13 +221,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
tid->baw_tail = tid->baw_head; tid->baw_tail = tid->baw_head;
} }
static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
bf->bf_state.bf_type |= BUF_RETRY; bf->bf_state.bf_type |= BUF_RETRY;
bf->bf_retries++; bf->bf_retries++;
TX_STAT_INC(txq->axq_qnum, a_retries);
skb = bf->bf_mpdu; skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
@ -328,7 +331,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (!(tid->state & AGGR_CLEANUP) && if (!(tid->state & AGGR_CLEANUP) &&
ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
if (bf->bf_retries < ATH_MAX_SW_RETRIES) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
ath_tx_set_retry(sc, bf); ath_tx_set_retry(sc, txq, bf);
txpending = 1; txpending = 1;
} else { } else {
bf->bf_state.bf_type |= BUF_XRETRY; bf->bf_state.bf_type |= BUF_XRETRY;
@ -375,7 +378,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_rc_status(bf, ds, nbad, txok, false); ath_tx_rc_status(bf, ds, nbad, txok, false);
} }
ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar);
} else { } else {
/* retry the un-acked ones */ /* retry the un-acked ones */
if (bf->bf_next == NULL && bf_last->bf_stale) { if (bf->bf_next == NULL && bf_last->bf_stale) {
@ -395,8 +398,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_state.bf_type |= BUF_XRETRY; bf->bf_state.bf_type |= BUF_XRETRY;
ath_tx_rc_status(bf, ds, nbad, ath_tx_rc_status(bf, ds, nbad,
0, false); 0, false);
ath_tx_complete_buf(sc, bf, &bf_head, ath_tx_complete_buf(sc, bf, txq,
0, 0); &bf_head, 0, 0);
break; break;
} }
@ -455,7 +458,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
struct ieee80211_tx_rate *rates; struct ieee80211_tx_rate *rates;
struct ath_tx_info_priv *tx_info_priv; struct ath_tx_info_priv *tx_info_priv;
u32 max_4ms_framelen, frmlen; u32 max_4ms_framelen, frmlen;
u16 aggr_limit, legacy = 0, maxampdu; u16 aggr_limit, legacy = 0;
int i; int i;
skb = bf->bf_mpdu; skb = bf->bf_mpdu;
@ -490,16 +493,15 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
return 0; return 0;
aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_DEFAULT); aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX);
/* /*
* h/w can accept aggregates upto 16 bit lengths (65535). * h/w can accept aggregates upto 16 bit lengths (65535).
* The IE, however can hold upto 65536, which shows up here * The IE, however can hold upto 65536, which shows up here
* as zero. Ignore 65536 since we are constrained by hw. * as zero. Ignore 65536 since we are constrained by hw.
*/ */
maxampdu = tid->an->maxampdu; if (tid->an->maxampdu)
if (maxampdu) aggr_limit = min(aggr_limit, tid->an->maxampdu);
aggr_limit = min(aggr_limit, maxampdu);
return aggr_limit; return aggr_limit;
} }
@ -507,7 +509,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
/* /*
* Returns the number of delimiters to be added to * Returns the number of delimiters to be added to
* meet the minimum required mpdudensity. * meet the minimum required mpdudensity.
* caller should make sure that the rate is HT rate .
*/ */
static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
struct ath_buf *bf, u16 frmlen) struct ath_buf *bf, u16 frmlen)
@ -515,7 +516,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
const struct ath_rate_table *rt = sc->cur_rate_table; const struct ath_rate_table *rt = sc->cur_rate_table;
struct sk_buff *skb = bf->bf_mpdu; struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
u32 nsymbits, nsymbols, mpdudensity; u32 nsymbits, nsymbols;
u16 minlen; u16 minlen;
u8 rc, flags, rix; u8 rc, flags, rix;
int width, half_gi, ndelim, mindelim; int width, half_gi, ndelim, mindelim;
@ -537,14 +538,12 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
* on highest rate in rate series (i.e. first rate) to determine * on highest rate in rate series (i.e. first rate) to determine
* required minimum length for subframe. Take into account * required minimum length for subframe. Take into account
* whether high rate is 20 or 40Mhz and half or full GI. * whether high rate is 20 or 40Mhz and half or full GI.
*/ *
mpdudensity = tid->an->mpdudensity;
/*
* If there is no mpdu density restriction, no further calculation * If there is no mpdu density restriction, no further calculation
* is needed. * is needed.
*/ */
if (mpdudensity == 0)
if (tid->an->mpdudensity == 0)
return ndelim; return ndelim;
rix = tx_info->control.rates[0].idx; rix = tx_info->control.rates[0].idx;
@ -554,9 +553,9 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
if (half_gi) if (half_gi)
nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
else else
nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity); nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
if (nsymbols == 0) if (nsymbols == 0)
nsymbols = 1; nsymbols = 1;
@ -573,6 +572,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
} }
static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
struct ath_txq *txq,
struct ath_atx_tid *tid, struct ath_atx_tid *tid,
struct list_head *bf_q) struct list_head *bf_q)
{ {
@ -637,6 +637,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
bf_prev->bf_desc->ds_link = bf->bf_daddr; bf_prev->bf_desc->ds_link = bf->bf_daddr;
} }
bf_prev = bf; bf_prev = bf;
} while (!list_empty(&tid->buf_q)); } while (!list_empty(&tid->buf_q));
bf_first->bf_al = al; bf_first->bf_al = al;
@ -659,7 +660,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_q); INIT_LIST_HEAD(&bf_q);
status = ath_tx_form_aggr(sc, tid, &bf_q); status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
/* /*
* no frames picked up to be aggregated; * no frames picked up to be aggregated;
@ -690,30 +691,26 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
txq->axq_aggr_depth++; txq->axq_aggr_depth++;
ath_tx_txqaddbuf(sc, txq, &bf_q); ath_tx_txqaddbuf(sc, txq, &bf_q);
TX_STAT_INC(txq->axq_qnum, a_aggr);
} while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH && } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
status != ATH_AGGR_BAW_CLOSED); status != ATH_AGGR_BAW_CLOSED);
} }
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn) u16 tid, u16 *ssn)
{ {
struct ath_atx_tid *txtid; struct ath_atx_tid *txtid;
struct ath_node *an; struct ath_node *an;
an = (struct ath_node *)sta->drv_priv; an = (struct ath_node *)sta->drv_priv;
txtid = ATH_AN_2_TID(an, tid);
if (sc->sc_flags & SC_OP_TXAGGR) { txtid->state |= AGGR_ADDBA_PROGRESS;
txtid = ATH_AN_2_TID(an, tid); ath_tx_pause_tid(sc, txtid);
txtid->state |= AGGR_ADDBA_PROGRESS; *ssn = txtid->seq_start;
ath_tx_pause_tid(sc, txtid);
*ssn = txtid->seq_start;
}
return 0;
} }
int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
{ {
struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_node *an = (struct ath_node *)sta->drv_priv;
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
@ -723,11 +720,11 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
INIT_LIST_HEAD(&bf_head); INIT_LIST_HEAD(&bf_head);
if (txtid->state & AGGR_CLEANUP) if (txtid->state & AGGR_CLEANUP)
return 0; return;
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
txtid->state &= ~AGGR_ADDBA_PROGRESS; txtid->state &= ~AGGR_ADDBA_PROGRESS;
return 0; return;
} }
ath_tx_pause_tid(sc, txtid); ath_tx_pause_tid(sc, txtid);
@ -746,7 +743,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
} }
list_move_tail(&bf->list, &bf_head); list_move_tail(&bf->list, &bf_head);
ath_tx_update_baw(sc, txtid, bf->bf_seqno); ath_tx_update_baw(sc, txtid, bf->bf_seqno);
ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
} }
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
@ -756,8 +753,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
txtid->state &= ~AGGR_ADDBA_COMPLETE; txtid->state &= ~AGGR_ADDBA_COMPLETE;
ath_tx_flush_tid(sc, txtid); ath_tx_flush_tid(sc, txtid);
} }
return 0;
} }
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
@ -870,7 +865,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
spin_lock_init(&txq->axq_lock); spin_lock_init(&txq->axq_lock);
txq->axq_depth = 0; txq->axq_depth = 0;
txq->axq_aggr_depth = 0; txq->axq_aggr_depth = 0;
txq->axq_totalqueued = 0;
txq->axq_linkbuf = NULL; txq->axq_linkbuf = NULL;
txq->axq_tx_inprogress = false; txq->axq_tx_inprogress = false;
sc->tx.txqsetup |= 1<<qnum; sc->tx.txqsetup |= 1<<qnum;
@ -1036,7 +1030,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
if (bf_isampdu(bf)) if (bf_isampdu(bf))
ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0); ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0);
else else
ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
} }
spin_lock_bh(&txq->axq_lock); spin_lock_bh(&txq->axq_lock);
@ -1187,7 +1181,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
list_splice_tail_init(head, &txq->axq_q); list_splice_tail_init(head, &txq->axq_q);
txq->axq_depth++; txq->axq_depth++;
txq->axq_totalqueued++;
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
DPRINTF(sc, ATH_DBG_QUEUE, DPRINTF(sc, ATH_DBG_QUEUE,
@ -1235,6 +1228,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
bf = list_first_entry(bf_head, struct ath_buf, list); bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_state.bf_type |= BUF_AMPDU; 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: * Do not queue to h/w when any of the following conditions is true:
@ -1281,6 +1275,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_lastbf = bf; bf->bf_lastbf = bf;
ath_buf_set_rate(sc, bf); ath_buf_set_rate(sc, bf);
ath_tx_txqaddbuf(sc, txq, bf_head); ath_tx_txqaddbuf(sc, txq, bf_head);
TX_STAT_INC(txq->axq_qnum, queued);
} }
static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
@ -1294,6 +1289,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_nframes = 1; bf->bf_nframes = 1;
ath_buf_set_rate(sc, bf); ath_buf_set_rate(sc, bf);
ath_tx_txqaddbuf(sc, txq, bf_head); ath_tx_txqaddbuf(sc, txq, bf_head);
TX_STAT_INC(txq->axq_qnum, queued);
} }
static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
@ -1819,6 +1815,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
} }
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
struct ath_txq *txq,
struct list_head *bf_q, struct list_head *bf_q,
int txok, int sendbar) int txok, int sendbar)
{ {
@ -1826,7 +1823,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
unsigned long flags; unsigned long flags;
int tx_flags = 0; int tx_flags = 0;
if (sendbar) if (sendbar)
tx_flags = ATH_TX_BAR; tx_flags = ATH_TX_BAR;
@ -1839,6 +1835,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
ath_tx_complete(sc, skb, tx_flags); ath_tx_complete(sc, skb, tx_flags);
ath_debug_stat_tx(sc, txq, bf);
/* /*
* Return the list of ath_buf of this mpdu to free queue * Return the list of ath_buf of this mpdu to free queue
@ -2026,7 +2023,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf_isampdu(bf)) if (bf_isampdu(bf))
ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok);
else else
ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0);
ath_wake_mac80211_queue(sc, txq); ath_wake_mac80211_queue(sc, txq);
@ -2037,7 +2034,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
} }
} }
void ath_tx_complete_poll_work(struct work_struct *work) static void ath_tx_complete_poll_work(struct work_struct *work)
{ {
struct ath_softc *sc = container_of(work, struct ath_softc, struct ath_softc *sc = container_of(work, struct ath_softc,
tx_complete_work.work); tx_complete_work.work);

View file

@ -450,7 +450,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"},
{CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_SYRIA, NULL1_WORLD, "SY"},
{CTRY_TAIWAN, APL3_FCCA, "TW"}, {CTRY_TAIWAN, APL3_FCCA, "TW"},
{CTRY_THAILAND, NULL1_WORLD, "TH"}, {CTRY_THAILAND, FCC3_WORLD, "TH"},
{CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"}, {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"},
{CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"},
{CTRY_TURKEY, ETSI3_WORLD, "TR"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"},

View file

@ -9,6 +9,9 @@ config IWLWIFI
config IWLWIFI_LEDS config IWLWIFI_LEDS
bool "Enable LED support in iwlagn and iwl3945 drivers" bool "Enable LED support in iwlagn and iwl3945 drivers"
depends on IWLWIFI depends on IWLWIFI
default y
---help---
Select this if you want LED support.
config IWLWIFI_SPECTRUM_MEASUREMENT config IWLWIFI_SPECTRUM_MEASUREMENT
bool "Enable Spectrum Measurement in iwlagn driver" bool "Enable Spectrum Measurement in iwlagn driver"

View file

@ -55,13 +55,88 @@
#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" #define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api) #define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
/*
* For 1000, use advance thermal throttling critical temperature threshold,
* but legacy thermal management implementation for now.
* This is for the reason of 1000 uCode using advance thermal throttling API
* but not implement ct_kill_exit based on ct_kill exit temperature
* so the thermal throttling will still based on legacy thermal throttling
* management.
* The code here need to be modified once 1000 uCode has the advanced thermal
* throttling algorithm in place
*/
static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
{
/* want Celsius */
priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}
static struct iwl_lib_ops iwl1000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwl5000_txq_set_sched,
.txq_agg_enable = iwl5000_txq_agg_enable,
.txq_agg_disable = iwl5000_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 = iwl5000_rx_handler_setup,
.setup_deferred_work = iwl5000_setup_deferred_work,
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
.load_ucode = iwl5000_load_ucode,
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl5000_apm_stop,
.config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
EEPROM_5000_REG_BAND_1_CHANNELS,
EEPROM_5000_REG_BAND_2_CHANNELS,
EEPROM_5000_REG_BAND_3_CHANNELS,
EEPROM_5000_REG_BAND_4_CHANNELS,
EEPROM_5000_REG_BAND_5_CHANNELS,
EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
EEPROM_5000_REG_BAND_52_FAT_CHANNELS
},
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwl5000_eeprom_calib_version,
.query_addr = iwl5000_eeprom_query_addr,
},
.post_associate = iwl_post_associate,
.isr = iwl_isr_ict,
.config_ap = iwl_config_ap,
.temp_ops = {
.temperature = iwl5000_temperature,
.set_ct_kill = iwl1000_set_ct_threshold,
},
};
static struct iwl_ops iwl1000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl1000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
};
struct iwl_cfg iwl1000_bgn_cfg = { struct iwl_cfg iwl1000_bgn_cfg = {
.name = "1000 Series BGN", .name = "1000 Series BGN",
.fw_name_pre = IWL1000_FW_PRE, .fw_name_pre = IWL1000_FW_PRE,
.ucode_api_max = IWL1000_UCODE_API_MAX, .ucode_api_max = IWL1000_UCODE_API_MAX,
.ucode_api_min = IWL1000_UCODE_API_MIN, .ucode_api_min = IWL1000_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N, .sku = IWL_SKU_G|IWL_SKU_N,
.ops = &iwl5000_ops, .ops = &iwl1000_ops,
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,

View file

@ -79,11 +79,10 @@ static const struct {
#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/ #define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/
#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
static int iwl3945_led_cmd_callback(struct iwl_priv *priv, static void iwl3945_led_cmd_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb) struct sk_buff *skb)
{ {
return 1;
} }
static inline int iwl3945_brightness_to_idx(enum led_brightness brightness) static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
@ -99,8 +98,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv,
.id = REPLY_LEDS_CMD, .id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd), .len = sizeof(struct iwl_led_cmd),
.data = led_cmd, .data = led_cmd,
.meta.flags = CMD_ASYNC, .flags = CMD_ASYNC,
.meta.u.callback = iwl3945_led_cmd_callback, .callback = iwl3945_led_cmd_callback,
}; };
return iwl_send_cmd(priv, &cmd); return iwl_send_cmd(priv, &cmd);

View file

@ -749,8 +749,8 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */ /* Unmap tx_cmd */
if (counter) if (counter)
pci_unmap_single(dev, pci_unmap_single(dev,
pci_unmap_addr(&txq->cmd[index]->meta, mapping), pci_unmap_addr(&txq->meta[index], mapping),
pci_unmap_len(&txq->cmd[index]->meta, len), pci_unmap_len(&txq->meta[index], len),
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
/* unmap chunks if any */ /* unmap chunks if any */
@ -774,9 +774,11 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
* iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
* *
*/ */
void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
struct ieee80211_tx_info *info, struct iwl_device_cmd *cmd,
struct ieee80211_hdr *hdr, int sta_id, int tx_id) struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr,
int sta_id, int tx_id)
{ {
u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value; u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
@ -1858,7 +1860,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_RXON_ASSOC, .id = REPLY_RXON_ASSOC,
.len = sizeof(rxon_assoc), .len = sizeof(rxon_assoc),
.meta.flags = CMD_WANT_SKB, .flags = CMD_WANT_SKB,
.data = &rxon_assoc, .data = &rxon_assoc,
}; };
const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
@ -1882,14 +1884,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
if (rc) if (rc)
return rc; return rc;
res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
rc = -EIO; rc = -EIO;
} }
priv->alloc_rxb_skb--; priv->alloc_rxb_skb--;
dev_kfree_skb_any(cmd.meta.u.skb); dev_kfree_skb_any(cmd.reply_skb);
return rc; return rc;
} }

View file

@ -254,10 +254,11 @@ extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq); struct iwl_tx_queue *txq);
extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv, extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv,
struct iwl3945_frame *frame, u8 rate); struct iwl3945_frame *frame, u8 rate);
void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
struct ieee80211_tx_info *info, struct iwl_device_cmd *cmd,
struct ieee80211_hdr *hdr, struct ieee80211_tx_info *info,
int sta_id, int tx_id); struct ieee80211_hdr *hdr,
int sta_id, int tx_id);
extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv); extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv);
extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv, extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,

View file

@ -776,7 +776,8 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
static void iwl4965_set_ct_threshold(struct iwl_priv *priv) static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
{ {
/* want Kelvin */ /* want Kelvin */
priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); priv->hw_params.ct_kill_threshold =
CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY);
} }
/** /**
@ -1796,6 +1797,7 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv)
} }
priv->temperature = temp; priv->temperature = temp;
iwl_tt_handler(priv);
set_bit(STATUS_TEMPERATURE, &priv->status); set_bit(STATUS_TEMPERATURE, &priv->status);
if (!priv->disable_tx_power_cal && if (!priv->disable_tx_power_cal &&

View file

@ -91,7 +91,7 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv)
} }
static int iwl5000_apm_init(struct iwl_priv *priv) int iwl5000_apm_init(struct iwl_priv *priv)
{ {
int ret = 0; int ret = 0;
@ -137,7 +137,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
} }
/* FIXME: this is identical to 4965 */ /* FIXME: this is identical to 4965 */
static void iwl5000_apm_stop(struct iwl_priv *priv) void iwl5000_apm_stop(struct iwl_priv *priv)
{ {
unsigned long flags; unsigned long flags;
@ -156,7 +156,7 @@ static void iwl5000_apm_stop(struct iwl_priv *priv)
} }
static int iwl5000_apm_reset(struct iwl_priv *priv) int iwl5000_apm_reset(struct iwl_priv *priv)
{ {
int ret = 0; int ret = 0;
@ -198,7 +198,7 @@ out:
} }
static void iwl5000_nic_config(struct iwl_priv *priv) void iwl5000_nic_config(struct iwl_priv *priv)
{ {
unsigned long flags; unsigned long flags;
u16 radio_cfg; u16 radio_cfg;
@ -290,7 +290,7 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
return (address & ADDRESS_MSK) + (offset << 1); return (address & ADDRESS_MSK) + (offset << 1);
} }
static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
{ {
struct iwl_eeprom_calib_hdr { struct iwl_eeprom_calib_hdr {
u8 version; u8 version;
@ -436,7 +436,7 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
.nrg_th_ofdm = 95, .nrg_th_ofdm = 95,
}; };
static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset) size_t offset)
{ {
u32 address = eeprom_indirect_address(priv, offset); u32 address = eeprom_indirect_address(priv, offset);
@ -447,7 +447,7 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
static void iwl5150_set_ct_threshold(struct iwl_priv *priv) static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
{ {
const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
iwl_temp_calib_to_offset(priv); iwl_temp_calib_to_offset(priv);
priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
@ -456,7 +456,7 @@ static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
static void iwl5000_set_ct_threshold(struct iwl_priv *priv) static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
{ {
/* want Celsius */ /* want Celsius */
priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
} }
/* /*
@ -631,7 +631,7 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv,
return ret; return ret;
} }
static int iwl5000_load_ucode(struct iwl_priv *priv) int iwl5000_load_ucode(struct iwl_priv *priv)
{ {
int ret = 0; int ret = 0;
@ -658,7 +658,7 @@ static int iwl5000_load_ucode(struct iwl_priv *priv)
return ret; return ret;
} }
static void iwl5000_init_alive_start(struct iwl_priv *priv) void iwl5000_init_alive_start(struct iwl_priv *priv)
{ {
int ret = 0; int ret = 0;
@ -734,7 +734,7 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
sizeof(coex_cmd), &coex_cmd); sizeof(coex_cmd), &coex_cmd);
} }
static int iwl5000_alive_notify(struct iwl_priv *priv) int iwl5000_alive_notify(struct iwl_priv *priv)
{ {
u32 a; u32 a;
unsigned long flags; unsigned long flags;
@ -821,7 +821,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
return 0; return 0;
} }
static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
{ {
if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) ||
(priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
@ -892,7 +892,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
/** /**
* iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/ */
static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq, struct iwl_tx_queue *txq,
u16 byte_cnt) u16 byte_cnt)
{ {
@ -932,7 +932,7 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
} }
static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq) struct iwl_tx_queue *txq)
{ {
struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
@ -987,7 +987,7 @@ static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
(1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); (1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
} }
static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int tx_fifo, int sta_id, int tid, u16 ssn_idx) int tx_fifo, int sta_id, int tid, u16 ssn_idx)
{ {
unsigned long flags; unsigned long flags;
@ -1048,7 +1048,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
return 0; return 0;
} }
static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo) u16 ssn_idx, u8 tx_fifo)
{ {
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
@ -1091,7 +1091,7 @@ u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
* Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
* must be called under priv->lock and mac access * must be called under priv->lock and mac access
*/ */
static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
{ {
iwl_write_prph(priv, IWL50_SCD_TXFACT, mask); iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
} }
@ -1312,13 +1312,13 @@ u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
return len; return len;
} }
static void iwl5000_setup_deferred_work(struct iwl_priv *priv) void iwl5000_setup_deferred_work(struct iwl_priv *priv)
{ {
/* in 5000 the tx power calibration is done in uCode */ /* in 5000 the tx power calibration is done in uCode */
priv->disable_tx_power_cal = 1; priv->disable_tx_power_cal = 1;
} }
static void iwl5000_rx_handler_setup(struct iwl_priv *priv) void iwl5000_rx_handler_setup(struct iwl_priv *priv)
{ {
/* init calibration handlers */ /* init calibration handlers */
priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
@ -1329,7 +1329,7 @@ static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
} }
static int iwl5000_hw_valid_rtc_data_addr(u32 addr) int iwl5000_hw_valid_rtc_data_addr(u32 addr)
{ {
return (addr >= IWL50_RTC_DATA_LOWER_BOUND) && return (addr >= IWL50_RTC_DATA_LOWER_BOUND) &&
(addr < IWL50_RTC_DATA_UPPER_BOUND); (addr < IWL50_RTC_DATA_UPPER_BOUND);
@ -1381,7 +1381,7 @@ static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
return ret; return ret;
} }
static int iwl5000_send_tx_power(struct iwl_priv *priv) int iwl5000_send_tx_power(struct iwl_priv *priv)
{ {
struct iwl5000_tx_power_dbm_cmd tx_power_cmd; struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
u8 tx_ant_cfg_cmd; u8 tx_ant_cfg_cmd;
@ -1401,10 +1401,11 @@ static int iwl5000_send_tx_power(struct iwl_priv *priv)
NULL); NULL);
} }
static void iwl5000_temperature(struct iwl_priv *priv) void iwl5000_temperature(struct iwl_priv *priv)
{ {
/* store temperature from statistics (in Celsius) */ /* store temperature from statistics (in Celsius) */
priv->temperature = le32_to_cpu(priv->statistics.general.temperature); priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
iwl_tt_handler(priv);
} }
static void iwl5150_temperature(struct iwl_priv *priv) static void iwl5150_temperature(struct iwl_priv *priv)

View file

@ -61,6 +61,63 @@
#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" #define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api) #define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
static void iwl6000_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;
}
static struct iwl_lib_ops iwl6000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwl5000_txq_set_sched,
.txq_agg_enable = iwl5000_txq_agg_enable,
.txq_agg_disable = iwl5000_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 = iwl5000_rx_handler_setup,
.setup_deferred_work = iwl5000_setup_deferred_work,
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
.load_ucode = iwl5000_load_ucode,
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl5000_apm_stop,
.config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
EEPROM_5000_REG_BAND_1_CHANNELS,
EEPROM_5000_REG_BAND_2_CHANNELS,
EEPROM_5000_REG_BAND_3_CHANNELS,
EEPROM_5000_REG_BAND_4_CHANNELS,
EEPROM_5000_REG_BAND_5_CHANNELS,
EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
EEPROM_5000_REG_BAND_52_FAT_CHANNELS
},
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwl5000_eeprom_calib_version,
.query_addr = iwl5000_eeprom_query_addr,
},
.post_associate = iwl_post_associate,
.isr = iwl_isr_ict,
.config_ap = iwl_config_ap,
.temp_ops = {
.temperature = iwl5000_temperature,
.set_ct_kill = iwl6000_set_ct_threshold,
},
};
static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = { static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
.get_hcmd_size = iwl5000_get_hcmd_size, .get_hcmd_size = iwl5000_get_hcmd_size,
.build_addsta_hcmd = iwl5000_build_addsta_hcmd, .build_addsta_hcmd = iwl5000_build_addsta_hcmd,
@ -70,7 +127,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
static struct iwl_ops iwl6000_ops = { static struct iwl_ops iwl6000_ops = {
.ucode = &iwl5000_ucode, .ucode = &iwl5000_ucode,
.lib = &iwl5000_lib, .lib = &iwl6000_lib,
.hcmd = &iwl5000_hcmd, .hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils, .utils = &iwl6000_hcmd_utils,
}; };

View file

@ -177,7 +177,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
struct sk_buff *skb, struct sk_buff *skb,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta); struct iwl_lq_sta *lq_sta);
static void rs_fill_link_cmd(const struct iwl_priv *priv, static void rs_fill_link_cmd(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, u32 rate_n_flags); struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
@ -1398,6 +1398,12 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
int ret = 0; int ret = 0;
u8 update_search_tbl_counter = 0; u8 update_search_tbl_counter = 0;
if (!iwl_ht_enabled(priv))
/* stay in Legacy */
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE &&
tbl->action > IWL_LEGACY_SWITCH_SISO)
tbl->action = IWL_LEGACY_SWITCH_SISO;
for (; ;) { for (; ;) {
lq_sta->action_counter++; lq_sta->action_counter++;
switch (tbl->action) { switch (tbl->action) {
@ -1529,6 +1535,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
u8 update_search_tbl_counter = 0; u8 update_search_tbl_counter = 0;
int ret; int ret;
if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE &&
tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
/* stay in SISO */
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
}
for (;;) { for (;;) {
lq_sta->action_counter++; lq_sta->action_counter++;
switch (tbl->action) { switch (tbl->action) {
@ -1663,6 +1674,12 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
u8 update_search_tbl_counter = 0; u8 update_search_tbl_counter = 0;
int ret; int ret;
if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) &&
(tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
/* switch in SISO */
tbl->action = IWL_MIMO2_SWITCH_SISO_A;
}
for (;;) { for (;;) {
lq_sta->action_counter++; lq_sta->action_counter++;
switch (tbl->action) { switch (tbl->action) {
@ -1799,6 +1816,12 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
int ret; int ret;
u8 update_search_tbl_counter = 0; u8 update_search_tbl_counter = 0;
if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) &&
(tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
/* switch in SISO */
tbl->action = IWL_MIMO3_SWITCH_SISO_A;
}
for (;;) { for (;;) {
lq_sta->action_counter++; lq_sta->action_counter++;
switch (tbl->action) { switch (tbl->action) {
@ -2002,6 +2025,25 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
} }
} }
/*
* setup rate table in uCode
* return rate_n_flags as used in the table
*/
static u32 rs_update_rate_tbl(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl,
int index, u8 is_green)
{
u32 rate;
/* Update uCode's rate table. */
rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
rs_fill_link_cmd(priv, lq_sta, rate);
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
return rate;
}
/* /*
* Do rate scaling and search for new modulation mode. * Do rate scaling and search for new modulation mode.
*/ */
@ -2098,6 +2140,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (!((1 << index) & rate_scale_index_msk)) { if (!((1 << index) & rate_scale_index_msk)) {
IWL_ERR(priv, "Current Rate is not valid\n"); IWL_ERR(priv, "Current Rate is not valid\n");
if (lq_sta->search_better_tbl) {
/* revert to active table if search table is not valid*/
tbl->lq_type = LQ_NONE;
lq_sta->search_better_tbl = 0;
tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
/* get "active" rate info */
index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
rate = rs_update_rate_tbl(priv, lq_sta,
tbl, index, is_green);
}
return; return;
} }
@ -2149,8 +2201,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
tbl->expected_tpt[index] + 64) / 128)); tbl->expected_tpt[index] + 64) / 128));
/* If we are searching for better modulation mode, check success. */ /* If we are searching for better modulation mode, check success. */
if (lq_sta->search_better_tbl) { if (lq_sta->search_better_tbl &&
(iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) {
/* If good success, continue using the "search" mode; /* If good success, continue using the "search" mode;
* no need to send new link quality command, since we're * no need to send new link quality command, since we're
* continuing to use the setup that we've been trying. */ * continuing to use the setup that we've been trying. */
@ -2278,7 +2330,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
((sr > IWL_RATE_HIGH_TH) || ((sr > IWL_RATE_HIGH_TH) ||
(current_tpt > (100 * tbl->expected_tpt[low])))) (current_tpt > (100 * tbl->expected_tpt[low]))))
scale_action = 0; scale_action = 0;
if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type))
scale_action = -1;
if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI &&
(is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
scale_action = -1;
switch (scale_action) { switch (scale_action) {
case -1: case -1:
/* Decrease starting rate, update uCode's rate table */ /* Decrease starting rate, update uCode's rate table */
@ -2308,15 +2364,15 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
lq_update: lq_update:
/* Replace uCode's rate table for the destination station. */ /* Replace uCode's rate table for the destination station. */
if (update_lq) { if (update_lq)
rate = rate_n_flags_from_tbl(priv, tbl, index, is_green); rate = rs_update_rate_tbl(priv, lq_sta,
rs_fill_link_cmd(priv, lq_sta, rate); tbl, index, is_green);
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) {
/* Should we stay with this modulation mode,
* or search for a new one? */
rs_stay_in_table(lq_sta);
} }
/* Should we stay with this modulation mode, or search for a new one? */
rs_stay_in_table(lq_sta);
/* /*
* Search for new modulation mode if we're: * Search for new modulation mode if we're:
* 1) Not changing rates right now * 1) Not changing rates right now
@ -2373,7 +2429,8 @@ lq_update:
* have been tried and compared, stay in this best modulation * have been tried and compared, stay in this best modulation
* mode for a while before next round of mode comparisons. */ * mode for a while before next round of mode comparisons. */
if (lq_sta->enable_counter && if (lq_sta->enable_counter &&
(lq_sta->action_counter >= tbl1->max_search)) { (lq_sta->action_counter >= tbl1->max_search) &&
iwl_ht_enabled(priv)) {
if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
(lq_sta->tx_agg_tid_en & (1 << tid)) && (lq_sta->tx_agg_tid_en & (1 << tid)) &&
(tid != MAX_TID_COUNT)) { (tid != MAX_TID_COUNT)) {
@ -2659,7 +2716,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
rs_initialize_lq(priv, conf, sta, lq_sta); rs_initialize_lq(priv, conf, sta, lq_sta);
} }
static void rs_fill_link_cmd(const struct iwl_priv *priv, static void rs_fill_link_cmd(struct iwl_priv *priv,
struct iwl_lq_sta *lq_sta, u32 new_rate) struct iwl_lq_sta *lq_sta, u32 new_rate)
{ {
struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info tbl_type;

View file

@ -442,8 +442,8 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */ /* Unmap tx_cmd */
if (num_tbs) if (num_tbs)
pci_unmap_single(dev, pci_unmap_single(dev,
pci_unmap_addr(&txq->cmd[index]->meta, mapping), pci_unmap_addr(&txq->meta[index], mapping),
pci_unmap_len(&txq->cmd[index]->meta, len), pci_unmap_len(&txq->meta[index], len),
PCI_DMA_BIDIRECTIONAL); PCI_DMA_BIDIRECTIONAL);
/* Unmap chunks, if any. */ /* Unmap chunks, if any. */
@ -637,7 +637,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status; unsigned long status = priv->status;
unsigned long reg_flags;
IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On", (flags & HW_CARD_DISABLED) ? "Kill" : "On",
@ -657,19 +656,12 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
iwl_write_direct32(priv, HBUS_TARG_MBX_C, iwl_write_direct32(priv, HBUS_TARG_MBX_C,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
}
if (flags & RF_CARD_DISABLED) {
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
iwl_read32(priv, CSR_UCODE_DRV_GP1);
spin_lock_irqsave(&priv->reg_lock, reg_flags);
if (!iwl_grab_nic_access(priv))
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
} }
if (flags & RF_CARD_DISABLED)
iwl_tt_enter_ct_kill(priv);
} }
if (!(flags & RF_CARD_DISABLED))
iwl_tt_exit_ct_kill(priv);
if (flags & HW_CARD_DISABLED) if (flags & HW_CARD_DISABLED)
set_bit(STATUS_RF_KILL_HW, &priv->status); set_bit(STATUS_RF_KILL_HW, &priv->status);
@ -3015,6 +3007,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
test_bit(STATUS_RF_KILL_HW, &priv->status)); test_bit(STATUS_RF_KILL_HW, &priv->status));
iwl_power_initialize(priv); iwl_power_initialize(priv);
iwl_tt_initialize(priv);
return 0; return 0;
out_remove_sysfs: out_remove_sysfs:
@ -3067,6 +3060,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_down(priv); iwl_down(priv);
} }
iwl_tt_exit(priv);
/* make sure we flush any pending irq or /* make sure we flush any pending irq or
* tasklet for the driver * tasklet for the driver
*/ */

View file

@ -86,7 +86,7 @@ int iwl_send_calib_results(struct iwl_priv *priv)
struct iwl_host_cmd hcmd = { struct iwl_host_cmd hcmd = {
.id = REPLY_PHY_CALIBRATION_CMD, .id = REPLY_PHY_CALIBRATION_CMD,
.meta.flags = CMD_SIZE_HUGE, .flags = CMD_SIZE_HUGE,
}; };
for (i = 0; i < IWL_CALIB_MAX; i++) { for (i = 0; i < IWL_CALIB_MAX; i++) {
@ -419,7 +419,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
struct iwl_host_cmd cmd_out = { struct iwl_host_cmd cmd_out = {
.id = SENSITIVITY_CMD, .id = SENSITIVITY_CMD,
.len = sizeof(struct iwl_sensitivity_cmd), .len = sizeof(struct iwl_sensitivity_cmd),
.meta.flags = CMD_ASYNC, .flags = CMD_ASYNC,
.data = &cmd, .data = &cmd,
}; };

View file

@ -2413,6 +2413,13 @@ struct iwl_ct_kill_config {
__le32 critical_temperature_R; __le32 critical_temperature_R;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* 1000, and 6x00 */
struct iwl_ct_kill_throttling_config {
__le32 critical_temperature_exit;
__le32 reserved;
__le32 critical_temperature_enter;
} __attribute__ ((packed));
/****************************************************************************** /******************************************************************************
* (8) * (8)
* Scan Commands, Responses, Notifications: * Scan Commands, Responses, Notifications:

View file

@ -632,6 +632,10 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
if (!sta_ht_inf->ht_supported) if (!sta_ht_inf->ht_supported)
return 0; return 0;
} }
#ifdef CONFIG_IWLWIFI_DEBUG
if (priv->disable_ht40)
return 0;
#endif
return iwl_is_channel_extension(priv, priv->band, return iwl_is_channel_extension(priv, priv->band,
le16_to_cpu(priv->staging_rxon.channel), le16_to_cpu(priv->staging_rxon.channel),
iwl_ht_conf->extension_chan_offset); iwl_ht_conf->extension_chan_offset);
@ -1291,7 +1295,6 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
} }
#endif
static const char *desc_lookup_text[] = { static const char *desc_lookup_text[] = {
"OK", "OK",
@ -1496,6 +1499,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
iwl_print_event_log(priv, 0, next_entry, mode); iwl_print_event_log(priv, 0, next_entry, mode);
} }
#endif
/** /**
* iwl_irq_handle_error - called for HW or SW error interrupt from card * iwl_irq_handle_error - called for HW or SW error interrupt from card
*/ */
@ -2089,7 +2093,7 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
u32 stat_flags = 0; u32 stat_flags = 0;
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_STATISTICS_CMD, .id = REPLY_STATISTICS_CMD,
.meta.flags = flags, .flags = flags,
.len = sizeof(stat_flags), .len = sizeof(stat_flags),
.data = (u8 *) &stat_flags, .data = (u8 *) &stat_flags,
}; };
@ -2224,6 +2228,7 @@ EXPORT_SYMBOL(iwl_verify_ucode);
void iwl_rf_kill_ct_config(struct iwl_priv *priv) void iwl_rf_kill_ct_config(struct iwl_priv *priv)
{ {
struct iwl_ct_kill_config cmd; struct iwl_ct_kill_config cmd;
struct iwl_ct_kill_throttling_config adv_cmd;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
@ -2231,10 +2236,28 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
priv->power_data.ct_kill_toggle = false;
cmd.critical_temperature_R = switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
cpu_to_le32(priv->hw_params.ct_kill_threshold); case CSR_HW_REV_TYPE_1000:
case CSR_HW_REV_TYPE_6x00:
case CSR_HW_REV_TYPE_6x50:
adv_cmd.critical_temperature_enter =
cpu_to_le32(priv->hw_params.ct_kill_threshold);
adv_cmd.critical_temperature_exit =
cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
sizeof(adv_cmd), &adv_cmd);
break;
default:
cmd.critical_temperature_R =
cpu_to_le32(priv->hw_params.ct_kill_threshold);
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
sizeof(cmd), &cmd);
break;
}
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
sizeof(cmd), &cmd); sizeof(cmd), &cmd);
if (ret) if (ret)
@ -2263,7 +2286,7 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
.id = REPLY_CARD_STATE_CMD, .id = REPLY_CARD_STATE_CMD,
.len = sizeof(u32), .len = sizeof(u32),
.data = &flags, .data = &flags,
.meta.flags = meta_flag, .flags = meta_flag,
}; };
return iwl_send_cmd(priv, &cmd); return iwl_send_cmd(priv, &cmd);

View file

@ -446,9 +446,9 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id,
u16 len, const void *data); u16 len, const void *data);
int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
const void *data, const void *data,
int (*callback)(struct iwl_priv *priv, void (*callback)(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb)); struct sk_buff *skb));
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);

View file

@ -84,9 +84,11 @@ struct iwl_debugfs {
struct dentry *file_status; struct dentry *file_status;
struct dentry *file_interrupt; struct dentry *file_interrupt;
struct dentry *file_qos; struct dentry *file_qos;
struct dentry *file_thermal_throttling;
#ifdef CONFIG_IWLWIFI_LEDS #ifdef CONFIG_IWLWIFI_LEDS
struct dentry *file_led; struct dentry *file_led;
#endif #endif
struct dentry *file_disable_ht40;
} dbgfs_data_files; } dbgfs_data_files;
struct dir_rf_files { struct dir_rf_files {
struct dentry *file_disable_sensitivity; struct dentry *file_disable_sensitivity;

View file

@ -618,6 +618,84 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
} }
#endif #endif
static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
struct iwl_tt_restriction *restriction;
char buf[100];
int pos = 0;
const size_t bufsz = sizeof(buf);
ssize_t ret;
pos += scnprintf(buf + pos, bufsz - pos,
"Thermal Throttling Mode: %s\n",
(priv->power_data.adv_tt)
? "Advance" : "Legacy");
pos += scnprintf(buf + pos, bufsz - pos,
"Thermal Throttling State: %d\n",
tt->state);
if (priv->power_data.adv_tt) {
restriction = tt->restriction + tt->state;
pos += scnprintf(buf + pos, bufsz - pos,
"Tx mode: %d\n",
restriction->tx_stream);
pos += scnprintf(buf + pos, bufsz - pos,
"Rx mode: %d\n",
restriction->rx_stream);
pos += scnprintf(buf + pos, bufsz - pos,
"HT mode: %d\n",
restriction->is_ht);
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
return ret;
}
static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
char buf[8];
int buf_size;
int ht40;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%d", &ht40) != 1)
return -EFAULT;
if (!iwl_is_associated(priv))
priv->disable_ht40 = ht40 ? true : false;
else {
IWL_ERR(priv, "Sta associated with AP - "
"Change to 40MHz channel support is not allowed\n");
return -EINVAL;
}
return count;
}
static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
char buf[100];
int pos = 0;
const size_t bufsz = sizeof(buf);
ssize_t ret;
pos += scnprintf(buf + pos, bufsz - pos,
"11n 40MHz Mode: %s\n",
priv->disable_ht40 ? "Disabled" : "Enabled");
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
return ret;
}
DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_WRITE_FILE_OPS(log_event);
DEBUGFS_READ_FILE_OPS(nvm); DEBUGFS_READ_FILE_OPS(nvm);
@ -631,6 +709,8 @@ DEBUGFS_READ_FILE_OPS(qos);
#ifdef CONFIG_IWLWIFI_LEDS #ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_READ_FILE_OPS(led); DEBUGFS_READ_FILE_OPS(led);
#endif #endif
DEBUGFS_READ_FILE_OPS(thermal_throttling);
DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
/* /*
* Create the debugfs files and directories * Create the debugfs files and directories
@ -671,6 +751,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
#ifdef CONFIG_IWLWIFI_LEDS #ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_ADD_FILE(led, data); DEBUGFS_ADD_FILE(led, data);
#endif #endif
DEBUGFS_ADD_FILE(thermal_throttling, data);
DEBUGFS_ADD_FILE(disable_ht40, data);
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, rf, DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
&priv->disable_chain_noise_cal); &priv->disable_chain_noise_cal);
@ -709,6 +791,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
#ifdef CONFIG_IWLWIFI_LEDS #ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
#endif #endif
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40);
DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dir_data);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);

View file

@ -63,6 +63,8 @@ extern struct iwl_cfg iwl6050_2agn_cfg;
extern struct iwl_cfg iwl6050_3agn_cfg; extern struct iwl_cfg iwl6050_3agn_cfg;
extern struct iwl_cfg iwl1000_bgn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg;
struct iwl_tx_queue;
/* shared structures from iwl-5000.c */ /* shared structures from iwl-5000.c */
extern struct iwl_mod_params iwl50_mod_params; extern struct iwl_mod_params iwl50_mod_params;
extern struct iwl_ops iwl5000_ops; extern struct iwl_ops iwl5000_ops;
@ -79,9 +81,37 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags); __le32 *tx_flags);
extern int iwl5000_calc_rssi(struct iwl_priv *priv, extern int iwl5000_calc_rssi(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp); struct iwl_rx_phy_res *rx_resp);
extern int iwl5000_apm_init(struct iwl_priv *priv);
extern void iwl5000_apm_stop(struct iwl_priv *priv);
extern int iwl5000_apm_reset(struct iwl_priv *priv);
extern void iwl5000_nic_config(struct iwl_priv *priv);
extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv);
extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset);
extern void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
u16 byte_cnt);
extern void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq);
extern int iwl5000_load_ucode(struct iwl_priv *priv);
extern void iwl5000_init_alive_start(struct iwl_priv *priv);
extern int iwl5000_alive_notify(struct iwl_priv *priv);
extern int iwl5000_hw_set_hw_params(struct iwl_priv *priv);
extern int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int tx_fifo, int sta_id, int tid, u16 ssn_idx);
extern int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo);
extern void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask);
extern void iwl5000_setup_deferred_work(struct iwl_priv *priv);
extern void iwl5000_rx_handler_setup(struct iwl_priv *priv);
extern int iwl5000_hw_valid_rtc_data_addr(u32 addr);
extern int iwl5000_send_tx_power(struct iwl_priv *priv);
extern void iwl5000_temperature(struct iwl_priv *priv);
/* CT-KILL constants */ /* CT-KILL constants */
#define CT_KILL_THRESHOLD 110 /* in Celsius */ #define CT_KILL_THRESHOLD_LEGACY 110 /* in Celsius */
#define CT_KILL_THRESHOLD 114 /* in Celsius */
#define CT_KILL_EXIT_THRESHOLD 95 /* in Celsius */
/* Default noise level to report when noise measurement is not available. /* Default noise level to report when noise measurement is not available.
* This may be because we're: * This may be because we're:
@ -120,6 +150,31 @@ struct iwl_rx_mem_buffer {
struct list_head list; struct list_head list;
}; };
/* defined below */
struct iwl_device_cmd;
struct iwl_cmd_meta {
/* only for SYNC commands, iff the reply skb is wanted */
struct iwl_host_cmd *source;
/*
* only for ASYNC commands
* (which is somewhat stupid -- look at iwl-sta.c for instance
* which duplicates a bunch of code because the callback isn't
* invoked for SYNC commands, if it were and its result passed
* through it would be simpler...)
*/
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
struct sk_buff *skb);
/* The CMD_SIZE_HUGE flag bit indicates that the command
* structure is stored at the end of the shared queue memory. */
u32 flags;
DECLARE_PCI_UNMAP_ADDR(mapping)
DECLARE_PCI_UNMAP_LEN(len)
};
/* /*
* Generic queue structure * Generic queue structure
* *
@ -147,7 +202,8 @@ struct iwl_tx_info {
* struct iwl_tx_queue - Tx Queue for DMA * struct iwl_tx_queue - Tx Queue for DMA
* @q: generic Rx/Tx queue descriptor * @q: generic Rx/Tx queue descriptor
* @bd: base of circular buffer of TFDs * @bd: base of circular buffer of TFDs
* @cmd: array of command/Tx buffers * @cmd: array of command/TX buffer pointers
* @meta: array of meta data for each command/tx buffer
* @dma_addr_cmd: physical address of cmd/tx buffer array * @dma_addr_cmd: physical address of cmd/tx buffer array
* @txb: array of per-TFD driver data * @txb: array of per-TFD driver data
* @need_update: indicates need to update read/write index * @need_update: indicates need to update read/write index
@ -162,7 +218,8 @@ struct iwl_tx_info {
struct iwl_tx_queue { struct iwl_tx_queue {
struct iwl_queue q; struct iwl_queue q;
void *tfds; void *tfds;
struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS]; struct iwl_device_cmd **cmd;
struct iwl_cmd_meta *meta;
struct iwl_tx_info *txb; struct iwl_tx_info *txb;
u8 need_update; u8 need_update;
u8 sched_retry; u8 sched_retry;
@ -299,35 +356,16 @@ enum {
CMD_WANT_SKB = (1 << 2), CMD_WANT_SKB = (1 << 2),
}; };
struct iwl_cmd;
struct iwl_priv;
struct iwl_cmd_meta {
struct iwl_cmd_meta *source;
union {
struct sk_buff *skb;
int (*callback)(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb);
} __attribute__ ((packed)) u;
/* The CMD_SIZE_HUGE flag bit indicates that the command
* structure is stored at the end of the shared queue memory. */
u32 flags;
DECLARE_PCI_UNMAP_ADDR(mapping)
DECLARE_PCI_UNMAP_LEN(len)
} __attribute__ ((packed));
#define IWL_CMD_MAX_PAYLOAD 320 #define IWL_CMD_MAX_PAYLOAD 320
/** /**
* struct iwl_cmd * struct iwl_device_cmd
* *
* For allocation of the command and tx queues, this establishes the overall * For allocation of the command and tx queues, this establishes the overall
* size of the largest command we send to uCode, except for a scan command * size of the largest command we send to uCode, except for a scan command
* (which is relatively huge; space is allocated separately). * (which is relatively huge; space is allocated separately).
*/ */
struct iwl_cmd { struct iwl_device_cmd {
struct iwl_cmd_meta meta; /* driver data */
struct iwl_cmd_header hdr; /* uCode API */ struct iwl_cmd_header hdr; /* uCode API */
union { union {
u32 flags; u32 flags;
@ -339,17 +377,20 @@ struct iwl_cmd {
} __attribute__ ((packed)) cmd; } __attribute__ ((packed)) cmd;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
struct iwl_host_cmd { struct iwl_host_cmd {
u8 id;
u16 len;
struct iwl_cmd_meta meta;
const void *data; const void *data;
struct sk_buff *reply_skb;
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
struct sk_buff *skb);
u32 flags;
u16 len;
u8 id;
}; };
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
sizeof(struct iwl_cmd_meta))
/* /*
* RX related structures and functions * RX related structures and functions
*/ */
@ -450,8 +491,16 @@ union iwl_ht_rate_supp {
}; };
#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) #define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3)
#define CFG_HT_MPDU_DENSITY_2USEC (0x5)
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC /*
* Maximal MPDU density for TX aggregation
* 4 - 2us density
* 5 - 4us density
* 6 - 8us density
* 7 - 16us density
*/
#define CFG_HT_MPDU_DENSITY_4USEC (0x5)
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
struct iwl_ht_info { struct iwl_ht_info {
/* self configuration data */ /* self configuration data */
@ -630,6 +679,8 @@ struct iwl_hw_params {
u32 max_data_size; u32 max_data_size;
u32 max_bsm_size; u32 max_bsm_size;
u32 ct_kill_threshold; /* value in hw-dependent units */ u32 ct_kill_threshold; /* value in hw-dependent units */
u32 ct_kill_exit_threshold; /* value in hw-dependent units */
/* for 1000, 6000 series and up */
u32 calib_init_cfg; u32 calib_init_cfg;
const struct iwl_sensitivity_ranges *sens; const struct iwl_sensitivity_ranges *sens;
}; };
@ -1113,6 +1164,7 @@ struct iwl_priv {
/* debugging info */ /* debugging info */
u32 framecnt_to_us; u32 framecnt_to_us;
atomic_t restrict_refcnt; atomic_t restrict_refcnt;
bool disable_ht40;
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
/* debugfs */ /* debugfs */
struct iwl_debugfs *dbgfs; struct iwl_debugfs *dbgfs;

View file

@ -103,22 +103,23 @@ EXPORT_SYMBOL(get_cmd_string);
#define HOST_COMPLETE_TIMEOUT (HZ / 2) #define HOST_COMPLETE_TIMEOUT (HZ / 2)
static int iwl_generic_cmd_callback(struct iwl_priv *priv, static void iwl_generic_cmd_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb) struct iwl_device_cmd *cmd,
struct sk_buff *skb)
{ {
struct iwl_rx_packet *pkt = NULL; struct iwl_rx_packet *pkt = NULL;
if (!skb) { if (!skb) {
IWL_ERR(priv, "Error: Response NULL in %s.\n", IWL_ERR(priv, "Error: Response NULL in %s.\n",
get_cmd_string(cmd->hdr.cmd)); get_cmd_string(cmd->hdr.cmd));
return 1; return;
} }
pkt = (struct iwl_rx_packet *)skb->data; pkt = (struct iwl_rx_packet *)skb->data;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from %s (0x%08X)\n", IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
return 1; return;
} }
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
@ -127,29 +128,26 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv,
case SENSITIVITY_CMD: case SENSITIVITY_CMD:
IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n", IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
break; break;
default: default:
IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n", IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
} }
#endif #endif
/* Let iwl_tx_complete free the response skb */
return 1;
} }
static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{ {
int ret; int ret;
BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); BUG_ON(!(cmd->flags & CMD_ASYNC));
/* An asynchronous command can not expect an SKB to be set. */ /* An asynchronous command can not expect an SKB to be set. */
BUG_ON(cmd->meta.flags & CMD_WANT_SKB); BUG_ON(cmd->flags & CMD_WANT_SKB);
/* Assign a generic callback if one is not provided */ /* Assign a generic callback if one is not provided */
if (!cmd->meta.u.callback) if (!cmd->callback)
cmd->meta.u.callback = iwl_generic_cmd_callback; cmd->callback = iwl_generic_cmd_callback;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return -EBUSY; return -EBUSY;
@ -168,10 +166,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
int cmd_idx; int cmd_idx;
int ret; int ret;
BUG_ON(cmd->meta.flags & CMD_ASYNC); BUG_ON(cmd->flags & CMD_ASYNC);
/* A synchronous command can not have a callback set. */ /* A synchronous command can not have a callback set. */
BUG_ON(cmd->meta.u.callback != NULL); BUG_ON(cmd->callback);
if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) { if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
IWL_ERR(priv, IWL_ERR(priv,
@ -183,9 +181,6 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
set_bit(STATUS_HCMD_ACTIVE, &priv->status); set_bit(STATUS_HCMD_ACTIVE, &priv->status);
if (cmd->meta.flags & CMD_WANT_SKB)
cmd->meta.source = &cmd->meta;
cmd_idx = iwl_enqueue_hcmd(priv, cmd); cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) { if (cmd_idx < 0) {
ret = cmd_idx; ret = cmd_idx;
@ -222,7 +217,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
ret = -EIO; ret = -EIO;
goto fail; goto fail;
} }
if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) {
IWL_ERR(priv, "Error: Response NULL in '%s'\n", IWL_ERR(priv, "Error: Response NULL in '%s'\n",
get_cmd_string(cmd->id)); get_cmd_string(cmd->id));
ret = -EIO; ret = -EIO;
@ -233,20 +228,20 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
goto out; goto out;
cancel: cancel:
if (cmd->meta.flags & CMD_WANT_SKB) { if (cmd->flags & CMD_WANT_SKB) {
struct iwl_cmd *qcmd; /*
* Cancel the CMD_WANT_SKB flag for the cmd in the
/* Cancel the CMD_WANT_SKB flag for the cmd in the
* TX cmd queue. Otherwise in case the cmd comes * TX cmd queue. Otherwise in case the cmd comes
* in later, it will possibly set an invalid * in later, it will possibly set an invalid
* address (cmd->meta.source). */ * address (cmd->meta.source).
qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; */
qcmd->meta.flags &= ~CMD_WANT_SKB; priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &=
~CMD_WANT_SKB;
} }
fail: fail:
if (cmd->meta.u.skb) { if (cmd->reply_skb) {
dev_kfree_skb_any(cmd->meta.u.skb); dev_kfree_skb_any(cmd->reply_skb);
cmd->meta.u.skb = NULL; cmd->reply_skb = NULL;
} }
out: out:
clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
@ -256,7 +251,7 @@ EXPORT_SYMBOL(iwl_send_cmd_sync);
int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{ {
if (cmd->meta.flags & CMD_ASYNC) if (cmd->flags & CMD_ASYNC)
return iwl_send_cmd_async(priv, cmd); return iwl_send_cmd_async(priv, cmd);
return iwl_send_cmd_sync(priv, cmd); return iwl_send_cmd_sync(priv, cmd);
@ -277,9 +272,9 @@ EXPORT_SYMBOL(iwl_send_cmd_pdu);
int iwl_send_cmd_pdu_async(struct iwl_priv *priv, int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
u8 id, u16 len, const void *data, u8 id, u16 len, const void *data,
int (*callback)(struct iwl_priv *priv, void (*callback)(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb)) struct sk_buff *skb))
{ {
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = id, .id = id,
@ -287,8 +282,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
.data = data, .data = data,
}; };
cmd.meta.flags |= CMD_ASYNC; cmd.flags |= CMD_ASYNC;
cmd.meta.u.callback = callback; cmd.callback = callback;
return iwl_send_cmd_async(priv, &cmd); return iwl_send_cmd_async(priv, &cmd);
} }

View file

@ -91,8 +91,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
.id = REPLY_LEDS_CMD, .id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd), .len = sizeof(struct iwl_led_cmd),
.data = led_cmd, .data = led_cmd,
.meta.flags = CMD_ASYNC, .flags = CMD_ASYNC,
.meta.u.callback = NULL, .callback = NULL,
}; };
u32 reg; u32 reg;

View file

@ -36,6 +36,7 @@
#include "iwl-eeprom.h" #include "iwl-eeprom.h"
#include "iwl-dev.h" #include "iwl-dev.h"
#include "iwl-core.h" #include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-commands.h" #include "iwl-commands.h"
#include "iwl-debug.h" #include "iwl-debug.h"
#include "iwl-power.h" #include "iwl-power.h"
@ -97,6 +98,45 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
}; };
/* default Thermal Throttling transaction table
* Current state | Throttling Down | Throttling Up
*=============================================================================
* Condition Nxt State Condition Nxt State Condition Nxt State
*-----------------------------------------------------------------------------
* IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A
* IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0
* IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1
* IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
*=============================================================================
*/
static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
{IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
{IWL_TI_1, 105, CT_KILL_THRESHOLD},
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
};
static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
{IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
{IWL_TI_2, 110, CT_KILL_THRESHOLD},
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
};
static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
{IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
};
static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
{IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
};
/* Advance Thermal Throttling default restriction table */
static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
{IWL_TX_MULTI, true, IWL_RX_MULTI},
{IWL_TX_SINGLE, true, IWL_RX_MULTI},
{IWL_TX_SINGLE, false, IWL_RX_SINGLE},
{IWL_TX_NONE, false, IWL_RX_NONE}
};
/* set card power command */ /* set card power command */
static int iwl_set_power(struct iwl_priv *priv, void *cmd) static int iwl_set_power(struct iwl_priv *priv, void *cmd)
@ -211,6 +251,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
{ {
struct iwl_power_mgr *setting = &(priv->power_data); struct iwl_power_mgr *setting = &(priv->power_data);
int ret = 0; int ret = 0;
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
u16 uninitialized_var(final_mode); u16 uninitialized_var(final_mode);
bool update_chains; bool update_chains;
@ -223,6 +264,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
if (setting->power_disabled) if (setting->power_disabled)
final_mode = IWL_POWER_MODE_CAM; final_mode = IWL_POWER_MODE_CAM;
if (tt->state >= IWL_TI_1) {
/* TT power setting overwrite user & system power setting */
final_mode = tt->tt_power_mode;
}
if (iwl_is_ready_rf(priv) && if (iwl_is_ready_rf(priv) &&
((setting->power_mode != final_mode) || force)) { ((setting->power_mode != final_mode) || force)) {
struct iwl_powertable_cmd cmd; struct iwl_powertable_cmd cmd;
@ -267,6 +312,487 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
} }
EXPORT_SYMBOL(iwl_power_set_user_mode); EXPORT_SYMBOL(iwl_power_set_user_mode);
bool iwl_ht_enabled(struct iwl_priv *priv)
{
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
struct iwl_tt_restriction *restriction;
if (!priv->power_data.adv_tt)
return true;
restriction = tt->restriction + tt->state;
return restriction->is_ht;
}
EXPORT_SYMBOL(iwl_ht_enabled);
u8 iwl_tx_ant_restriction(struct iwl_priv *priv)
{
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
struct iwl_tt_restriction *restriction;
if (!priv->power_data.adv_tt)
return IWL_TX_MULTI;
restriction = tt->restriction + tt->state;
return restriction->tx_stream;
}
EXPORT_SYMBOL(iwl_tx_ant_restriction);
u8 iwl_rx_ant_restriction(struct iwl_priv *priv)
{
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
struct iwl_tt_restriction *restriction;
if (!priv->power_data.adv_tt)
return IWL_RX_MULTI;
restriction = tt->restriction + tt->state;
return restriction->rx_stream;
}
EXPORT_SYMBOL(iwl_rx_ant_restriction);
#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
/*
* toggle the bit to wake up uCode and check the temperature
* if the temperature is below CT, uCode will stay awake and send card
* state notification with CT_KILL bit clear to inform Thermal Throttling
* Management to change state. Otherwise, uCode will go back to sleep
* without doing anything, driver should continue the 5 seconds timer
* to wake up uCode for temperature check until temperature drop below CT
*/
static void iwl_tt_check_exit_ct_kill(unsigned long data)
{
struct iwl_priv *priv = (struct iwl_priv *)data;
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
unsigned long flags;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
if (tt->state == IWL_TI_CT_KILL) {
if (priv->power_data.ct_kill_toggle) {
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
priv->power_data.ct_kill_toggle = false;
} else {
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
priv->power_data.ct_kill_toggle = true;
}
iwl_read32(priv, CSR_UCODE_DRV_GP1);
spin_lock_irqsave(&priv->reg_lock, flags);
if (!iwl_grab_nic_access(priv))
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, flags);
/* Reschedule the ct_kill timer to occur in
* CT_KILL_EXIT_DURATION seconds to ensure we get a
* thermal update */
mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies +
CT_KILL_EXIT_DURATION * HZ);
}
}
static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
bool stop)
{
if (stop) {
IWL_DEBUG_POWER(priv, "Stop all queues\n");
if (priv->mac80211_registered)
ieee80211_stop_queues(priv->hw);
IWL_DEBUG_POWER(priv,
"Schedule 5 seconds CT_KILL Timer\n");
mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies +
CT_KILL_EXIT_DURATION * HZ);
} else {
IWL_DEBUG_POWER(priv, "Wake all queues\n");
if (priv->mac80211_registered)
ieee80211_wake_queues(priv->hw);
}
}
#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY)
#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100)
#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90)
/*
* Legacy thermal throttling
* 1) Avoid NIC destruction due to high temperatures
* Chip will identify dangerously high temperatures that can
* harm the device and will power down
* 2) Avoid the NIC power down due to high temperature
* Throttle early enough to lower the power consumption before
* drastic steps are needed
*/
static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
{
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
enum iwl_tt_state new_state;
struct iwl_power_mgr *setting = &priv->power_data;
#ifdef CONFIG_IWLWIFI_DEBUG
if ((tt->tt_previous_temp) &&
(temp > tt->tt_previous_temp) &&
((temp - tt->tt_previous_temp) >
IWL_TT_INCREASE_MARGIN)) {
IWL_DEBUG_POWER(priv,
"Temperature increase %d degree Celsius\n",
(temp - tt->tt_previous_temp));
}
#endif
/* in Celsius */
if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
new_state = IWL_TI_CT_KILL;
else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
new_state = IWL_TI_2;
else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
new_state = IWL_TI_1;
else
new_state = IWL_TI_0;
#ifdef CONFIG_IWLWIFI_DEBUG
tt->tt_previous_temp = temp;
#endif
if (tt->state != new_state) {
if (tt->state == IWL_TI_0) {
tt->sys_power_mode = setting->power_mode;
IWL_DEBUG_POWER(priv, "current power mode: %u\n",
setting->power_mode);
}
switch (new_state) {
case IWL_TI_0:
/* when system ready to go back to IWL_TI_0 state
* using system power mode instead of TT power mode
* revert back to the orginal power mode which was saved
* before enter Thermal Throttling state
* update priv->power_data.user_power_setting to the
* required power mode to make sure
* iwl_power_update_mode() will update power correctly.
*/
priv->power_data.user_power_setting =
tt->sys_power_mode;
tt->tt_power_mode = tt->sys_power_mode;
break;
case IWL_TI_1:
tt->tt_power_mode = IWL_POWER_INDEX_3;
break;
case IWL_TI_2:
tt->tt_power_mode = IWL_POWER_INDEX_4;
break;
default:
tt->tt_power_mode = IWL_POWER_INDEX_5;
break;
}
if (iwl_power_update_mode(priv, true)) {
/* TT state not updated
* try again during next temperature read
*/
IWL_ERR(priv, "Cannot update power mode, "
"TT state not updated\n");
} else {
if (new_state == IWL_TI_CT_KILL)
iwl_perform_ct_kill_task(priv, true);
else if (tt->state == IWL_TI_CT_KILL &&
new_state != IWL_TI_CT_KILL)
iwl_perform_ct_kill_task(priv, false);
tt->state = new_state;
IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
tt->state);
IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
tt->tt_power_mode);
}
}
}
/*
* Advance thermal throttling
* 1) Avoid NIC destruction due to high temperatures
* Chip will identify dangerously high temperatures that can
* harm the device and will power down
* 2) Avoid the NIC power down due to high temperature
* Throttle early enough to lower the power consumption before
* drastic steps are needed
* Actions include relaxing the power down sleep thresholds and
* decreasing the number of TX streams
* 3) Avoid throughput performance impact as much as possible
*
*=============================================================================
* Condition Nxt State Condition Nxt State Condition Nxt State
*-----------------------------------------------------------------------------
* IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A
* IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0
* IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1
* IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
*=============================================================================
*/
static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
{
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
int i;
bool changed = false;
enum iwl_tt_state old_state;
struct iwl_tt_trans *transaction;
old_state = tt->state;
for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
/* based on the current TT state,
* find the curresponding transaction table
* each table has (IWL_TI_STATE_MAX - 1) entries
* tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
* will advance to the correct table.
* then based on the current temperature
* find the next state need to transaction to
* go through all the possible (IWL_TI_STATE_MAX - 1) entries
* in the current table to see if transaction is needed
*/
transaction = tt->transaction +
((old_state * (IWL_TI_STATE_MAX - 1)) + i);
if (temp >= transaction->tt_low &&
temp <= transaction->tt_high) {
#ifdef CONFIG_IWLWIFI_DEBUG
if ((tt->tt_previous_temp) &&
(temp > tt->tt_previous_temp) &&
((temp - tt->tt_previous_temp) >
IWL_TT_INCREASE_MARGIN)) {
IWL_DEBUG_POWER(priv,
"Temperature increase %d "
"degree Celsius\n",
(temp - tt->tt_previous_temp));
}
tt->tt_previous_temp = temp;
#endif
if (old_state !=
transaction->next_state) {
changed = true;
tt->state =
transaction->next_state;
}
break;
}
}
if (changed) {
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
struct iwl_power_mgr *setting = &priv->power_data;
if (tt->state >= IWL_TI_1) {
/* if switching from IWL_TI_0 to other TT state
* save previous power setting in tt->sys_power_mode */
if (old_state == IWL_TI_0)
tt->sys_power_mode = setting->power_mode;
/* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
tt->tt_power_mode = IWL_POWER_INDEX_5;
if (!iwl_ht_enabled(priv))
/* disable HT */
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
RXON_FLG_FAT_PROT_MSK |
RXON_FLG_HT_PROT_MSK);
else {
/* check HT capability and set
* according to the system HT capability
* in case get disabled before */
iwl_set_rxon_ht(priv, &priv->current_ht_config);
}
} else {
/* restore system power setting */
/* the previous power mode was saved in
* tt->sys_power_mode when system move into
* Thermal Throttling state
* set power_data.user_power_setting to the previous
* system power mode to make sure power will get
* updated correctly
*/
priv->power_data.user_power_setting =
tt->sys_power_mode;
tt->tt_power_mode = tt->sys_power_mode;
/* check HT capability and set
* according to the system HT capability
* in case get disabled before */
iwl_set_rxon_ht(priv, &priv->current_ht_config);
}
if (iwl_power_update_mode(priv, true)) {
/* TT state not updated
* try again during next temperature read
*/
IWL_ERR(priv, "Cannot update power mode, "
"TT state not updated\n");
tt->state = old_state;
} else {
IWL_DEBUG_POWER(priv,
"Thermal Throttling to new state: %u\n",
tt->state);
if (old_state != IWL_TI_CT_KILL &&
tt->state == IWL_TI_CT_KILL) {
IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n");
iwl_perform_ct_kill_task(priv, true);
} else if (old_state == IWL_TI_CT_KILL &&
tt->state != IWL_TI_CT_KILL) {
IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
iwl_perform_ct_kill_task(priv, false);
}
}
}
}
/* Card State Notification indicated reach critical temperature
* if PSP not enable, no Thermal Throttling function will be performed
* just set the GP1 bit to acknowledge the event
* otherwise, go into IWL_TI_CT_KILL state
* since Card State Notification will not provide any temperature reading
* for Legacy mode
* so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
* for advance mode
* pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
*/
void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
{
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
if (tt->state != IWL_TI_CT_KILL) {
IWL_ERR(priv, "Device reached critical temperature "
"- ucode going to sleep!\n");
if (!priv->power_data.adv_tt)
iwl_legacy_tt_handler(priv,
IWL_MINIMAL_POWER_THRESHOLD);
else
iwl_advance_tt_handler(priv,
CT_KILL_THRESHOLD + 1);
}
}
EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
/* Card State Notification indicated out of critical temperature
* since Card State Notification will not provide any temperature reading
* so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
* to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
*/
void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
{
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
/* stop ct_kill_exit_tm timer */
del_timer_sync(&priv->power_data.ct_kill_exit_tm);
if (tt->state == IWL_TI_CT_KILL) {
IWL_ERR(priv,
"Device temperature below critical"
"- ucode awake!\n");
if (!priv->power_data.adv_tt)
iwl_legacy_tt_handler(priv,
IWL_REDUCED_PERFORMANCE_THRESHOLD_2);
else
iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD);
}
}
EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
void iwl_tt_handler(struct iwl_priv *priv)
{
s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
temp = KELVIN_TO_CELSIUS(priv->temperature);
if (!priv->power_data.adv_tt)
iwl_legacy_tt_handler(priv, temp);
else
iwl_advance_tt_handler(priv, temp);
}
EXPORT_SYMBOL(iwl_tt_handler);
/* Thermal throttling initialization
* For advance thermal throttling:
* Initialize Thermal Index and temperature threshold table
* Initialize thermal throttling restriction table
*/
void iwl_tt_initialize(struct iwl_priv *priv)
{
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
struct iwl_power_mgr *setting = &priv->power_data;
int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
struct iwl_tt_trans *transaction;
IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n");
memset(tt, 0, sizeof(struct iwl_tt_mgmt));
tt->state = IWL_TI_0;
tt->sys_power_mode = setting->power_mode;
tt->tt_power_mode = tt->sys_power_mode;
init_timer(&priv->power_data.ct_kill_exit_tm);
priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv;
priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_6x00:
case CSR_HW_REV_TYPE_6x50:
IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
IWL_TI_STATE_MAX, GFP_KERNEL);
tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
GFP_KERNEL);
if (!tt->restriction || !tt->transaction) {
IWL_ERR(priv, "Fallback to Legacy Throttling\n");
priv->power_data.adv_tt = false;
kfree(tt->restriction);
tt->restriction = NULL;
kfree(tt->transaction);
tt->transaction = NULL;
} else {
transaction = tt->transaction +
(IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
memcpy(transaction, &tt_range_0[0], size);
transaction = tt->transaction +
(IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
memcpy(transaction, &tt_range_1[0], size);
transaction = tt->transaction +
(IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
memcpy(transaction, &tt_range_2[0], size);
transaction = tt->transaction +
(IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
memcpy(transaction, &tt_range_3[0], size);
size = sizeof(struct iwl_tt_restriction) *
IWL_TI_STATE_MAX;
memcpy(tt->restriction,
&restriction_range[0], size);
priv->power_data.adv_tt = true;
}
break;
default:
IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
priv->power_data.adv_tt = false;
break;
}
}
EXPORT_SYMBOL(iwl_tt_initialize);
/* cleanup thermal throttling management related memory and timer */
void iwl_tt_exit(struct iwl_priv *priv)
{
struct iwl_tt_mgmt *tt = &priv->power_data.tt;
/* stop ct_kill_exit_tm timer if activated */
del_timer_sync(&priv->power_data.ct_kill_exit_tm);
if (priv->power_data.adv_tt) {
/* free advance thermal throttling memory */
kfree(tt->restriction);
tt->restriction = NULL;
kfree(tt->transaction);
tt->transaction = NULL;
}
}
EXPORT_SYMBOL(iwl_tt_exit);
/* initialize to default */ /* initialize to default */
void iwl_power_initialize(struct iwl_priv *priv) void iwl_power_initialize(struct iwl_priv *priv)
{ {

View file

@ -33,6 +33,84 @@
struct iwl_priv; struct iwl_priv;
#define IWL_ABSOLUTE_ZERO 0
#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
#define IWL_TT_INCREASE_MARGIN 5
/* Tx/Rx restrictions */
#define IWL_TX_MULTI 0x02
#define IWL_TX_SINGLE 0x01
#define IWL_TX_NONE 0x00
#define IWL_RX_MULTI 0x02
#define IWL_RX_SINGLE 0x01
#define IWL_RX_NONE 0x00
/* Thermal Throttling State Machine states */
enum iwl_tt_state {
IWL_TI_0, /* normal temperature, system power state */
IWL_TI_1, /* high temperature detect, low power state */
IWL_TI_2, /* higher temperature detected, lower power state */
IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
IWL_TI_STATE_MAX
};
/**
* struct iwl_tt_restriction - Thermal Throttling restriction table used
* by advance thermal throttling management
* based on the current thermal throttling state, determine
* number of tx/rx streams; and the status of HT operation
* @tx_stream: number of tx stream allowed
* @is_ht: ht enable/disable
* @rx_stream: number of rx stream allowed
*/
struct iwl_tt_restriction {
u8 tx_stream;
bool is_ht;
u8 rx_stream;
};
/**
* struct iwl_tt_trans - Thermal Throttling transaction table; used by
* advance thermal throttling algorithm to determine next
* thermal state to go based on the current temperature
* @next_state: next thermal throttling mode
* @tt_low: low temperature threshold to change state
* @tt_high: high temperature threshold to change state
*/
struct iwl_tt_trans {
enum iwl_tt_state next_state;
u32 tt_low;
u32 tt_high;
};
/**
* struct iwl_tt_mgnt - Thermal Throttling Management structure
* @state: current Thermal Throttling state
* @tt_power_mode: Thermal Throttling power mode index
* being used to set power level when
* when thermal throttling state != IWL_TI_0
* the tt_power_mode should set to different
* power mode based on the current tt state
* @sys_power_mode: previous system power mode
* before transition into TT state
* @tt_previous_temperature: last measured temperature
* @iwl_tt_restriction: ptr to restriction tbl, used by advance
* thermal throttling to determine how many tx/rx streams
* should be used in tt state; and can HT be enabled or not
* @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
* state transaction
*/
struct iwl_tt_mgmt {
enum iwl_tt_state state;
u8 tt_power_mode;
u8 sys_power_mode;
#ifdef CONFIG_IWLWIFI_DEBUG
s32 tt_previous_temp;
#endif
struct iwl_tt_restriction *restriction;
struct iwl_tt_trans *transaction;
};
enum { enum {
IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */
IWL_POWER_INDEX_1, IWL_POWER_INDEX_1,
@ -59,10 +137,25 @@ struct iwl_power_mgr {
u8 power_mode; u8 power_mode;
u8 user_power_setting; /* set by user through sysfs */ u8 user_power_setting; /* set by user through sysfs */
u8 power_disabled; /* set by mac80211's CONF_PS */ u8 power_disabled; /* set by mac80211's CONF_PS */
struct iwl_tt_mgmt tt; /* Thermal Throttling Management */
bool adv_tt; /* false: legacy mode */
/* true: advance mode */
bool ct_kill_toggle; /* use to toggle the CSR bit when
* checking uCode temperature
*/
struct timer_list ct_kill_exit_tm;
}; };
int iwl_power_update_mode(struct iwl_priv *priv, bool force); int iwl_power_update_mode(struct iwl_priv *priv, bool force);
int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
bool iwl_ht_enabled(struct iwl_priv *priv);
u8 iwl_tx_ant_restriction(struct iwl_priv *priv);
u8 iwl_rx_ant_restriction(struct iwl_priv *priv);
void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
void iwl_tt_handler(struct iwl_priv *priv);
void iwl_tt_initialize(struct iwl_priv *priv);
void iwl_tt_exit(struct iwl_priv *priv);
void iwl_power_initialize(struct iwl_priv *priv); void iwl_power_initialize(struct iwl_priv *priv);
#endif /* __iwl_power_setting_h__ */ #endif /* __iwl_power_setting_h__ */

View file

@ -115,7 +115,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
struct iwl_rx_packet *res; struct iwl_rx_packet *res;
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_ABORT_CMD, .id = REPLY_SCAN_ABORT_CMD,
.meta.flags = CMD_WANT_SKB, .flags = CMD_WANT_SKB,
}; };
/* If there isn't a scan actively going on in the hardware /* If there isn't a scan actively going on in the hardware
@ -132,7 +132,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
return ret; return ret;
} }
res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->u.status != CAN_ABORT_STATUS) { if (res->u.status != CAN_ABORT_STATUS) {
/* The scan abort will return 1 for success or /* The scan abort will return 1 for success or
* 2 for "failure". A failure condition can be * 2 for "failure". A failure condition can be
@ -146,7 +146,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
} }
priv->alloc_rxb_skb--; priv->alloc_rxb_skb--;
dev_kfree_skb_any(cmd.meta.u.skb); dev_kfree_skb_any(cmd.reply_skb);
return ret; return ret;
} }
@ -567,7 +567,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_CMD, .id = REPLY_SCAN_CMD,
.len = sizeof(struct iwl_scan_cmd), .len = sizeof(struct iwl_scan_cmd),
.meta.flags = CMD_SIZE_HUGE, .flags = CMD_SIZE_HUGE,
}; };
struct iwl_scan_cmd *scan; struct iwl_scan_cmd *scan;
struct ieee80211_conf *conf = NULL; struct ieee80211_conf *conf = NULL;

View file

@ -97,8 +97,9 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
} }
static int iwl_add_sta_callback(struct iwl_priv *priv, static void iwl_add_sta_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb) struct iwl_device_cmd *cmd,
struct sk_buff *skb)
{ {
struct iwl_rx_packet *res = NULL; struct iwl_rx_packet *res = NULL;
struct iwl_addsta_cmd *addsta = struct iwl_addsta_cmd *addsta =
@ -107,14 +108,14 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
if (!skb) { if (!skb) {
IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n"); IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
return 1; return;
} }
res = (struct iwl_rx_packet *)skb->data; res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags); res->hdr.flags);
return 1; return;
} }
switch (res->u.add_sta.status) { switch (res->u.add_sta.status) {
@ -126,9 +127,6 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
res->u.add_sta.status); res->u.add_sta.status);
break; break;
} }
/* We didn't cache the SKB; let the caller free it */
return 1;
} }
int iwl_send_add_sta(struct iwl_priv *priv, int iwl_send_add_sta(struct iwl_priv *priv,
@ -139,14 +137,14 @@ int iwl_send_add_sta(struct iwl_priv *priv,
u8 data[sizeof(*sta)]; u8 data[sizeof(*sta)];
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_ADD_STA, .id = REPLY_ADD_STA,
.meta.flags = flags, .flags = flags,
.data = data, .data = data,
}; };
if (flags & CMD_ASYNC) if (flags & CMD_ASYNC)
cmd.meta.u.callback = iwl_add_sta_callback; cmd.callback = iwl_add_sta_callback;
else else
cmd.meta.flags |= CMD_WANT_SKB; cmd.flags |= CMD_WANT_SKB;
cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
ret = iwl_send_cmd(priv, &cmd); ret = iwl_send_cmd(priv, &cmd);
@ -154,7 +152,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
if (ret || (flags & CMD_ASYNC)) if (ret || (flags & CMD_ASYNC))
return ret; return ret;
res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags); res->hdr.flags);
@ -175,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
} }
priv->alloc_rxb_skb--; priv->alloc_rxb_skb--;
dev_kfree_skb_any(cmd.meta.u.skb); dev_kfree_skb_any(cmd.reply_skb);
return ret; return ret;
} }
@ -324,8 +322,9 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
} }
static int iwl_remove_sta_callback(struct iwl_priv *priv, static void iwl_remove_sta_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb) struct iwl_device_cmd *cmd,
struct sk_buff *skb)
{ {
struct iwl_rx_packet *res = NULL; struct iwl_rx_packet *res = NULL;
struct iwl_rem_sta_cmd *rm_sta = struct iwl_rem_sta_cmd *rm_sta =
@ -334,14 +333,14 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
if (!skb) { if (!skb) {
IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n"); IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
return 1; return;
} }
res = (struct iwl_rx_packet *)skb->data; res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags); res->hdr.flags);
return 1; return;
} }
switch (res->u.rem_sta.status) { switch (res->u.rem_sta.status) {
@ -352,9 +351,6 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
break; break;
} }
/* We didn't cache the SKB; let the caller free it */
return 1;
} }
static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
@ -368,7 +364,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_REMOVE_STA, .id = REPLY_REMOVE_STA,
.len = sizeof(struct iwl_rem_sta_cmd), .len = sizeof(struct iwl_rem_sta_cmd),
.meta.flags = flags, .flags = flags,
.data = &rm_sta_cmd, .data = &rm_sta_cmd,
}; };
@ -377,15 +373,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN); memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);
if (flags & CMD_ASYNC) if (flags & CMD_ASYNC)
cmd.meta.u.callback = iwl_remove_sta_callback; cmd.callback = iwl_remove_sta_callback;
else else
cmd.meta.flags |= CMD_WANT_SKB; cmd.flags |= CMD_WANT_SKB;
ret = iwl_send_cmd(priv, &cmd); ret = iwl_send_cmd(priv, &cmd);
if (ret || (flags & CMD_ASYNC)) if (ret || (flags & CMD_ASYNC))
return ret; return ret;
res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags); res->hdr.flags);
@ -406,7 +402,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
} }
priv->alloc_rxb_skb--; priv->alloc_rxb_skb--;
dev_kfree_skb_any(cmd.meta.u.skb); dev_kfree_skb_any(cmd.reply_skb);
return ret; return ret;
} }
@ -525,7 +521,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_WEPKEY, .id = REPLY_WEPKEY,
.data = wep_cmd, .data = wep_cmd,
.meta.flags = CMD_ASYNC, .flags = CMD_ASYNC,
}; };
memset(wep_cmd, 0, cmd_size + memset(wep_cmd, 0, cmd_size +
@ -930,7 +926,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_TX_LINK_QUALITY_CMD, .id = REPLY_TX_LINK_QUALITY_CMD,
.len = sizeof(struct iwl_link_quality_cmd), .len = sizeof(struct iwl_link_quality_cmd),
.meta.flags = flags, .flags = flags,
.data = lq, .data = lq,
}; };

View file

@ -141,7 +141,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
priv->cfg->ops->lib->txq_free_tfd(priv, txq); priv->cfg->ops->lib->txq_free_tfd(priv, txq);
len = sizeof(struct iwl_cmd) * q->n_window; len = sizeof(struct iwl_device_cmd) * q->n_window;
/* De-alloc array of command/tx buffers */ /* De-alloc array of command/tx buffers */
for (i = 0; i < TFD_TX_CMD_SLOTS; i++) for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
@ -156,6 +156,12 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
kfree(txq->txb); kfree(txq->txb);
txq->txb = NULL; txq->txb = NULL;
/* deallocate arrays */
kfree(txq->cmd);
kfree(txq->meta);
txq->cmd = NULL;
txq->meta = NULL;
/* 0-fill queue descriptor structure */ /* 0-fill queue descriptor structure */
memset(txq, 0, sizeof(*txq)); memset(txq, 0, sizeof(*txq));
} }
@ -179,7 +185,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
if (q->n_bd == 0) if (q->n_bd == 0)
return; return;
len = sizeof(struct iwl_cmd) * q->n_window; len = sizeof(struct iwl_device_cmd) * q->n_window;
len += IWL_MAX_SCAN_SIZE; len += IWL_MAX_SCAN_SIZE;
/* De-alloc array of command/tx buffers */ /* De-alloc array of command/tx buffers */
@ -318,6 +324,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
{ {
int i, len; int i, len;
int ret; int ret;
int actual_slots = slots_num;
/* /*
* Alloc buffer array for commands (Tx or other types of commands). * Alloc buffer array for commands (Tx or other types of commands).
@ -327,14 +334,22 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
* For normal Tx queues (all other queues), no super-size command * For normal Tx queues (all other queues), no super-size command
* space is needed. * space is needed.
*/ */
len = sizeof(struct iwl_cmd); if (txq_id == IWL_CMD_QUEUE_NUM)
for (i = 0; i <= slots_num; i++) { actual_slots++;
if (i == slots_num) {
if (txq_id == IWL_CMD_QUEUE_NUM) txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
len += IWL_MAX_SCAN_SIZE; GFP_KERNEL);
else txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots,
continue; GFP_KERNEL);
}
if (!txq->meta || !txq->cmd)
goto out_free_arrays;
len = sizeof(struct iwl_device_cmd);
for (i = 0; i < actual_slots; i++) {
/* only happens for cmd queue */
if (i == slots_num)
len += IWL_MAX_SCAN_SIZE;
txq->cmd[i] = kmalloc(len, GFP_KERNEL); txq->cmd[i] = kmalloc(len, GFP_KERNEL);
if (!txq->cmd[i]) if (!txq->cmd[i])
@ -364,15 +379,12 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
return 0; return 0;
err: err:
for (i = 0; i < slots_num; i++) { for (i = 0; i < actual_slots; i++)
kfree(txq->cmd[i]); kfree(txq->cmd[i]);
txq->cmd[i] = NULL; out_free_arrays:
} kfree(txq->meta);
kfree(txq->cmd);
if (txq_id == IWL_CMD_QUEUE_NUM) {
kfree(txq->cmd[slots_num]);
txq->cmd[slots_num] = NULL;
}
return -ENOMEM; return -ENOMEM;
} }
EXPORT_SYMBOL(iwl_tx_queue_init); EXPORT_SYMBOL(iwl_tx_queue_init);
@ -673,7 +685,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_tx_queue *txq; struct iwl_tx_queue *txq;
struct iwl_queue *q; struct iwl_queue *q;
struct iwl_cmd *out_cmd; struct iwl_device_cmd *out_cmd;
struct iwl_cmd_meta *out_meta;
struct iwl_tx_cmd *tx_cmd; struct iwl_tx_cmd *tx_cmd;
int swq_id, txq_id; int swq_id, txq_id;
dma_addr_t phys_addr; dma_addr_t phys_addr;
@ -767,6 +780,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up first empty entry in queue's array of Tx/cmd buffers */ /* Set up first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[q->write_ptr]; out_cmd = txq->cmd[q->write_ptr];
out_meta = &txq->meta[q->write_ptr];
tx_cmd = &out_cmd->cmd.tx; tx_cmd = &out_cmd->cmd.tx;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
@ -829,8 +843,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txcmd_phys = pci_map_single(priv->pci_dev, txcmd_phys = pci_map_single(priv->pci_dev,
&out_cmd->hdr, len, &out_cmd->hdr, len,
PCI_DMA_BIDIRECTIONAL); PCI_DMA_BIDIRECTIONAL);
pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
pci_unmap_len_set(&out_cmd->meta, len, len); pci_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's /* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */ * first entry */
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@ -923,7 +937,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{ {
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q; struct iwl_queue *q = &txq->q;
struct iwl_cmd *out_cmd; struct iwl_device_cmd *out_cmd;
struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr; dma_addr_t phys_addr;
unsigned long flags; unsigned long flags;
int len, ret; int len, ret;
@ -937,25 +952,31 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
* the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
* we will need to increase the size of the TFD entries */ * we will need to increase the size of the TFD entries */
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
!(cmd->meta.flags & CMD_SIZE_HUGE)); !(cmd->flags & CMD_SIZE_HUGE));
if (iwl_is_rfkill(priv)) { if (iwl_is_rfkill(priv)) {
IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n"); IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
return -EIO; return -EIO;
} }
if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
IWL_ERR(priv, "No space for Tx\n"); IWL_ERR(priv, "No space for Tx\n");
return -ENOSPC; return -ENOSPC;
} }
spin_lock_irqsave(&priv->hcmd_lock, flags); spin_lock_irqsave(&priv->hcmd_lock, flags);
idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
out_cmd = txq->cmd[idx]; out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx];
out_meta->flags = cmd->flags;
if (cmd->flags & CMD_WANT_SKB)
out_meta->source = cmd;
if (cmd->flags & CMD_ASYNC)
out_meta->callback = cmd->callback;
out_cmd->hdr.cmd = cmd->id; out_cmd->hdr.cmd = cmd->id;
memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
/* At this point, the out_cmd now has all of the incoming cmd /* At this point, the out_cmd now has all of the incoming cmd
@ -964,9 +985,9 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
out_cmd->hdr.flags = 0; out_cmd->hdr.flags = 0;
out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
INDEX_TO_SEQ(q->write_ptr)); INDEX_TO_SEQ(q->write_ptr));
if (out_cmd->meta.flags & CMD_SIZE_HUGE) if (cmd->flags & CMD_SIZE_HUGE)
out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
len = sizeof(struct iwl_cmd) - sizeof(struct iwl_cmd_meta); len = sizeof(struct iwl_device_cmd);
len += (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : 0; len += (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : 0;
@ -998,8 +1019,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr, phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
fix_size, PCI_DMA_BIDIRECTIONAL); fix_size, PCI_DMA_BIDIRECTIONAL);
pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr); pci_unmap_addr_set(out_meta, mapping, phys_addr);
pci_unmap_len_set(&out_cmd->meta, len, fix_size); pci_unmap_len_set(out_meta, len, fix_size);
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
phys_addr, fix_size, 1, phys_addr, fix_size, 1,
@ -1068,8 +1089,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
} }
pci_unmap_single(priv->pci_dev, pci_unmap_single(priv->pci_dev,
pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping), pci_unmap_addr(&txq->meta[cmd_idx], mapping),
pci_unmap_len(&txq->cmd[cmd_idx]->meta, len), pci_unmap_len(&txq->meta[cmd_idx], len),
PCI_DMA_BIDIRECTIONAL); PCI_DMA_BIDIRECTIONAL);
for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
@ -1100,7 +1121,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
int index = SEQ_TO_INDEX(sequence); int index = SEQ_TO_INDEX(sequence);
int cmd_index; int cmd_index;
bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
struct iwl_cmd *cmd; struct iwl_device_cmd *cmd;
struct iwl_cmd_meta *meta;
/* If a Tx command is being handled and it isn't in the actual /* If a Tx command is being handled and it isn't in the actual
* command queue then there a command routing bug has been introduced * command queue then there a command routing bug has been introduced
@ -1110,24 +1132,24 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
txq_id, sequence, txq_id, sequence,
priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr, priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) { priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
iwl_print_hex_error(priv, rxb, 32); iwl_print_hex_error(priv, pkt, 32);
return; return;
} }
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index];
/* Input error checking is done when commands are added to queue. */ /* Input error checking is done when commands are added to queue. */
if (cmd->meta.flags & CMD_WANT_SKB) { if (meta->flags & CMD_WANT_SKB) {
cmd->meta.source->u.skb = rxb->skb; meta->source->reply_skb = rxb->skb;
rxb->skb = NULL;
} else if (cmd->meta.u.callback &&
!cmd->meta.u.callback(priv, cmd, rxb->skb))
rxb->skb = NULL; rxb->skb = NULL;
} else if (meta->callback)
meta->callback(priv, cmd, rxb->skb);
iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
if (!(cmd->meta.flags & CMD_ASYNC)) { if (!(meta->flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status); clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue); wake_up_interruptible(&priv->wait_command_queue);
} }

View file

@ -363,7 +363,7 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv)
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct ieee80211_tx_info *info, struct ieee80211_tx_info *info,
struct iwl_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb_frag, struct sk_buff *skb_frag,
int sta_id) int sta_id)
{ {
@ -403,7 +403,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
* handle build REPLY_TX command notification. * handle build REPLY_TX command notification.
*/ */
static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct iwl_device_cmd *cmd,
struct ieee80211_tx_info *info, struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, u8 std_id) struct ieee80211_hdr *hdr, u8 std_id)
{ {
@ -476,7 +476,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct iwl3945_tx_cmd *tx; struct iwl3945_tx_cmd *tx;
struct iwl_tx_queue *txq = NULL; struct iwl_tx_queue *txq = NULL;
struct iwl_queue *q = NULL; struct iwl_queue *q = NULL;
struct iwl_cmd *out_cmd = NULL; struct iwl_device_cmd *out_cmd;
struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr; dma_addr_t phys_addr;
dma_addr_t txcmd_phys; dma_addr_t txcmd_phys;
int txq_id = skb_get_queue_mapping(skb); int txq_id = skb_get_queue_mapping(skb);
@ -565,6 +566,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Init first empty entry in queue's array of Tx/cmd buffers */ /* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[idx]; out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx];
tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload; tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
memset(tx, 0, sizeof(*tx)); memset(tx, 0, sizeof(*tx));
@ -642,8 +644,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
len, PCI_DMA_TODEVICE); len, PCI_DMA_TODEVICE);
/* we do not map meta data ... so we can safely access address to /* we do not map meta data ... so we can safely access address to
* provide to unmap command*/ * provide to unmap command*/
pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
pci_unmap_len_set(&out_cmd->meta, len, len); pci_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's /* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */ * first entry */
@ -753,7 +755,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_SPECTRUM_MEASUREMENT_CMD, .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
.data = (void *)&spectrum, .data = (void *)&spectrum,
.meta.flags = CMD_WANT_SKB, .flags = CMD_WANT_SKB,
}; };
u32 add_time = le64_to_cpu(params->start_time); u32 add_time = le64_to_cpu(params->start_time);
int rc; int rc;
@ -794,7 +796,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
if (rc) if (rc)
return rc; return rc;
res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; res = (struct iwl_rx_packet *)cmd.reply_skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n"); IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
rc = -EIO; rc = -EIO;
@ -817,7 +819,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
break; break;
} }
dev_kfree_skb_any(cmd.meta.u.skb); dev_kfree_skb_any(cmd.reply_skb);
return rc; return rc;
} }
@ -2717,7 +2719,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_CMD, .id = REPLY_SCAN_CMD,
.len = sizeof(struct iwl3945_scan_cmd), .len = sizeof(struct iwl3945_scan_cmd),
.meta.flags = CMD_SIZE_HUGE, .flags = CMD_SIZE_HUGE,
}; };
int rc = 0; int rc = 0;
struct iwl3945_scan_cmd *scan; struct iwl3945_scan_cmd *scan;

View file

@ -2,7 +2,6 @@ config IWM
tristate "Intel Wireless Multicomm 3200 WiFi driver" tristate "Intel Wireless Multicomm 3200 WiFi driver"
depends on MMC && WLAN_80211 && EXPERIMENTAL depends on MMC && WLAN_80211 && EXPERIMENTAL
depends on CFG80211 depends on CFG80211
select WIRELESS_EXT
select FW_LOADER select FW_LOADER
help help
The Intel Wireless Multicomm 3200 hardware is a combo The Intel Wireless Multicomm 3200 hardware is a combo

View file

@ -1,5 +1,5 @@
obj-$(CONFIG_IWM) := iwmc3200wifi.o obj-$(CONFIG_IWM) := iwmc3200wifi.o
iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o
iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o

View file

@ -306,8 +306,6 @@ static inline void *iwm_private(struct iwm_priv *iwm)
#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) #define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb))
#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) #define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb)
extern const struct iw_handler_def iwm_iw_handler_def;
void *iwm_if_alloc(int sizeof_bus, struct device *dev, void *iwm_if_alloc(int sizeof_bus, struct device *dev,
struct iwm_if_ops *if_ops); struct iwm_if_ops *if_ops);
void iwm_if_free(struct iwm_priv *iwm); void iwm_if_free(struct iwm_priv *iwm);

View file

@ -121,7 +121,6 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
} }
ndev->netdev_ops = &iwm_netdev_ops; ndev->netdev_ops = &iwm_netdev_ops;
ndev->wireless_handlers = &iwm_iw_handler_def;
ndev->ieee80211_ptr = wdev; ndev->ieee80211_ptr = wdev;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev; wdev->netdev = ndev;

View file

@ -1,187 +0,0 @@
/*
* Intel Wireless Multicomm 3200 WiFi driver
*
* Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
* Samuel Ortiz <samuel.ortiz@intel.com>
* Zhu Yi <yi.zhu@intel.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 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-1301, USA.
*
*/
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include "iwm.h"
#include "commands.h"
static int iwm_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
default:
return -EOPNOTSUPP;
}
}
static int iwm_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
case UMAC_MODE_BSS:
return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
default:
return -EOPNOTSUPP;
}
}
static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
case UMAC_MODE_BSS:
return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
default:
return -EOPNOTSUPP;
}
}
static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
case UMAC_MODE_BSS:
return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
default:
return -EOPNOTSUPP;
}
}
static int iwm_wext_siwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
case UMAC_MODE_BSS:
return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
default:
return -EOPNOTSUPP;
}
}
static int iwm_wext_giwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
case UMAC_MODE_BSS:
return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
default:
return -EOPNOTSUPP;
}
}
static const iw_handler iwm_handlers[] =
{
(iw_handler) NULL, /* SIOCSIWCOMMIT */
(iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
(iw_handler) NULL, /* SIOCSIWNWID */
(iw_handler) NULL, /* SIOCGIWNWID */
(iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */
(iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */
(iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
(iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
(iw_handler) NULL, /* SIOCSIWSENS */
(iw_handler) NULL, /* SIOCGIWSENS */
(iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
(iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
(iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
(iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
(iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
(iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
(iw_handler) NULL, /* SIOCSIWSPY */
(iw_handler) NULL, /* SIOCGIWSPY */
(iw_handler) NULL, /* SIOCSIWTHRSPY */
(iw_handler) NULL, /* SIOCGIWTHRSPY */
(iw_handler) iwm_wext_siwap, /* SIOCSIWAP */
(iw_handler) iwm_wext_giwap, /* SIOCGIWAP */
(iw_handler) NULL, /* SIOCSIWMLME */
(iw_handler) NULL, /* SIOCGIWAPLIST */
(iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
(iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
(iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */
(iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */
(iw_handler) NULL, /* SIOCSIWNICKN */
(iw_handler) NULL, /* SIOCGIWNICKN */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* SIOCSIWRATE */
(iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */
(iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
(iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
(iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
(iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
(iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */
(iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) NULL, /* SIOCSIWRETRY */
(iw_handler) NULL, /* SIOCGIWRETRY */
(iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
(iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
(iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */
(iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
(iw_handler) NULL, /* SIOCGIWGENIE */
(iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
(iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
(iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
(iw_handler) NULL, /* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */
(iw_handler) NULL, /* -- hole -- */
};
const struct iw_handler_def iwm_iw_handler_def = {
.num_standard = ARRAY_SIZE(iwm_handlers),
.standard = (iw_handler *) iwm_handlers,
.get_wireless_stats = cfg80211_wireless_stats,
};

View file

@ -614,7 +614,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
*flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)
*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
*queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA; *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;

View file

@ -1511,9 +1511,6 @@ static iw_stats *ray_get_wireless_stats(struct net_device *dev)
struct pcmcia_device *link = local->finder; struct pcmcia_device *link = local->finder;
struct status __iomem *p = local->sram + STATUS_BASE; struct status __iomem *p = local->sram + STATUS_BASE;
if (local == (ray_dev_t *) NULL)
return (iw_stats *) NULL;
local->wstats.status = local->card_status; local->wstats.status = local->card_status;
#ifdef WIRELESS_SPY #ifdef WIRELESS_SPY
if ((local->spy_data.spy_number > 0) if ((local->spy_data.spy_number > 0)

View file

@ -124,7 +124,7 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
} }
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
struct antenna_setup *ant) struct antenna_setup ant)
{ {
struct antenna_setup *def = &rt2x00dev->default_ant; struct antenna_setup *def = &rt2x00dev->default_ant;
struct antenna_setup *active = &rt2x00dev->link.ant.active; struct antenna_setup *active = &rt2x00dev->link.ant.active;
@ -138,10 +138,10 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* might have caused that we restore back to the already * might have caused that we restore back to the already
* active setting. If that has happened we can quit. * active setting. If that has happened we can quit.
*/ */
ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx); ant.rx = rt2x00lib_config_antenna_check(ant.rx, def->rx);
ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx); ant.tx = rt2x00lib_config_antenna_check(ant.tx, def->tx);
if (ant->rx == active->rx && ant->tx == active->tx) if (ant.rx == active->rx && ant.tx == active->tx)
return; return;
/* /*
@ -156,11 +156,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* The latter is required since we need to recalibrate the * The latter is required since we need to recalibrate the
* noise-sensitivity ratio for the new setup. * noise-sensitivity ratio for the new setup.
*/ */
rt2x00dev->ops->lib->config_ant(rt2x00dev, ant); rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant);
rt2x00link_reset_tuner(rt2x00dev, true); rt2x00link_reset_tuner(rt2x00dev, true);
memcpy(active, ant, sizeof(*ant)); memcpy(active, &ant, sizeof(ant));
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);

View file

@ -88,7 +88,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf, struct rt2x00_intf *intf,
struct ieee80211_bss_conf *conf); struct ieee80211_bss_conf *conf);
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
struct antenna_setup *ant); struct antenna_setup ant);
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf, struct ieee80211_conf *conf,
const unsigned int changed_flags); const unsigned int changed_flags);

View file

@ -173,7 +173,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
if (ant->flags & ANTENNA_TX_DIVERSITY) if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
rt2x00lib_config_antenna(rt2x00dev, &new_ant); rt2x00lib_config_antenna(rt2x00dev, new_ant);
} }
static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
@ -213,7 +213,7 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
if (ant->flags & ANTENNA_TX_DIVERSITY) if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
rt2x00lib_config_antenna(rt2x00dev, &new_ant); rt2x00lib_config_antenna(rt2x00dev, new_ant);
} }
static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)

View file

@ -378,7 +378,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
*/ */
if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED)
rt2x00lib_config_antenna(rt2x00dev, rt2x00lib_config_antenna(rt2x00dev,
&rt2x00dev->default_ant); rt2x00dev->default_ant);
/* Turn RX back on */ /* Turn RX back on */
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);

View file

@ -802,6 +802,31 @@ struct ieee80211_ht_cap {
#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 #define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03
#define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C #define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C
/*
* Maximum length of AMPDU that the STA can receive.
* Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
*/
enum ieee80211_max_ampdu_length_exp {
IEEE80211_HT_MAX_AMPDU_8K = 0,
IEEE80211_HT_MAX_AMPDU_16K = 1,
IEEE80211_HT_MAX_AMPDU_32K = 2,
IEEE80211_HT_MAX_AMPDU_64K = 3
};
#define IEEE80211_HT_MAX_AMPDU_FACTOR 13
/* Minimum MPDU start spacing */
enum ieee80211_min_mpdu_spacing {
IEEE80211_HT_MPDU_DENSITY_NONE = 0, /* No restriction */
IEEE80211_HT_MPDU_DENSITY_0_25 = 1, /* 1/4 usec */
IEEE80211_HT_MPDU_DENSITY_0_5 = 2, /* 1/2 usec */
IEEE80211_HT_MPDU_DENSITY_1 = 3, /* 1 usec */
IEEE80211_HT_MPDU_DENSITY_2 = 4, /* 2 usec */
IEEE80211_HT_MPDU_DENSITY_4 = 5, /* 4 usec */
IEEE80211_HT_MPDU_DENSITY_8 = 6, /* 8 usec */
IEEE80211_HT_MPDU_DENSITY_16 = 7 /* 16 usec */
};
/** /**
* struct ieee80211_ht_info - HT information * struct ieee80211_ht_info - HT information
* *

View file

@ -262,6 +262,9 @@
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
* %NL80211_ATTR_REASON_CODE attributes are used. * %NL80211_ATTR_REASON_CODE attributes are used.
* *
* @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
* associated with this wiphy must be down and will follow.
*
* @NL80211_CMD_MAX: highest used command number * @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
@ -336,6 +339,8 @@ enum nl80211_commands {
NL80211_CMD_ROAM, NL80211_CMD_ROAM,
NL80211_CMD_DISCONNECT, NL80211_CMD_DISCONNECT,
NL80211_CMD_SET_WIPHY_NETNS,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
@ -573,6 +578,8 @@ enum nl80211_commands {
* and join_ibss(), key information is in a nested attribute each * and join_ibss(), key information is in a nested attribute each
* with %NL80211_KEY_* sub-attributes * with %NL80211_KEY_* sub-attributes
* *
* @NL80211_ATTR_PID: Process ID of a network namespace.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
*/ */
@ -701,6 +708,8 @@ enum nl80211_attrs {
NL80211_ATTR_KEY, NL80211_ATTR_KEY,
NL80211_ATTR_KEYS, NL80211_ATTR_KEYS,
NL80211_ATTR_PID,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,

View file

@ -542,7 +542,7 @@ struct cfg80211_ssid {
* @ie: optional information element(s) to add into Probe Request or %NULL * @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets * @ie_len: length of ie in octets
* @wiphy: the wiphy this was for * @wiphy: the wiphy this was for
* @ifidx: the interface index * @dev: the interface
*/ */
struct cfg80211_scan_request { struct cfg80211_scan_request {
struct cfg80211_ssid *ssids; struct cfg80211_ssid *ssids;
@ -554,7 +554,7 @@ struct cfg80211_scan_request {
/* internal */ /* internal */
struct wiphy *wiphy; struct wiphy *wiphy;
int ifidx; struct net_device *dev;
bool aborted; bool aborted;
}; };
@ -845,7 +845,8 @@ struct cfg80211_bitrate_mask {
* @resume: wiphy device needs to be resumed * @resume: wiphy device needs to be resumed
* *
* @add_virtual_intf: create a new virtual interface with the given name, * @add_virtual_intf: create a new virtual interface with the given name,
* must set the struct wireless_dev's iftype. * must set the struct wireless_dev's iftype. Beware: You must create
* the new netdev in the wiphy's network namespace!
* *
* @del_virtual_intf: remove the virtual interface determined by ifindex. * @del_virtual_intf: remove the virtual interface determined by ifindex.
* *
@ -937,7 +938,7 @@ struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name, int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
enum nl80211_iftype type, u32 *flags, enum nl80211_iftype type, u32 *flags,
struct vif_params *params); struct vif_params *params);
int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev);
int (*change_virtual_intf)(struct wiphy *wiphy, int (*change_virtual_intf)(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
enum nl80211_iftype type, u32 *flags, enum nl80211_iftype type, u32 *flags,
@ -1088,6 +1089,9 @@ struct cfg80211_ops {
* @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold); * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold);
* -1 = fragmentation disabled, only odd values >= 256 used * -1 = fragmentation disabled, only odd values >= 256 used
* @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
* @net: the network namespace this wiphy currently lives in
* @netnsok: if set to false, do not allow changing the netns of this
* wiphy at all
*/ */
struct wiphy { struct wiphy {
/* assign these fields before you register the wiphy */ /* assign these fields before you register the wiphy */
@ -1101,6 +1105,8 @@ struct wiphy {
bool custom_regulatory; bool custom_regulatory;
bool strict_regulatory; bool strict_regulatory;
bool netnsok;
enum cfg80211_signal_type signal_type; enum cfg80211_signal_type signal_type;
int bss_priv_size; int bss_priv_size;
@ -1139,9 +1145,35 @@ struct wiphy {
/* dir in debugfs: ieee80211/<wiphyname> */ /* dir in debugfs: ieee80211/<wiphyname> */
struct dentry *debugfsdir; struct dentry *debugfsdir;
#ifdef CONFIG_NET_NS
/* the network namespace this phy lives in currently */
struct net *_net;
#endif
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
}; };
#ifdef CONFIG_NET_NS
static inline struct net *wiphy_net(struct wiphy *wiphy)
{
return wiphy->_net;
}
static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
{
wiphy->_net = net;
}
#else
static inline struct net *wiphy_net(struct wiphy *wiphy)
{
return &init_net;
}
static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
{
}
#endif
/** /**
* wiphy_priv - return priv from wiphy * wiphy_priv - return priv from wiphy
* *
@ -1563,43 +1595,6 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
int cfg80211_wext_giwrange(struct net_device *dev, int cfg80211_wext_giwrange(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct iw_point *data, char *extra); struct iw_point *data, char *extra);
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_ibss_wext_siwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
int cfg80211_ibss_wext_giwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
int cfg80211_ibss_wext_siwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra);
int cfg80211_ibss_wext_giwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra);
int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_mgd_wext_siwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
int cfg80211_mgd_wext_giwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
int cfg80211_mgd_wext_siwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra);
int cfg80211_mgd_wext_giwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra);
int cfg80211_wext_siwgenie(struct net_device *dev, int cfg80211_wext_siwgenie(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct iw_point *data, char *extra); struct iw_point *data, char *extra);
@ -1610,9 +1605,18 @@ int cfg80211_wext_giwauth(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct iw_param *data, char *extra); struct iw_param *data, char *extra);
struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, int cfg80211_wext_siwfreq(struct net_device *dev,
struct iw_freq *freq); struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_wext_siwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
int cfg80211_wext_giwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
int cfg80211_wext_siwrate(struct net_device *dev, int cfg80211_wext_siwrate(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct iw_param *rate, char *extra); struct iw_param *rate, char *extra);
@ -1662,12 +1666,12 @@ int cfg80211_wext_giwpower(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct iw_param *wrq, char *extra); struct iw_param *wrq, char *extra);
int cfg80211_wds_wext_siwap(struct net_device *dev, int cfg80211_wext_siwap(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct sockaddr *addr, char *extra); struct sockaddr *ap_addr, char *extra);
int cfg80211_wds_wext_giwap(struct net_device *dev, int cfg80211_wext_giwap(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct sockaddr *addr, char *extra); struct sockaddr *ap_addr, char *extra);
/* /*
* callbacks for asynchronous cfg80211 methods, notification * callbacks for asynchronous cfg80211 methods, notification

View file

@ -243,6 +243,9 @@ struct ieee80211_bss_conf {
* used to indicate that a frame was already retried due to PS * used to indicate that a frame was already retried due to PS
* @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
* used to indicate frame should not be encrypted * used to indicate frame should not be encrypted
* @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?)
* This frame is a response to a PS-poll frame and should be sent
* although the station is in powersave mode.
*/ */
enum mac80211_tx_control_flags { enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
@ -262,6 +265,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
IEEE80211_TX_INTFL_RETRIED = BIT(15), IEEE80211_TX_INTFL_RETRIED = BIT(15),
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17),
}; };
/** /**

View file

@ -5344,6 +5344,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
out: out:
return err; return err;
} }
EXPORT_SYMBOL_GPL(dev_change_net_namespace);
static int dev_cpu_callback(struct notifier_block *nfb, static int dev_cpu_callback(struct notifier_block *nfb,
unsigned long action, unsigned long action,

View file

@ -6,7 +6,6 @@ config MAC80211
select CRYPTO_ARC4 select CRYPTO_ARC4
select CRYPTO_AES select CRYPTO_AES
select CRC32 select CRC32
select WIRELESS_EXT
---help--- ---help---
This option enables the hardware independent IEEE 802.11 This option enables the hardware independent IEEE 802.11
networking stack. networking stack.

View file

@ -3,7 +3,6 @@ obj-$(CONFIG_MAC80211) += mac80211.o
# mac80211 objects # mac80211 objects
mac80211-y := \ mac80211-y := \
main.o \ main.o \
wext.o \
sta_info.o \ sta_info.o \
wep.o \ wep.o \
wpa.o \ wpa.o \

View file

@ -57,19 +57,9 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
return 0; return 0;
} }
static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev)
{ {
struct net_device *dev; ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev));
struct ieee80211_sub_if_data *sdata;
/* we're under RTNL */
dev = __dev_get_by_index(&init_net, ifindex);
if (!dev)
return -ENODEV;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_if_remove(sdata);
return 0; return 0;
} }

View file

@ -742,7 +742,7 @@ static void ieee80211_ibss_work(struct work_struct *work)
if (!netif_running(sdata->dev)) if (!netif_running(sdata->dev))
return; return;
if (local->sw_scanning || local->hw_scanning) if (local->scanning)
return; return;
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC)) if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC))

View file

@ -24,7 +24,6 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/iw_handler.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include "key.h" #include "key.h"
#include "sta_info.h" #include "sta_info.h"
@ -570,6 +569,43 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_SKB_ADD, IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
}; };
/**
* mac80211 scan flags - currently active scan mode
*
* @SCAN_SW_SCANNING: We're currently in the process of scanning but may as
* well be on the operating channel
* @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to
* determine if we are on the operating channel or not
* @SCAN_OFF_CHANNEL: We're off our operating channel for scanning,
* gets only set in conjunction with SCAN_SW_SCANNING
*/
enum {
SCAN_SW_SCANNING,
SCAN_HW_SCANNING,
SCAN_OFF_CHANNEL,
};
/**
* enum mac80211_scan_state - scan state machine states
*
* @SCAN_DECISION: Main entry point to the scan state machine, this state
* determines if we should keep on scanning or switch back to the
* operating channel
* @SCAN_SET_CHANNEL: Set the next channel to be scanned
* @SCAN_SEND_PROBE: Send probe requests and wait for probe responses
* @SCAN_LEAVE_OPER_CHANNEL: Leave the operating channel, notify the AP
* about us leaving the channel and stop all associated STA interfaces
* @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the
* AP about us being back and restart all associated STA interfaces
*/
enum mac80211_scan_state {
SCAN_DECISION,
SCAN_SET_CHANNEL,
SCAN_SEND_PROBE,
SCAN_LEAVE_OPER_CHANNEL,
SCAN_ENTER_OPER_CHANNEL,
};
struct ieee80211_local { struct ieee80211_local {
/* embed the driver visible part. /* embed the driver visible part.
* don't cast (use the static inlines below), but we keep * don't cast (use the static inlines below), but we keep
@ -668,7 +704,7 @@ struct ieee80211_local {
/* Scanning and BSS list */ /* Scanning and BSS list */
struct mutex scan_mtx; struct mutex scan_mtx;
bool sw_scanning, hw_scanning; unsigned long scanning;
struct cfg80211_ssid scan_ssid; struct cfg80211_ssid scan_ssid;
struct cfg80211_scan_request int_scan_req; struct cfg80211_scan_request int_scan_req;
struct cfg80211_scan_request *scan_req; struct cfg80211_scan_request *scan_req;
@ -678,7 +714,7 @@ struct ieee80211_local {
int scan_channel_idx; int scan_channel_idx;
int scan_ies_len; int scan_ies_len;
enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work; struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata; struct ieee80211_sub_if_data *scan_sdata;
enum nl80211_channel_type oper_channel_type; enum nl80211_channel_type oper_channel_type;
@ -914,9 +950,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
void ieee80211_configure_filter(struct ieee80211_local *local); void ieee80211_configure_filter(struct ieee80211_local *local);
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
/* wireless extensions */
extern const struct iw_handler_def ieee80211_iw_handler_def;
/* STA code */ /* STA code */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,

View file

@ -335,7 +335,10 @@ static int ieee80211_stop(struct net_device *dev)
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_if_init_conf conf; struct ieee80211_if_init_conf conf;
struct sta_info *sta; struct sta_info *sta;
unsigned long flags;
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0; u32 hw_reconf_flags = 0;
int i;
/* /*
* Stop TX on this interface first. * Stop TX on this interface first.
@ -515,7 +518,7 @@ static int ieee80211_stop(struct net_device *dev)
* the scan_sdata is NULL already don't send out a * the scan_sdata is NULL already don't send out a
* scan event to userspace -- the scan is incomplete. * scan event to userspace -- the scan is incomplete.
*/ */
if (local->sw_scanning) if (test_bit(SCAN_SW_SCANNING, &local->scanning))
ieee80211_scan_completed(&local->hw, true); ieee80211_scan_completed(&local->hw, true);
} }
@ -551,6 +554,18 @@ static int ieee80211_stop(struct net_device *dev)
if (hw_reconf_flags) if (hw_reconf_flags)
ieee80211_hw_config(local, hw_reconf_flags); ieee80211_hw_config(local, hw_reconf_flags);
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
skb_queue_walk_safe(&local->pending[i], skb, tmp) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (info->control.vif == &sdata->vif) {
__skb_unlink(skb, &local->pending[i]);
dev_kfree_skb_irq(skb);
}
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
return 0; return 0;
} }
@ -669,7 +684,6 @@ static void ieee80211_if_setup(struct net_device *dev)
{ {
ether_setup(dev); ether_setup(dev);
dev->netdev_ops = &ieee80211_dataif_ops; dev->netdev_ops = &ieee80211_dataif_ops;
dev->wireless_handlers = &ieee80211_iw_handler_def;
dev->destructor = free_netdev; dev->destructor = free_netdev;
} }
@ -772,6 +786,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
name, ieee80211_if_setup); name, ieee80211_if_setup);
if (!ndev) if (!ndev)
return -ENOMEM; return -ENOMEM;
dev_net_set(ndev, wiphy_net(local->hw.wiphy));
ndev->needed_headroom = local->tx_headroom + ndev->needed_headroom = local->tx_headroom +
4*6 /* four MAC addresses */ 4*6 /* four MAC addresses */
@ -788,7 +803,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
ndev->features |= NETIF_F_NETNS_LOCAL;
/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
sdata = netdev_priv(ndev); sdata = netdev_priv(ndev);
@ -905,7 +919,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int count = 0; int count = 0;
if (local->hw_scanning || local->sw_scanning) if (local->scanning)
return ieee80211_idle_off(local, "scanning"); return ieee80211_idle_off(local, "scanning");
list_for_each_entry(sdata, &local->interfaces, list) { list_for_each_entry(sdata, &local->interfaces, list) {

View file

@ -198,7 +198,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
} }
if (changed & BSS_CHANGED_BEACON_ENABLED) { if (changed & BSS_CHANGED_BEACON_ENABLED) {
if (local->sw_scanning) { if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {
sdata->vif.bss_conf.enable_beacon = false; sdata->vif.bss_conf.enable_beacon = false;
} else { } else {
/* /*
@ -620,6 +620,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
if (!wiphy) if (!wiphy)
return NULL; return NULL;
wiphy->netnsok = true;
wiphy->privid = mac80211_wiphy_privid; wiphy->privid = mac80211_wiphy_privid;
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */

View file

@ -597,7 +597,7 @@ static void ieee80211_mesh_work(struct work_struct *work)
if (!netif_running(sdata->dev)) if (!netif_running(sdata->dev))
return; return;
if (local->sw_scanning || local->hw_scanning) if (local->scanning)
return; return;
while ((skb = skb_dequeue(&ifmsh->skb_queue))) while ((skb = skb_dequeue(&ifmsh->skb_queue)))

View file

@ -581,7 +581,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (!ifmgd->associated) if (!ifmgd->associated)
return; return;
if (sdata->local->sw_scanning || sdata->local->hw_scanning) if (sdata->local->scanning)
return; return;
/* Disregard subsequent beacons if we are already running a timer /* Disregard subsequent beacons if we are already running a timer
@ -639,7 +639,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
* If we are scanning right now then the parameters will * If we are scanning right now then the parameters will
* take effect when scan finishes. * take effect when scan finishes.
*/ */
if (local->hw_scanning || local->sw_scanning) if (local->scanning)
return; return;
if (conf->dynamic_ps_timeout > 0 && if (conf->dynamic_ps_timeout > 0 &&
@ -1166,6 +1166,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
if (!netif_running(sdata->dev)) if (!netif_running(sdata->dev))
return; return;
if (sdata->local->scanning)
return;
mutex_lock(&ifmgd->mtx); mutex_lock(&ifmgd->mtx);
if (!ifmgd->associated) if (!ifmgd->associated)
@ -2000,6 +2003,9 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
case RX_MGMT_CFG80211_ASSOC: case RX_MGMT_CFG80211_ASSOC:
cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len);
break; break;
case RX_MGMT_CFG80211_DEAUTH:
cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL);
break;
default: default:
WARN(1, "unexpected: %d", rma); WARN(1, "unexpected: %d", rma);
} }
@ -2038,7 +2044,7 @@ static void ieee80211_sta_work(struct work_struct *work)
if (!netif_running(sdata->dev)) if (!netif_running(sdata->dev))
return; return;
if (local->sw_scanning || local->hw_scanning) if (local->scanning)
return; return;
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
@ -2213,9 +2219,6 @@ static void ieee80211_sta_monitor_work(struct work_struct *work)
container_of(work, struct ieee80211_sub_if_data, container_of(work, struct ieee80211_sub_if_data,
u.mgd.monitor_work); u.mgd.monitor_work);
if (sdata->local->sw_scanning || sdata->local->hw_scanning)
return;
ieee80211_mgd_probe_ap(sdata, false); ieee80211_mgd_probe_ap(sdata, false);
} }
@ -2377,6 +2380,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
wk->state = IEEE80211_MGD_STATE_PROBE; wk->state = IEEE80211_MGD_STATE_PROBE;
wk->auth_alg = auth_alg; wk->auth_alg = auth_alg;
wk->timeout = jiffies; /* run right away */
/* /*
* XXX: if still associated need to tell AP that we're going * XXX: if still associated need to tell AP that we're going
@ -2448,6 +2452,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
wk->state = IEEE80211_MGD_STATE_ASSOC; wk->state = IEEE80211_MGD_STATE_ASSOC;
wk->tries = 0; wk->tries = 0;
wk->timeout = jiffies; /* run right away */
if (req->use_mfp) { if (req->use_mfp) {
ifmgd->mfp = IEEE80211_MFP_REQUIRED; ifmgd->mfp = IEEE80211_MFP_REQUIRED;
@ -2496,8 +2501,13 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
} }
} }
/* cfg80211 should catch this... */ /*
if (WARN_ON(!bssid)) { * cfg80211 should catch this ... but it's racy since
* we can receive a deauth frame, process it, hand it
* to cfg80211 while that's in a locked section already
* trying to tell us that the user wants to disconnect.
*/
if (!bssid) {
mutex_unlock(&ifmgd->mtx); mutex_unlock(&ifmgd->mtx);
return -ENOLINK; return -ENOLINK;
} }
@ -2522,8 +2532,13 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
mutex_lock(&ifmgd->mtx); mutex_lock(&ifmgd->mtx);
/* cfg80211 should catch that */ /*
if (WARN_ON(&ifmgd->associated->cbss != req->bss)) { * cfg80211 should catch this ... but it's racy since
* we can receive a disassoc frame, process it, hand it
* to cfg80211 while that's in a locked section already
* trying to tell us that the user wants to disconnect.
*/
if (&ifmgd->associated->cbss != req->bss) {
mutex_unlock(&ifmgd->mtx); mutex_unlock(&ifmgd->mtx);
return -ENOLINK; return -ENOLINK;
} }

View file

@ -418,10 +418,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
struct ieee80211_local *local = rx->local; struct ieee80211_local *local = rx->local;
struct sk_buff *skb = rx->skb; struct sk_buff *skb = rx->skb;
if (unlikely(local->hw_scanning)) if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning)))
return ieee80211_scan_rx(rx->sdata, skb); return ieee80211_scan_rx(rx->sdata, skb);
if (unlikely(local->sw_scanning)) { if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) &&
(rx->flags & IEEE80211_RX_IN_SCAN))) {
/* drop all the other packets during a software scan anyway */ /* drop all the other packets during a software scan anyway */
if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
dev_kfree_skb(skb); dev_kfree_skb(skb);
@ -782,7 +783,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
atomic_inc(&sdata->bss->num_sta_ps); atomic_inc(&sdata->bss->num_sta_ps);
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); set_sta_flags(sta, WLAN_STA_PS);
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
@ -798,7 +799,7 @@ static int ap_sta_ps_end(struct sta_info *sta)
atomic_dec(&sdata->bss->num_sta_ps); atomic_dec(&sdata->bss->num_sta_ps);
clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); clear_sta_flags(sta, WLAN_STA_PS);
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
if (!skb_queue_empty(&sta->ps_tx_buf)) if (!skb_queue_empty(&sta->ps_tx_buf))
@ -1116,14 +1117,15 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
skb_queue_empty(&rx->sta->ps_tx_buf); skb_queue_empty(&rx->sta->ps_tx_buf);
if (skb) { if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *) skb->data; (struct ieee80211_hdr *) skb->data;
/* /*
* Tell TX path to send one frame even though the STA may * Tell TX path to send this frame even though the STA may
* still remain is PS mode after this frame exchange. * still remain is PS mode after this frame exchange.
*/ */
set_sta_flags(rx->sta, WLAN_STA_PSPOLL); info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
@ -1138,7 +1140,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
else else
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
dev_queue_xmit(skb); ieee80211_add_pending_skb(rx->local, skb);
if (no_pending_pkts) if (no_pending_pkts)
sta_info_clear_tim_bit(rx->sta); sta_info_clear_tim_bit(rx->sta);
@ -1539,7 +1541,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
info = IEEE80211_SKB_CB(fwd_skb); info = IEEE80211_SKB_CB(fwd_skb);
memset(info, 0, sizeof(*info)); memset(info, 0, sizeof(*info));
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
fwd_skb->iif = rx->dev->ifindex; info->control.vif = &rx->sdata->vif;
ieee80211_select_queue(local, fwd_skb); ieee80211_select_queue(local, fwd_skb);
if (is_multicast_ether_addr(fwd_hdr->addr3)) if (is_multicast_ether_addr(fwd_hdr->addr3))
memcpy(fwd_hdr->addr1, fwd_hdr->addr3, memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
@ -2136,7 +2138,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
return; return;
} }
if (unlikely(local->sw_scanning || local->hw_scanning)) if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
rx.flags |= IEEE80211_RX_IN_SCAN; rx.flags |= IEEE80211_RX_IN_SCAN;
ieee80211_parse_qos(&rx); ieee80211_parse_qos(&rx);

View file

@ -18,7 +18,6 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include <net/iw_handler.h>
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "driver-ops.h" #include "driver-ops.h"
@ -265,7 +264,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
mutex_lock(&local->scan_mtx); mutex_lock(&local->scan_mtx);
if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) { if (WARN_ON(!local->scanning)) {
mutex_unlock(&local->scan_mtx); mutex_unlock(&local->scan_mtx);
return; return;
} }
@ -275,16 +274,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
return; return;
} }
if (local->hw_scanning) if (test_bit(SCAN_HW_SCANNING, &local->scanning))
ieee80211_restore_scan_ies(local); ieee80211_restore_scan_ies(local);
if (local->scan_req != &local->int_scan_req) if (local->scan_req != &local->int_scan_req)
cfg80211_scan_done(local->scan_req, aborted); cfg80211_scan_done(local->scan_req, aborted);
local->scan_req = NULL; local->scan_req = NULL;
was_hw_scan = local->hw_scanning; was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
local->hw_scanning = false; local->scanning = 0;
local->sw_scanning = false;
local->scan_channel = NULL; local->scan_channel = NULL;
/* we only have to protect scan_req and hw/sw scan */ /* we only have to protect scan_req and hw/sw scan */
@ -366,17 +364,16 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
ieee80211_bss_info_change_notify( ieee80211_bss_info_change_notify(
sdata, BSS_CHANGED_BEACON_ENABLED); sdata, BSS_CHANGED_BEACON_ENABLED);
if (sdata->vif.type == NL80211_IFTYPE_STATION) { /*
if (sdata->u.mgd.associated) { * only handle non-STA interfaces here, STA interfaces
netif_tx_stop_all_queues(sdata->dev); * are handled in the scan state machine
ieee80211_scan_ps_enable(sdata); */
} if (sdata->vif.type != NL80211_IFTYPE_STATION)
} else
netif_tx_stop_all_queues(sdata->dev); netif_tx_stop_all_queues(sdata->dev);
} }
mutex_unlock(&local->iflist_mtx); mutex_unlock(&local->iflist_mtx);
local->scan_state = SCAN_SET_CHANNEL; local->next_scan_state = SCAN_DECISION;
local->scan_channel_idx = 0; local->scan_channel_idx = 0;
spin_lock_bh(&local->filter_lock); spin_lock_bh(&local->filter_lock);
@ -434,9 +431,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
} }
if (local->ops->hw_scan) if (local->ops->hw_scan)
local->hw_scanning = true; __set_bit(SCAN_HW_SCANNING, &local->scanning);
else else
local->sw_scanning = true; __set_bit(SCAN_SW_SCANNING, &local->scanning);
/* /*
* Kicking off the scan need not be protected, * Kicking off the scan need not be protected,
* only the scan variable stuff, since now * only the scan variable stuff, since now
@ -459,11 +456,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->scan_mtx); mutex_lock(&local->scan_mtx);
if (rc) { if (rc) {
if (local->ops->hw_scan) { if (local->ops->hw_scan)
local->hw_scanning = false;
ieee80211_restore_scan_ies(local); ieee80211_restore_scan_ies(local);
} else local->scanning = 0;
local->sw_scanning = false;
ieee80211_recalc_idle(local); ieee80211_recalc_idle(local);
@ -474,13 +469,195 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
return rc; return rc;
} }
static int ieee80211_scan_state_decision(struct ieee80211_local *local,
unsigned long *next_delay)
{
bool associated = false;
struct ieee80211_sub_if_data *sdata;
/* if no more bands/channels left, complete scan and advance to the idle state */
if (local->scan_channel_idx >= local->scan_req->n_channels) {
ieee80211_scan_completed(&local->hw, false);
return 1;
}
/* check if at least one STA interface is associated */
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.associated) {
associated = true;
break;
}
}
}
mutex_unlock(&local->iflist_mtx);
if (local->scan_channel) {
/*
* we're currently scanning a different channel, let's
* switch back to the operating channel now if at least
* one interface is associated. Otherwise just scan the
* next channel
*/
if (associated)
local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
else
local->next_scan_state = SCAN_SET_CHANNEL;
} else {
/*
* we're on the operating channel currently, let's
* leave that channel now to scan another one
*/
local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
}
*next_delay = 0;
return 0;
}
static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
unsigned long *next_delay)
{
struct ieee80211_sub_if_data *sdata;
/*
* notify the AP about us leaving the channel and stop all STA interfaces
*/
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
netif_tx_stop_all_queues(sdata->dev);
if (sdata->u.mgd.associated)
ieee80211_scan_ps_enable(sdata);
}
}
mutex_unlock(&local->iflist_mtx);
__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
/* advance to the next channel to be scanned */
*next_delay = HZ / 10;
local->next_scan_state = SCAN_SET_CHANNEL;
}
static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
unsigned long *next_delay)
{
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
/* switch back to the operating channel */
local->scan_channel = NULL;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
/*
* notify the AP about us being back and restart all STA interfaces
*/
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
continue;
/* Tell AP we're back */
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.associated)
ieee80211_scan_ps_disable(sdata);
netif_tx_wake_all_queues(sdata->dev);
}
}
mutex_unlock(&local->iflist_mtx);
__clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
*next_delay = HZ / 5;
local->next_scan_state = SCAN_DECISION;
}
static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
unsigned long *next_delay)
{
int skip;
struct ieee80211_channel *chan;
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
skip = 0;
chan = local->scan_req->channels[local->scan_channel_idx];
if (chan->flags & IEEE80211_CHAN_DISABLED ||
(sdata->vif.type == NL80211_IFTYPE_ADHOC &&
chan->flags & IEEE80211_CHAN_NO_IBSS))
skip = 1;
if (!skip) {
local->scan_channel = chan;
if (ieee80211_hw_config(local,
IEEE80211_CONF_CHANGE_CHANNEL))
skip = 1;
}
/* advance state machine to next channel/band */
local->scan_channel_idx++;
if (skip) {
/* if we skip this channel return to the decision state */
local->next_scan_state = SCAN_DECISION;
return;
}
/*
* Probe delay is used to update the NAV, cf. 11.1.3.2.2
* (which unfortunately doesn't say _why_ step a) is done,
* but it waits for the probe delay or until a frame is
* received - and the received frame would update the NAV).
* For now, we do not support waiting until a frame is
* received.
*
* In any case, it is not necessary for a passive scan.
*/
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
!local->scan_req->n_ssids) {
*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
local->next_scan_state = SCAN_DECISION;
return;
}
/* active scan, send probes */
*next_delay = IEEE80211_PROBE_DELAY;
local->next_scan_state = SCAN_SEND_PROBE;
}
static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
unsigned long *next_delay)
{
int i;
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
for (i = 0; i < local->scan_req->n_ssids; i++)
ieee80211_send_probe_req(
sdata, NULL,
local->scan_req->ssids[i].ssid,
local->scan_req->ssids[i].ssid_len,
local->scan_req->ie, local->scan_req->ie_len);
/*
* After sending probe requests, wait for probe responses
* on the channel.
*/
*next_delay = IEEE80211_CHANNEL_TIME;
local->next_scan_state = SCAN_DECISION;
}
void ieee80211_scan_work(struct work_struct *work) void ieee80211_scan_work(struct work_struct *work)
{ {
struct ieee80211_local *local = struct ieee80211_local *local =
container_of(work, struct ieee80211_local, scan_work.work); container_of(work, struct ieee80211_local, scan_work.work);
struct ieee80211_sub_if_data *sdata = local->scan_sdata; struct ieee80211_sub_if_data *sdata = local->scan_sdata;
struct ieee80211_channel *chan;
int skip, i;
unsigned long next_delay = 0; unsigned long next_delay = 0;
mutex_lock(&local->scan_mtx); mutex_lock(&local->scan_mtx);
@ -489,7 +666,7 @@ void ieee80211_scan_work(struct work_struct *work)
return; return;
} }
if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) { if (local->scan_req && !local->scanning) {
struct cfg80211_scan_request *req = local->scan_req; struct cfg80211_scan_request *req = local->scan_req;
int rc; int rc;
@ -513,69 +690,30 @@ void ieee80211_scan_work(struct work_struct *work)
return; return;
} }
switch (local->scan_state) { /*
case SCAN_SET_CHANNEL: * as long as no delay is required advance immediately
/* if no more bands/channels left, complete scan */ * without scheduling a new work
if (local->scan_channel_idx >= local->scan_req->n_channels) { */
ieee80211_scan_completed(&local->hw, false); do {
return; switch (local->next_scan_state) {
} case SCAN_DECISION:
skip = 0; if (ieee80211_scan_state_decision(local, &next_delay))
chan = local->scan_req->channels[local->scan_channel_idx]; return;
if (chan->flags & IEEE80211_CHAN_DISABLED ||
(sdata->vif.type == NL80211_IFTYPE_ADHOC &&
chan->flags & IEEE80211_CHAN_NO_IBSS))
skip = 1;
if (!skip) {
local->scan_channel = chan;
if (ieee80211_hw_config(local,
IEEE80211_CONF_CHANGE_CHANNEL))
skip = 1;
}
/* advance state machine to next channel/band */
local->scan_channel_idx++;
if (skip)
break; break;
case SCAN_SET_CHANNEL:
/* ieee80211_scan_state_set_channel(local, &next_delay);
* Probe delay is used to update the NAV, cf. 11.1.3.2.2 break;
* (which unfortunately doesn't say _why_ step a) is done, case SCAN_SEND_PROBE:
* but it waits for the probe delay or until a frame is ieee80211_scan_state_send_probe(local, &next_delay);
* received - and the received frame would update the NAV). break;
* For now, we do not support waiting until a frame is case SCAN_LEAVE_OPER_CHANNEL:
* received. ieee80211_scan_state_leave_oper_channel(local, &next_delay);
* break;
* In any case, it is not necessary for a passive scan. case SCAN_ENTER_OPER_CHANNEL:
*/ ieee80211_scan_state_enter_oper_channel(local, &next_delay);
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
!local->scan_req->n_ssids) {
next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
break; break;
} }
} while (next_delay == 0);
next_delay = IEEE80211_PROBE_DELAY;
local->scan_state = SCAN_SEND_PROBE;
break;
case SCAN_SEND_PROBE:
for (i = 0; i < local->scan_req->n_ssids; i++)
ieee80211_send_probe_req(
sdata, NULL,
local->scan_req->ssids[i].ssid,
local->scan_req->ssids[i].ssid_len,
local->scan_req->ie, local->scan_req->ie_len);
/*
* After sending probe requests, wait for probe responses
* on the channel.
*/
next_delay = IEEE80211_CHANNEL_TIME;
local->scan_state = SCAN_SET_CHANNEL;
break;
}
queue_delayed_work(local->hw.workqueue, &local->scan_work, queue_delayed_work(local->hw.workqueue, &local->scan_work,
next_delay); next_delay);
@ -625,7 +763,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
* queued -- mostly at suspend under RTNL. * queued -- mostly at suspend under RTNL.
*/ */
mutex_lock(&local->scan_mtx); mutex_lock(&local->scan_mtx);
swscan = local->sw_scanning; swscan = test_bit(SCAN_SW_SCANNING, &local->scanning);
mutex_unlock(&local->scan_mtx); mutex_unlock(&local->scan_mtx);
if (swscan) if (swscan)

View file

@ -30,7 +30,6 @@
* @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP. * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
* @WLAN_STA_WME: Station is a QoS-STA. * @WLAN_STA_WME: Station is a QoS-STA.
* @WLAN_STA_WDS: Station is one of our WDS peers. * @WLAN_STA_WDS: Station is one of our WDS peers.
* @WLAN_STA_PSPOLL: Station has just PS-polled us.
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
* frame to this station is transmitted. * frame to this station is transmitted.
@ -47,7 +46,6 @@ enum ieee80211_sta_info_flags {
WLAN_STA_ASSOC_AP = 1<<5, WLAN_STA_ASSOC_AP = 1<<5,
WLAN_STA_WME = 1<<6, WLAN_STA_WME = 1<<6,
WLAN_STA_WDS = 1<<7, WLAN_STA_WDS = 1<<7,
WLAN_STA_PSPOLL = 1<<8,
WLAN_STA_CLEAR_PS_FILT = 1<<9, WLAN_STA_CLEAR_PS_FILT = 1<<9,
WLAN_STA_MFP = 1<<10, WLAN_STA_MFP = 1<<10,
WLAN_STA_SUSPEND = 1<<11 WLAN_STA_SUSPEND = 1<<11
@ -359,17 +357,6 @@ static inline void clear_sta_flags(struct sta_info *sta, const u32 flags)
spin_unlock_irqrestore(&sta->flaglock, irqfl); spin_unlock_irqrestore(&sta->flaglock, irqfl);
} }
static inline void set_and_clear_sta_flags(struct sta_info *sta,
const u32 set, const u32 clear)
{
unsigned long irqfl;
spin_lock_irqsave(&sta->flaglock, irqfl);
sta->flags |= set;
sta->flags &= ~clear;
spin_unlock_irqrestore(&sta->flaglock, irqfl);
}
static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
{ {
u32 ret; u32 ret;

View file

@ -192,7 +192,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
return TX_CONTINUE; return TX_CONTINUE;
if (unlikely(tx->local->sw_scanning) && if (unlikely(test_bit(SCAN_OFF_CHANNEL, &tx->local->scanning)) &&
!ieee80211_is_probe_req(hdr->frame_control) && !ieee80211_is_probe_req(hdr->frame_control) &&
!ieee80211_is_nullfunc(hdr->frame_control)) !ieee80211_is_nullfunc(hdr->frame_control))
/* /*
@ -373,7 +373,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
staflags = get_sta_flags(sta); staflags = get_sta_flags(sta);
if (unlikely((staflags & WLAN_STA_PS) && if (unlikely((staflags & WLAN_STA_PS) &&
!(staflags & WLAN_STA_PSPOLL))) { !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
"before %d)\n", "before %d)\n",
@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta_info_set_tim_bit(sta); sta_info_set_tim_bit(sta);
info->control.jiffies = jiffies; info->control.jiffies = jiffies;
info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
skb_queue_tail(&sta->ps_tx_buf, tx->skb); skb_queue_tail(&sta->ps_tx_buf, tx->skb);
return TX_QUEUED; return TX_QUEUED;
@ -411,24 +412,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta->sta.addr); sta->sta.addr);
} }
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) {
/*
* The sleeping station with pending data is now snoozing.
* It queried us for its buffered frames and will go back
* to deep sleep once it got everything.
*
* inform the driver, in case the hardware does powersave
* frame filtering and keeps a station blacklist on its own
* (e.g: p54), so that frames can be delivered unimpeded.
*
* Note: It should be safe to disable the filter now.
* As, it is really unlikely that we still have any pending
* frame for this station in the hw's buffers/fifos left,
* that is not rejected with a unsuccessful tx_status yet.
*/
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
}
return TX_CONTINUE; return TX_CONTINUE;
} }
@ -551,7 +535,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
* Lets not bother rate control if we're associated and cannot * Lets not bother rate control if we're associated and cannot
* talk to the sta. This should not happen. * talk to the sta. This should not happen.
*/ */
if (WARN((tx->local->sw_scanning) && if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) &&
(sta_flags & WLAN_STA_ASSOC) && (sta_flags & WLAN_STA_ASSOC) &&
!rate_usable_index_exists(sband, &tx->sta->sta), !rate_usable_index_exists(sband, &tx->sta->sta),
"%s: Dropped data frame as no usable bitrate found while " "%s: Dropped data frame as no usable bitrate found while "
@ -696,7 +680,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
* number, if we have no matching interface then we * number, if we have no matching interface then we
* neither assign one ourselves nor ask the driver to. * neither assign one ourselves nor ask the driver to.
*/ */
if (unlikely(!info->control.vif)) if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR))
return TX_CONTINUE; return TX_CONTINUE;
if (unlikely(ieee80211_is_ctl(hdr->frame_control))) if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
@ -1092,6 +1076,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
} else if (*state != HT_AGG_STATE_IDLE) { } else if (*state != HT_AGG_STATE_IDLE) {
/* in progress */ /* in progress */
queued = true; queued = true;
info->control.vif = &sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
__skb_queue_tail(&tid_tx->pending, skb); __skb_queue_tail(&tid_tx->pending, skb);
} }
@ -1143,6 +1128,7 @@ static int __ieee80211_tx(struct ieee80211_local *local,
{ {
struct sk_buff *skb = *skbp, *next; struct sk_buff *skb = *skbp, *next;
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
struct ieee80211_sub_if_data *sdata;
unsigned long flags; unsigned long flags;
int ret, len; int ret, len;
bool fragm = false; bool fragm = false;
@ -1167,13 +1153,32 @@ static int __ieee80211_tx(struct ieee80211_local *local,
next = skb->next; next = skb->next;
len = skb->len; len = skb->len;
sdata = vif_to_sdata(info->control.vif);
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
info->control.vif = NULL;
break;
case NL80211_IFTYPE_AP_VLAN:
info->control.vif = &container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap)->vif;
break;
default:
/* keep */
break;
}
ret = drv_tx(local, skb); ret = drv_tx(local, skb);
if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
dev_kfree_skb(skb); dev_kfree_skb(skb);
ret = NETDEV_TX_OK; ret = NETDEV_TX_OK;
} }
if (ret != NETDEV_TX_OK) if (ret != NETDEV_TX_OK) {
info->control.vif = &sdata->vif;
return IEEE80211_TX_AGAIN; return IEEE80211_TX_AGAIN;
}
*skbp = skb = next; *skbp = skb = next;
ieee80211_led_tx(local, 1); ieee80211_led_tx(local, 1);
fragm = true; fragm = true;
@ -1386,17 +1391,12 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *tmp_sdata; struct ieee80211_sub_if_data *tmp_sdata;
int headroom; int headroom;
bool may_encrypt; bool may_encrypt;
enum {
NOT_MONITOR,
FOUND_SDATA,
UNKNOWN_ADDRESS,
} monitor_iface = NOT_MONITOR;
dev_hold(sdata->dev); dev_hold(sdata->dev);
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
local->hw.conf.dynamic_ps_timeout > 0 && local->hw.conf.dynamic_ps_timeout > 0 &&
!local->sw_scanning && !local->hw_scanning && local->ps_sdata) { !(local->scanning) && local->ps_sdata) {
if (local->hw.conf.flags & IEEE80211_CONF_PS) { if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw, ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_QUEUE_STOP_REASON_PS); IEEE80211_QUEUE_STOP_REASON_PS);
@ -1424,7 +1424,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
u16 len_rthdr; u16 len_rthdr;
info->flags |= IEEE80211_TX_CTL_INJECTED; info->flags |= IEEE80211_TX_CTL_INJECTED;
monitor_iface = UNKNOWN_ADDRESS;
len_rthdr = ieee80211_get_radiotap_len(skb->data); len_rthdr = ieee80211_get_radiotap_len(skb->data);
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
@ -1454,7 +1453,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
dev_hold(tmp_sdata->dev); dev_hold(tmp_sdata->dev);
dev_put(sdata->dev); dev_put(sdata->dev);
sdata = tmp_sdata; sdata = tmp_sdata;
monitor_iface = FOUND_SDATA;
break; break;
} }
} }
@ -1476,13 +1474,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
return; return;
} }
tmp_sdata = sdata; info->control.vif = &sdata->vif;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
tmp_sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
if (likely(monitor_iface != UNKNOWN_ADDRESS))
info->control.vif = &tmp_sdata->vif;
ieee80211_select_queue(local, skb); ieee80211_select_queue(local, skb);
ieee80211_tx(sdata, skb, false); ieee80211_tx(sdata, skb, false);
@ -1534,9 +1526,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
if (unlikely(skb->len < len_rthdr)) if (unlikely(skb->len < len_rthdr))
goto fail; /* skb too short for claimed rt header extent */ goto fail; /* skb too short for claimed rt header extent */
/* needed because we set skb device to master */
skb->iif = dev->ifindex;
/* /*
* fix up the pointers accounting for the radiotap * fix up the pointers accounting for the radiotap
* header still being in there. We are being given * header still being in there. We are being given
@ -1810,8 +1799,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
nh_pos += hdrlen; nh_pos += hdrlen;
h_pos += hdrlen; h_pos += hdrlen;
skb->iif = dev->ifindex;
dev->stats.tx_packets++; dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len; dev->stats.tx_bytes += skb->len;
@ -1856,32 +1843,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct sta_info *sta; struct sta_info *sta;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct net_device *dev;
int ret; int ret;
bool result = true; bool result = true;
/* does interface still exist? */ sdata = vif_to_sdata(info->control.vif);
dev = dev_get_by_index(&init_net, skb->iif);
if (!dev) {
dev_kfree_skb(skb);
return true;
}
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
if (unlikely(info->control.vif && info->control.vif != &sdata->vif)) {
dev_kfree_skb(skb);
result = true;
goto out;
}
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
/* do not use sdata, it may have been changed above */ ieee80211_tx(sdata, skb, true);
ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true);
} else { } else {
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
sta = sta_info_get(local, hdr->addr1); sta = sta_info_get(local, hdr->addr1);
@ -1891,9 +1859,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
result = false; result = false;
} }
out:
dev_put(dev);
return result; return result;
} }
@ -1921,10 +1886,21 @@ void ieee80211_tx_pending(unsigned long data)
while (!skb_queue_empty(&local->pending[i])) { while (!skb_queue_empty(&local->pending[i])) {
struct sk_buff *skb = __skb_dequeue(&local->pending[i]); struct sk_buff *skb = __skb_dequeue(&local->pending[i]);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sub_if_data *sdata;
if (WARN_ON(!info->control.vif)) {
kfree_skb(skb);
continue;
}
sdata = vif_to_sdata(info->control.vif);
dev_hold(sdata->dev);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, spin_unlock_irqrestore(&local->queue_stop_reason_lock,
flags); flags);
txok = ieee80211_tx_pending_skb(local, skb); txok = ieee80211_tx_pending_skb(local, skb);
dev_put(sdata->dev);
if (!txok) if (!txok)
__skb_queue_head(&local->pending[i], skb); __skb_queue_head(&local->pending[i], skb);
spin_lock_irqsave(&local->queue_stop_reason_lock, spin_lock_irqsave(&local->queue_stop_reason_lock,
@ -2234,7 +2210,6 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
skb_set_network_header(skb, 0); skb_set_network_header(skb, 0);
skb_set_transport_header(skb, 0); skb_set_transport_header(skb, 0);
skb->iif = sdata->dev->ifindex;
if (!encrypt) if (!encrypt)
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;

View file

@ -336,6 +336,12 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
struct ieee80211_hw *hw = &local->hw; struct ieee80211_hw *hw = &local->hw;
unsigned long flags; unsigned long flags;
int queue = skb_get_queue_mapping(skb); int queue = skb_get_queue_mapping(skb);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (WARN_ON(!info->control.vif)) {
kfree(skb);
return;
}
spin_lock_irqsave(&local->queue_stop_reason_lock, flags); spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
__ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
@ -358,6 +364,13 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD); IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
while ((skb = skb_dequeue(skbs))) { while ((skb = skb_dequeue(skbs))) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (WARN_ON(!info->control.vif)) {
kfree(skb);
continue;
}
ret++; ret++;
queue = skb_get_queue_mapping(skb); queue = skb_get_queue_mapping(skb);
__skb_queue_tail(&local->pending[queue], skb); __skb_queue_tail(&local->pending[queue], skb);

View file

@ -1,235 +0,0 @@
/*
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
#include <asm/uaccess.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "led.h"
#include "rate.h"
#include "wpa.h"
#include "aes_ccm.h"
static int ieee80211_ioctl_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct ieee80211_channel *chan;
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra);
/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
if (freq->e == 0) {
if (freq->m < 0)
return -EINVAL;
else
chan = ieee80211_get_channel(local->hw.wiphy,
ieee80211_channel_to_frequency(freq->m));
} else {
int i, div = 1000000;
for (i = 0; i < freq->e; i++)
div /= 10;
if (div <= 0)
return -EINVAL;
chan = ieee80211_get_channel(local->hw.wiphy, freq->m / div);
}
if (!chan)
return -EINVAL;
if (chan->flags & IEEE80211_CHAN_DISABLED)
return -EINVAL;
/*
* no change except maybe auto -> fixed, ignore the HT
* setting so you can fix a channel you're on already
*/
if (local->oper_channel == chan)
return 0;
local->oper_channel = chan;
local->oper_channel_type = NL80211_CHAN_NO_HT;
ieee80211_hw_config(local, 0);
return 0;
}
static int ieee80211_ioctl_giwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
freq->m = local->oper_channel->center_freq;
freq->e = 6;
return 0;
}
static int ieee80211_ioctl_siwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
return -EOPNOTSUPP;
}
static int ieee80211_ioctl_giwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
return -EOPNOTSUPP;
}
static int ieee80211_ioctl_siwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
if (sdata->vif.type == NL80211_IFTYPE_STATION)
return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
if (sdata->vif.type == NL80211_IFTYPE_WDS)
return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra);
return -EOPNOTSUPP;
}
static int ieee80211_ioctl_giwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
if (sdata->vif.type == NL80211_IFTYPE_STATION)
return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
if (sdata->vif.type == NL80211_IFTYPE_WDS)
return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra);
return -EOPNOTSUPP;
}
/* Structures to export the Wireless Handlers */
static const iw_handler ieee80211_handler[] =
{
(iw_handler) NULL, /* SIOCSIWCOMMIT */
(iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
(iw_handler) NULL, /* SIOCSIWNWID */
(iw_handler) NULL, /* SIOCGIWNWID */
(iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */
(iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */
(iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
(iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
(iw_handler) NULL, /* SIOCSIWSENS */
(iw_handler) NULL, /* SIOCGIWSENS */
(iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
(iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
(iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
(iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
(iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
(iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
(iw_handler) NULL, /* SIOCSIWSPY */
(iw_handler) NULL, /* SIOCGIWSPY */
(iw_handler) NULL, /* SIOCSIWTHRSPY */
(iw_handler) NULL, /* SIOCGIWTHRSPY */
(iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */
(iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
(iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */
(iw_handler) NULL, /* SIOCGIWAPLIST */
(iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
(iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
(iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */
(iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */
(iw_handler) NULL, /* SIOCSIWNICKN */
(iw_handler) NULL, /* SIOCGIWNICKN */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) cfg80211_wext_siwrate, /* SIOCSIWRATE */
(iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */
(iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
(iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
(iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
(iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
(iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */
(iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */
(iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
(iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
(iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
(iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */
(iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
(iw_handler) NULL, /* SIOCGIWGENIE */
(iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
(iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
(iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
(iw_handler) NULL, /* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */
(iw_handler) NULL, /* -- hole -- */
};
const struct iw_handler_def ieee80211_iw_handler_def =
{
.num_standard = ARRAY_SIZE(ieee80211_handler),
.standard = (iw_handler *) ieee80211_handler,
.get_wireless_stats = cfg80211_wireless_stats,
};

View file

@ -19,6 +19,7 @@
#include "core.h" #include "core.h"
#include "sysfs.h" #include "sysfs.h"
#include "debugfs.h" #include "debugfs.h"
#include "wext-compat.h"
/* name for sysfs, %d is appended */ /* name for sysfs, %d is appended */
#define PHY_NAME "phy" #define PHY_NAME "phy"
@ -106,7 +107,7 @@ __cfg80211_rdev_from_info(struct genl_info *info)
if (info->attrs[NL80211_ATTR_IFINDEX]) { if (info->attrs[NL80211_ATTR_IFINDEX]) {
ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
dev = dev_get_by_index(&init_net, ifindex); dev = dev_get_by_index(genl_info_net(info), ifindex);
if (dev) { if (dev) {
if (dev->ieee80211_ptr) if (dev->ieee80211_ptr)
byifidx = byifidx =
@ -151,13 +152,13 @@ cfg80211_get_dev_from_info(struct genl_info *info)
} }
struct cfg80211_registered_device * struct cfg80211_registered_device *
cfg80211_get_dev_from_ifindex(int ifindex) cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
{ {
struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV);
struct net_device *dev; struct net_device *dev;
mutex_lock(&cfg80211_mutex); mutex_lock(&cfg80211_mutex);
dev = dev_get_by_index(&init_net, ifindex); dev = dev_get_by_index(net, ifindex);
if (!dev) if (!dev)
goto out; goto out;
if (dev->ieee80211_ptr) { if (dev->ieee80211_ptr) {
@ -222,6 +223,42 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
return 0; return 0;
} }
int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
struct net *net)
{
struct wireless_dev *wdev;
int err = 0;
if (!rdev->wiphy.netnsok)
return -EOPNOTSUPP;
list_for_each_entry(wdev, &rdev->netdev_list, list) {
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
if (err)
break;
wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
}
if (err) {
/* failed -- clean up to old netns */
net = wiphy_net(&rdev->wiphy);
list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list,
list) {
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
err = dev_change_net_namespace(wdev->netdev, net,
"wlan%d");
WARN_ON(err);
wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
}
}
wiphy_net_set(&rdev->wiphy, net);
return err;
}
static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
{ {
struct cfg80211_registered_device *rdev = data; struct cfg80211_registered_device *rdev = data;
@ -375,6 +412,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.class = &ieee80211_class;
rdev->wiphy.dev.platform_data = rdev; rdev->wiphy.dev.platform_data = rdev;
wiphy_net_set(&rdev->wiphy, &init_net);
rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block;
rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev), rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev),
&rdev->wiphy.dev, RFKILL_TYPE_WLAN, &rdev->wiphy.dev, RFKILL_TYPE_WLAN,
@ -615,6 +654,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
spin_lock_init(&wdev->event_lock); spin_lock_init(&wdev->event_lock);
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
list_add(&wdev->list, &rdev->netdev_list); list_add(&wdev->list, &rdev->netdev_list);
/* can only change netns with wiphy */
dev->features |= NETIF_F_NETNS_LOCAL;
if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
"phy80211")) { "phy80211")) {
printk(KERN_ERR "wireless: failed to add phy80211 " printk(KERN_ERR "wireless: failed to add phy80211 "
@ -624,6 +666,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
wdev->sme_state = CFG80211_SME_IDLE; wdev->sme_state = CFG80211_SME_IDLE;
mutex_unlock(&rdev->devlist_mtx); mutex_unlock(&rdev->devlist_mtx);
#ifdef CONFIG_WIRELESS_EXT #ifdef CONFIG_WIRELESS_EXT
if (!dev->wireless_handlers)
dev->wireless_handlers = &cfg80211_wext_handler;
wdev->wext.default_key = -1; wdev->wext.default_key = -1;
wdev->wext.default_mgmt_key = -1; wdev->wext.default_mgmt_key = -1;
wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
@ -705,10 +749,32 @@ static struct notifier_block cfg80211_netdev_notifier = {
.notifier_call = cfg80211_netdev_notifier_call, .notifier_call = cfg80211_netdev_notifier_call,
}; };
static int cfg80211_init(void) static void __net_exit cfg80211_pernet_exit(struct net *net)
{
struct cfg80211_registered_device *rdev;
rtnl_lock();
mutex_lock(&cfg80211_mutex);
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
if (net_eq(wiphy_net(&rdev->wiphy), net))
WARN_ON(cfg80211_switch_netns(rdev, &init_net));
}
mutex_unlock(&cfg80211_mutex);
rtnl_unlock();
}
static struct pernet_operations cfg80211_pernet_ops = {
.exit = cfg80211_pernet_exit,
};
static int __init cfg80211_init(void)
{ {
int err; int err;
err = register_pernet_device(&cfg80211_pernet_ops);
if (err)
goto out_fail_pernet;
err = wiphy_sysfs_init(); err = wiphy_sysfs_init();
if (err) if (err)
goto out_fail_sysfs; goto out_fail_sysfs;
@ -736,9 +802,10 @@ out_fail_nl80211:
out_fail_notifier: out_fail_notifier:
wiphy_sysfs_exit(); wiphy_sysfs_exit();
out_fail_sysfs: out_fail_sysfs:
unregister_pernet_device(&cfg80211_pernet_ops);
out_fail_pernet:
return err; return err;
} }
subsys_initcall(cfg80211_init); subsys_initcall(cfg80211_init);
static void cfg80211_exit(void) static void cfg80211_exit(void)
@ -748,5 +815,6 @@ static void cfg80211_exit(void)
unregister_netdevice_notifier(&cfg80211_netdev_notifier); unregister_netdevice_notifier(&cfg80211_netdev_notifier);
wiphy_sysfs_exit(); wiphy_sysfs_exit();
regulatory_exit(); regulatory_exit();
unregister_pernet_device(&cfg80211_pernet_ops);
} }
module_exit(cfg80211_exit); module_exit(cfg80211_exit);

View file

@ -66,6 +66,9 @@ struct cfg80211_registered_device {
struct work_struct conn_work; struct work_struct conn_work;
struct work_struct event_work; struct work_struct event_work;
/* current channel */
struct ieee80211_channel *channel;
#ifdef CONFIG_CFG80211_DEBUGFS #ifdef CONFIG_CFG80211_DEBUGFS
/* Debugfs entries */ /* Debugfs entries */
struct wiphy_debugfsdentries { struct wiphy_debugfsdentries {
@ -170,7 +173,10 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx);
/* identical to cfg80211_get_dev_from_info but only operate on ifindex */ /* identical to cfg80211_get_dev_from_info but only operate on ifindex */
extern struct cfg80211_registered_device * extern struct cfg80211_registered_device *
cfg80211_get_dev_from_ifindex(int ifindex); cfg80211_get_dev_from_ifindex(struct net *net, int ifindex);
int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
struct net *net);
static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev)
{ {

View file

@ -7,6 +7,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "wext-compat.h"
#include "nl80211.h" #include "nl80211.h"
@ -312,8 +313,6 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
return err; return err;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
int cfg80211_ibss_wext_giwfreq(struct net_device *dev, int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -342,8 +341,6 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
/* no channel if not joining */ /* no channel if not joining */
return -EINVAL; return -EINVAL;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq);
int cfg80211_ibss_wext_siwessid(struct net_device *dev, int cfg80211_ibss_wext_siwessid(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -384,8 +381,6 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
return err; return err;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
int cfg80211_ibss_wext_giwessid(struct net_device *dev, int cfg80211_ibss_wext_giwessid(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -413,8 +408,6 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
return 0; return 0;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid);
int cfg80211_ibss_wext_siwap(struct net_device *dev, int cfg80211_ibss_wext_siwap(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -469,8 +462,6 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
return err; return err;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
int cfg80211_ibss_wext_giwap(struct net_device *dev, int cfg80211_ibss_wext_giwap(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -496,6 +487,4 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
return 0; return 0;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap);
#endif #endif

View file

@ -8,7 +8,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/nl80211.h> #include <linux/nl80211.h>
#include <linux/wireless.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/iw_handler.h>
#include "core.h" #include "core.h"
#include "nl80211.h" #include "nl80211.h"
@ -545,6 +547,12 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (wdev->sme_state != CFG80211_SME_CONNECTED)
return -ENOTCONN;
if (WARN_ON(!wdev->current_bss))
return -ENOTCONN;
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
req.reason_code = reason; req.reason_code = reason;
req.ie = ie; req.ie = ie;

View file

@ -14,8 +14,10 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <net/net_namespace.h>
#include <net/genetlink.h> #include <net/genetlink.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/sock.h>
#include "core.h" #include "core.h"
#include "nl80211.h" #include "nl80211.h"
#include "reg.h" #include "reg.h"
@ -27,24 +29,26 @@ static struct genl_family nl80211_fam = {
.hdrsize = 0, /* no private header */ .hdrsize = 0, /* no private header */
.version = 1, /* no particular meaning now */ .version = 1, /* no particular meaning now */
.maxattr = NL80211_ATTR_MAX, .maxattr = NL80211_ATTR_MAX,
.netnsok = true,
}; };
/* internal helper: get rdev and dev */ /* internal helper: get rdev and dev */
static int get_rdev_dev_by_info_ifindex(struct nlattr **attrs, static int get_rdev_dev_by_info_ifindex(struct genl_info *info,
struct cfg80211_registered_device **rdev, struct cfg80211_registered_device **rdev,
struct net_device **dev) struct net_device **dev)
{ {
struct nlattr **attrs = info->attrs;
int ifindex; int ifindex;
if (!attrs[NL80211_ATTR_IFINDEX]) if (!attrs[NL80211_ATTR_IFINDEX])
return -EINVAL; return -EINVAL;
ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
*dev = dev_get_by_index(&init_net, ifindex); *dev = dev_get_by_index(genl_info_net(info), ifindex);
if (!*dev) if (!*dev)
return -ENODEV; return -ENODEV;
*rdev = cfg80211_get_dev_from_ifindex(ifindex); *rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex);
if (IS_ERR(*rdev)) { if (IS_ERR(*rdev)) {
dev_put(*dev); dev_put(*dev);
return PTR_ERR(*rdev); return PTR_ERR(*rdev);
@ -133,6 +137,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
[NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
[NL80211_ATTR_PID] = { .type = NLA_U32 },
}; };
/* policy for the attributes */ /* policy for the attributes */
@ -532,6 +537,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(deauth, DEAUTHENTICATE); CMD(deauth, DEAUTHENTICATE);
CMD(disassoc, DISASSOCIATE); CMD(disassoc, DISASSOCIATE);
CMD(join_ibss, JOIN_IBSS); CMD(join_ibss, JOIN_IBSS);
if (dev->wiphy.netnsok) {
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
}
#undef CMD #undef CMD
@ -562,6 +571,8 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
mutex_lock(&cfg80211_mutex); mutex_lock(&cfg80211_mutex);
list_for_each_entry(dev, &cfg80211_rdev_list, list) { list_for_each_entry(dev, &cfg80211_rdev_list, list) {
if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
continue;
if (++idx <= start) if (++idx <= start)
continue; continue;
if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
@ -746,6 +757,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
channel_type); channel_type);
if (result) if (result)
goto bad_res; goto bad_res;
rdev->channel = chan;
} }
changed = 0; changed = 0;
@ -867,6 +880,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
mutex_lock(&cfg80211_mutex); mutex_lock(&cfg80211_mutex);
list_for_each_entry(dev, &cfg80211_rdev_list, list) { list_for_each_entry(dev, &cfg80211_rdev_list, list) {
if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
continue;
if (wp_idx < wp_start) { if (wp_idx < wp_start) {
wp_idx++; wp_idx++;
continue; continue;
@ -907,7 +922,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
struct net_device *netdev; struct net_device *netdev;
int err; int err;
err = get_rdev_dev_by_info_ifindex(info->attrs, &dev, &netdev); err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev);
if (err) if (err)
return err; return err;
@ -975,7 +990,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -1098,26 +1113,25 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev;
int ifindex, err; int err;
struct net_device *dev; struct net_device *dev;
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
ifindex = dev->ifindex;
dev_put(dev);
if (!rdev->ops->del_virtual_intf) { if (!rdev->ops->del_virtual_intf) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
err = rdev->ops->del_virtual_intf(&rdev->wiphy, ifindex); err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
out: out:
cfg80211_unlock_rdev(rdev); cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl: unlock_rtnl:
rtnl_unlock(); rtnl_unlock();
return err; return err;
@ -1195,7 +1209,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -1274,7 +1288,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -1333,7 +1347,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -1380,7 +1394,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -1429,7 +1443,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -1516,7 +1530,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -1726,13 +1740,13 @@ static int nl80211_dump_station(struct sk_buff *skb,
rtnl_lock(); rtnl_lock();
netdev = __dev_get_by_index(&init_net, ifidx); netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
if (!netdev) { if (!netdev) {
err = -ENODEV; err = -ENODEV;
goto out_rtnl; goto out_rtnl;
} }
dev = cfg80211_get_dev_from_ifindex(ifidx); dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
err = PTR_ERR(dev); err = PTR_ERR(dev);
goto out_rtnl; goto out_rtnl;
@ -1791,7 +1805,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -1829,14 +1843,16 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
/* /*
* Get vlan interface making sure it is on the right wiphy. * Get vlan interface making sure it is on the right wiphy.
*/ */
static int get_vlan(struct nlattr *vlanattr, static int get_vlan(struct genl_info *info,
struct cfg80211_registered_device *rdev, struct cfg80211_registered_device *rdev,
struct net_device **vlan) struct net_device **vlan)
{ {
struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
*vlan = NULL; *vlan = NULL;
if (vlanattr) { if (vlanattr) {
*vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); *vlan = dev_get_by_index(genl_info_net(info),
nla_get_u32(vlanattr));
if (!*vlan) if (!*vlan)
return -ENODEV; return -ENODEV;
if (!(*vlan)->ieee80211_ptr) if (!(*vlan)->ieee80211_ptr)
@ -1891,11 +1907,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, &params.vlan); err = get_vlan(info, rdev, &params.vlan);
if (err) if (err)
goto out; goto out;
@ -2004,11 +2020,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, &params.vlan); err = get_vlan(info, rdev, &params.vlan);
if (err) if (err)
goto out; goto out;
@ -2079,7 +2095,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -2185,13 +2201,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
rtnl_lock(); rtnl_lock();
netdev = __dev_get_by_index(&init_net, ifidx); netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
if (!netdev) { if (!netdev) {
err = -ENODEV; err = -ENODEV;
goto out_rtnl; goto out_rtnl;
} }
dev = cfg80211_get_dev_from_ifindex(ifidx); dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
err = PTR_ERR(dev); err = PTR_ERR(dev);
goto out_rtnl; goto out_rtnl;
@ -2255,7 +2271,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -2314,7 +2330,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -2362,7 +2378,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -2404,7 +2420,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -2455,7 +2471,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -2574,7 +2590,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
rtnl_lock(); rtnl_lock();
/* Look up our device */ /* Look up our device */
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -2691,7 +2707,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -2947,7 +2963,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto out_rtnl; goto out_rtnl;
@ -3069,14 +3085,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
request->ie_len); request->ie_len);
} }
request->ifidx = dev->ifindex; request->dev = dev;
request->wiphy = &rdev->wiphy; request->wiphy = &rdev->wiphy;
rdev->scan_req = request; rdev->scan_req = request;
err = rdev->ops->scan(&rdev->wiphy, dev, request); err = rdev->ops->scan(&rdev->wiphy, dev, request);
if (!err) if (!err) {
nl80211_send_scan_start(rdev, dev); nl80211_send_scan_start(rdev, dev);
dev_hold(dev);
}
out_free: out_free:
if (err) { if (err) {
@ -3198,11 +3216,11 @@ static int nl80211_dump_scan(struct sk_buff *skb,
cb->args[0] = ifidx; cb->args[0] = ifidx;
} }
dev = dev_get_by_index(&init_net, ifidx); dev = dev_get_by_index(sock_net(skb->sk), ifidx);
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
rdev = cfg80211_get_dev_from_ifindex(ifidx); rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
if (IS_ERR(rdev)) { if (IS_ERR(rdev)) {
err = PTR_ERR(rdev); err = PTR_ERR(rdev);
goto out_put_netdev; goto out_put_netdev;
@ -3312,7 +3330,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -3369,6 +3387,8 @@ static int nl80211_crypto_settings(struct genl_info *info,
struct cfg80211_crypto_settings *settings, struct cfg80211_crypto_settings *settings,
int cipher_limit) int cipher_limit)
{ {
memset(settings, 0, sizeof(*settings));
settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
@ -3448,7 +3468,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -3531,7 +3551,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -3593,7 +3613,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -3666,7 +3686,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -3739,7 +3759,7 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -3924,7 +3944,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
return err; return err;
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -4000,7 +4020,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
rtnl_lock(); rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err) if (err)
goto unlock_rtnl; goto unlock_rtnl;
@ -4024,6 +4044,47 @@ unlock_rtnl:
return err; return err;
} }
static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
struct net *net;
int err;
u32 pid;
if (!info->attrs[NL80211_ATTR_PID])
return -EINVAL;
pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
rtnl_lock();
rdev = cfg80211_get_dev_from_info(info);
if (IS_ERR(rdev)) {
err = PTR_ERR(rdev);
goto out;
}
net = get_net_ns_by_pid(pid);
if (IS_ERR(net)) {
err = PTR_ERR(net);
goto out;
}
err = 0;
/* check if anything to do */
if (net_eq(wiphy_net(&rdev->wiphy), net))
goto out_put_net;
err = cfg80211_switch_netns(rdev, net);
out_put_net:
put_net(net);
out:
cfg80211_unlock_rdev(rdev);
rtnl_unlock();
return err;
}
static struct genl_ops nl80211_ops[] = { static struct genl_ops nl80211_ops[] = {
{ {
.cmd = NL80211_CMD_GET_WIPHY, .cmd = NL80211_CMD_GET_WIPHY,
@ -4257,6 +4318,12 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
}, },
{
.cmd = NL80211_CMD_SET_WIPHY_NETNS,
.doit = nl80211_wiphy_netns,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
}; };
static struct genl_multicast_group nl80211_mlme_mcgrp = { static struct genl_multicast_group nl80211_mlme_mcgrp = {
.name = "mlme", .name = "mlme",
@ -4288,7 +4355,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_config_mcgrp.id, GFP_KERNEL);
} }
static int nl80211_add_scan_req(struct sk_buff *msg, static int nl80211_add_scan_req(struct sk_buff *msg,
@ -4365,7 +4433,8 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_scan_mcgrp.id, GFP_KERNEL);
} }
void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
@ -4383,7 +4452,8 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_scan_mcgrp.id, GFP_KERNEL);
} }
void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
@ -4401,7 +4471,8 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_scan_mcgrp.id, GFP_KERNEL);
} }
/* /*
@ -4450,7 +4521,10 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL); rcu_read_lock();
genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
GFP_ATOMIC);
rcu_read_unlock();
return; return;
@ -4486,7 +4560,8 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
return; return;
nla_put_failure: nla_put_failure:
@ -4553,7 +4628,8 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
return; return;
nla_put_failure: nla_put_failure:
@ -4611,7 +4687,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
return; return;
nla_put_failure: nla_put_failure:
@ -4651,7 +4728,8 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
return; return;
nla_put_failure: nla_put_failure:
@ -4691,7 +4769,8 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, GFP_KERNEL);
return; return;
nla_put_failure: nla_put_failure:
@ -4726,7 +4805,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
return; return;
nla_put_failure: nla_put_failure:
@ -4766,7 +4846,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
return; return;
nla_put_failure: nla_put_failure:
@ -4819,7 +4900,10 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
return; return;
} }
genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); rcu_read_lock();
genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
GFP_ATOMIC);
rcu_read_unlock();
return; return;

View file

@ -14,8 +14,9 @@
#include <net/iw_handler.h> #include <net/iw_handler.h>
#include "core.h" #include "core.h"
#include "nl80211.h" #include "nl80211.h"
#include "wext-compat.h"
#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ)
void __cfg80211_scan_done(struct work_struct *wk) void __cfg80211_scan_done(struct work_struct *wk)
{ {
@ -32,9 +33,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
mutex_lock(&rdev->mtx); mutex_lock(&rdev->mtx);
request = rdev->scan_req; request = rdev->scan_req;
dev = dev_get_by_index(&init_net, request->ifidx); dev = request->dev;
if (!dev)
goto out;
/* /*
* This must be before sending the other events! * This must be before sending the other events!
@ -58,7 +57,6 @@ void __cfg80211_scan_done(struct work_struct *wk)
dev_put(dev); dev_put(dev);
out:
cfg80211_unlock_rdev(rdev); cfg80211_unlock_rdev(rdev);
wiphy_to_dev(request->wiphy)->scan_req = NULL; wiphy_to_dev(request->wiphy)->scan_req = NULL;
kfree(request); kfree(request);
@ -66,17 +64,10 @@ void __cfg80211_scan_done(struct work_struct *wk)
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
{ {
struct net_device *dev = dev_get_by_index(&init_net, request->ifidx);
if (WARN_ON(!dev)) {
kfree(request);
return;
}
WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
request->aborted = aborted; request->aborted = aborted;
schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
dev_put(dev);
} }
EXPORT_SYMBOL(cfg80211_scan_done); EXPORT_SYMBOL(cfg80211_scan_done);
@ -592,7 +583,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
if (!netif_running(dev)) if (!netif_running(dev))
return -ENETDOWN; return -ENETDOWN;
rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
if (IS_ERR(rdev)) if (IS_ERR(rdev))
return PTR_ERR(rdev); return PTR_ERR(rdev);
@ -617,7 +608,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
} }
creq->wiphy = wiphy; creq->wiphy = wiphy;
creq->ifidx = dev->ifindex; creq->dev = dev;
creq->ssids = (void *)(creq + 1); creq->ssids = (void *)(creq + 1);
creq->channels = (void *)(creq->ssids + 1); creq->channels = (void *)(creq->ssids + 1);
creq->n_channels = n_channels; creq->n_channels = n_channels;
@ -654,8 +645,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
if (err) { if (err) {
rdev->scan_req = NULL; rdev->scan_req = NULL;
kfree(creq); kfree(creq);
} else } else {
nl80211_send_scan_start(rdev, dev); nl80211_send_scan_start(rdev, dev);
dev_hold(dev);
}
out: out:
cfg80211_unlock_rdev(rdev); cfg80211_unlock_rdev(rdev);
return err; return err;
@ -948,7 +941,7 @@ int cfg80211_wext_giwscan(struct net_device *dev,
if (!netif_running(dev)) if (!netif_running(dev))
return -ENETDOWN; return -ENETDOWN;
rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
if (IS_ERR(rdev)) if (IS_ERR(rdev))
return PTR_ERR(rdev); return PTR_ERR(rdev);

View file

@ -8,6 +8,8 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include "nl80211.h" #include "nl80211.h"
@ -86,7 +88,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
wdev->conn->params.ssid_len); wdev->conn->params.ssid_len);
request->ssids[0].ssid_len = wdev->conn->params.ssid_len; request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
request->ifidx = wdev->netdev->ifindex; request->dev = wdev->netdev;
request->wiphy = &rdev->wiphy; request->wiphy = &rdev->wiphy;
rdev->scan_req = request; rdev->scan_req = request;
@ -95,6 +97,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
if (!err) { if (!err) {
wdev->conn->state = CFG80211_CONN_SCANNING; wdev->conn->state = CFG80211_CONN_SCANNING;
nl80211_send_scan_start(rdev, wdev->netdev); nl80211_send_scan_start(rdev, wdev->netdev);
dev_hold(wdev->netdev);
} else { } else {
rdev->scan_req = NULL; rdev->scan_req = NULL;
kfree(request); kfree(request);

View file

@ -14,6 +14,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <net/iw_handler.h> #include <net/iw_handler.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "wext-compat.h"
#include "core.h" #include "core.h"
int cfg80211_wext_giwname(struct net_device *dev, int cfg80211_wext_giwname(struct net_device *dev,
@ -300,7 +301,6 @@ struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
return chan; return chan;
} }
EXPORT_SYMBOL_GPL(cfg80211_wext_freq);
int cfg80211_wext_siwrts(struct net_device *dev, int cfg80211_wext_siwrts(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -759,6 +759,58 @@ int cfg80211_wext_giwencode(struct net_device *dev,
} }
EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
int cfg80211_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct ieee80211_channel *chan;
int err;
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra);
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
default:
chan = cfg80211_wext_freq(wdev->wiphy, freq);
if (!chan)
return -EINVAL;
if (IS_ERR(chan))
return PTR_ERR(chan);
err = rdev->ops->set_channel(wdev->wiphy, chan,
NL80211_CHAN_NO_HT);
if (err)
return err;
rdev->channel = chan;
return 0;
}
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
int cfg80211_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
default:
if (!rdev->channel)
return -EINVAL;
freq->m = rdev->channel->center_freq;
freq->e = 6;
return 0;
}
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwfreq);
int cfg80211_wext_siwtxpower(struct net_device *dev, int cfg80211_wext_siwtxpower(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
union iwreq_data *data, char *extra) union iwreq_data *data, char *extra)
@ -1097,9 +1149,9 @@ int cfg80211_wext_giwpower(struct net_device *dev,
} }
EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower); EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower);
int cfg80211_wds_wext_siwap(struct net_device *dev, static int cfg80211_wds_wext_siwap(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct sockaddr *addr, char *extra) struct sockaddr *addr, char *extra)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@ -1125,11 +1177,10 @@ int cfg80211_wds_wext_siwap(struct net_device *dev,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cfg80211_wds_wext_siwap);
int cfg80211_wds_wext_giwap(struct net_device *dev, static int cfg80211_wds_wext_giwap(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
struct sockaddr *addr, char *extra) struct sockaddr *addr, char *extra)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
@ -1141,7 +1192,6 @@ int cfg80211_wds_wext_giwap(struct net_device *dev,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap);
int cfg80211_wext_siwrate(struct net_device *dev, int cfg80211_wext_siwrate(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -1275,3 +1325,115 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
return &wstats; return &wstats;
} }
EXPORT_SYMBOL_GPL(cfg80211_wireless_stats); EXPORT_SYMBOL_GPL(cfg80211_wireless_stats);
int cfg80211_wext_siwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
switch (wdev->iftype) {
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
case NL80211_IFTYPE_STATION:
return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
case NL80211_IFTYPE_WDS:
return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra);
default:
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwap);
int cfg80211_wext_giwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
switch (wdev->iftype) {
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
case NL80211_IFTYPE_STATION:
return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
case NL80211_IFTYPE_WDS:
return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra);
default:
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwap);
int cfg80211_wext_siwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
switch (wdev->iftype) {
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
case NL80211_IFTYPE_STATION:
return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
default:
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwessid);
int cfg80211_wext_giwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
switch (wdev->iftype) {
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
case NL80211_IFTYPE_STATION:
return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
default:
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid);
static const iw_handler cfg80211_handlers[] = {
[IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname,
[IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq,
[IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq,
[IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode,
[IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode,
[IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange,
[IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap,
[IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap,
[IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme,
[IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan,
[IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan,
[IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid,
[IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid,
[IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate,
[IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate,
[IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts,
[IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts,
[IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag,
[IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag,
[IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower,
[IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower,
[IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry,
[IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry,
[IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode,
[IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode,
[IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower,
[IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower,
[IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie,
[IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth,
[IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth,
[IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext,
};
const struct iw_handler_def cfg80211_wext_handler = {
.num_standard = ARRAY_SIZE(cfg80211_handlers),
.standard = cfg80211_handlers,
.get_wireless_stats = cfg80211_wireless_stats,
};

View file

@ -0,0 +1,50 @@
#ifndef __WEXT_COMPAT
#define __WEXT_COMPAT
#include <net/iw_handler.h>
#include <linux/wireless.h>
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_ibss_wext_siwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra);
int cfg80211_ibss_wext_giwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra);
int cfg80211_ibss_wext_siwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
int cfg80211_ibss_wext_giwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
int cfg80211_mgd_wext_siwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra);
int cfg80211_mgd_wext_giwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra);
int cfg80211_mgd_wext_siwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
int cfg80211_mgd_wext_giwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
struct iw_freq *freq);
extern const struct iw_handler_def cfg80211_wext_handler;
#endif /* __WEXT_COMPAT */

View file

@ -8,6 +8,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "wext-compat.h"
#include "nl80211.h" #include "nl80211.h"
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
@ -108,8 +109,6 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
cfg80211_unlock_rdev(rdev); cfg80211_unlock_rdev(rdev);
return err; return err;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq);
int cfg80211_mgd_wext_giwfreq(struct net_device *dev, int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -138,8 +137,6 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
/* no channel if not joining */ /* no channel if not joining */
return -EINVAL; return -EINVAL;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwfreq);
int cfg80211_mgd_wext_siwessid(struct net_device *dev, int cfg80211_mgd_wext_siwessid(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -195,8 +192,6 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
return err; return err;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid);
int cfg80211_mgd_wext_giwessid(struct net_device *dev, int cfg80211_mgd_wext_giwessid(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -221,8 +216,6 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
return 0; return 0;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwessid);
int cfg80211_mgd_wext_siwap(struct net_device *dev, int cfg80211_mgd_wext_siwap(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -276,8 +269,6 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
return err; return err;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap);
int cfg80211_mgd_wext_giwap(struct net_device *dev, int cfg80211_mgd_wext_giwap(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -302,8 +293,6 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev,
return 0; return 0;
} }
/* temporary symbol - mark GPL - in the future the handler won't be */
EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwap);
int cfg80211_wext_siwgenie(struct net_device *dev, int cfg80211_wext_siwgenie(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,